Version 0.4.0.0 .

Revert change 18601 in trunk.
svn merge -r 18562:18904  https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 18912 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@18915 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/dart.gyp b/dart.gyp
index c988d74..860d4464 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -95,6 +95,14 @@
       ],
     },
     {
+      'target_name': 'analyzer',
+      'type': 'none',
+      'dependencies': [
+        'create_sdk',
+        'editor/analyzer.gyp:analyzer',
+      ],
+    },
+    {
       # This is the target that is built on the dartc bots.
       # It must depend on anything that is required by dartc
       # tests.
diff --git a/pkg/args/lib/src/usage.dart b/pkg/args/lib/src/usage.dart
index 72525e2..b83a2d5 100644
--- a/pkg/args/lib/src/usage.dart
+++ b/pkg/args/lib/src/usage.dart
@@ -170,7 +170,7 @@
   writeLine(int column, String text) {
     // Write any pending newlines.
     while (newlinesNeeded > 0) {
-      buffer.add('\n');
+      buffer.write('\n');
       newlinesNeeded--;
     }
 
@@ -178,19 +178,19 @@
     // to the next line.
     while (currentColumn != column) {
       if (currentColumn < NUM_COLUMNS - 1) {
-        buffer.add(padRight('', columnWidths[currentColumn]));
+        buffer.write(padRight('', columnWidths[currentColumn]));
       } else {
-        buffer.add('\n');
+        buffer.write('\n');
       }
       currentColumn = (currentColumn + 1) % NUM_COLUMNS;
     }
 
     if (column < columnWidths.length) {
       // Fixed-size column, so pad it.
-      buffer.add(padRight(text, columnWidths[column]));
+      buffer.write(padRight(text, columnWidths[column]));
     } else {
       // The last column, so just write it.
-      buffer.add(text);
+      buffer.write(text);
     }
 
     // Advance to the next column.
@@ -210,17 +210,17 @@
 
   buildAllowedList(Option option) {
     var allowedBuffer = new StringBuffer();
-    allowedBuffer.add('[');
+    allowedBuffer.write('[');
     bool first = true;
     for (var allowed in option.allowed) {
-      if (!first) allowedBuffer.add(', ');
-      allowedBuffer.add(allowed);
+      if (!first) allowedBuffer.write(', ');
+      allowedBuffer.write(allowed);
       if (allowed == option.defaultValue) {
-        allowedBuffer.add(' (default)');
+        allowedBuffer.write(' (default)');
       }
       first = false;
     }
-    allowedBuffer.add(']');
+    allowedBuffer.write(']');
     return allowedBuffer.toString();
   }
 }
@@ -228,11 +228,11 @@
 /** Pads [source] to [length] by adding spaces at the end. */
 String padRight(String source, int length) {
   final result = new StringBuffer();
-  result.add(source);
+  result.write(source);
 
   while (result.length < length) {
-    result.add(' ');
+    result.write(' ');
   }
 
   return result.toString();
-}
\ No newline at end of file
+}
diff --git a/pkg/fixnum/lib/src/int32.dart b/pkg/fixnum/lib/src/int32.dart
index bbff8a0..2aad272 100644
--- a/pkg/fixnum/lib/src/int32.dart
+++ b/pkg/fixnum/lib/src/int32.dart
@@ -288,7 +288,7 @@
     return _i == _convert(other);
   }
 
-  int compareTo(Comparable other) {
+  int compareTo(other) {
     if (other is int64) {
       return this.toInt64().compareTo(other);
     }
diff --git a/pkg/http/lib/src/io_client.dart b/pkg/http/lib/src/io_client.dart
index 47fb1f0..9bbb7ee 100644
--- a/pkg/http/lib/src/io_client.dart
+++ b/pkg/http/lib/src/io_client.dart
@@ -24,67 +24,38 @@
   Future<StreamedResponse> send(BaseRequest request) {
     var stream = request.finalize();
 
-    var completer = new Completer<StreamedResponse>();
-    var connection = _inner.openUrl(request.method, request.url);
-    bool completed = false;
-    connection.followRedirects = request.followRedirects;
-    connection.maxRedirects = request.maxRedirects;
-    connection.onError = (e) {
-      async.then((_) {
-        // TODO(nweiz): issue 4974 means that any errors that appear in the
-        // onRequest or onResponse callbacks get passed to onError. If the
-        // completer has already fired, we want to re-throw those exceptions
-        // to the top level so that they aren't silently ignored.
-        if (completed) throw e;
-
-        completed = true;
-        completer.completeError(e);
-      });
-    };
-
-    var pipeCompleter = new Completer();
-    connection.onRequest = (underlyingRequest) {
-      underlyingRequest.contentLength = request.contentLength;
-      underlyingRequest.persistentConnection = request.persistentConnection;
+    return _inner.openUrl(request.method, request.url).then((ioRequest) {
+      ioRequest.followRedirects = request.followRedirects;
+      ioRequest.maxRedirects = request.maxRedirects;
+      ioRequest.contentLength = request.contentLength;
+      ioRequest.persistentConnection = request.persistentConnection;
       request.headers.forEach((name, value) {
-        underlyingRequest.headers.set(name, value);
+        ioRequest.headers.set(name, value);
       });
-
-      chainToCompleter(
-          stream.pipe(wrapOutputStream(underlyingRequest.outputStream)),
-          pipeCompleter);
-    };
-
-    connection.onResponse = (response) {
+      return Future.wait([stream.pipe(ioRequest), ioRequest.response])
+          .then((list) => list[1]);
+    }).then((response) {
       var headers = {};
       response.headers.forEach((key, values) {
         headers[key] = values.join(',');
       });
 
-      if (completed) return;
-
-      completed = true;
-      completer.complete(new StreamedResponse(
-          wrapInputStream(response.inputStream),
+      return new StreamedResponse(
+          response,
           response.statusCode,
           response.contentLength,
           request: request,
           headers: headers,
           isRedirect: response.isRedirect,
           persistentConnection: response.persistentConnection,
-          reasonPhrase: response.reasonPhrase));
-    };
-
-    return Future.wait([
-      completer.future,
-      pipeCompleter.future
-    ]).then((values) => values.first);
+          reasonPhrase: response.reasonPhrase);
+    });
   }
 
   /// Closes the client. This terminates all active connections. If a client
   /// remains unclosed, the Dart process may not terminate.
   void close() {
-    if (_inner != null) _inner.shutdown(force: true);
+    if (_inner != null) _inner.close(force: true);
     _inner = null;
   }
 }
diff --git a/pkg/http/lib/src/multipart_file.dart b/pkg/http/lib/src/multipart_file.dart
index a0b50cb..50f4704 100644
--- a/pkg/http/lib/src/multipart_file.dart
+++ b/pkg/http/lib/src/multipart_file.dart
@@ -87,7 +87,7 @@
       {String filename, ContentType contentType}) {
     if (filename == null) filename = new Path(file.name).filename;
     return file.length().then((length) {
-      var stream = wrapInputStream(file.openInputStream());
+      var stream = new ByteStream(file.openRead());
       return new MultipartFile(field, stream, length,
           filename: filename,
           contentType: contentType);
diff --git a/pkg/http/lib/src/multipart_request.dart b/pkg/http/lib/src/multipart_request.dart
index b311b8e..b89c839 100644
--- a/pkg/http/lib/src/multipart_request.dart
+++ b/pkg/http/lib/src/multipart_request.dart
@@ -73,7 +73,7 @@
   ///
   /// This doesn't need to be closed. When the request is sent, whichever files
   /// are written to this sink at that point will be used.
-  StreamSink<MultipartFile> get files => _files;
+  CollectionSink<MultipartFile> get files => _files;
 
   /// The private version of [files], typed so that the underlying collection is
   /// accessible.
diff --git a/pkg/http/test/client_test.dart b/pkg/http/test/client_test.dart
index fd056c9..e101f28 100644
--- a/pkg/http/test/client_test.dart
+++ b/pkg/http/test/client_test.dart
@@ -13,48 +13,51 @@
 import 'utils.dart';
 
 void main() {
-  setUp(startServer);
   tearDown(stopServer);
 
   test('#send a StreamedRequest', () {
-    var client = new http.Client();
-    var request = new http.StreamedRequest("POST", serverUrl);
-    request.headers[HttpHeaders.CONTENT_TYPE] =
-      'application/json; charset=utf-8';
+    expect(startServer().then((_) {
+      var client = new http.Client();
+      var request = new http.StreamedRequest("POST", serverUrl);
+      request.headers[HttpHeaders.CONTENT_TYPE] =
+        'application/json; charset=utf-8';
 
-    expect(client.send(request).then((response) {
-      expect(response.request, equals(request));
-      expect(response.statusCode, equals(200));
-      expect(response.headers['single'], equals('value'));
-      // dart:io internally normalizes outgoing headers so that they never have
-      // multiple headers with the same name, so there's no way to test whether
-      // we handle that case correctly.
+      expect(client.send(request).then((response) {
+        expect(response.request, equals(request));
+        expect(response.statusCode, equals(200));
+        expect(response.headers['single'], equals('value'));
+        // dart:io internally normalizes outgoing headers so that they never
+        // have multiple headers with the same name, so there's no way to test
+        // whether we handle that case correctly.
 
-      return response.stream.bytesToString();
-    }).whenComplete(client.close), completion(parse(equals({
-      'method': 'POST',
-      'path': '/',
-      'headers': {
-        'content-type': ['application/json; charset=utf-8'],
-        'transfer-encoding': ['chunked']
-      },
-      'body': '{"hello": "world"}'
-    }))));
+        return response.stream.bytesToString();
+      }).whenComplete(client.close), completion(parse(equals({
+        'method': 'POST',
+        'path': '/',
+        'headers': {
+          'content-type': ['application/json; charset=utf-8'],
+          'transfer-encoding': ['chunked']
+        },
+        'body': '{"hello": "world"}'
+      }))));
 
-    request.sink.add('{"hello": "world"}'.charCodes);
-    request.sink.close();
+      request.sink.add('{"hello": "world"}'.charCodes);
+      request.sink.close();
+    }), completes);
   });
 
   test('#send with an invalid URL', () {
-    var client = new http.Client();
-    var url = Uri.parse('http://http.invalid');
-    var request = new http.StreamedRequest("POST", url);
-    request.headers[HttpHeaders.CONTENT_TYPE] =
-        'application/json; charset=utf-8';
+    expect(startServer().then((_) {
+      var client = new http.Client();
+      var url = Uri.parse('http://http.invalid');
+      var request = new http.StreamedRequest("POST", url);
+      request.headers[HttpHeaders.CONTENT_TYPE] =
+          'application/json; charset=utf-8';
 
-    expect(client.send(request), throwsSocketIOException);
+      expect(client.send(request), throwsSocketIOException);
 
-    request.sink.add('{"hello": "world"}'.charCodes);
-    request.sink.close();
+      request.sink.add('{"hello": "world"}'.charCodes);
+      request.sink.close();
+    }), completes);
   });
 }
diff --git a/pkg/http/test/http_test.dart b/pkg/http/test/http_test.dart
index 48eada0..9c567cf 100644
--- a/pkg/http/test/http_test.dart
+++ b/pkg/http/test/http_test.dart
@@ -12,23 +12,161 @@
 
 main() {
   group('http.', () {
-    setUp(startServer);
     tearDown(stopServer);
 
     test('head', () {
-      expect(http.head(serverUrl).then((response) {
-        expect(response.statusCode, equals(200));
-        expect(response.body, equals(''));
+      expect(startServer().then((_) {
+        expect(http.head(serverUrl).then((response) {
+          expect(response.statusCode, equals(200));
+          expect(response.body, equals(''));
+        }), completes);
       }), completes);
     });
 
     test('get', () {
-      expect(http.get(serverUrl, headers: {
-        'X-Random-Header': 'Value',
-        'X-Other-Header': 'Other Value'
-      }).then((response) {
-        expect(response.statusCode, equals(200));
-        expect(response.body, parse(equals({
+      expect(startServer().then((_) {
+        expect(http.get(serverUrl, headers: {
+          'X-Random-Header': 'Value',
+          'X-Other-Header': 'Other Value'
+        }).then((response) {
+          expect(response.statusCode, equals(200));
+          expect(response.body, parse(equals({
+            'method': 'GET',
+            'path': '/',
+            'headers': {
+              'content-length': ['0'],
+              'x-random-header': ['Value'],
+              'x-other-header': ['Other Value']
+            },
+          })));
+        }), completes);
+      }), completes);
+    });
+
+    test('post', () {
+      expect(startServer().then((_) {
+        expect(http.post(serverUrl, headers: {
+          'X-Random-Header': 'Value',
+          'X-Other-Header': 'Other Value'
+        }, fields: {
+          'some-field': 'value',
+          'other-field': 'other value'
+        }).then((response) {
+          expect(response.statusCode, equals(200));
+          expect(response.body, parse(equals({
+            'method': 'POST',
+            'path': '/',
+            'headers': {
+              'content-type': [
+                'application/x-www-form-urlencoded; charset=UTF-8'
+              ],
+              'content-length': ['40'],
+              'x-random-header': ['Value'],
+              'x-other-header': ['Other Value']
+            },
+            'body': 'some-field=value&other-field=other+value'
+          })));
+        }), completes);
+      }), completes);
+    });
+
+    test('post without fields', () {
+      expect(startServer().then((_) {
+        expect(http.post(serverUrl, headers: {
+          'X-Random-Header': 'Value',
+          'X-Other-Header': 'Other Value',
+          'Content-Type': 'text/plain'
+        }).then((response) {
+          expect(response.statusCode, equals(200));
+          expect(response.body, parse(equals({
+            'method': 'POST',
+            'path': '/',
+            'headers': {
+              'content-length': ['0'],
+              'content-type': ['text/plain'],
+              'x-random-header': ['Value'],
+              'x-other-header': ['Other Value']
+            }
+          })));
+        }), completes);
+      }), completes);
+    });
+
+    test('put', () {
+      expect(startServer().then((_) {
+        expect(http.put(serverUrl, headers: {
+          'X-Random-Header': 'Value',
+          'X-Other-Header': 'Other Value'
+        }, fields: {
+          'some-field': 'value',
+          'other-field': 'other value'
+        }).then((response) {
+          expect(response.statusCode, equals(200));
+          expect(response.body, parse(equals({
+            'method': 'PUT',
+            'path': '/',
+            'headers': {
+              'content-type': [
+                'application/x-www-form-urlencoded; charset=UTF-8'
+              ],
+              'content-length': ['40'],
+              'x-random-header': ['Value'],
+              'x-other-header': ['Other Value']
+            },
+            'body': 'some-field=value&other-field=other+value'
+          })));
+        }), completes);
+      }), completes);
+    });
+
+    test('put without fields', () {
+      expect(startServer().then((_) {
+        expect(http.put(serverUrl, headers: {
+          'X-Random-Header': 'Value',
+          'X-Other-Header': 'Other Value',
+          'Content-Type': 'text/plain'
+        }).then((response) {
+          expect(response.statusCode, equals(200));
+          expect(response.body, parse(equals({
+            'method': 'PUT',
+            'path': '/',
+            'headers': {
+              'content-length': ['0'],
+              'content-type': ['text/plain'],
+              'x-random-header': ['Value'],
+              'x-other-header': ['Other Value']
+            }
+          })));
+        }), completes);
+      }), completes);
+    });
+
+    test('delete', () {
+      expect(startServer().then((_) {
+        expect(http.delete(serverUrl, headers: {
+          'X-Random-Header': 'Value',
+          'X-Other-Header': 'Other Value'
+        }).then((response) {
+          expect(response.statusCode, equals(200));
+          expect(response.body, parse(equals({
+            'method': 'DELETE',
+            'path': '/',
+            'headers': {
+              'content-length': ['0'],
+              'x-random-header': ['Value'],
+              'x-other-header': ['Other Value']
+            }
+          })));
+        }), completes);
+      }), completes);
+    });
+
+    test('read', () {
+      expect(startServer().then((_) {
+        expect(http.read(serverUrl, headers: {
+          'X-Random-Header': 'Value',
+          'X-Other-Header': 'Other Value'
+        }).then((val) => val), completion(parse(equals({
           'method': 'GET',
           'path': '/',
           'headers': {
@@ -36,156 +174,39 @@
             'x-random-header': ['Value'],
             'x-other-header': ['Other Value']
           },
-        })));
+        }))));
       }), completes);
     });
 
-    test('post', () {
-      expect(http.post(serverUrl, headers: {
-        'X-Random-Header': 'Value',
-        'X-Other-Header': 'Other Value'
-      }, fields: {
-        'some-field': 'value',
-        'other-field': 'other value'
-      }).then((response) {
-        expect(response.statusCode, equals(200));
-        expect(response.body, parse(equals({
-          'method': 'POST',
-          'path': '/',
-          'headers': {
-            'content-type': [
-              'application/x-www-form-urlencoded; charset=UTF-8'
-            ],
-            'content-length': ['40'],
-            'x-random-header': ['Value'],
-            'x-other-header': ['Other Value']
-          },
-          'body': 'some-field=value&other-field=other+value'
-        })));
-      }), completes);
-    });
-
-    test('post without fields', () {
-      expect(http.post(serverUrl, headers: {
-        'X-Random-Header': 'Value',
-        'X-Other-Header': 'Other Value',
-        'Content-Type': 'text/plain'
-      }).then((response) {
-        expect(response.statusCode, equals(200));
-        expect(response.body, parse(equals({
-          'method': 'POST',
-          'path': '/',
-          'headers': {
-            'content-length': ['0'],
-            'content-type': ['text/plain'],
-            'x-random-header': ['Value'],
-            'x-other-header': ['Other Value']
-          }
-        })));
-      }), completes);
-    });
-
-    test('put', () {
-      expect(http.put(serverUrl, headers: {
-        'X-Random-Header': 'Value',
-        'X-Other-Header': 'Other Value'
-      }, fields: {
-        'some-field': 'value',
-        'other-field': 'other value'
-      }).then((response) {
-        expect(response.statusCode, equals(200));
-        expect(response.body, parse(equals({
-          'method': 'PUT',
-          'path': '/',
-          'headers': {
-            'content-type': [
-              'application/x-www-form-urlencoded; charset=UTF-8'
-            ],
-            'content-length': ['40'],
-            'x-random-header': ['Value'],
-            'x-other-header': ['Other Value']
-          },
-          'body': 'some-field=value&other-field=other+value'
-        })));
-      }), completes);
-    });
-
-    test('put without fields', () {
-      expect(http.put(serverUrl, headers: {
-        'X-Random-Header': 'Value',
-        'X-Other-Header': 'Other Value',
-        'Content-Type': 'text/plain'
-      }).then((response) {
-        expect(response.statusCode, equals(200));
-        expect(response.body, parse(equals({
-          'method': 'PUT',
-          'path': '/',
-          'headers': {
-            'content-length': ['0'],
-            'content-type': ['text/plain'],
-            'x-random-header': ['Value'],
-            'x-other-header': ['Other Value']
-          }
-        })));
-      }), completes);
-    });
-
-    test('delete', () {
-      expect(http.delete(serverUrl, headers: {
-        'X-Random-Header': 'Value',
-        'X-Other-Header': 'Other Value'
-      }).then((response) {
-        expect(response.statusCode, equals(200));
-        expect(response.body, parse(equals({
-          'method': 'DELETE',
-          'path': '/',
-          'headers': {
-            'content-length': ['0'],
-            'x-random-header': ['Value'],
-            'x-other-header': ['Other Value']
-          }
-        })));
-      }), completes);
-    });
-
-    test('read', () {
-      expect(http.read(serverUrl, headers: {
-        'X-Random-Header': 'Value',
-        'X-Other-Header': 'Other Value'
-      }).then((val) => val), completion(parse(equals({
-        'method': 'GET',
-        'path': '/',
-        'headers': {
-          'content-length': ['0'],
-          'x-random-header': ['Value'],
-          'x-other-header': ['Other Value']
-        },
-      }))));
-    });
-
     test('read throws an error for a 4** status code', () {
-      expect(http.read(serverUrl.resolve('/error')), throwsHttpException);
+      expect(startServer().then((_) {
+        expect(http.read(serverUrl.resolve('/error')), throwsHttpException);
+      }), completes);
     });
 
     test('readBytes', () {
-      var future = http.readBytes(serverUrl, headers: {
-        'X-Random-Header': 'Value',
-        'X-Other-Header': 'Other Value'
-      }).then((bytes) => new String.fromCharCodes(bytes));
+      expect(startServer().then((_) {
+        var future = http.readBytes(serverUrl, headers: {
+          'X-Random-Header': 'Value',
+          'X-Other-Header': 'Other Value'
+        }).then((bytes) => new String.fromCharCodes(bytes));
 
-      expect(future, completion(parse(equals({
-        'method': 'GET',
-        'path': '/',
-        'headers': {
-          'content-length': ['0'],
-          'x-random-header': ['Value'],
-          'x-other-header': ['Other Value']
-        },
-      }))));
+        expect(future, completion(parse(equals({
+          'method': 'GET',
+          'path': '/',
+          'headers': {
+            'content-length': ['0'],
+            'x-random-header': ['Value'],
+            'x-other-header': ['Other Value']
+          },
+        }))));
+      }), completes);
     });
 
     test('readBytes throws an error for a 4** status code', () {
-      expect(http.readBytes(serverUrl.resolve('/error')), throwsHttpException);
+      expect(startServer().then((_) {
+        expect(http.readBytes(serverUrl.resolve('/error')), throwsHttpException);
+      }), completes);
     });
   });
 }
diff --git a/pkg/http/test/request_test.dart b/pkg/http/test/request_test.dart
index 843cdab..1f009b9 100644
--- a/pkg/http/test/request_test.dart
+++ b/pkg/http/test/request_test.dart
@@ -13,23 +13,24 @@
 
 void main() {
   test('.send', () {
-    startServer();
+    expect(startServer().then((_) {
 
-    var request = new http.Request('POST', serverUrl);
-    request.body = "hello";
+      var request = new http.Request('POST', serverUrl);
+      request.body = "hello";
 
-    expect(request.send().then((response) {
-      expect(response.statusCode, equals(200));
-      return response.stream.bytesToString();
-    }).whenComplete(stopServer), completion(parse(equals({
-      'method': 'POST',
-      'path': '/',
-      'headers': {
-        'content-type': ['text/plain; charset=UTF-8'],
-        'content-length': ['5']
-      },
-      'body': 'hello'
-    }))));
+      expect(request.send().then((response) {
+        expect(response.statusCode, equals(200));
+        return response.stream.bytesToString();
+      }).whenComplete(stopServer), completion(parse(equals({
+        'method': 'POST',
+        'path': '/',
+        'headers': {
+          'content-type': ['text/plain; charset=UTF-8'],
+          'content-length': ['5']
+        },
+        'body': 'hello'
+      }))));
+    }), completes);
   });
 
   group('#contentLength', () {
@@ -183,47 +184,49 @@
     print("This test is known to be flaky, please ignore "
           "(debug prints below added by sgjesse@)");
     print("#followRedirects test starting server...");
-    startServer();
-    print("#followRedirects test server running");
+    expect(startServer().then((_) {
+      print("#followRedirects test server running");
 
-    var request = new http.Request('POST', serverUrl.resolve('/redirect'))
-        ..followRedirects = false;
-    var future = request.send().then((response) {
-      print("#followRedirects test response received");
-      expect(response.statusCode, equals(302));
-    });
-    future.catchError((_) {}).then(expectAsync1((_) {
-      print("#followRedirects test stopping server...");
-      stopServer();
-      print("#followRedirects test server stopped");
-    }));
+      var request = new http.Request('POST', serverUrl.resolve('/redirect'))
+          ..followRedirects = false;
+      var future = request.send().then((response) {
+        print("#followRedirects test response received");
+        expect(response.statusCode, equals(302));
+      });
+      expect(future.catchError((_) {}).then((_) {
+        print("#followRedirects test stopping server...");
+        stopServer();
+        print("#followRedirects test server stopped");
+      }), completes);
 
-    expect(future, completes);
-    print("#followRedirects test started");
+      expect(future, completes);
+      print("#followRedirects test started");
+    }), completes);
   });
 
   test('#maxRedirects', () {
     print("This test is known to be flaky, please ignore "
           "(debug prints below added by sgjesse@)");
     print("#maxRedirects test starting server...");
-    startServer();
-    print("#maxRedirects test server running");
+    expect(startServer().then((_) {
+      print("#maxRedirects test server running");
 
-    var request = new http.Request('POST', serverUrl.resolve('/loop?1'))
-      ..maxRedirects = 2;
-    var future = request.send().catchError((e) {
-      print("#maxRedirects test exception received");
-      expect(e.error, isRedirectLimitExceededException);
-      expect(e.error.redirects.length, equals(2));
-    });
-    future.catchError((_) {}).then(expectAsync1((_) {
-      print("#maxRedirects test stopping server...");
-      stopServer();
-      print("#maxRedirects test server stopped");
-    }));
+      var request = new http.Request('POST', serverUrl.resolve('/loop?1'))
+        ..maxRedirects = 2;
+      var future = request.send().catchError((e) {
+        print("#maxRedirects test exception received");
+        expect(e.error, isRedirectLimitExceededException);
+        expect(e.error.redirects.length, equals(2));
+      });
+      expect(future.catchError((_) {}).then((_) {
+        print("#maxRedirects test stopping server...");
+        stopServer();
+        print("#maxRedirects test server stopped");
+      }), completes);
 
-    expect(future, completes);
-    print("#maxRedirects test started");
+      expect(future, completes);
+      print("#maxRedirects test started");
+    }), completes);
   });
 
   group('content-type header', () {
diff --git a/pkg/http/test/utils.dart b/pkg/http/test/utils.dart
index 10067d2..606bb77 100644
--- a/pkg/http/test/utils.dart
+++ b/pkg/http/test/utils.dart
@@ -10,6 +10,7 @@
 import 'dart:uri';
 
 import 'package:unittest/unittest.dart';
+import 'package:http/src/byte_stream.dart';
 import 'package:http/http.dart' as http;
 import 'package:http/src/utils.dart';
 
@@ -23,81 +24,83 @@
 Uri get dummyUrl => Uri.parse('http://dartlang.org/');
 
 /// Starts a new HTTP server.
-void startServer() {
-  _server = new HttpServer();
+Future startServer() {
+  return HttpServer.bind("127.0.0.1", 0).then((s) {
+    _server = s;
+    s.listen((request) {
+      var path = request.uri.path;
+      var response = request.response;
 
-  _server.addRequestHandler((request) => request.path == '/error',
-      (request, response) {
-    response.statusCode = 400;
-    response.contentLength = 0;
-    response.outputStream.close();
-  });
+      if (path == '/error') {
+        response.statusCode = 400;
+        response.contentLength = 0;
+        response.close();
+        return;
+      }
 
-  _server.addRequestHandler((request) => request.path == '/loop',
-      (request, response) {
-    var n = int.parse(Uri.parse(request.uri).query);
-    response.statusCode = 302;
-    response.headers.set('location',
-        serverUrl.resolve('/loop?${n + 1}').toString());
-    response.contentLength = 0;
-    response.outputStream.close();
-  });
+      if (path == '/loop') {
+        var n = int.parse(request.uri.query);
+        response.statusCode = 302;
+        response.headers.set('location',
+            serverUrl.resolve('/loop?${n + 1}').toString());
+        response.contentLength = 0;
+        response.close();
+        return;
+      }
 
-  _server.addRequestHandler((request) => request.path == '/redirect',
-      (request, response) {
-    response.statusCode = 302;
-    response.headers.set('location', serverUrl.resolve('/').toString());
-    response.contentLength = 0;
-    response.outputStream.close();
-  });
+      if (path == '/redirect') {
+        response.statusCode = 302;
+        response.headers.set('location', serverUrl.resolve('/').toString());
+        response.contentLength = 0;
+        response.close();
+        return;
+      }
 
-  _server.defaultRequestHandler = (request, response) {
-    consumeInputStream(request.inputStream).then((requestBodyBytes) {
-      response.statusCode = 200;
-      response.headers.contentType = new ContentType("application", "json");
+      new ByteStream(request).toBytes().then((requestBodyBytes) {
+        response.statusCode = 200;
+        response.headers.contentType = new ContentType("application", "json");
       response.headers.set('single', 'value');
 
-      var requestBody;
-      if (requestBodyBytes.isEmpty) {
-        requestBody = null;
-      } else if (request.headers.contentType.charset != null) {
-        var encoding = requiredEncodingForCharset(
-            request.headers.contentType.charset);
-        requestBody = decodeString(requestBodyBytes, encoding);
-      } else {
-        requestBody = requestBodyBytes;
-      }
+        var requestBody;
+        if (requestBodyBytes.isEmpty) {
+          requestBody = null;
+        } else if (request.headers.contentType.charset != null) {
+          var encoding = requiredEncodingForCharset(
+              request.headers.contentType.charset);
+          requestBody = decodeString(requestBodyBytes, encoding);
+        } else {
+          requestBody = requestBodyBytes;
+        }
 
-      var content = {
-        'method': request.method,
-        'path': request.path,
-        'headers': {}
-      };
-      if (requestBody != null) content['body'] = requestBody;
-      request.headers.forEach((name, values) {
-        // These headers are automatically generated by dart:io, so we don't
-        // want to test them here.
-        if (name == 'cookie' || name == 'host') return;
+        var content = {
+          'method': request.method,
+          'path': request.uri.path,
+          'headers': {}
+        };
+        if (requestBody != null) content['body'] = requestBody;
+        request.headers.forEach((name, values) {
+          // These headers are automatically generated by dart:io, so we don't
+          // want to test them here.
+          if (name == 'cookie' || name == 'host') return;
 
-        content['headers'][name] = values;
+          content['headers'][name] = values;
+        });
+
+        var outputEncoding;
+        var encodingName = request.queryParameters['response-encoding'];
+        if (encodingName != null) {
+          outputEncoding = requiredEncodingForCharset(encodingName);
+        } else {
+          outputEncoding = Encoding.ASCII;
+        }
+
+        var body = json.stringify(content);
+        response.contentLength = body.length;
+        response.addString(body, outputEncoding);
+        response.close();
       });
-
-      var outputEncoding;
-      var encodingName = request.queryParameters['response-encoding'];
-      if (encodingName != null) {
-        outputEncoding = requiredEncodingForCharset(encodingName);
-      } else {
-        outputEncoding = Encoding.ASCII;
-      }
-
-      var body = json.stringify(content);
-      response.contentLength = body.length;
-      response.outputStream.writeString(body, outputEncoding);
-      response.outputStream.close();
     });
-  };
-
-  _server.listen("127.0.0.1", 0);
+  });
 }
 
 /// Stops the current HTTP server.
@@ -106,11 +109,6 @@
   _server = null;
 }
 
-// TODO(nweiz): remove this once issue 7785 is fixed.
-/// Buffers all input from an InputStream and returns it as a future.
-Future<List<int>> consumeInputStream(InputStream stream) =>
-  new http.ByteStream(wrapInputStream(stream)).toBytes();
-
 /// A matcher that matches JSON that parses to a value that matches the inner
 /// matcher.
 Matcher parse(matcher) => new _Parse(matcher);
diff --git a/pkg/intl/test/date_time_format_http_request_test.dart b/pkg/intl/test/date_time_format_http_request_test.dart
index 139cf6d..65bc87b 100644
--- a/pkg/intl/test/date_time_format_http_request_test.dart
+++ b/pkg/intl/test/date_time_format_http_request_test.dart
@@ -21,7 +21,7 @@
 
 main() {
   useHtmlConfiguration();
-  url = "http://localhost:${window.location.port}/pkg/intl/lib/src/data/dates/";
+  url = "http://localhost:${window.location.port}/root_dart/pkg/intl/lib/src/data/dates/";
   // Initialize one locale just so we know what the list is.
   test('Run everything', () {
     initializeDateFormatting("en_US", url).then(expectAsync1(runEverything));});
diff --git a/pkg/intl/tool/generate_locale_data_files.dart b/pkg/intl/tool/generate_locale_data_files.dart
index b999926..a6fe140 100644
--- a/pkg/intl/tool/generate_locale_data_files.dart
+++ b/pkg/intl/tool/generate_locale_data_files.dart
@@ -29,23 +29,24 @@
 
 void writeLocaleList() {
   var file = new File('${dataDirectory}localeList.dart');
-  var outputStream = file.openOutputStream();
-  outputStream.writeString(
+  var output = file.openWrite();
+  output.addString(
       '// Copyright (c) 2012, the Dart project authors.  Please see the '
       'AUTHORS file\n// for details. All rights reserved. Use of this source'
       'code is governed by a\n// BSD-style license that can be found in the'
       ' LICENSE file.\n\n'
       '/// Hard-coded list of all available locales for dates.\n');
-  outputStream.writeString('final availableLocalesForDateFormatting = const [');
+  output.addString('final availableLocalesForDateFormatting = const [');
   List<String> allLocales = DateFormat.allLocalesWithSymbols();
   allLocales.forEach((locale) {
-    outputStream.writeString('"$locale"');
+    output.addString('"$locale"');
     if (locale == allLocales.last) {
-      outputStream.writeString('];');
+      output.addString('];');
     } else {
-      outputStream.writeString(',\n    ');
+      output.addString(',\n    ');
     }
   });
+  output.close();
 }
 
 void writeSymbolData() {
@@ -60,18 +61,18 @@
 
 void writeSymbols(locale, symbols) {
   var file = new File('${dataDirectory}symbols/${locale}.json');
-  var outputStream = file.openOutputStream();
-  writeToJSON(symbols, outputStream);
-  outputStream.close();
+  var output = file.openWrite();
+  writeToJSON(symbols, output);
+  output.close();
 }
 
 void writePatterns(locale, patterns) {
   var file = new File('${dataDirectory}patterns/${locale}.json');
-  var outputStream = file.openOutputStream();
-  outputStream.writeString(json.stringify(patterns));
-  outputStream.close();
+  var output = file.openWrite();
+  output.addString(json.stringify(patterns));
+  output.close();
 }
 
-void writeToJSON(dynamic data, OutputStream out) {
-  out.writeString(json.stringify(data.serializeToMap()));
+void writeToJSON(dynamic data, IOSink out) {
+  out.addString(json.stringify(data.serializeToMap()));
 }
diff --git a/pkg/logging/lib/logging.dart b/pkg/logging/lib/logging.dart
index 5e0a239..935b3ae 100644
--- a/pkg/logging/lib/logging.dart
+++ b/pkg/logging/lib/logging.dart
@@ -247,7 +247,7 @@
  * own level, make sure you use a value between those used in [Level.ALL] and
  * [Level.OFF].
  */
-class Level implements Comparable {
+class Level implements Comparable<Level> {
 
   // TODO(sigmund): mark name/value as 'const' when the language supports it.
   final String name;
diff --git a/pkg/path/lib/path.dart b/pkg/path/lib/path.dart
index 3bd2332..9e540b2 100644
--- a/pkg/path/lib/path.dart
+++ b/pkg/path/lib/path.dart
@@ -112,6 +112,23 @@
             String part5, String part6, String part7, String part8]) =>
   _builder.join(part1, part2, part3, part4, part5, part6, part7, part8);
 
+/// Joins the given path parts into a single path using the current platform's
+/// [separator]. Example:
+///
+///     path.joinAll(['path', 'to', 'foo']); // -> 'path/to/foo'
+///
+/// If any part ends in a path separator, then a redundant separator will not
+/// be added:
+///
+///     path.joinAll(['path/', 'to', 'foo']); // -> 'path/to/foo
+///
+/// If a part is an absolute path, then anything before that will be ignored:
+///
+///     path.joinAll(['path', '/to', 'foo']); // -> '/to/foo'
+///
+/// For a fixed number of parts, [join] is usually terser.
+String joinAll(Iterable<String> parts) => _builder.joinAll(parts);
+
 // TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
 /// Splits [path] into its components using the current platform's [separator].
 ///
@@ -321,15 +338,30 @@
   ///
   String join(String part1, [String part2, String part3, String part4,
               String part5, String part6, String part7, String part8]) {
+    var parts = [part1, part2, part3, part4, part5, part6, part7, part8];
+    _validateArgList("join", parts);
+    return joinAll(parts.where((part) => part != null));
+  }
+
+  /// Joins the given path parts into a single path. Example:
+  ///
+  ///     builder.joinAll(['path', 'to', 'foo']); // -> 'path/to/foo'
+  ///
+  /// If any part ends in a path separator, then a redundant separator will not
+  /// be added:
+  ///
+  ///     builder.joinAll(['path/', 'to', 'foo']); // -> 'path/to/foo
+  ///
+  /// If a part is an absolute path, then anything before that will be ignored:
+  ///
+  ///     builder.joinAll(['path', '/to', 'foo']); // -> '/to/foo'
+  ///
+  /// For a fixed number of parts, [join] is usually terser.
+  String joinAll(Iterable<String> parts) {
     var buffer = new StringBuffer();
     var needsSeparator = false;
 
-    var parts = [part1, part2, part3, part4, part5, part6, part7, part8];
-    _validateArgList("join", parts);
-
     for (var part in parts) {
-      if (part == null) continue;
-
       if (this.isAbsolute(part)) {
         // An absolute path discards everything before it.
         buffer.clear();
diff --git a/pkg/path/test/path_posix_test.dart b/pkg/path/test/path_posix_test.dart
index e1c3942..763035f 100644
--- a/pkg/path/test/path_posix_test.dart
+++ b/pkg/path/test/path_posix_test.dart
@@ -161,6 +161,25 @@
     });
   });
 
+  group('joinAll', () {
+    test('allows more than eight parts', () {
+      expect(builder.joinAll(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']),
+          'a/b/c/d/e/f/g/h/i');
+    });
+
+    test('does not add separator if a part ends in one', () {
+      expect(builder.joinAll(['a/', 'b', 'c/', 'd']), 'a/b/c/d');
+      expect(builder.joinAll(['a\\', 'b']), r'a\/b');
+    });
+
+    test('ignores parts before an absolute path', () {
+      expect(builder.joinAll(['a', '/', 'b', 'c']), '/b/c');
+      expect(builder.joinAll(['a', '/b', '/c', 'd']), '/c/d');
+      expect(builder.joinAll(['a', r'c:\b', 'c', 'd']), r'a/c:\b/c/d');
+      expect(builder.joinAll(['a', r'\\b', 'c', 'd']), r'a/\\b/c/d');
+    });
+  });
+
   group('split', () {
     test('simple cases', () {
       expect(builder.split(''), []);
diff --git a/pkg/path/test/path_windows_test.dart b/pkg/path/test/path_windows_test.dart
index 12e370b..8164224 100644
--- a/pkg/path/test/path_windows_test.dart
+++ b/pkg/path/test/path_windows_test.dart
@@ -180,6 +180,26 @@
     });
   });
 
+  group('joinAll', () {
+    test('allows more than eight parts', () {
+      expect(builder.joinAll(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']),
+          r'a\b\c\d\e\f\g\h\i');
+    });
+
+    test('does not add separator if a part ends or begins in one', () {
+      expect(builder.joinAll([r'a\', 'b', r'c\', 'd']), r'a\b\c\d');
+      expect(builder.joinAll(['a/', 'b']), r'a/b');
+      expect(builder.joinAll(['a', '/b']), 'a/b');
+      expect(builder.joinAll(['a', r'\b']), r'a\b');
+    });
+
+    test('ignores parts before an absolute path', () {
+      expect(builder.joinAll(['a', '/b', '/c', 'd']), r'a/b/c\d');
+      expect(builder.joinAll(['a', r'c:\b', 'c', 'd']), r'c:\b\c\d');
+      expect(builder.joinAll(['a', r'\\b', r'\\c', 'd']), r'\\c\d');
+    });
+  });
+
   group('split', () {
     test('simple cases', () {
       expect(builder.split(''), []);
diff --git a/pkg/scheduled_test/lib/scheduled_test.dart b/pkg/scheduled_test/lib/scheduled_test.dart
index 05fb9f0..456e50b3 100644
--- a/pkg/scheduled_test/lib/scheduled_test.dart
+++ b/pkg/scheduled_test/lib/scheduled_test.dart
@@ -109,7 +109,8 @@
 /// It's important that errors in these callbacks are still registered, though,
 /// and that [Schedule.onException] and [Schedule.onComplete] still run after
 /// they finish. When using `unittest`, you wrap these callbacks with
-/// `expectAsyncN`; when using `scheduled_test`, you use [wrapAsync].
+/// `expectAsyncN`; when using `scheduled_test`, you use [wrapAsync] or
+/// [wrapFuture].
 ///
 /// [wrapAsync] has two important functions. First, any errors that occur in it
 /// will be passed into the [Schedule] instead of causing the whole test to
@@ -139,6 +140,25 @@
 ///       });
 ///     }
 ///
+/// [wrapFuture] works similarly to [wrapAsync], but instead of wrapping a
+/// single callback it wraps a whole [Future] chain. Like [wrapAsync], it
+/// ensures that the task queue doesn't complete until the out-of-band chain has
+/// finished, and that any errors in the chain are piped back into the scheduled
+/// test. For example:
+///
+///     import 'package:scheduled_test/scheduled_test.dart';
+///
+///     void main() {
+///       test('sendRequest sends a request', () {
+///         wrapFuture(server.nextRequest.then((request) {
+///           expect(request.body, equals('payload'));
+///           expect(request.headers['content-type'], equals('text/plain'));
+///         }));
+///
+///         schedule(() => sendRequest('payload'));
+///       });
+///     }
+///
 /// ## Timeouts
 ///
 /// `scheduled_test` has a built-in timeout of 30 seconds (configurable via
@@ -244,7 +264,10 @@
 /// If [description] is passed, it's used to describe the task for debugging
 /// purposes when an error occurs.
 ///
-/// This function is identical to [currentSchedule.tasks.schedule].
+/// If this is called when a task queue is currently running, it will run [fn]
+/// on the next event loop iteration rather than adding it to a queue. The
+/// current task will not complete until [fn] (and any [Future] it returns) has
+/// finished running. Any errors in [fn] will automatically be handled.
 Future schedule(fn(), [String description]) =>
   currentSchedule.tasks.schedule(fn, description);
 
@@ -302,3 +325,18 @@
     return currentSchedule.wrapAsync(f);
   };
 }
+
+/// Like [wrapAsync], this ensures that the current task queue waits for
+/// out-of-band asynchronous code, and that errors raised in that code are
+/// handled correctly. However, [wrapFuture] wraps a [Future] chain rather than
+/// a single callback.
+///
+/// The returned [Future] completes to the same value or error as [future].
+Future wrapFuture(Future future) {
+  if (currentSchedule == null) {
+    throw new StateError("Unexpected call to wrapFuture with no current "
+        "schedule.");
+  }
+
+  return currentSchedule.wrapFuture(future);
+}
diff --git a/pkg/scheduled_test/lib/src/future_group.dart b/pkg/scheduled_test/lib/src/future_group.dart
new file mode 100644
index 0000000..213f0fc
--- /dev/null
+++ b/pkg/scheduled_test/lib/src/future_group.dart
@@ -0,0 +1,49 @@
+// 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 future_group;
+
+import 'dart:async';
+
+/// A completer that waits until all added [Future]s complete.
+// TODO(rnystrom): Copied from web_components. Remove from here when it gets
+// added to dart:core. (See #6626.)
+class FutureGroup<T> {
+  int _pending = 0;
+  Completer<List<T>> _completer = new Completer<List<T>>();
+  final List<Future<T>> futures = <Future<T>>[];
+  bool completed = false;
+
+  final List<T> _values = <T>[];
+
+  /// Wait for [task] to complete.
+  Future<T> add(Future<T> task) {
+    if (completed) {
+      throw new StateError("The FutureGroup has already completed.");
+    }
+
+    _pending++;
+    futures.add(task.then((value) {
+      if (completed) return;
+
+      _pending--;
+      _values.add(value);
+
+      if (_pending <= 0) {
+        completed = true;
+        _completer.complete(_values);
+      }
+    }).catchError((e) {
+      if (completed) return;
+
+      completed = true;
+      _completer.completeError(e.error, e.stackTrace);
+    }));
+
+    return task;
+  }
+
+  Future<List> get future => _completer.future;
+}
+
diff --git a/pkg/scheduled_test/lib/src/schedule.dart b/pkg/scheduled_test/lib/src/schedule.dart
index 58a1487..ac601ea 100644
--- a/pkg/scheduled_test/lib/src/schedule.dart
+++ b/pkg/scheduled_test/lib/src/schedule.dart
@@ -127,19 +127,22 @@
       try {
         setUp();
       } catch (e, stackTrace) {
+        // Even though the scheduling failed, we need to run the onException and
+        // onComplete queues, so we set the schedule state to RUNNING.
+        _state = ScheduleState.RUNNING;
         throw new ScheduleError.from(this, e, stackTrace: stackTrace);
       }
 
       _state = ScheduleState.RUNNING;
       return tasks._run();
     }).catchError((e) {
-      errors.add(e);
+      _addError(e);
       return onException._run().catchError((innerError) {
         // If an error occurs in a task in the onException queue, make sure it's
         // registered in the error list and re-throw it. We could also re-throw
         // `e`; ultimately, all the errors will be shown to the user if any
         // ScheduleError is thrown.
-        errors.add(innerError);
+        _addError(innerError);
         throw innerError;
       }).then((_) {
         // If there are no errors in the onException queue, re-throw the
@@ -150,7 +153,7 @@
       return onComplete._run().catchError((e) {
         // If an error occurs in a task in the onComplete queue, make sure it's
         // registered in the error list and re-throw it.
-        errors.add(e);
+        _addError(e);
         throw e;
       });
     }).whenComplete(() {
@@ -189,7 +192,7 @@
   void _signalPostTimeoutError(error, [stackTrace]) {
     var scheduleError = new ScheduleError.from(this, error,
         stackTrace: stackTrace);
-    errors.add(scheduleError);
+    _addError(scheduleError);
     if (_state == ScheduleState.DONE) {
       throw new StateError(
         "An out-of-band error was caught after the test timed out.\n"
@@ -203,7 +206,7 @@
   /// out-of-band callbacks are properly handled by the scheduled test.
   ///
   /// The top-level `wrapAsync` function should usually be used in preference to
-  /// this.
+  /// this in test code.
   Function wrapAsync(fn(arg)) {
     if (_state == ScheduleState.DONE) {
       throw new StateError("wrapAsync called after the schedule has finished "
@@ -237,6 +240,35 @@
     };
   }
 
+  /// Like [wrapAsync], this ensures that the current task queue waits for
+  /// out-of-band asynchronous code, and that errors raised in that code are
+  /// handled correctly. However, [wrapFuture] wraps a [Future] chain rather
+  /// than a single callback.
+  ///
+  /// The returned [Future] completes to the same value or error as [future].
+  ///
+  /// The top-level `wrapFuture` function should usually be used in preference
+  /// to this in test code.
+  Future wrapFuture(Future future) {
+    var doneCallback = wrapAsync((_) => null);
+    done() => new Future.immediate(null).then(doneCallback);
+
+    future = future.then((result) {
+      done();
+      return result;
+    }).catchError((e) {
+      signalError(e);
+      done();
+      throw e;
+    });
+
+    // Don't top-level the error, since it's already been signaled to the
+    // schedule.
+    future.catchError((_) => null);
+
+    return future;
+  }
+
   /// Returns a string representation of all errors registered on this schedule.
   String errorString() {
     if (errors.isEmpty) return "The schedule had no errors.";
@@ -285,6 +317,14 @@
     if (_noPendingCallbacks == null) _noPendingCallbacks = new Completer();
     return _noPendingCallbacks.future;
   }
+
+  /// Register an error in the schedule's error list. This ensures that there
+  /// are no duplicate errors, and that all errors are wrapped in
+  /// [ScheduleError].
+  void _addError(error) {
+    if (errors.contains(error)) return;
+    errors.add(new ScheduleError.from(this, error));
+  }
 }
 
 /// An enum of states for a [Schedule].
@@ -333,6 +373,10 @@
 
   TaskQueue._(this.name, this._schedule);
 
+  /// Whether this queue is currently running.
+  bool get isRunning => _schedule.state == ScheduleState.RUNNING &&
+      _schedule.currentQueue == this;
+
   /// Schedules a task, [fn], to run asynchronously as part of this queue. Tasks
   /// will be run in the order they're scheduled. In [fn] returns a [Future],
   /// tasks after it won't be run until that [Future] completes.
@@ -343,8 +387,23 @@
   ///
   /// If [description] is passed, it's used to describe the task for debugging
   /// purposes when an error occurs.
+  ///
+  /// If this is called when this queue is currently running, it will run [fn]
+  /// on the next event loop iteration rather than adding it to a queue--this is
+  /// known as a "nested task". The current task will not complete until [fn]
+  /// (and any [Future] it returns) has finished running. Any errors in [fn]
+  /// will automatically be handled. Nested tasks run in parallel, unlike
+  /// top-level tasks which run in sequence.
   Future schedule(fn(), [String description]) {
-    var task = new Task(fn, this, description);
+    if (isRunning) {
+      var task = _schedule.currentTask;
+      var wrappedFn = () => _schedule.wrapFuture(
+          new Future.immediate(null).then((_) => fn()));
+      if (task == null) return wrappedFn();
+      return task.runChild(wrappedFn, description);
+    }
+
+    var task = new Task(fn, description, this);
     _contents.add(task);
     return task.result;
   }
@@ -362,7 +421,7 @@
         _taskFuture = null;
         _schedule.heartbeat();
       }).catchError((e) {
-        if (_error != null) _schedule.errors.add(_error);
+        if (_error != null) _schedule._addError(_error);
         throw new ScheduleError.from(_schedule, e);
       });
     }).whenComplete(() {
@@ -379,7 +438,7 @@
   void _signalError(ScheduleError error) {
     // If multiple errors are detected while a task is running, make sure the
     // earlier ones are recorded in the schedule.
-    if (_error != null) _schedule.errors.add(_error);
+    if (_error != null) _schedule._addError(_error);
     _error = error;
   }
 
diff --git a/pkg/scheduled_test/lib/src/schedule_error.dart b/pkg/scheduled_test/lib/src/schedule_error.dart
index 76d6e00..d36be02 100644
--- a/pkg/scheduled_test/lib/src/schedule_error.dart
+++ b/pkg/scheduled_test/lib/src/schedule_error.dart
@@ -26,13 +26,15 @@
   /// The state of the schedule at the time the error was detected.
   final ScheduleState _stateWhenDetected;
 
+  int get hashCode => schedule.hashCode ^ task.hashCode ^ queue.hashCode ^
+      _stateWhenDetected.hashCode ^ error.hashCode ^ stackTrace.hashCode ^
+      cause.hashCode;
+
   /// Creates a new [ScheduleError] wrapping [error]. The metadata in
   /// [AsyncError]s and [ScheduleError]s will be preserved.
   factory ScheduleError.from(Schedule schedule, error, {stackTrace,
       AsyncError cause}) {
-    if (error is ScheduleError) {
-      if (schedule == null) schedule = error.schedule;
-    }
+    if (error is ScheduleError) return error;
 
     if (error is AsyncError) {
       // Overwrite the explicit stack trace, because it probably came from a
@@ -52,6 +54,11 @@
         this.queue = schedule.currentQueue,
         this._stateWhenDetected = schedule.state;
 
+  bool operator ==(other) => other is ScheduleError && task == other.task &&
+      queue == other.queue && _stateWhenDetected == other._stateWhenDetected &&
+      error == other.error && stackTrace == other.stackTrace &&
+      cause == other.cause;
+
   String toString() {
     var result = new StringBuffer();
 
diff --git a/pkg/scheduled_test/lib/src/task.dart b/pkg/scheduled_test/lib/src/task.dart
index 558a9cd..0819bd0 100644
--- a/pkg/scheduled_test/lib/src/task.dart
+++ b/pkg/scheduled_test/lib/src/task.dart
@@ -5,25 +5,49 @@
 library task;
 
 import 'dart:async';
+import 'dart:collection';
 
+import 'future_group.dart';
 import 'schedule.dart';
 import 'utils.dart';
 
 typedef Future TaskBody();
 
 /// A single task to be run as part of a [TaskQueue].
+///
+/// There are two levels of tasks. **Top-level tasks** are created by calling
+/// [TaskQueue.schedule] before the queue in question is running. They're run in
+/// sequence as part of that [TaskQueue]. **Nested tasks** are created by
+/// calling [TaskQueue.schedule] once the queue is already running, and are run
+/// in parallel as part of a top-level task.
 class Task {
   /// The queue to which this [Task] belongs.
   final TaskQueue queue;
 
+  // TODO(nweiz): make this a read-only view when issue 8321 is fixed.
+  /// Child tasks that have been spawned while running this task. This will be
+  /// empty if this task is a nested task.
+  final children = new Queue<Task>();
+
+  /// A [FutureGroup] that will complete once all current child tasks are
+  /// finished running. This will be null if no child tasks are currently
+  /// running.
+  FutureGroup _childGroup;
+
   /// A description of this task. Used for debugging. May be `null`.
   final String description;
 
+  /// The parent task, if this is a nested task that was started while another
+  /// task was running. This will be `null` for top-level tasks.
+  final Task parent;
+
   /// The body of the task.
   TaskBody fn;
 
-  /// The identifier of the task. This is unique within [queue]. It's used for
-  /// debugging when [description] isn't provided.
+  /// The identifier of the task. For top-level tasks, this is the index of the
+  /// task within [queue]; for nested tasks, this is the index within
+  /// [parent.children]. It's used for debugging when [description] isn't
+  /// provided.
   int _id;
 
   /// A Future that will complete to the return value of [fn] once this task
@@ -31,10 +55,19 @@
   Future get result => _resultCompleter.future;
   final _resultCompleter = new Completer();
 
-  Task(fn(), this.queue, this.description) {
-    _id = this.queue.contents.length;
+  Task(fn(), String description, TaskQueue queue)
+    : this._(fn, description, queue, null, queue.contents.length);
+
+  Task._child(fn(), String description, Task parent)
+    : this._(fn, description, parent.queue, parent, parent.children.length);
+
+  Task._(fn(), this.description, this.queue, this.parent, this._id) {
     this.fn = () {
-      var future = new Future.immediate(null).then((_) => fn());
+      var future = new Future.immediate(null).then((_) => fn())
+          .whenComplete(() {
+        if (_childGroup == null || _childGroup.completed) return;
+        return _childGroup.future;
+      });
       chainToCompleter(future, _resultCompleter);
       return future;
     };
@@ -44,6 +77,22 @@
     result.catchError((_) {});
   }
 
+  /// Run [fn] as a child of this task. Returns a Future that will complete with
+  /// the result of the child task. This task will not complete until [fn] has
+  /// finished.
+  Future runChild(fn(), String description) {
+    var task = new Task._child(fn, description, this);
+    children.add(task);
+    if (_childGroup == null || _childGroup.completed) {
+      _childGroup = new FutureGroup();
+    }
+    // Ignore errors in the FutureGroup; they'll get picked up via wrapFuture,
+    // and we don't want them to short-circuit the other Futures.
+    _childGroup.add(task.result.catchError((_) {}));
+    task.fn();
+    return task.result;
+  }
+
   String toString() => description == null ? "#$_id" : description;
 
   /// Returns a detailed representation of [queue] with this task highlighted.
diff --git a/pkg/scheduled_test/test/scheduled_test_test.dart b/pkg/scheduled_test/test/scheduled_test_test.dart
index dcf5bea..f07024d 100644
--- a/pkg/scheduled_test/test/scheduled_test_test.dart
+++ b/pkg/scheduled_test/test/scheduled_test_test.dart
@@ -142,6 +142,74 @@
     });
   });
 
+  expectTestsFail('an out-of-band failure in wrapFuture is handled', () {
+    mock_clock.mock().run();
+    test('test', () {
+      schedule(() {
+        wrapFuture(sleep(1).then((_) => expect('foo', equals('bar'))));
+      });
+      schedule(() => sleep(2));
+    });
+  });
+
+  expectTestsFail('an out-of-band failure in wrapFuture that finishes after '
+      'the schedule is handled', () {
+    mock_clock.mock().run();
+    test('test', () {
+      schedule(() {
+        wrapFuture(sleep(2).then((_) => expect('foo', equals('bar'))));
+      });
+      schedule(() => sleep(1));
+    });
+  });
+
+  expectTestsPass("wrapFuture should return the value of the wrapped future",
+      () {
+    test('test', () {
+      schedule(() {
+        expect(wrapFuture(pumpEventQueue().then((_) => 'foo')),
+            completion(equals('foo')));
+      });
+    });
+  });
+
+  expectTestsPass("wrapFuture should pass through the error of the wrapped "
+      "future", () {
+    var error;
+    test('test 1', () {
+      schedule(() {
+        wrapFuture(pumpEventQueue().then((_) {
+          throw 'error';
+        })).catchError(wrapAsync((e) {
+          error = e.error;
+        }));
+      });
+    });
+
+    test('test 2', () {
+      expect(error, equals('error'));
+    });
+  }, passing: ['test 2']);
+
+  expectTestsPass("scheduled blocks whose return values are passed to "
+      "wrapFuture should report exceptions once", () {
+    var errors;
+    test('test 1', () {
+      currentSchedule.onException.schedule(() {
+        errors = currentSchedule.errors;
+      });
+
+      wrapFuture(schedule(() {
+        throw 'error';
+      }));
+    });
+
+    test('test 2', () {
+      expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
+      expect(errors.map((e) => e.error), equals(['error']));
+    });
+  }, passing: ['test 2']);
+
   expectTestsFail('an out-of-band error reported via signalError is '
       'handled', () {
     mock_clock.mock().run();
@@ -524,6 +592,40 @@
     });
   }, passing: ['test 2']);
 
+  expectTestsPass('currentSchedule.errors contains multiple out-of-band errors '
+      'from both the main task queue and onException in onComplete reported '
+      'via wrapFuture', () {
+    mock_clock.mock().run();
+    var errors;
+    test('test 1', () {
+      currentSchedule.onComplete.schedule(() {
+        errors = currentSchedule.errors;
+      });
+
+      currentSchedule.onException.schedule(() {
+        wrapFuture(sleep(1).then((_) {
+          throw 'error3';
+        }));
+        wrapFuture(sleep(2).then((_) {
+          throw 'error4';
+        }));
+      });
+
+      wrapFuture(sleep(1).then((_) {
+        throw 'error1';
+      }));
+      wrapFuture(sleep(2).then((_) {
+        throw 'error2';
+      }));
+    });
+
+    test('test 2', () {
+      expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
+      expect(errors.map((e) => e.error),
+          orderedEquals(['error1', 'error2', 'error3', 'error4']));
+    });
+  }, passing: ['test 2']);
+
   expectTestsPass('currentSchedule.errors contains both an out-of-band error '
       'and an error raised afterwards in a task', () {
     mock_clock.mock().run();
@@ -917,4 +1019,158 @@
 
   // TODO(nweiz): test out-of-band post-timeout errors that are detected after
   // the test finishes once we can detect top-level errors (issue 8417).
+
+  expectTestsPass("nested schedule() runs its function immediately (but "
+      "asynchronously)", () {
+    test('test', () {
+      schedule(() {
+        var nestedScheduleRun = false;
+        schedule(() {
+          nestedScheduleRun = true;
+        });
+
+        expect(nestedScheduleRun, isFalse);
+        expect(pumpEventQueue().then((_) => nestedScheduleRun),
+            completion(isTrue));
+      });
+    });
+  });
+
+  expectTestsPass("out-of-band schedule() runs its function immediately (but "
+      "asynchronously)", () {
+    mock_clock.mock().run();
+    test('test', () {
+      schedule(() {
+        wrapFuture(sleep(1).then((_) {
+          var nestedScheduleRun = false;
+          schedule(() {
+            nestedScheduleRun = true;
+          });
+
+          expect(nestedScheduleRun, isFalse);
+          expect(pumpEventQueue().then((_) => nestedScheduleRun),
+              completion(isTrue));
+        }));
+      });
+    });
+  });
+
+  expectTestsPass("nested schedule() calls don't wait for one another", () {
+    mock_clock.mock().run();
+    test('test', () {
+      var sleepFinished = false;
+      schedule(() {
+        schedule(() => sleep(1).then((_) {
+          sleepFinished = true;
+        }));
+        schedule(() => expect(sleepFinished, isFalse));
+      });
+    });
+  });
+
+  expectTestsPass("nested schedule() calls block their parent task", () {
+    mock_clock.mock().run();
+    test('test', () {
+      var sleepFinished = false;
+      schedule(() {
+        schedule(() => sleep(1).then((_) {
+          sleepFinished = true;
+        }));
+      });
+
+      schedule(() => expect(sleepFinished, isTrue));
+    });
+  });
+
+  expectTestsPass("out-of-band schedule() calls block their parent queue", () {
+    mock_clock.mock().run();
+    test('test', () {
+      var scheduleRun = false;
+      wrapFuture(sleep(1).then((_) {
+        schedule(() => sleep(1).then((_) {
+          scheduleRun = true;
+        }));
+      }));
+
+      currentSchedule.onComplete.schedule(() => expect(scheduleRun, isTrue));
+    });
+  });
+
+  expectTestsPass("nested schedule() calls forward their Future values", () {
+    mock_clock.mock().run();
+    test('test', () {
+      schedule(() {
+        expect(schedule(() => 'foo'), completion(equals('foo')));
+      });
+    });
+  });
+
+  expectTestsPass("errors in nested schedule() calls are properly registered",
+      () {
+    var errors;
+    test('test 1', () {
+      currentSchedule.onException.schedule(() {
+        errors = currentSchedule.errors;
+      });
+
+      schedule(() {
+        schedule(() {
+          throw 'error';
+        });
+      });
+    });
+
+    test('test 2', () {
+      expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
+      expect(errors.map((e) => e.error), equals(['error']));
+    });
+  }, passing: ['test 2']);
+
+  expectTestsPass("nested scheduled blocks whose return values are passed to "
+      "wrapFuture should report exceptions once", () {
+    var errors;
+    test('test 1', () {
+      currentSchedule.onException.schedule(() {
+        errors = currentSchedule.errors;
+      });
+
+      schedule(() {
+        wrapFuture(schedule(() {
+          throw 'error';
+        }));
+
+        return pumpEventQueue();
+      });
+    });
+
+    test('test 2', () {
+      expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
+      expect(errors.map((e) => e.error), equals(['error']));
+    });
+  }, passing: ['test 2']);
+
+  expectTestsPass("a nested task failing shouldn't short-circuit the parent "
+      "task", () {
+    var parentTaskFinishedBeforeOnComplete = false;
+    test('test 1', () {
+      var parentTaskFinished = false;
+      currentSchedule.onComplete.schedule(() {
+        parentTaskFinishedBeforeOnComplete = parentTaskFinished;
+      });
+
+      schedule(() {
+        schedule(() {
+          throw 'error';
+        });
+
+        return sleep(1).then((_) {
+          parentTaskFinished = true;
+        });
+      });
+    });
+
+    test('test 2', () {
+      expect(parentTaskFinishedBeforeOnComplete, isTrue);
+    });
+  }, passing: ['test 2']);
 }
diff --git a/pkg/serialization/lib/src/basic_rule.dart b/pkg/serialization/lib/src/basic_rule.dart
index 303a9e1..19a8bca 100644
--- a/pkg/serialization/lib/src/basic_rule.dart
+++ b/pkg/serialization/lib/src/basic_rule.dart
@@ -271,7 +271,7 @@
  * This represents a field in an object. It is intended to be used as part of
  * a [_FieldList].
  */
-abstract class _Field implements Comparable {
+abstract class _Field implements Comparable<_Field> {
 
   /** The FieldList that contains us. */
   final _FieldList fieldList;
diff --git a/pkg/unittest/lib/compact_vm_config.dart b/pkg/unittest/lib/compact_vm_config.dart
index 6b46a65..ede7010 100644
--- a/pkg/unittest/lib/compact_vm_config.dart
+++ b/pkg/unittest/lib/compact_vm_config.dart
@@ -89,24 +89,24 @@
     var duration = (new DateTime.now()).difference(startTime);
     var buffer = new StringBuffer();
     // \r moves back to the beginnig of the current line.
-    buffer.add('\r${_timeString(duration)} ');
-    buffer.add(_GREEN);
-    buffer.add('+');
-    buffer.add(passed);
-    buffer.add(_NONE);
-    if (failed != 0) buffer.add(_RED);
-    buffer.add(' -');
-    buffer.add(failed);
-    if (failed != 0) buffer.add(_NONE);
-    buffer.add(': ');
-    buffer.add(color);
+    buffer.write('\r${_timeString(duration)} ');
+    buffer.write(_GREEN);
+    buffer.write('+');
+    buffer.write(passed);
+    buffer.write(_NONE);
+    if (failed != 0) buffer.write(_RED);
+    buffer.write(' -');
+    buffer.write(failed);
+    if (failed != 0) buffer.write(_NONE);
+    buffer.write(': ');
+    buffer.write(color);
 
     int nonVisible = _nonVisiblePrefix + color.length  +
         (failed != 0 ? (_RED.length + _NONE.length) : 0);
     int len = buffer.length - nonVisible;
     var mx = MAX_LINE - len;
-    buffer.add(_snippet(message, MAX_LINE - len));
-    buffer.add(_NONE);
+    buffer.write(_snippet(message, MAX_LINE - len));
+    buffer.write(_NONE);
 
     // Pad the rest of the line so that it looks erased.
     len = buffer.length - nonVisible - _NONE.length;
@@ -114,11 +114,11 @@
       _lastLength = len;
     } else {
       while (len < _lastLength) {
-        buffer.add(' ');
+        buffer.write(' ');
         _lastLength--;
       }
     }
-    stdout.writeString(buffer.toString());
+    stdout.addString(buffer.toString());
   }
 
   String _padTime(int time) =>
@@ -146,11 +146,11 @@
       if (i < words.length - 4) {
         // Require at least 3 words at the end.
         var buffer = new StringBuffer();
-        buffer.add(words.first);
-        buffer.add(' ...');
+        buffer.write(words.first);
+        buffer.write(' ...');
         for (; i < words.length; i++) {
-          buffer.add(' ');
-          buffer.add(words[i]);
+          buffer.write(' ');
+          buffer.write(words[i]);
         }
         return buffer.toString();
       }
diff --git a/pkg/unittest/lib/html_config.dart b/pkg/unittest/lib/html_config.dart
index d4c9cdb..9c64b53 100644
--- a/pkg/unittest/lib/html_config.dart
+++ b/pkg/unittest/lib/html_config.dart
@@ -18,17 +18,17 @@
     document.body.innerHtml = "PASS";
   } else {
     var newBody = new StringBuffer();
-    newBody.add("<table class='unittest-table'><tbody>");
-    newBody.add(passed == results.length && uncaughtError == null
+    newBody.write("<table class='unittest-table'><tbody>");
+    newBody.write(passed == results.length && uncaughtError == null
         ? "<tr><td colspan='3' class='unittest-pass'>PASS</td></tr>"
         : "<tr><td colspan='3' class='unittest-fail'>FAIL</td></tr>");
 
     for (final test_ in results) {
-      newBody.add(_toHtml(test_));
+      newBody.write(_toHtml(test_));
     }
 
     if (uncaughtError != null) {
-        newBody.add('''<tr>
+        newBody.write('''<tr>
           <td>--</td>
           <td class="unittest-error">ERROR</td>
           <td>Uncaught error: $uncaughtError</td>
@@ -36,12 +36,12 @@
     }
 
     if (passed == results.length && uncaughtError == null) {
-      newBody.add("""
+      newBody.write("""
           <tr><td colspan='3' class='unittest-pass'>
             All ${passed} tests passed
           </td></tr>""");
     } else {
-      newBody.add("""
+      newBody.write("""
           <tr><td colspan='3'>Total
             <span class='unittest-pass'>${passed} passed</span>,
             <span class='unittest-fail'>${failed} failed</span>
@@ -49,7 +49,7 @@
             ${errors + (uncaughtError == null ? 0 : 1)} errors</span>
           </td></tr>""");
     }
-    newBody.add("</tbody></table>");
+    newBody.write("</tbody></table>");
     document.body.innerHtml = newBody.toString();
   }
 }
diff --git a/pkg/unittest/lib/src/string_matchers.dart b/pkg/unittest/lib/src/string_matchers.dart
index 7f04a0c..933d0a0 100644
--- a/pkg/unittest/lib/src/string_matchers.dart
+++ b/pkg/unittest/lib/src/string_matchers.dart
@@ -74,11 +74,11 @@
     var character = _string[i];
     if (isWhitespace(character)) {
       if (!skipSpace) {
-        result.add(' ');
+        result.write(' ');
         skipSpace = true;
       }
     } else {
-      result.add(character);
+      result.write(character);
       skipSpace = false;
     }
   }
diff --git a/pkg/unittest/lib/test_controller.js b/pkg/unittest/lib/test_controller.js
index 5332c19..34d56ed 100644
--- a/pkg/unittest/lib/test_controller.js
+++ b/pkg/unittest/lib/test_controller.js
@@ -135,6 +135,8 @@
   try {
     main();
   } catch (e) {
+    dartPrint(e);
+    if (e.stack) dartPrint(e.stack);
     window.postMessage('unittest-suite-fail', '*');
     return;
   }
diff --git a/pkg/webdriver/lib/webdriver.dart b/pkg/webdriver/lib/webdriver.dart
index 837836b..ffb0dff 100644
--- a/pkg/webdriver/lib/webdriver.dart
+++ b/pkg/webdriver/lib/webdriver.dart
@@ -52,17 +52,11 @@
  */
 
 void writeStringToFile(String fileName, String contents) {
-  var file = new File(fileName);
-  var ostream = file.openOutputStream(FileMode.WRITE);
-  ostream.writeString(contents);
-  ostream.close();
+  new File(fileName).writeAsStringSync(contents);
 }
 
 void writeBytesToFile(String fileName, List<int> contents) {
-  var file = new File(fileName);
-  var ostream = file.openOutputStream(FileMode.WRITE);
-  ostream.write(contents);
-  ostream.close();
+  new File(fileName).writeAsBytesSync(contents);
 }
 
 class WebDriverError {
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index d2a1657..51d6740 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -4,12 +4,8 @@
 
 {
   'variables': {
-    'crypto_cc_file': '<(SHARED_INTERMEDIATE_DIR)/crypto_gen.cc',
     'io_cc_file': '<(SHARED_INTERMEDIATE_DIR)/io_gen.cc',
     'io_patch_cc_file': '<(SHARED_INTERMEDIATE_DIR)/io_patch_gen.cc',
-    'json_cc_file': '<(SHARED_INTERMEDIATE_DIR)/json_gen.cc',
-    'uri_cc_file': '<(SHARED_INTERMEDIATE_DIR)/uri_gen.cc',
-    'utf_cc_file': '<(SHARED_INTERMEDIATE_DIR)/utf_gen.cc',
     'builtin_in_cc_file': 'builtin_in.cc',
     'builtin_cc_file': '<(SHARED_INTERMEDIATE_DIR)/builtin_gen.cc',
     'snapshot_in_cc_file': 'snapshot_in.cc',
@@ -48,55 +44,6 @@
       ]
     },
     {
-      'target_name': 'generate_crypto_cc_file',
-      'type': 'none',
-      'variables': {
-        'crypto_dart': '<(SHARED_INTERMEDIATE_DIR)/crypto_gen.dart',
-      },
-      'includes': [
-        'crypto_sources.gypi',
-      ],
-      'actions': [
-        {
-          'action_name': 'generate_crypto_dart',
-          'inputs': [
-            '../tools/concat_library.py',
-            '<@(_sources)',
-          ],
-          'outputs': [
-            '<(crypto_dart)',
-          ],
-          'action': [
-            'python',
-            '<@(_inputs)',
-            '--output', '<(crypto_dart)',
-          ],
-          'message': 'Generating ''<(crypto_dart)'' file.',
-        },
-        {
-          'action_name': 'generate_crypto_cc',
-          'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
-            '<(crypto_dart)',
-          ],
-          'outputs': [
-            '<(crypto_cc_file)',
-          ],
-          'action': [
-            'python',
-            'tools/create_string_literal.py',
-            '--output', '<(crypto_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
-            '--include', 'bin/builtin.h',
-            '--var_name', 'Builtin::crypto_source_',
-            '<(crypto_dart)',
-          ],
-          'message': 'Generating ''<(crypto_cc_file)'' file.'
-        },
-      ]
-    },
-    {
       'target_name': 'generate_io_cc_file',
       'type': 'none',
       'variables': {
@@ -179,163 +126,12 @@
       ]
     },
     {
-      'target_name': 'generate_json_cc_file',
-      'type': 'none',
-      'variables': {
-        'json_dart': '<(SHARED_INTERMEDIATE_DIR)/json_gen.dart',
-      },
-      'includes': [
-        'json_sources.gypi',
-      ],
-      'actions': [
-        {
-          'action_name': 'generate_json_dart',
-          'inputs': [
-            '../tools/concat_library.py',
-            '<@(_sources)',
-          ],
-          'outputs': [
-            '<(json_dart)',
-          ],
-          'action': [
-            'python',
-            '<@(_inputs)',
-            '--output', '<(json_dart)',
-          ],
-          'message': 'Generating ''<(json_dart)'' file.',
-        },
-        {
-          'action_name': 'generate_json_cc',
-          'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
-            '<(json_dart)',
-          ],
-          'outputs': [
-            '<(json_cc_file)',
-          ],
-          'action': [
-            'python',
-            'tools/create_string_literal.py',
-            '--output', '<(json_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
-            '--include', 'bin/builtin.h',
-            '--var_name', 'Builtin::json_source_',
-            '<(json_dart)',
-          ],
-          'message': 'Generating ''<(json_cc_file)'' file.'
-        },
-      ]
-    },
-    {
-      'target_name': 'generate_uri_cc_file',
-      'type': 'none',
-      'variables': {
-        'uri_dart': '<(SHARED_INTERMEDIATE_DIR)/uri_gen.dart',
-      },
-      'includes': [
-        'uri_sources.gypi',
-      ],
-      'actions': [
-        {
-          'action_name': 'generate_uri_dart',
-          'inputs': [
-            '../tools/concat_library.py',
-            '<@(_sources)',
-          ],
-          'outputs': [
-            '<(uri_dart)',
-          ],
-          'action': [
-            'python',
-            '<@(_inputs)',
-            '--output', '<(uri_dart)',
-          ],
-          'message': 'Generating ''<(uri_dart)'' file.'
-        },
-        {
-          'action_name': 'generate_uri_cc',
-          'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
-            '<(uri_dart)',
-          ],
-          'outputs': [
-            '<(uri_cc_file)',
-          ],
-          'action': [
-            'python',
-            'tools/create_string_literal.py',
-            '--output', '<(uri_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
-            '--include', 'bin/builtin.h',
-            '--var_name', 'Builtin::uri_source_',
-            '<(uri_dart)',
-          ],
-          'message': 'Generating ''<(uri_cc_file)'' file.'
-        },
-      ]
-    },
-    {
-      'target_name': 'generate_utf_cc_file',
-      'type': 'none',
-      'variables': {
-        'utf_dart': '<(SHARED_INTERMEDIATE_DIR)/utf_gen.dart',
-      },
-      'includes': [
-        'utf_sources.gypi',
-      ],
-      'actions': [
-        {
-          'action_name': 'generate_utf_dart',
-          'inputs': [
-            '../tools/concat_library.py',
-            '<@(_sources)',
-          ],
-          'outputs': [
-            '<(utf_dart)',
-          ],
-          'action': [
-            'python',
-            '<@(_inputs)',
-            '--output', '<(utf_dart)',
-          ],
-          'message': 'Generating ''<(utf_dart)'' file.',
-        },
-        {
-          'action_name': 'generate_utf_cc',
-          'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
-            '<(utf_dart)',
-          ],
-          'outputs': [
-            '<(utf_cc_file)',
-          ],
-          'action': [
-            'python',
-            'tools/create_string_literal.py',
-            '--output', '<(utf_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
-            '--include', 'bin/builtin.h',
-            '--var_name', 'Builtin::utf_source_',
-            '<(utf_dart)',
-          ],
-          'message': 'Generating ''<(utf_cc_file)'' file.'
-        },
-      ]
-    },
-    {
       'target_name': 'libdart_builtin',
       'type': 'static_library',
       'dependencies': [
         'generate_builtin_cc_file',
-        'generate_crypto_cc_file',
         'generate_io_cc_file',
         'generate_io_patch_cc_file',
-        'generate_json_cc_file',
-        'generate_uri_cc_file',
-        'generate_utf_cc_file',
       ],
       'include_dirs': [
         '..',
@@ -459,12 +255,8 @@
         'builtin_gen_snapshot.cc',
         # Include generated source files.
         '<(builtin_cc_file)',
-        '<(crypto_cc_file)',
         '<(io_cc_file)',
         '<(io_patch_cc_file)',
-        '<(json_cc_file)',
-        '<(uri_cc_file)',
-        '<(utf_cc_file)',
       ],
       'conditions': [
         ['OS=="win"', {
@@ -594,12 +386,8 @@
         'builtin.cc',
         # Include generated source files.
         '<(builtin_cc_file)',
-        '<(crypto_cc_file)',
         '<(io_cc_file)',
         '<(io_patch_cc_file)',
-        '<(json_cc_file)',
-        '<(uri_cc_file)',
-        '<(utf_cc_file)',
         'snapshot_empty.cc',
       ],
       'conditions': [
@@ -649,12 +437,8 @@
         'builtin.cc',
         # Include generated source files.
         '<(builtin_cc_file)',
-        '<(crypto_cc_file)',
         '<(io_cc_file)',
         '<(io_patch_cc_file)',
-        '<(json_cc_file)',
-        '<(uri_cc_file)',
-        '<(utf_cc_file)',
       ],
       'includes': [
         'builtin_impl_sources.gypi',
diff --git a/runtime/bin/builtin.cc b/runtime/bin/builtin.cc
index f9218df..2af1339 100644
--- a/runtime/bin/builtin.cc
+++ b/runtime/bin/builtin.cc
@@ -13,12 +13,8 @@
 Builtin::builtin_lib_props Builtin::builtin_libraries_[] = {
   /* { url_, source_, patch_url_, patch_source_, has_natives_ } */
   { DartUtils::kBuiltinLibURL, builtin_source_, NULL, NULL, true },
-  { DartUtils::kJsonLibURL, json_source_, NULL, NULL, false },
-  { DartUtils::kUriLibURL, uri_source_, NULL, NULL, false },
-  { DartUtils::kCryptoLibURL, crypto_source_, NULL, NULL, false },
   { DartUtils::kIOLibURL, io_source_,
     DartUtils::kIOLibPatchURL, io_patch_, true },
-  { DartUtils::kUtfLibURL, utf_source_, NULL, NULL, false }
 };
 
 
diff --git a/runtime/bin/builtin.h b/runtime/bin/builtin.h
index ca33e57..4a33b6c 100644
--- a/runtime/bin/builtin.h
+++ b/runtime/bin/builtin.h
@@ -25,11 +25,7 @@
   // the builtin_libraries_ array in builtin.cc and builtin_nolib.cc.
   enum BuiltinLibraryId {
     kBuiltinLibrary = 0,
-    kJsonLibrary,
-    kUriLibrary,
-    kCryptoLibrary,
     kIOLibrary,
-    kUtfLibrary,
 
     kInvalidLibrary,
   };
@@ -45,14 +41,9 @@
   static Dart_NativeFunction BuiltinNativeLookup(Dart_Handle name,
                                                  int argument_count);
 
-  static const char async_source_[];
   static const char builtin_source_[];
-  static const char crypto_source_[];
   static const char io_source_[];
   static const char io_patch_[];
-  static const char json_source_[];
-  static const char uri_source_[];
-  static const char utf_source_[];
   static const char web_source_[];
 
   typedef struct {
diff --git a/runtime/bin/builtin_gen_snapshot.cc b/runtime/bin/builtin_gen_snapshot.cc
index fd64f46..af68759 100644
--- a/runtime/bin/builtin_gen_snapshot.cc
+++ b/runtime/bin/builtin_gen_snapshot.cc
@@ -13,12 +13,8 @@
 Builtin::builtin_lib_props Builtin::builtin_libraries_[] = {
   /* { url_, source_, patch_url_, patch_source_, has_natives_ } */
   { DartUtils::kBuiltinLibURL, builtin_source_, NULL, NULL, true },
-  { DartUtils::kJsonLibURL, json_source_, NULL, NULL, false },
-  { DartUtils::kUriLibURL, uri_source_, NULL, NULL, false },
-  { DartUtils::kCryptoLibURL, crypto_source_, NULL, NULL, false },
   { DartUtils::kIOLibURL, io_source_,
     DartUtils::kIOLibPatchURL, io_patch_, true },
-  { DartUtils::kUtfLibURL, utf_source_, NULL, NULL, false }
 };
 
 
diff --git a/runtime/bin/builtin_impl_sources.gypi b/runtime/bin/builtin_impl_sources.gypi
index 54c8707..2f0f9d5 100644
--- a/runtime/bin/builtin_impl_sources.gypi
+++ b/runtime/bin/builtin_impl_sources.gypi
@@ -47,6 +47,8 @@
     'fdutils_macos.cc',
     'hashmap_test.cc',
     'isolate_data.h',
+    'native_service.h',
+    'native_service.cc',
     'thread.h',
     'utils.h',
     'utils_android.cc',
diff --git a/runtime/bin/builtin_nolib.cc b/runtime/bin/builtin_nolib.cc
index be941a7..048aa86 100644
--- a/runtime/bin/builtin_nolib.cc
+++ b/runtime/bin/builtin_nolib.cc
@@ -13,11 +13,7 @@
 Builtin::builtin_lib_props Builtin::builtin_libraries_[] = {
   /* { url_, source_, patch_url_, patch_source_, has_natives_ } */
   { DartUtils::kBuiltinLibURL, NULL, NULL, NULL, true },
-  { DartUtils::kJsonLibURL, NULL, NULL, NULL, false },
-  { DartUtils::kUriLibURL, NULL, NULL, NULL, false },
-  { DartUtils::kCryptoLibURL, NULL, NULL, NULL, false },
   { DartUtils::kIOLibURL, NULL, NULL, NULL, true  },
-  { DartUtils::kUtfLibURL, NULL, NULL, NULL, false }
 };
 
 
@@ -58,7 +54,7 @@
   Dart_Handle url = DartUtils::NewString(builtin_libraries_[id].url_);
   Dart_Handle library = Dart_LookupLibrary(url);
   if (Dart_IsError(library)) {
-    ASSERT(id > kUtfLibrary);
+    ASSERT(id > kIOLibrary);
     library = Dart_LoadLibrary(url, Source(id));
     if (!Dart_IsError(library) && (builtin_libraries_[id].has_natives_)) {
       // Setup the native resolver for built in library functions.
diff --git a/runtime/bin/crypto.cc b/runtime/bin/crypto.cc
index e4db17c..af5886d 100644
--- a/runtime/bin/crypto.cc
+++ b/runtime/bin/crypto.cc
@@ -23,7 +23,7 @@
     delete[] buffer;
     Dart_ThrowException(DartUtils::NewDartOSError());
   }
-  Dart_Handle result = Dart_NewByteArray(count);
+  Dart_Handle result = Dart_NewTypedData(kUint8, count);
   if (Dart_IsError(result)) {
     delete[] buffer;
     Dart_Handle error = DartUtils::NewString("Failed to allocate storage.");
diff --git a/runtime/bin/crypto_android.cc b/runtime/bin/crypto_android.cc
index 08f6dac..701a208 100644
--- a/runtime/bin/crypto_android.cc
+++ b/runtime/bin/crypto_android.cc
@@ -2,8 +2,11 @@
 // 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 <errno.h>
-#include <fcntl.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
 
 #include "bin/fdutils.h"
 #include "bin/crypto.h"
@@ -16,3 +19,5 @@
   close(fd);
   return bytes_read == count;
 }
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/crypto_linux.cc b/runtime/bin/crypto_linux.cc
index 08f6dac..7ff6b6e 100644
--- a/runtime/bin/crypto_linux.cc
+++ b/runtime/bin/crypto_linux.cc
@@ -2,8 +2,11 @@
 // 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 <errno.h>
-#include <fcntl.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
 
 #include "bin/fdutils.h"
 #include "bin/crypto.h"
@@ -16,3 +19,5 @@
   close(fd);
   return bytes_read == count;
 }
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/crypto_macos.cc b/runtime/bin/crypto_macos.cc
index 08f6dac..0a44ff8 100644
--- a/runtime/bin/crypto_macos.cc
+++ b/runtime/bin/crypto_macos.cc
@@ -2,8 +2,11 @@
 // 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 <errno.h>
-#include <fcntl.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
 
 #include "bin/fdutils.h"
 #include "bin/crypto.h"
@@ -16,3 +19,5 @@
   close(fd);
   return bytes_read == count;
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/crypto_sources.gypi b/runtime/bin/crypto_sources.gypi
deleted file mode 100644
index fc8f00f..0000000
--- a/runtime/bin/crypto_sources.gypi
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# This file contains all sources for the dart:crypto library.
-#
-# TODO(ager): ../lib/crypto/crypto_vm.dart should be removed when the
-# VM can use the #source directive for libraries.  At that point
-# ../../sdk/lib/crypto/crypto.dart should be the only crypto library file.
-{
-  'sources': [
-    '../lib/crypto/crypto_vm.dart',
-    '../../sdk/lib/crypto/crypto_utils.dart',
-    '../../sdk/lib/crypto/hash_utils.dart',
-    '../../sdk/lib/crypto/hmac.dart',
-    '../../sdk/lib/crypto/md5.dart',
-    '../../sdk/lib/crypto/sha1.dart',
-    '../../sdk/lib/crypto/sha256.dart',
-  ],
-}
diff --git a/runtime/bin/crypto_win.cc b/runtime/bin/crypto_win.cc
index 640efb2..8f4952f 100644
--- a/runtime/bin/crypto_win.cc
+++ b/runtime/bin/crypto_win.cc
@@ -3,6 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #define _CRT_RAND_S
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "bin/crypto.h"
 
 
@@ -20,3 +24,5 @@
   }
   return true;
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 2f281ac..ea53472 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -18,14 +18,10 @@
 const char* DartUtils::kASyncLibURL = "dart:async";
 const char* DartUtils::kBuiltinLibURL = "dart:builtin";
 const char* DartUtils::kCoreLibURL = "dart:core";
-const char* DartUtils::kCryptoLibURL = "dart:crypto";
 const char* DartUtils::kIOLibURL = "dart:io";
 const char* DartUtils::kIOLibPatchURL = "dart:io-patch";
-const char* DartUtils::kJsonLibURL = "dart:json";
 const char* DartUtils::kUriLibURL = "dart:uri";
 const char* DartUtils::kUtfLibURL = "dart:utf";
-const char* DartUtils::kIsolateLibURL = "dart:isolate";
-
 
 const char* DartUtils::kIdFieldName = "_id";
 
@@ -149,11 +145,6 @@
 }
 
 
-bool DartUtils::IsDartCryptoLibURL(const char* url_name) {
-  return (strcmp(url_name, kCryptoLibURL) == 0);
-}
-
-
 bool DartUtils::IsDartIOLibURL(const char* url_name) {
   return (strcmp(url_name, kIOLibURL) == 0);
 }
@@ -164,21 +155,6 @@
 }
 
 
-bool DartUtils::IsDartJsonLibURL(const char* url_name) {
-  return (strcmp(url_name, kJsonLibURL) == 0);
-}
-
-
-bool DartUtils::IsDartUriLibURL(const char* url_name) {
-  return (strcmp(url_name, kUriLibURL) == 0);
-}
-
-
-bool DartUtils::IsDartUtfLibURL(const char* url_name) {
-  return (strcmp(url_name, kUtfLibURL) == 0);
-}
-
-
 Dart_Handle DartUtils::CanonicalizeURL(CommandLineOptions* url_mapping,
                                        Dart_Handle library,
                                        const char* url_str) {
@@ -314,16 +290,8 @@
     if (tag == kImportTag) {
       // Handle imports of other built-in libraries present in the SDK.
       Builtin::BuiltinLibraryId id;
-      if (DartUtils::IsDartCryptoLibURL(url_string)) {
-        id = Builtin::kCryptoLibrary;
-      } else if (DartUtils::IsDartIOLibURL(url_string)) {
+      if (DartUtils::IsDartIOLibURL(url_string)) {
         id = Builtin::kIOLibrary;
-      } else if (DartUtils::IsDartJsonLibURL(url_string)) {
-        id = Builtin::kJsonLibrary;
-      } else if (DartUtils::IsDartUriLibURL(url_string)) {
-        id = Builtin::kUriLibrary;
-      } else if (DartUtils::IsDartUtfLibURL(url_string)) {
-        id = Builtin::kUtfLibrary;
       } else {
         return Dart_Error("Do not know how to load '%s'", url_string);
       }
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index eca83d5..07404e5 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -97,12 +97,8 @@
                              const char* val);
   static bool IsDartSchemeURL(const char* url_name);
   static bool IsDartExtensionSchemeURL(const char* url_name);
-  static bool IsDartCryptoLibURL(const char* url_name);
   static bool IsDartIOLibURL(const char* url_name);
   static bool IsDartBuiltinLibURL(const char* url_name);
-  static bool IsDartJsonLibURL(const char* url_name);
-  static bool IsDartUriLibURL(const char* url_name);
-  static bool IsDartUtfLibURL(const char* url_name);
   static Dart_Handle CanonicalizeURL(CommandLineOptions* url_mapping,
                                      Dart_Handle library,
                                      const char* url_str);
@@ -166,10 +162,8 @@
   static const char* kASyncLibURL;
   static const char* kBuiltinLibURL;
   static const char* kCoreLibURL;
-  static const char* kCryptoLibURL;
   static const char* kIOLibURL;
   static const char* kIOLibPatchURL;
-  static const char* kJsonLibURL;
   static const char* kUriLibURL;
   static const char* kUtfLibURL;
   static const char* kIsolateLibURL;
diff --git a/runtime/bin/dbg_connection_android.cc b/runtime/bin/dbg_connection_android.cc
index ce25559..0fc57ac 100644
--- a/runtime/bin/dbg_connection_android.cc
+++ b/runtime/bin/dbg_connection_android.cc
@@ -2,10 +2,13 @@
 // 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/epoll.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
+#include <errno.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
+#include <sys/epoll.h>  // NOLINT
 
 #include "bin/dbg_connection.h"
 #include "bin/fdutils.h"
@@ -115,3 +118,5 @@
 intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
   return TEMP_FAILURE_RETRY(read(socket, buf, len));
 }
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/dbg_connection_linux.cc b/runtime/bin/dbg_connection_linux.cc
index ce25559..c278987f 100644
--- a/runtime/bin/dbg_connection_linux.cc
+++ b/runtime/bin/dbg_connection_linux.cc
@@ -2,10 +2,13 @@
 // 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/epoll.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
+#include <errno.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
+#include <sys/epoll.h>  // NOLINT
 
 #include "bin/dbg_connection.h"
 #include "bin/fdutils.h"
@@ -115,3 +118,5 @@
 intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
   return TEMP_FAILURE_RETRY(read(socket, buf, len));
 }
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/dbg_connection_macos.cc b/runtime/bin/dbg_connection_macos.cc
index 675e129..a3e17fd 100644
--- a/runtime/bin/dbg_connection_macos.cc
+++ b/runtime/bin/dbg_connection_macos.cc
@@ -2,12 +2,15 @@
 // 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/event.h>
-#include <unistd.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
+#include <errno.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/event.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/dartutils.h"
 #include "bin/dbg_connection.h"
@@ -169,3 +172,5 @@
 intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
   return TEMP_FAILURE_RETRY(read(socket, buf, len));
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/dbg_connection_win.cc b/runtime/bin/dbg_connection_win.cc
index 1c9bf54..a241c85 100644
--- a/runtime/bin/dbg_connection_win.cc
+++ b/runtime/bin/dbg_connection_win.cc
@@ -2,6 +2,9 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "bin/dbg_connection.h"
 
 #include "bin/eventhandler.h"
@@ -39,3 +42,5 @@
   ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(socket);
   return recv(client_socket->socket(), buf, len, 0);
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index a4b5e08..1493b2d 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -9,10 +9,14 @@
 #include "include/dart_api.h"
 #include "platform/assert.h"
 
-dart::Mutex Directory::mutex_;
-int Directory::service_ports_size_ = 0;
-Dart_Port* Directory::service_ports_ = NULL;
-int Directory::service_ports_index_ = 0;
+
+// Forward declaration.
+static void DirectoryService(Dart_Port, Dart_Port, Dart_CObject*);
+
+NativeService Directory::directory_service_("DirectoryService",
+                                            DirectoryService,
+                                            16);
+
 
 void FUNCTION_NAME(Directory_Current)(Dart_NativeArguments args) {
   Dart_EnterScope();
@@ -236,10 +240,10 @@
 }
 
 
-void DirectoryService(Dart_Port dest_port_id,
-                      Dart_Port reply_port_id,
-                      Dart_CObject* message) {
-  CObject* response = CObject::False();
+static void DirectoryService(Dart_Port dest_port_id,
+                             Dart_Port reply_port_id,
+                             Dart_CObject* message) {
+  CObject* response = CObject::IllegalArgumentError();
   CObjectArray request(message);
   if (message->type == Dart_CObject::kArray) {
     if (request.Length() > 1 && request[0]->IsInt32()) {
@@ -274,27 +278,7 @@
 
 
 Dart_Port Directory::GetServicePort() {
-  MutexLocker lock(&mutex_);
-  if (service_ports_size_ == 0) {
-    ASSERT(service_ports_ == NULL);
-    service_ports_size_ = 16;
-    service_ports_ = new Dart_Port[service_ports_size_];
-    service_ports_index_ = 0;
-    for (int i = 0; i < service_ports_size_; i++) {
-      service_ports_[i] = ILLEGAL_PORT;
-    }
-  }
-
-  Dart_Port result = service_ports_[service_ports_index_];
-  if (result == ILLEGAL_PORT) {
-    result = Dart_NewNativePort("DirectoryService",
-                                DirectoryService,
-                                true);
-    ASSERT(result != ILLEGAL_PORT);
-    service_ports_[service_ports_index_] = result;
-  }
-  service_ports_index_ = (service_ports_index_ + 1) % service_ports_size_;
-  return result;
+  return directory_service_.GetServicePort();
 }
 
 
@@ -342,14 +326,16 @@
 
 bool SyncDirectoryListing::HandleDirectory(char* dir_name) {
   Dart_Handle dir_name_dart = DartUtils::NewString(dir_name);
-  Dart_Handle dir = Dart_New(directory_class_, Dart_Null(), 1, &dir_name_dart);
+  Dart_Handle dir =
+      Dart_New(directory_class_, Dart_Null(), 1, &dir_name_dart);
   Dart_Invoke(results_, add_string_, 1, &dir);
   return true;
 }
 
 bool SyncDirectoryListing::HandleFile(char* file_name) {
   Dart_Handle file_name_dart = DartUtils::NewString(file_name);
-  Dart_Handle file = Dart_New(file_class_, Dart_Null(), 1, &file_name_dart);
+  Dart_Handle file =
+      Dart_New(file_class_, Dart_Null(), 1, &file_name_dart);
   Dart_Invoke(results_, add_string_, 1, &file);
   return true;
 }
diff --git a/runtime/bin/directory.h b/runtime/bin/directory.h
index b038ad1..87bea9f 100644
--- a/runtime/bin/directory.h
+++ b/runtime/bin/directory.h
@@ -7,6 +7,7 @@
 
 #include "bin/builtin.h"
 #include "bin/dartutils.h"
+#include "bin/native_service.h"
 #include "platform/globals.h"
 #include "platform/thread.h"
 
@@ -22,8 +23,8 @@
 class AsyncDirectoryListing : public DirectoryListing {
  public:
   enum Response {
-    kListDirectory = 0,
-    kListFile = 1,
+    kListFile = 0,
+    kListDirectory = 1,
     kListError = 2,
     kListDone = 3
   };
@@ -99,10 +100,7 @@
   static Dart_Port GetServicePort();
 
  private:
-  static dart::Mutex mutex_;
-  static int service_ports_size_;
-  static Dart_Port* service_ports_;
-  static int service_ports_index_;
+  static NativeService directory_service_;
 
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(Directory);
diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc
index 8b40073..fd58c81 100644
--- a/runtime/bin/directory_android.cc
+++ b/runtime/bin/directory_android.cc
@@ -2,34 +2,43 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "bin/directory.h"
 
-#include <dirent.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <unistd.h>
+#include <dirent.h>  // NOLINT
+#include <errno.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/param.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/file.h"
 #include "bin/platform.h"
 
 class PathBuffer {
  public:
-  PathBuffer() : length(0) { }
+  PathBuffer() : length(0) {
+    data = new char[PATH_MAX + 1];
+  }
 
+  ~PathBuffer() {
+    delete[] data;
+  }
 
-
-  char data[PATH_MAX + 1];
+  char* data;
   int length;
 
   bool Add(const char* name) {
-    size_t written = snprintf(data + length,
-                              PATH_MAX - length,
-                              "%s",
-                              name);
+    int written = snprintf(data + length,
+                           PATH_MAX - length,
+                           "%s",
+                           name);
     data[PATH_MAX] = '\0';
-    if (written == strnlen(name, PATH_MAX + 1)) {
+    if (written <= PATH_MAX - length &&
+        written >= 0 &&
+        static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) {
       length += written;
       return true;
     } else {
@@ -45,12 +54,11 @@
 };
 
 
-
 // Forward declarations.
-static bool ListRecursively(const char* dir_name,
+static bool ListRecursively(PathBuffer* path,
                             bool recursive,
                             DirectoryListing* listing);
-static bool DeleteRecursively(const char* dir_name);
+static bool DeleteRecursively(PathBuffer* path);
 
 
 static void PostError(DirectoryListing *listing,
@@ -59,25 +67,6 @@
 }
 
 
-static PathBuffer* ComputeFullPath(const char* dir_name) {
-  PathBuffer* path = new PathBuffer();
-  char* abs_path;
-  do {
-    abs_path = realpath(dir_name, path->data);
-  } while (abs_path == NULL && errno == EINTR);
-  if (abs_path == NULL) {
-    delete path;
-    return NULL;
-  }
-  path->length = strnlen(path->data, PATH_MAX);
-  if (path->Add(File::PathSeparator())) {
-    return path;
-  } else {
-    delete path;
-    return NULL;
-  }
-}
-
 static bool HandleDir(char* dir_name,
                       PathBuffer* path,
                       bool recursive,
@@ -87,11 +76,11 @@
   if (!path->Add(dir_name)) {
     PostError(listing, path->data);
     return false;
-  }
   return listing->HandleDirectory(path->data) &&
-      (!recursive || ListRecursively(path->data, recursive, listing));
+      (!recursive || ListRecursively(path, recursive, listing));
 }
 
+
 static bool HandleFile(char* file_name,
                        PathBuffer* path,
                        DirectoryListing *listing) {
@@ -103,28 +92,22 @@
 }
 
 
-static bool ListRecursively(const char* dir_name,
+static bool ListRecursively(PathBuffer* path,
                             bool recursive,
                             DirectoryListing *listing) {
+  if (!path->Add(File::PathSeparator())) {
+    PostError(listing, path->data);
+    return false;
+  }
   DIR* dir_pointer;
   do {
-    dir_pointer = opendir(dir_name);
+    dir_pointer = opendir(path->data);
   } while (dir_pointer == NULL && errno == EINTR);
   if (dir_pointer == NULL) {
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
     return false;
   }
 
-  // Compute full path for the directory currently being listed.  The
-  // path buffer will be used to construct the current path in the
-  // recursive traversal. path_length does not always equal
-  // strlen(path) but indicates the current prefix of path that is the
-  // path of the current directory in the traversal.
-  PathBuffer* path = ComputeFullPath(dir_name);
-  if (path == NULL) {
-    PostError(listing, dir_name);
-    return false;
-  }
   // Iterate the directory and post the directories and files to the
   // ports.
   int path_length = path->length;
@@ -188,14 +171,13 @@
   if (status != 0) {
     errno = status;
     success = false;
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
   }
 
   if (closedir(dir_pointer) == -1) {
     success = false;
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
   }
-  delete path;
 
   return success;
 }
@@ -211,36 +193,31 @@
                       PathBuffer* path) {
   if (strcmp(dir_name, ".") == 0) return true;
   if (strcmp(dir_name, "..") == 0) return true;
-  return path->Add(dir_name) && DeleteRecursively(path->data);
+  return path->Add(dir_name) && DeleteRecursively(path);
 }
 
 
-static bool DeleteRecursively(const char* dir_name) {
+static bool DeleteRecursively(PathBuffer* path) {
+  if (!path->Add(File::PathSeparator())) return false;
   // Do not recurse into links for deletion. Instead delete the link.
   struct stat st;
-  if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) {
+  if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
     return false;
   } else if (S_ISLNK(st.st_mode)) {
-    return (remove(dir_name) == 0);
+    return (remove(path->data) == 0);
   }
 
   // Not a link. Attempt to open as a directory and recurse into the
   // directory.
   DIR* dir_pointer;
   do {
-    dir_pointer = opendir(dir_name);
+    dir_pointer = opendir(path->data);
   } while (dir_pointer == NULL && errno == EINTR);
 
   if (dir_pointer == NULL) {
     return false;
   }
 
-  // Compute full path for the directory currently being deleted.  The
-  // path buffer will be used to construct the current path in the
-  // recursive traversal.
-  PathBuffer* path = ComputeFullPath(dir_name);
-  if (path == NULL) return false;
-
   // Iterate the directory and delete all files and directories.
   int path_length = path->length;
   int read = 0;
@@ -293,14 +270,12 @@
     }
     path->Reset(path_length);
   }
-  delete path;
 
   if ((read != 0) ||
       (closedir(dir_pointer) == -1) ||
-      (remove(dir_name) == -1)) {
+      (remove(path->data) == -1)) {
     return false;
   }
-
   return success;
 }
 
@@ -308,8 +283,12 @@
 bool Directory::List(const char* dir_name,
                      bool recursive,
                      DirectoryListing *listing) {
-  bool completed = ListRecursively(dir_name, recursive, listing);
-  return completed;
+  PathBuffer path;
+  if (!path.Add(dir_name)) {
+    PostError(listing, dir_name);
+    return false;
+  }
+  return ListRecursively(&path, recursive, listing);
 }
 
 
@@ -385,9 +364,9 @@
   // dir_template.  Creates the directory with the permissions specified
   // by the process umask.
   // The return value must be freed by the caller.
-  PathBuffer* path = new PathBuffer();
-  path->Add(const_template);
-  if (path->length == 0) {
+  PathBuffer path;
+  path.Add(const_template);
+  if (path.length == 0) {
     // Android does not have a /tmp directory. A partial substitute,
     // suitable for bring-up work and tests, is to create a tmp
     // directory in /data/local/tmp.
@@ -400,12 +379,11 @@
       mkdir(ANDROID_TEMP_DIR, 0777);
     }
     path->Add(ANDROID_TEMP_DIR "/tmp/temp_dir1_");
-  } else if ((path->data)[path->length - 1] == '/') {
-    path->Add("temp_dir_");
+  } else if ((path.data)[path.length - 1] == '/') {
+    path.Add("temp_dir_");
   }
-  if (!path->Add("XXXXXX")) {
+  if (!path.Add("XXXXXX")) {
     // Pattern has overflowed.
-    delete path;
     return NULL;
   }
   char* result;
@@ -413,14 +391,12 @@
     result = MakeTempDirectory(path->data);
   } while (result == NULL && errno == EINTR);
   if (result == NULL) {
-    delete path;
     return NULL;
   }
-  int length = strnlen(path->data, PATH_MAX);
+  int length = strnlen(path.data, PATH_MAX);
   result = static_cast<char*>(malloc(length + 1));
-  strncpy(result, path->data, length);
+  strncpy(result, path.data, length);
   result[length] = '\0';
-  delete path;
   return result;
 }
 
@@ -429,7 +405,11 @@
   if (!recursive) {
     return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
   } else {
-    return DeleteRecursively(dir_name);
+    PathBuffer path;
+    if (!path.Add(dir_name)) {
+      return false;
+    }
+    return DeleteRecursively(&path);
   }
 }
 
@@ -439,3 +419,5 @@
   if (exists != EXISTS) return false;
   return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
 }
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/directory_linux.cc b/runtime/bin/directory_linux.cc
index 7b94aac..30cc860 100644
--- a/runtime/bin/directory_linux.cc
+++ b/runtime/bin/directory_linux.cc
@@ -2,34 +2,43 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "bin/directory.h"
 
-#include <dirent.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <unistd.h>
+#include <dirent.h>  // NOLINT
+#include <errno.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/param.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/file.h"
 #include "bin/platform.h"
 
 class PathBuffer {
  public:
-  PathBuffer() : length(0) { }
+  PathBuffer() : length(0) {
+    data = new char[PATH_MAX + 1];
+  }
 
+  ~PathBuffer() {
+    delete[] data;
+  }
 
-
-  char data[PATH_MAX + 1];
+  char* data;
   int length;
 
   bool Add(const char* name) {
-    size_t written = snprintf(data + length,
-                              PATH_MAX - length,
-                              "%s",
-                              name);
+    int written = snprintf(data + length,
+                           PATH_MAX - length,
+                           "%s",
+                           name);
     data[PATH_MAX] = '\0';
-    if (written == strnlen(name, PATH_MAX + 1)) {
+    if (written <= PATH_MAX - length &&
+        written >= 0 &&
+        static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) {
       length += written;
       return true;
     } else {
@@ -46,10 +55,10 @@
 
 
 // Forward declarations.
-static bool ListRecursively(const char* dir_name,
+static bool ListRecursively(PathBuffer* path,
                             bool recursive,
                             DirectoryListing* listing);
-static bool DeleteRecursively(const char* dir_name);
+static bool DeleteRecursively(PathBuffer* path);
 
 
 static void PostError(DirectoryListing *listing,
@@ -58,25 +67,6 @@
 }
 
 
-static PathBuffer* ComputeFullPath(const char* dir_name) {
-  PathBuffer* path = new PathBuffer();
-  char* abs_path;
-  do {
-    abs_path = realpath(dir_name, path->data);
-  } while (abs_path == NULL && errno == EINTR);
-  if (abs_path == NULL) {
-    delete path;
-    return NULL;
-  }
-  path->length = strnlen(path->data, PATH_MAX);
-  if (path->Add(File::PathSeparator())) {
-    return path;
-  } else {
-    delete path;
-    return NULL;
-  }
-}
-
 static bool HandleDir(char* dir_name,
                       PathBuffer* path,
                       bool recursive,
@@ -88,9 +78,10 @@
     return false;
   }
   return listing->HandleDirectory(path->data) &&
-      (!recursive || ListRecursively(path->data, recursive, listing));
+      (!recursive || ListRecursively(path, recursive, listing));
 }
 
+
 static bool HandleFile(char* file_name,
                        PathBuffer* path,
                        DirectoryListing *listing) {
@@ -102,28 +93,22 @@
 }
 
 
-static bool ListRecursively(const char* dir_name,
+static bool ListRecursively(PathBuffer* path,
                             bool recursive,
                             DirectoryListing *listing) {
+  if (!path->Add(File::PathSeparator())) {
+    PostError(listing, path->data);
+    return false;
+  }
   DIR* dir_pointer;
   do {
-    dir_pointer = opendir(dir_name);
+    dir_pointer = opendir(path->data);
   } while (dir_pointer == NULL && errno == EINTR);
   if (dir_pointer == NULL) {
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
     return false;
   }
 
-  // Compute full path for the directory currently being listed.  The
-  // path buffer will be used to construct the current path in the
-  // recursive traversal. path_length does not always equal
-  // strlen(path) but indicates the current prefix of path that is the
-  // path of the current directory in the traversal.
-  PathBuffer* path = ComputeFullPath(dir_name);
-  if (path == NULL) {
-    PostError(listing, dir_name);
-    return false;
-  }
   // Iterate the directory and post the directories and files to the
   // ports.
   int path_length = path->length;
@@ -187,14 +172,13 @@
   if (status != 0) {
     errno = status;
     success = false;
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
   }
 
   if (closedir(dir_pointer) == -1) {
     success = false;
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
   }
-  delete path;
 
   return success;
 }
@@ -210,36 +194,31 @@
                       PathBuffer* path) {
   if (strcmp(dir_name, ".") == 0) return true;
   if (strcmp(dir_name, "..") == 0) return true;
-  return path->Add(dir_name) && DeleteRecursively(path->data);
+  return path->Add(dir_name) && DeleteRecursively(path);
 }
 
 
-static bool DeleteRecursively(const char* dir_name) {
+static bool DeleteRecursively(PathBuffer* path) {
+  if (!path->Add(File::PathSeparator())) return false;
   // Do not recurse into links for deletion. Instead delete the link.
   struct stat st;
-  if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) {
+  if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
     return false;
   } else if (S_ISLNK(st.st_mode)) {
-    return (remove(dir_name) == 0);
+    return (remove(path->data) == 0);
   }
 
   // Not a link. Attempt to open as a directory and recurse into the
   // directory.
   DIR* dir_pointer;
   do {
-    dir_pointer = opendir(dir_name);
+    dir_pointer = opendir(path->data);
   } while (dir_pointer == NULL && errno == EINTR);
 
   if (dir_pointer == NULL) {
     return false;
   }
 
-  // Compute full path for the directory currently being deleted.  The
-  // path buffer will be used to construct the current path in the
-  // recursive traversal.
-  PathBuffer* path = ComputeFullPath(dir_name);
-  if (path == NULL) return false;
-
   // Iterate the directory and delete all files and directories.
   int path_length = path->length;
   int read = 0;
@@ -292,14 +271,12 @@
     }
     path->Reset(path_length);
   }
-  delete path;
 
   if ((read != 0) ||
       (closedir(dir_pointer) == -1) ||
-      (remove(dir_name) == -1)) {
+      (remove(path->data) == -1)) {
     return false;
   }
-
   return success;
 }
 
@@ -307,8 +284,12 @@
 bool Directory::List(const char* dir_name,
                      bool recursive,
                      DirectoryListing *listing) {
-  bool completed = ListRecursively(dir_name, recursive, listing);
-  return completed;
+  PathBuffer path;
+  if (!path.Add(dir_name)) {
+    PostError(listing, dir_name);
+    return false;
+  }
+  return ListRecursively(&path, recursive, listing);
 }
 
 
@@ -363,31 +344,28 @@
   // dir_template.  Creates the directory with the permissions specified
   // by the process umask.
   // The return value must be freed by the caller.
-  PathBuffer* path = new PathBuffer();
-  path->Add(const_template);
-  if (path->length == 0) {
-    path->Add("/tmp/temp_dir1_");
-  } else if ((path->data)[path->length - 1] == '/') {
-    path->Add("temp_dir_");
+  PathBuffer path;
+  path.Add(const_template);
+  if (path.length == 0) {
+    path.Add("/tmp/temp_dir1_");
+  } else if ((path.data)[path.length - 1] == '/') {
+    path.Add("temp_dir_");
   }
-  if (!path->Add("XXXXXX")) {
+  if (!path.Add("XXXXXX")) {
     // Pattern has overflowed.
-    delete path;
     return NULL;
   }
   char* result;
   do {
-    result = mkdtemp(path->data);
+    result = mkdtemp(path.data);
   } while (result == NULL && errno == EINTR);
   if (result == NULL) {
-    delete path;
     return NULL;
   }
-  int length = strnlen(path->data, PATH_MAX);
+  int length = strnlen(path.data, PATH_MAX);
   result = static_cast<char*>(malloc(length + 1));
-  strncpy(result, path->data, length);
+  strncpy(result, path.data, length);
   result[length] = '\0';
-  delete path;
   return result;
 }
 
@@ -396,7 +374,11 @@
   if (!recursive) {
     return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
   } else {
-    return DeleteRecursively(dir_name);
+    PathBuffer path;
+    if (!path.Add(dir_name)) {
+      return false;
+    }
+    return DeleteRecursively(&path);
   }
 }
 
@@ -406,3 +388,5 @@
   if (exists != EXISTS) return false;
   return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
 }
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/directory_macos.cc b/runtime/bin/directory_macos.cc
index 8a0f2b7..4685479 100644
--- a/runtime/bin/directory_macos.cc
+++ b/runtime/bin/directory_macos.cc
@@ -2,34 +2,43 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
 #include "bin/directory.h"
 
-#include <dirent.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <unistd.h>
+#include <dirent.h>  // NOLINT
+#include <errno.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/param.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/file.h"
 #include "bin/platform.h"
 
 class PathBuffer {
  public:
-  PathBuffer() : length(0) { }
+  PathBuffer() : length(0) {
+    data = new char[PATH_MAX + 1];
+  }
 
+  ~PathBuffer() {
+    delete[] data;
+  }
 
-
-  char data[PATH_MAX + 1];
+  char* data;
   int length;
 
   bool Add(const char* name) {
-    size_t written = snprintf(data + length,
-                              PATH_MAX - length,
-                              "%s",
-                              name);
+    int written = snprintf(data + length,
+                           PATH_MAX - length,
+                           "%s",
+                           name);
     data[PATH_MAX] = '\0';
-    if (written == strlen(name)) {
+    if (written <= PATH_MAX - length &&
+        written >= 0 &&
+        static_cast<size_t>(written) == strlen(name)) {
       length += written;
       return true;
     } else {
@@ -45,12 +54,11 @@
 };
 
 
-
 // Forward declarations.
-static bool ListRecursively(const char* dir_name,
+static bool ListRecursively(PathBuffer* path,
                             bool recursive,
                             DirectoryListing* listing);
-static bool DeleteRecursively(const char* dir_name);
+static bool DeleteRecursively(PathBuffer* path);
 
 
 static void PostError(DirectoryListing *listing,
@@ -59,25 +67,6 @@
 }
 
 
-static PathBuffer* ComputeFullPath(const char* dir_name) {
-  PathBuffer* path = new PathBuffer();
-  char* abs_path;
-  do {
-    abs_path = realpath(dir_name, path->data);
-  } while (abs_path == NULL && errno == EINTR);
-  if (abs_path == NULL) {
-    delete path;
-    return NULL;
-  }
-  path->length = strlen(path->data);
-  if (path->Add(File::PathSeparator())) {
-    return path;
-  } else {
-    delete path;
-    return NULL;
-  }
-}
-
 static bool HandleDir(char* dir_name,
                       PathBuffer* path,
                       bool recursive,
@@ -89,9 +78,10 @@
     return false;
   }
   return listing->HandleDirectory(path->data) &&
-      (!recursive || ListRecursively(path->data, recursive, listing));
+      (!recursive || ListRecursively(path, recursive, listing));
 }
 
+
 static bool HandleFile(char* file_name,
                        PathBuffer* path,
                        DirectoryListing *listing) {
@@ -103,28 +93,22 @@
 }
 
 
-static bool ListRecursively(const char* dir_name,
+static bool ListRecursively(PathBuffer* path,
                             bool recursive,
                             DirectoryListing *listing) {
+  if (!path->Add(File::PathSeparator())) {
+    PostError(listing, path->data);
+    return false;
+  }
   DIR* dir_pointer;
   do {
-    dir_pointer = opendir(dir_name);
+    dir_pointer = opendir(path->data);
   } while (dir_pointer == NULL && errno == EINTR);
   if (dir_pointer == NULL) {
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
     return false;
   }
 
-  // Compute full path for the directory currently being listed.  The
-  // path buffer will be used to construct the current path in the
-  // recursive traversal. path_length does not always equal
-  // strlen(path) but indicates the current prefix of path that is the
-  // path of the current directory in the traversal.
-  PathBuffer* path = ComputeFullPath(dir_name);
-  if (path == NULL) {
-    PostError(listing, dir_name);
-    return false;
-  }
   // Iterate the directory and post the directories and files to the
   // ports.
   int path_length = path->length;
@@ -188,14 +172,13 @@
   if (status != 0) {
     errno = status;
     success = false;
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
   }
 
   if (closedir(dir_pointer) == -1) {
     success = false;
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
   }
-  delete path;
 
   return success;
 }
@@ -211,36 +194,31 @@
                       PathBuffer* path) {
   if (strcmp(dir_name, ".") == 0) return true;
   if (strcmp(dir_name, "..") == 0) return true;
-  return path->Add(dir_name) && DeleteRecursively(path->data);
+  return path->Add(dir_name) && DeleteRecursively(path);
 }
 
 
-static bool DeleteRecursively(const char* dir_name) {
-  // Do not recurse into links for deletion. Instead delete the link.
+static bool DeleteRecursively(PathBuffer* path) {
+  if (!path->Add(File::PathSeparator())) return false;
+      // Do not recurse into links for deletion. Instead delete the link.
   struct stat st;
-  if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) {
+  if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
     return false;
   } else if (S_ISLNK(st.st_mode)) {
-    return (remove(dir_name) == 0);
+    return (remove(path->data) == 0);
   }
 
   // Not a link. Attempt to open as a directory and recurse into the
   // directory.
   DIR* dir_pointer;
   do {
-    dir_pointer = opendir(dir_name);
+    dir_pointer = opendir(path->data);
   } while (dir_pointer == NULL && errno == EINTR);
 
   if (dir_pointer == NULL) {
     return false;
   }
 
-  // Compute full path for the directory currently being deleted.  The
-  // path buffer will be used to construct the current path in the
-  // recursive traversal.
-  PathBuffer* path = ComputeFullPath(dir_name);
-  if (path == NULL) return false;
-
   // Iterate the directory and delete all files and directories.
   int path_length = path->length;
   int read = 0;
@@ -293,14 +271,12 @@
     }
     path->Reset(path_length);
   }
-  delete path;
 
   if ((read != 0) ||
       (closedir(dir_pointer) == -1) ||
-      (remove(dir_name) == -1)) {
+      (remove(path->data) == -1)) {
     return false;
   }
-
   return success;
 }
 
@@ -308,8 +284,12 @@
 bool Directory::List(const char* dir_name,
                      bool recursive,
                      DirectoryListing *listing) {
-  bool completed = ListRecursively(dir_name, recursive, listing);
-  return completed;
+  PathBuffer path;
+  if (!path.Add(dir_name)) {
+    PostError(listing, dir_name);
+    return false;
+  }
+  return ListRecursively(&path, recursive, listing);
 }
 
 
@@ -364,31 +344,28 @@
   // dir_template.  Creates the directory with the permissions specified
   // by the process umask.
   // The return value must be freed by the caller.
-  PathBuffer* path = new PathBuffer();
-  path->Add(const_template);
-  if (path->length == 0) {
-    path->Add("/tmp/temp_dir1_");
-  } else if ((path->data)[path->length - 1] == '/') {
-    path->Add("temp_dir_");
+  PathBuffer path;
+  path.Add(const_template);
+  if (path.length == 0) {
+    path.Add("/tmp/temp_dir1_");
+  } else if ((path.data)[path.length - 1] == '/') {
+    path.Add("temp_dir_");
   }
-  if (!path->Add("XXXXXX")) {
+  if (!path.Add("XXXXXX")) {
     // Pattern has overflowed.
-    delete path;
     return NULL;
   }
   char* result;
   do {
-    result = mkdtemp(path->data);
+    result = mkdtemp(path.data);
   } while (result == NULL && errno == EINTR);
   if (result == NULL) {
-    delete path;
     return NULL;
   }
-  int length = strlen(path->data);
+  int length = strlen(path.data);
   result = static_cast<char*>(malloc(length + 1));
-  strncpy(result, path->data, length);
+  strncpy(result, path.data, length);
   result[length] = '\0';
-  delete path;
   return result;
 }
 
@@ -397,7 +374,11 @@
   if (!recursive) {
     return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
   } else {
-    return DeleteRecursively(dir_name);
+    PathBuffer path;
+    if (!path.Add(dir_name)) {
+      return false;
+    }
+    return DeleteRecursively(&path);
   }
 }
 
@@ -407,3 +388,5 @@
   if (exists != EXISTS) return false;
   return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 84242c6..97a2207 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -2,27 +2,38 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "bin/directory.h"
 
-#include <errno.h>
-#include <sys/stat.h>
+#include <errno.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
 
 #include "bin/log.h"
 
 class PathBuffer {
  public:
-  PathBuffer() : length(0) { }
+  PathBuffer() : length(0) {
+    data = new wchar_t[MAX_PATH + 1];
+  }
 
-  wchar_t data[MAX_PATH + 1];
+  ~PathBuffer() {
+    delete[] data;
+  }
+
+  wchar_t* data;
   int length;
 
   bool Add(const wchar_t* name) {
-    size_t written = _snwprintf(data + length,
-                               MAX_PATH - length,
-                               L"%s",
-                               name);
+    int written = _snwprintf(data + length,
+                             MAX_PATH - length,
+                             L"%s",
+                             name);
     data[MAX_PATH] = L'\0';
-    if (written == wcsnlen(name, MAX_PATH + 1)) {
+    if (written <= MAX_PATH - length &&
+        written >= 0 &&
+        static_cast<size_t>(written) == wcsnlen(name, MAX_PATH + 1)) {
       length += written;
       return true;
     } else {
@@ -39,10 +50,10 @@
 
 
 // Forward declarations.
-static bool ListRecursively(const wchar_t* dir_name,
+static bool ListRecursively(PathBuffer* path,
                             bool recursive,
                             DirectoryListing* listing);
-static bool DeleteRecursively(const wchar_t* dir_name);
+static bool DeleteRecursively(PathBuffer* path);
 
 
 static void PostError(DirectoryListing* listing,
@@ -66,7 +77,7 @@
   char* utf8_path = StringUtils::WideToUtf8(path->data);
   bool ok = listing->HandleDirectory(utf8_path);
   free(utf8_path);
-  return ok && (!recursive || ListRecursively(path->data, recursive, listing));
+  return ok && (!recursive || ListRecursively(path, recursive, listing));
 }
 
 
@@ -100,42 +111,11 @@
 }
 
 
-static PathBuffer* ComputeFullSearchPath(const wchar_t* dir_name) {
-  // GetFullPathName only works in a multi-threaded environment if
-  // SetCurrentDirectory is not used. We currently have no plan for
-  // exposing SetCurrentDirectory.
-  PathBuffer* path = new PathBuffer();
-
-  size_t written = GetFullPathNameW(dir_name, MAX_PATH + 1, path->data, NULL);
-  // GetFullPathName only accepts input strings of size less than
-  // MAX_PATH and returns 0 to indicate failure for paths longer than
-  // that. Therefore the path buffer is always big enough.
-  if (written == 0 || written > MAX_PATH) {
-    delete path;
-    return NULL;
-  }
-  path->length = written;
-  if (path->Add(L"\\*")) {
-    return path;
-  } else {
-    delete path;
-    return NULL;
-  }
-}
-
-
-static bool ListRecursively(const wchar_t* dir_name,
+static bool ListRecursively(PathBuffer* path,
                             bool recursive,
                             DirectoryListing* listing) {
-  // Compute full path for the directory currently being listed.  The
-  // path buffer will be used to construct the current path in the
-  // recursive traversal. path_length does not always equal
-  // strlen(path) but indicates the current prefix of path that is the
-  // path of the current directory in the traversal.
-  PathBuffer* path = ComputeFullSearchPath(dir_name);
-  if (path == NULL) {
-    PostError(listing, dir_name);
-    delete path;
+  if (!path->Add(L"\\*")) {
+    PostError(listing, path->data);
     return false;
   }
 
@@ -147,7 +127,6 @@
 
   if (find_handle == INVALID_HANDLE_VALUE) {
     PostError(listing, path->data);
-    delete path;
     return false;
   }
 
@@ -167,14 +146,13 @@
 
   if (GetLastError() != ERROR_NO_MORE_FILES) {
     success = false;
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
   }
 
   if (FindClose(find_handle) == 0) {
     success = false;
-    PostError(listing, dir_name);
+    PostError(listing, path->data);
   }
-  delete path;
 
   return success;
 }
@@ -214,7 +192,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->data);
+  return path->Add(dir_name) && DeleteRecursively(path);
 }
 
 
@@ -229,23 +207,17 @@
 }
 
 
-static bool DeleteRecursively(const wchar_t* dir_name) {
+static bool DeleteRecursively(PathBuffer* path) {
   // If the directory is a junction, it's pointing to some other place in the
   // filesystem that we do not want to recurse into.
-  DWORD attributes = GetFileAttributesW(dir_name);
+  DWORD attributes = GetFileAttributesW(path->data);
   if ((attributes != INVALID_FILE_ATTRIBUTES) &&
       (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
     // Just delete the junction itself.
-    return RemoveDirectoryW(dir_name) != 0;
+    return RemoveDirectoryW(path->data) != 0;
   }
 
-  // Compute full path for the directory currently being deleted.  The
-  // path buffer will be used to construct the current path in the
-  // recursive traversal. path_length does not always equal
-  // strlen(path) but indicates the current prefix of path that is the
-  // path of the current directory in the traversal.
-  PathBuffer* path = ComputeFullSearchPath(dir_name);
-  if (path == NULL) return false;
+  if (!path->Add(L"\\*")) return false;
 
   WIN32_FIND_DATAW find_file_data;
   HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
@@ -255,7 +227,6 @@
   path->Reset(path_length);
 
   if (find_handle == INVALID_HANDLE_VALUE) {
-    delete path;
     return false;
   }
 
@@ -266,11 +237,10 @@
     success = success && DeleteEntry(&find_file_data, path);
   }
 
-  delete path;
-
+  path->Reset(path_length - 1);  // Drop the "\" from the end of the path.
   if ((GetLastError() != ERROR_NO_MORE_FILES) ||
       (FindClose(find_handle) == 0) ||
-      (RemoveDirectoryW(dir_name) == 0)) {
+      (RemoveDirectoryW(path->data) == 0)) {
     return false;
   }
 
@@ -282,9 +252,13 @@
                      bool recursive,
                      DirectoryListing* listing) {
   const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name);
-  bool completed = ListRecursively(system_name, recursive, listing);
+  PathBuffer path;
+  if (!path.Add(system_name)) {
+    PostError(listing, system_name);
+    return false;
+  }
   free(const_cast<wchar_t*>(system_name));
-  return completed;
+  return ListRecursively(&path, recursive, listing);
 }
 
 
@@ -345,51 +319,45 @@
   // dir_template.  Creates this directory, with a default security
   // descriptor inherited from its parent directory.
   // The return value must be freed by the caller.
-  PathBuffer* path = new PathBuffer();
+  PathBuffer path;
   if (0 == strncmp(const_template, "", 1)) {
-    path->length = GetTempPathW(MAX_PATH, path->data);
-    if (path->length == 0) {
-      delete path;
+    path.length = GetTempPathW(MAX_PATH, path.data);
+    if (path.length == 0) {
       return NULL;
     }
   } else {
     const wchar_t* system_template = StringUtils::Utf8ToWide(const_template);
-    path->Add(system_template);
+    path.Add(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) {
-    delete path;
+  if (path.length > MAX_PATH - 44) {
     return NULL;
   }
-  if ((path->data)[path->length - 1] == L'\\') {
+  if ((path.data)[path.length - 1] == L'\\') {
     // No base name for the directory - use "tempdir".
-    path->Add(L"tempdir");
+    path.Add(L"tempdir");
   }
 
   UUID uuid;
   RPC_STATUS status = UuidCreateSequential(&uuid);
   if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
-    delete path;
     return NULL;
   }
   RPC_WSTR uuid_string;
   status = UuidToStringW(&uuid, &uuid_string);
   if (status != RPC_S_OK) {
-    delete path;
     return NULL;
   }
 
-  path->Add(L"-");
+  path.Add(L"-");
   // RPC_WSTR is an unsigned short*, so we cast to wchar_t*.
-  path->Add(reinterpret_cast<wchar_t*>(uuid_string));
+  path.Add(reinterpret_cast<wchar_t*>(uuid_string));
   RpcStringFreeW(&uuid_string);
-  if (!CreateDirectoryW(path->data, NULL)) {
-    delete path;
+  if (!CreateDirectoryW(path.data, NULL)) {
     return NULL;
   }
-  char* result = StringUtils::WideToUtf8(path->data);
-  delete path;
+  char* result = StringUtils::WideToUtf8(path.data);
   return result;
 }
 
@@ -400,7 +368,11 @@
   if (!recursive) {
     result = (RemoveDirectoryW(system_dir_name) != 0);
   } else {
-    result = DeleteRecursively(system_dir_name);
+    PathBuffer path;
+    if (!path.Add(system_dir_name)) {
+      return false;
+    }
+    result = DeleteRecursively(&path);
   }
   free(const_cast<wchar_t*>(system_dir_name));
   return result;
@@ -417,7 +389,7 @@
   // if the new_path is currently a directory we need to delete it
   // first.
   if (new_exists == EXISTS) {
-    bool success = DeleteRecursively(system_new_path);
+    bool success = Delete(new_path, true);
     if (!success) return false;
   }
   DWORD flags = MOVEFILE_WRITE_THROUGH;
@@ -427,3 +399,5 @@
   free(const_cast<wchar_t*>(system_new_path));
   return (move_status != 0);
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index 9c2b619..2a708fd 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -2,35 +2,28 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "bin/eventhandler.h"
 
-#include <errno.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <unistd.h>
+#include <errno.h>  // NOLINT
+#include <pthread.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/epoll.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/dartutils.h"
 #include "bin/fdutils.h"
 #include "bin/log.h"
+#include "bin/utils.h"
 #include "platform/hashmap.h"
 #include "platform/thread.h"
 #include "platform/utils.h"
 
 
-int64_t GetCurrentTimeMilliseconds() {
-  struct timeval tv;
-  if (gettimeofday(&tv, NULL) < 0) {
-    UNREACHABLE();
-    return 0;
-  }
-  return ((static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec) / 1000;
-}
-
-
 static const int kInterruptMessageSize = sizeof(InterruptMessage);
 static const int kInfinityTimeout = -1;
 static const int kTimerId = -1;
@@ -358,14 +351,14 @@
   if (timeout_ == kInfinityTimeout) {
     return kInfinityTimeout;
   }
-  intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
+  intptr_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
   return (millis < 0) ? 0 : millis;
 }
 
 
 void EventHandlerImplementation::HandleTimeout() {
   if (timeout_ != kInfinityTimeout) {
-    intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
+    intptr_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
     if (millis <= 0) {
       DartUtils::PostNull(timeout_port_);
       timeout_ = kInfinityTimeout;
@@ -431,3 +424,5 @@
   // The hashmap does not support keys with value 0.
   return dart::Utils::WordHash(fd + 1);
 }
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 869e8bb..ce99057 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -2,35 +2,28 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "bin/eventhandler.h"
 
-#include <errno.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <unistd.h>
+#include <errno.h>  // NOLINT
+#include <pthread.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/epoll.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/dartutils.h"
 #include "bin/fdutils.h"
 #include "bin/log.h"
+#include "bin/utils.h"
 #include "platform/hashmap.h"
 #include "platform/thread.h"
 #include "platform/utils.h"
 
 
-int64_t GetCurrentTimeMilliseconds() {
-  struct timeval tv;
-  if (gettimeofday(&tv, NULL) < 0) {
-    UNREACHABLE();
-    return 0;
-  }
-  return ((static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec) / 1000;
-}
-
-
 static const int kInterruptMessageSize = sizeof(InterruptMessage);
 static const int kInfinityTimeout = -1;
 static const int kTimerId = -1;
@@ -223,9 +216,13 @@
         socket_map_.Remove(GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd));
         delete sd;
       } else {
-        // Setup events to wait for.
-        sd->SetPortAndMask(msg.dart_port, msg.data);
-        UpdateEpollInstance(epoll_fd_, sd);
+        if ((msg.data & (1 << kInEvent)) != 0 && sd->IsClosedRead()) {
+          DartUtils::PostInt32(msg.dart_port, 1 << kCloseEvent);
+        } else {
+          // Setup events to wait for.
+          sd->SetPortAndMask(msg.dart_port, msg.data);
+          UpdateEpollInstance(epoll_fd_, sd);
+        }
       }
     }
   }
@@ -268,8 +265,9 @@
     }
   } else {
     // Prioritize data events over close and error events.
-    if ((events & EPOLLIN) != 0) {
-      if (FDUtils::AvailableBytes(sd->fd()) != 0) {
+    if ((events & (EPOLLIN | EPOLLHUP | EPOLLERR)) != 0) {
+      // If we have EPOLLIN and we have available bytes, report that.
+      if ((events & EPOLLIN) && FDUtils::AvailableBytes(sd->fd()) != 0) {
         event_mask = (1 << kInEvent);
       } else if ((events & EPOLLHUP) != 0) {
         // If both EPOLLHUP and EPOLLERR are reported treat it as an
@@ -309,16 +307,6 @@
       }
     }
 
-    // On pipes EPOLLHUP is reported without EPOLLIN when there is no
-    // more data to read.
-    if (sd->IsPipe()) {
-      if (((events & EPOLLIN) == 0) &&
-          ((events & EPOLLHUP) != 0)) {
-        event_mask = (1 << kCloseEvent);
-        sd->MarkClosedRead();
-      }
-    }
-
     if ((events & EPOLLOUT) != 0) {
       if ((events & EPOLLERR) != 0) {
         event_mask = (1 << kErrorEvent);
@@ -350,6 +338,8 @@
       }
     }
   }
+  // Handle after socket events, so we avoid closing a socket before we handle
+  // the current events.
   HandleInterruptFd();
 }
 
@@ -358,14 +348,14 @@
   if (timeout_ == kInfinityTimeout) {
     return kInfinityTimeout;
   }
-  intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
+  intptr_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
   return (millis < 0) ? 0 : millis;
 }
 
 
 void EventHandlerImplementation::HandleTimeout() {
   if (timeout_ != kInfinityTimeout) {
-    intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
+    intptr_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
     if (millis <= 0) {
       DartUtils::PostNull(timeout_port_);
       timeout_ = kInfinityTimeout;
@@ -431,3 +421,5 @@
   // The hashmap does not support keys with value 0.
   return dart::Utils::WordHash(fd + 1);
 }
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index 51f1e70..fbced64 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -2,34 +2,27 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
 #include "bin/eventhandler.h"
 
-#include <errno.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/event.h>
-#include <sys/time.h>
-#include <unistd.h>
+#include <errno.h>  // NOLINT
+#include <pthread.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/event.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/dartutils.h"
 #include "bin/fdutils.h"
 #include "bin/log.h"
+#include "bin/utils.h"
 #include "platform/hashmap.h"
 #include "platform/thread.h"
 #include "platform/utils.h"
 
 
-int64_t GetCurrentTimeMilliseconds() {
-  struct timeval tv;
-  if (gettimeofday(&tv, NULL) < 0) {
-    UNREACHABLE();
-    return 0;
-  }
-  return ((static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec) / 1000;
-}
-
-
 static const int kInterruptMessageSize = sizeof(InterruptMessage);
 static const int kInfinityTimeout = -1;
 static const int kTimerId = -1;
@@ -145,8 +138,8 @@
 
 
 EventHandlerImplementation::~EventHandlerImplementation() {
-  TEMP_FAILURE_RETRY(close(interrupt_fds_[0]));
-  TEMP_FAILURE_RETRY(close(interrupt_fds_[1]));
+  VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[0]));
+  VOID_TEMP_FAILURE_RETRY(close(interrupt_fds_[1]));
 }
 
 
@@ -234,9 +227,13 @@
         socket_map_.Remove(GetHashmapKeyFromFd(fd), GetHashmapHashFromFd(fd));
         delete sd;
       } else {
-        // Setup events to wait for.
-        sd->SetPortAndMask(msg.dart_port, msg.data);
-        UpdateKqueue(kqueue_fd_, sd);
+        if ((msg.data & (1 << kInEvent)) != 0 && sd->IsClosedRead()) {
+          DartUtils::PostInt32(msg.dart_port, 1 << kCloseEvent);
+        } else {
+          // Setup events to wait for.
+          sd->SetPortAndMask(msg.dart_port, msg.data);
+          UpdateKqueue(kqueue_fd_, sd);
+        }
       }
     }
   }
@@ -276,6 +273,8 @@
         }
       }
       if (event_mask == 0) event_mask |= (1 << kInEvent);
+    } else {
+      UNREACHABLE();
     }
   } else {
     // Prioritize data events over close and error events.
@@ -290,9 +289,7 @@
         }
         sd->MarkClosedRead();
       }
-    }
-
-    if (event->filter == EVFILT_WRITE) {
+    } else if (event->filter == EVFILT_WRITE) {
       if ((event->flags & EV_EOF) != 0) {
         if (event->fflags != 0) {
           event_mask |= (1 << kErrorEvent);
@@ -307,6 +304,8 @@
       } else {
         event_mask |= (1 << kOutEvent);
       }
+    } else {
+      UNREACHABLE();
     }
   }
 
@@ -343,14 +342,14 @@
   if (timeout_ == kInfinityTimeout) {
     return kInfinityTimeout;
   }
-  intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
+  intptr_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
   return (millis < 0) ? 0 : millis;
 }
 
 
 void EventHandlerImplementation::HandleTimeout() {
   if (timeout_ != kInfinityTimeout) {
-    intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
+    intptr_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
     if (millis <= 0) {
       DartUtils::PostNull(timeout_port_);
       timeout_ = kInfinityTimeout;
@@ -425,3 +424,5 @@
   // The hashmap does not support keys with value 0.
   return dart::Utils::WordHash(fd + 1);
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 60d0fed..a10dd04 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -2,17 +2,21 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "bin/eventhandler.h"
 
-#include <process.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <mswsock.h>
+#include <process.h>  // NOLINT
+#include <winsock2.h>  // NOLINT
+#include <ws2tcpip.h>  // NOLINT
+#include <mswsock.h>  // NOLINT
 
 #include "bin/builtin.h"
 #include "bin/dartutils.h"
 #include "bin/log.h"
 #include "bin/socket.h"
+#include "bin/utils.h"
 #include "platform/thread.h"
 
 
@@ -20,24 +24,6 @@
 static const int kTimeoutId = -1;
 static const int kShutdownId = -2;
 
-
-int64_t GetCurrentTimeMilliseconds() {
-  static const int64_t kTimeEpoc = 116444736000000000LL;
-
-  // Although win32 uses 64-bit integers for representing timestamps,
-  // these are packed into a FILETIME structure. The FILETIME structure
-  // is just a struct representing a 64-bit integer. The TimeStamp union
-  // allows access to both a FILETIME and an integer representation of
-  // the timestamp.
-  union TimeStamp {
-    FILETIME ft_;
-    int64_t t_;
-  };
-  TimeStamp time;
-  GetSystemTimeAsFileTime(&time.ft_);
-  return (time.t_ - kTimeEpoc) / 10000;
-}
-
 IOBuffer* IOBuffer::AllocateBuffer(int buffer_size, Operation operation) {
   IOBuffer* buffer = new(buffer_size) IOBuffer(buffer_size, operation);
   return buffer;
@@ -60,6 +46,11 @@
 }
 
 
+IOBuffer* IOBuffer::AllocateDisconnectBuffer() {
+  return AllocateBuffer(0, kDisconnect);
+}
+
+
 void IOBuffer::DisposeBuffer(IOBuffer* buffer) {
   delete buffer;
 }
@@ -153,25 +144,22 @@
 }
 
 
-void Handle::close() {
+void Handle::Close() {
   ScopedLock lock(this);
   if (!IsClosing()) {
     // Close the socket and set the closing state. This close method can be
     // called again if this socket has pending IO operations in flight.
     ASSERT(handle_ != INVALID_HANDLE_VALUE);
     MarkClosing();
-    // According to the documentation from Microsoft socket handles should
-    // not be closed using CloseHandle but using closesocket.
-    if (is_socket()) {
-      closesocket(reinterpret_cast<SOCKET>(handle_));
-    } else {
-      CloseHandle(handle_);
-    }
-    handle_ = INVALID_HANDLE_VALUE;
+    // Perform handle type specific closing.
+    DoClose();
   }
+}
 
-  // Perform socket type specific close handling.
-  AfterClose();
+
+void Handle::DoClose() {
+  CloseHandle(handle_);
+  handle_ = INVALID_HANDLE_VALUE;
 }
 
 
@@ -326,10 +314,6 @@
 }
 
 
-void FileHandle::AfterClose() {
-}
-
-
 void SocketHandle::HandleIssueError() {
   int error = WSAGetLastError();
   if (error == WSAECONNRESET) {
@@ -343,12 +327,6 @@
 
 bool ListenSocket::LoadAcceptEx() {
   // Load the AcceptEx function into memory using WSAIoctl.
-  // The WSAIoctl function is an extension of the ioctlsocket()
-  // function that can use overlapped I/O. The function's 3rd
-  // through 6th parameters are input and output buffers where
-  // we pass the pointer to our AcceptEx function. This is used
-  // so that we can call the AcceptEx function directly, rather
-  // than refer to the Mswsock.lib library.
   GUID guid_accept_ex = WSAID_ACCEPTEX;
   DWORD bytes;
   int status = WSAIoctl(socket(),
@@ -416,17 +394,6 @@
                         SO_UPDATE_ACCEPT_CONTEXT,
                         reinterpret_cast<char*>(&s), sizeof(s));
     if (rc == NO_ERROR) {
-      linger l;
-      l.l_onoff = 1;
-      l.l_linger = 10;
-      int status = setsockopt(buffer->client(),
-                              SOL_SOCKET,
-                              SO_LINGER,
-                              reinterpret_cast<char*>(&l),
-                              sizeof(l));
-      if (status != NO_ERROR) {
-        FATAL("Failed setting SO_LINGER on socket");
-      }
       // Insert the accepted socket into the list.
       ClientSocket* client_socket = new ClientSocket(buffer->client(), 0);
       client_socket->CreateCompletionPort(completion_port);
@@ -449,6 +416,27 @@
 }
 
 
+void ListenSocket::DoClose() {
+  closesocket(socket());
+  handle_ = INVALID_HANDLE_VALUE;
+  while (CanAccept()) {
+    // Get rid of connections already accepted.
+    ClientSocket *client = Accept();
+    if (client != NULL) {
+      client->Close();
+    } else {
+      break;
+    }
+  }
+}
+
+
+bool ListenSocket::CanAccept() {
+  ScopedLock lock(this);
+  return accepted_head_ != NULL;
+}
+
+
 ClientSocket* ListenSocket::Accept() {
   ScopedLock lock(this);
   if (accepted_head_ == NULL) return NULL;
@@ -473,20 +461,6 @@
 }
 
 
-void ListenSocket::AfterClose() {
-  ScopedLock lock(this);
-  while (true) {
-    // Get rid of connections already accepted.
-    ClientSocket *client = Accept();
-    if (client != NULL) {
-      client->close();
-    } else {
-      break;
-    }
-  }
-}
-
-
 bool ListenSocket::IsClosed() {
   return IsClosing() && !HasPendingAccept();
 }
@@ -540,11 +514,29 @@
 }
 
 
+bool ClientSocket::LoadDisconnectEx() {
+  // Load the DisconnectEx function into memory using WSAIoctl.
+  GUID guid_disconnect_ex = WSAID_DISCONNECTEX;
+  DWORD bytes;
+  int status = WSAIoctl(socket(),
+                        SIO_GET_EXTENSION_FUNCTION_POINTER,
+                        &guid_disconnect_ex,
+                        sizeof(guid_disconnect_ex),
+                        &DisconnectEx_,
+                        sizeof(DisconnectEx_),
+                        &bytes,
+                        NULL,
+                        NULL);
+  if (status == SOCKET_ERROR) {
+    Log::PrintErr("Error WSAIoctl failed: %d\n", WSAGetLastError());
+    return false;
+  }
+  return true;
+}
+
+
 void ClientSocket::Shutdown(int how) {
   int rc = shutdown(socket(), how);
-  if (rc == SOCKET_ERROR) {
-    Log::PrintErr("shutdown failed: %d %d\n", socket(), WSAGetLastError());
-  }
   if (how == SD_RECEIVE) MarkClosedRead();
   if (how == SD_SEND) MarkClosedWrite();
   if (how == SD_BOTH) {
@@ -554,6 +546,13 @@
 }
 
 
+void ClientSocket::DoClose() {
+  // Always do a suhtdown before initiating a disconnect.
+  shutdown(socket(), SD_BOTH);
+  IssueDisconnect();
+}
+
+
 bool ClientSocket::IssueRead() {
   ScopedLock lock(this);
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
@@ -604,6 +603,27 @@
 }
 
 
+void ClientSocket::IssueDisconnect() {
+  IOBuffer* buffer = IOBuffer::AllocateDisconnectBuffer();
+  BOOL ok = DisconnectEx_(
+    socket(), buffer->GetCleanOverlapped(), TF_REUSE_SOCKET, 0);
+  if (!ok && WSAGetLastError() != WSA_IO_PENDING) {
+    DisconnectComplete(buffer);
+  }
+}
+
+
+void ClientSocket::DisconnectComplete(IOBuffer* buffer) {
+  IOBuffer::DisposeBuffer(buffer);
+  closesocket(socket());
+  if (data_ready_ != NULL) {
+    IOBuffer::DisposeBuffer(data_ready_);
+  }
+  // When disconnect is complete get rid of the object.
+  delete this;
+}
+
+
 void ClientSocket::EnsureInitialized(
     EventHandlerImplementation* event_handler) {
   ScopedLock lock(this);
@@ -615,17 +635,8 @@
 }
 
 
-void ClientSocket::AfterClose() {
-  ScopedLock lock(this);
-  if (data_ready_ != NULL) {
-    IOBuffer::DisposeBuffer(data_ready_);
-    data_ready_ = NULL;
-  }
-}
-
-
 bool ClientSocket::IsClosed() {
-  return IsClosing() && !HasPendingRead() && !HasPendingWrite();
+  return false;
 }
 
 
@@ -649,49 +660,61 @@
 
       Handle::ScopedLock lock(listen_socket);
 
-      // If incomming connections are requested make sure that pending accepts
-      // are issued.
+      // If incomming connections are requested make sure to post already
+      // accepted connections.
       if ((msg->data & (1 << kInEvent)) != 0) {
+        if (listen_socket->CanAccept()) {
+          int event_mask = (1 << kInEvent);
+          handle->set_mask(handle->mask() & ~event_mask);
+          DartUtils::PostInt32(handle->port(), event_mask);
+        }
+        // Always keep 5 outstanding accepts going, to enhance performance.
         while (listen_socket->pending_accept_count() < 5) {
           listen_socket->IssueAccept();
         }
       }
 
       if ((msg->data & (1 << kCloseCommand)) != 0) {
-        listen_socket->close();
+        listen_socket->Close();
         if (listen_socket->IsClosed()) {
           delete_handle = true;
         }
       }
     } else {
-      handle->SetPortAndMask(msg->dart_port, msg->data);
       handle->EnsureInitialized(this);
 
       Handle::ScopedLock lock(handle);
 
       if (!handle->IsError()) {
-        // If in events (data available events) have been requested, and data
-        // is available, post an in event immediately. Otherwise make sure
-        // that a pending read is issued, unless the socket is already closed
-        // for read.
-        if ((msg->data & (1 << kInEvent)) != 0) {
-          if (handle->Available() > 0) {
-            int event_mask = (1 << kInEvent);
-            handle->set_mask(handle->mask() & ~event_mask);
-            DartUtils::PostInt32(handle->port(), event_mask);
-          } else if (!handle->HasPendingRead() &&
-                     !handle->IsClosedRead()) {
-            handle->IssueRead();
-          }
-        }
+        if ((msg->data & ((1 << kInEvent) | (1 << kOutEvent))) != 0) {
+          // Only set mask if we turned on kInEvent or kOutEvent.
+          handle->SetPortAndMask(msg->dart_port, msg->data);
 
-        // If out events (can write events) have been requested, and there
-        // are no pending writes, post an out event immediately.
-        if ((msg->data & (1 << kOutEvent)) != 0) {
-          if (!handle->HasPendingWrite()) {
-            int event_mask = (1 << kOutEvent);
-            handle->set_mask(handle->mask() & ~event_mask);
-            DartUtils::PostInt32(handle->port(), event_mask);
+          // If in events (data available events) have been requested, and data
+          // is available, post an in event immediately. Otherwise make sure
+          // that a pending read is issued, unless the socket is already closed
+          // for read.
+          if ((msg->data & (1 << kInEvent)) != 0) {
+            if (handle->Available() > 0) {
+              int event_mask = (1 << kInEvent);
+              handle->set_mask(handle->mask() & ~event_mask);
+              DartUtils::PostInt32(handle->port(), event_mask);
+            } else if (handle->IsClosedRead()) {
+              int event_mask = (1 << kCloseEvent);
+              DartUtils::PostInt32(handle->port(), event_mask);
+            } else if (!handle->HasPendingRead()) {
+              handle->IssueRead();
+            }
+          }
+
+          // If out events (can write events) have been requested, and there
+          // are no pending writes, post an out event immediately.
+          if ((msg->data & (1 << kOutEvent)) != 0) {
+            if (!handle->HasPendingWrite()) {
+              int event_mask = (1 << kOutEvent);
+              handle->set_mask(handle->mask() & ~event_mask);
+              DartUtils::PostInt32(handle->port(), event_mask);
+            }
           }
         }
 
@@ -708,7 +731,7 @@
       }
 
       if ((msg->data & (1 << kCloseCommand)) != 0) {
-        handle->close();
+        handle->Close();
         if (handle->IsClosed()) {
           delete_handle = true;
         }
@@ -807,6 +830,13 @@
 }
 
 
+void EventHandlerImplementation::HandleDisconnect(
+    ClientSocket* client_socket,
+    int bytes,
+    IOBuffer* buffer) {
+  client_socket->DisconnectComplete(buffer);
+}
+
 void EventHandlerImplementation::HandleTimeout() {
   // TODO(sgjesse) check if there actually is a timeout.
   DartUtils::PostNull(timeout_port_);
@@ -835,6 +865,11 @@
       HandleWrite(handle, bytes, buffer);
       break;
     }
+    case IOBuffer::kDisconnect: {
+      ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(key);
+      HandleDisconnect(client_socket, bytes, buffer);
+      break;
+    }
     default:
       UNREACHABLE();
   }
@@ -858,7 +893,7 @@
   if (timeout_ == kInfinityTimeout) {
     return kInfinityTimeout;
   }
-  intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
+  intptr_t millis = timeout_ - TimerUtils::GetCurrentTimeMilliseconds();
   return (millis < 0) ? 0 : millis;
 }
 
@@ -947,3 +982,5 @@
 void EventHandlerImplementation::Shutdown() {
   SendData(kShutdownId, 0, 0);
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index 7b4902f..44d710c 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -36,11 +36,12 @@
 // socket for the client.
 class IOBuffer {
  public:
-  enum Operation { kAccept, kRead, kWrite };
+  enum Operation { kAccept, kRead, kWrite, kDisconnect };
 
   static IOBuffer* AllocateAcceptBuffer(int buffer_size);
   static IOBuffer* AllocateReadBuffer(int buffer_size);
   static IOBuffer* AllocateWriteBuffer(int buffer_size);
+  static IOBuffer* AllocateDisconnectBuffer();
   static void DisposeBuffer(IOBuffer* buffer);
 
   // Find the IO buffer from the OVERLAPPED address.
@@ -177,7 +178,8 @@
 
   bool CreateCompletionPort(HANDLE completion_port);
 
-  void close();
+  void Close();
+  virtual void DoClose();
   virtual bool IsClosed() = 0;
 
   void SetPortAndMask(Dart_Port port, intptr_t mask) {
@@ -216,7 +218,6 @@
   explicit Handle(HANDLE handle);
   Handle(HANDLE handle, Dart_Port port);
 
-  virtual void AfterClose() = 0;
   virtual void HandleIssueError();
 
   Type type_;
@@ -247,9 +248,6 @@
 
   virtual void EnsureInitialized(EventHandlerImplementation* event_handler);
   virtual bool IsClosed();
-
- private:
-  virtual void AfterClose();
 };
 
 
@@ -284,6 +282,7 @@
 
   // Socket interface exposing normal socket operations.
   ClientSocket* Accept();
+  bool CanAccept();
 
   // Internal interface used by the event handler.
   bool HasPendingAccept() { return pending_accept_count_ > 0; }
@@ -292,13 +291,13 @@
 
   virtual void EnsureInitialized(
     EventHandlerImplementation* event_handler);
+  virtual void DoClose();
   virtual bool IsClosed();
 
   int pending_accept_count() { return pending_accept_count_; }
 
  private:
   bool LoadAcceptEx();
-  virtual void AfterClose();
 
   LPFN_ACCEPTEX AcceptEx_;
   int pending_accept_count_;
@@ -312,11 +311,17 @@
 // Information on connected sockets.
 class ClientSocket : public SocketHandle {
  public:
-  explicit ClientSocket(SOCKET s) : SocketHandle(s), next_(NULL) {
+  explicit ClientSocket(SOCKET s) : SocketHandle(s),
+                                    DisconnectEx_(NULL),
+                                    next_(NULL) {
+    LoadDisconnectEx();
     type_ = kClientSocket;
   }
 
-  ClientSocket(SOCKET s, Dart_Port port) : SocketHandle(s, port), next_(NULL) {
+  ClientSocket(SOCKET s, Dart_Port port) : SocketHandle(s, port),
+                                           DisconnectEx_(NULL),
+                                           next_(NULL) {
+    LoadDisconnectEx();
     type_ = kClientSocket;
   }
 
@@ -332,17 +337,21 @@
   // Internal interface used by the event handler.
   virtual bool IssueRead();
   virtual bool IssueWrite();
+  void IssueDisconnect();
+  void DisconnectComplete(IOBuffer* buffer);
 
   virtual void EnsureInitialized(
     EventHandlerImplementation* event_handler);
+  virtual void DoClose();
   virtual bool IsClosed();
 
   ClientSocket* next() { return next_; }
   void set_next(ClientSocket* next) { next_ = next; }
 
  private:
-  virtual void AfterClose();
+  bool LoadDisconnectEx();
 
+  LPFN_DISCONNECTEX DisconnectEx_;
   ClientSocket* next_;
 };
 
@@ -367,7 +376,9 @@
   void HandleError(Handle* handle);
   void HandleRead(Handle* handle, int bytes, IOBuffer* buffer);
   void HandleWrite(Handle* handle, int bytes, IOBuffer* buffer);
-  void HandleClose(ClientSocket* client_socket);
+  void HandleDisconnect(ClientSocket* client_socket,
+                        int bytes,
+                        IOBuffer* buffer);
   void HandleIOCompletion(DWORD bytes, ULONG_PTR key, OVERLAPPED* overlapped);
 
   HANDLE completion_port() { return completion_port_; }
diff --git a/runtime/bin/extensions_android.cc b/runtime/bin/extensions_android.cc
index 8066b13..b136736 100644
--- a/runtime/bin/extensions_android.cc
+++ b/runtime/bin/extensions_android.cc
@@ -2,8 +2,11 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "bin/extensions.h"
-#include <dlfcn.h>
+#include <dlfcn.h>  // NOLINT
 
 void* Extensions::LoadExtensionLibrary(const char* library_path,
                                        const char* extension_name) {
@@ -21,3 +24,5 @@
   if (dlerror() != NULL) return NULL;
   return result;
 }
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/extensions_linux.cc b/runtime/bin/extensions_linux.cc
index 8066b13..8321efe 100644
--- a/runtime/bin/extensions_linux.cc
+++ b/runtime/bin/extensions_linux.cc
@@ -2,8 +2,11 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "bin/extensions.h"
-#include <dlfcn.h>
+#include <dlfcn.h>  // NOLINT
 
 void* Extensions::LoadExtensionLibrary(const char* library_path,
                                        const char* extension_name) {
@@ -21,3 +24,5 @@
   if (dlerror() != NULL) return NULL;
   return result;
 }
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/extensions_macos.cc b/runtime/bin/extensions_macos.cc
index 54f5c71..6d7842a 100644
--- a/runtime/bin/extensions_macos.cc
+++ b/runtime/bin/extensions_macos.cc
@@ -2,8 +2,11 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
 #include "bin/extensions.h"
-#include <dlfcn.h>
+#include <dlfcn.h>  // NOLINT
 
 void* Extensions::LoadExtensionLibrary(const char* library_path,
                                        const char* extension_name) {
@@ -21,3 +24,5 @@
   if (dlerror() != NULL) return NULL;
   return result;
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/extensions_win.cc b/runtime/bin/extensions_win.cc
index 8590d7b..9e8a653 100644
--- a/runtime/bin/extensions_win.cc
+++ b/runtime/bin/extensions_win.cc
@@ -2,6 +2,9 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "bin/extensions.h"
 #include "bin/utils.h"
 
@@ -19,3 +22,5 @@
 void* Extensions::ResolveSymbol(void* lib_handle, const char* symbol) {
   return GetProcAddress(reinterpret_cast<HMODULE>(lib_handle), symbol);
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/fdutils_android.cc b/runtime/bin/fdutils_android.cc
index 8d946e6..18b4ec3 100644
--- a/runtime/bin/fdutils_android.cc
+++ b/runtime/bin/fdutils_android.cc
@@ -2,10 +2,13 @@
 // 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 <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
+#include <unistd.h>  // NOLINT
+#include <sys/ioctl.h>  // NOLINT
 
 #include "bin/fdutils.h"
 
@@ -132,3 +135,5 @@
   }
   return count;
 }
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/fdutils_linux.cc b/runtime/bin/fdutils_linux.cc
index 8d946e6..84c2194 100644
--- a/runtime/bin/fdutils_linux.cc
+++ b/runtime/bin/fdutils_linux.cc
@@ -2,10 +2,13 @@
 // 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 <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
+#include <unistd.h>  // NOLINT
+#include <sys/ioctl.h>  // NOLINT
 
 #include "bin/fdutils.h"
 
@@ -132,3 +135,5 @@
   }
   return count;
 }
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/fdutils_macos.cc b/runtime/bin/fdutils_macos.cc
index 92e63fc..7087add 100644
--- a/runtime/bin/fdutils_macos.cc
+++ b/runtime/bin/fdutils_macos.cc
@@ -2,10 +2,13 @@
 // 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 <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
+#include <unistd.h>  // NOLINT
+#include <sys/ioctl.h>  // NOLINT
 
 #include "bin/fdutils.h"
 
@@ -133,3 +136,5 @@
   }
   return count;
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index bd32b5b..e366fc2 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -14,10 +14,11 @@
 
 static const int kMSPerSecond = 1000;
 
-dart::Mutex File::mutex_;
-int File::service_ports_size_ = 0;
-Dart_Port* File::service_ports_ = NULL;
-int File::service_ports_index_ = 0;
+
+// Forward declaration.
+static void FileService(Dart_Port, Dart_Port, Dart_CObject*);
+
+NativeService File::file_service_("FileService", FileService, 16);
 
 
 // The file pointer has been passed into Dart as an intptr_t and it is safe
@@ -890,10 +891,10 @@
 }
 
 
-void FileService(Dart_Port dest_port_id,
+static void FileService(Dart_Port dest_port_id,
                  Dart_Port reply_port_id,
                  Dart_CObject* message) {
-  CObject* response = CObject::False();
+  CObject* response = CObject::IllegalArgumentError();
   CObjectArray request(message);
   if (message->type == Dart_CObject::kArray) {
     if (request.Length() > 1 && request[0]->IsInt32()) {
@@ -967,27 +968,7 @@
 
 
 Dart_Port File::GetServicePort() {
-  MutexLocker lock(&mutex_);
-  if (service_ports_size_ == 0) {
-    ASSERT(service_ports_ == NULL);
-    service_ports_size_ = 16;
-    service_ports_ = new Dart_Port[service_ports_size_];
-    service_ports_index_ = 0;
-    for (int i = 0; i < service_ports_size_; i++) {
-      service_ports_[i] = ILLEGAL_PORT;
-    }
-  }
-
-  Dart_Port result = service_ports_[service_ports_index_];
-  if (result == ILLEGAL_PORT) {
-    result = Dart_NewNativePort("FileService",
-                                FileService,
-                                true);
-    ASSERT(result != ILLEGAL_PORT);
-    service_ports_[service_ports_index_] = result;
-  }
-  service_ports_index_ = (service_ports_index_ + 1) % service_ports_size_;
-  return result;
+  return file_service_.GetServicePort();
 }
 
 
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index 5f3fd00..53a1e44 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -12,6 +12,7 @@
 
 #include "bin/builtin.h"
 #include "bin/dartutils.h"
+#include "bin/native_service.h"
 #include "platform/globals.h"
 #include "platform/thread.h"
 
@@ -138,10 +139,7 @@
   // FileHandle is an OS specific class which stores data about the file.
   FileHandle* handle_;  // OS specific handle for the file.
 
-  static dart::Mutex mutex_;
-  static int service_ports_size_;
-  static Dart_Port* service_ports_;
-  static int service_ports_index_;
+  static NativeService file_service_;
 
   DISALLOW_COPY_AND_ASSIGN(File);
 };
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index ddcec13..7ae6415 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -2,13 +2,16 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "bin/file.h"
 
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <libgen.h>
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+#include <unistd.h>  // NOLINT
+#include <libgen.h>  // NOLINT
 
 #include "bin/builtin.h"
 #include "bin/log.h"
@@ -242,3 +245,5 @@
   if (S_ISREG(buf.st_mode)) return kFile;
   return kOther;
 }
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index ddcec13..3a73135 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -2,13 +2,16 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "bin/file.h"
 
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <libgen.h>
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+#include <unistd.h>  // NOLINT
+#include <libgen.h>  // NOLINT
 
 #include "bin/builtin.h"
 #include "bin/log.h"
@@ -242,3 +245,5 @@
   if (S_ISREG(buf.st_mode)) return kFile;
   return kOther;
 }
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index 0fd0c8d..14b2fd8 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -2,14 +2,17 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
 #include "bin/file.h"
 
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <libgen.h>
-#include <limits.h>
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+#include <unistd.h>  // NOLINT
+#include <libgen.h>  // NOLINT
+#include <limits.h>  // NOLINT
 
 #include "bin/builtin.h"
 #include "bin/fdutils.h"
@@ -250,3 +253,5 @@
   if (S_ISREG(buf.st_mode)) return kFile;
   return kOther;
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 73d195c..2ce097d 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -2,13 +2,16 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "bin/file.h"
 
-#include <fcntl.h>
-#include <io.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
+#include <fcntl.h>  // NOLINT
+#include <io.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
 
 #include "bin/builtin.h"
 #include "bin/log.h"
@@ -266,3 +269,5 @@
   // socket code will handle the different handle types.
   return kPipe;
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index f5e53ee..091cb69 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -422,24 +422,15 @@
   Dart_Handle library =
       LoadGenericSnapshotCreationScript(Builtin::kBuiltinLibrary);
   VerifyLoaded(library);
-  library = LoadGenericSnapshotCreationScript(Builtin::kUriLibrary);
-  VerifyLoaded(library);
-  library = LoadGenericSnapshotCreationScript(Builtin::kUtfLibrary);
-  VerifyLoaded(library);
 }
 
 
 static void SetupForGenericSnapshotCreation() {
   SetupForUriResolution();
 
-  Dart_Handle library =
-      LoadGenericSnapshotCreationScript(Builtin::kJsonLibrary);
-  VerifyLoaded(library);
-  library = LoadGenericSnapshotCreationScript(Builtin::kCryptoLibrary);
-  VerifyLoaded(library);
   // TODO(regis): Reenable this code for arm and mips when possible.
 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
-  library = LoadGenericSnapshotCreationScript(Builtin::kIOLibrary);
+  Dart_Handle library = LoadGenericSnapshotCreationScript(Builtin::kIOLibrary);
   VerifyLoaded(library);
 #endif
 }
diff --git a/runtime/bin/io_buffer.cc b/runtime/bin/io_buffer.cc
index 5f40478..b1bc958 100644
--- a/runtime/bin/io_buffer.cc
+++ b/runtime/bin/io_buffer.cc
@@ -6,7 +6,8 @@
 
 Dart_Handle IOBuffer::Allocate(intptr_t size, uint8_t **buffer) {
   uint8_t* data = Allocate(size);
-  Dart_Handle result = Dart_NewExternalByteArray(data, size,
+  Dart_Handle result = Dart_NewExternalTypedData(kUint8,
+                                                 data, size,
                                                  data, IOBuffer::Finalizer);
   if (Dart_IsError(result)) {
     Free(data);
diff --git a/runtime/bin/log_android.cc b/runtime/bin/log_android.cc
index 0a6b552..5f878f2 100644
--- a/runtime/bin/log_android.cc
+++ b/runtime/bin/log_android.cc
@@ -2,10 +2,13 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "bin/log.h"
 
-#include <stdio.h>
-#include <android/log.h>
+#include <stdio.h>  // NOLINT
+#include <android/log.h>  // NOLINT
 
 // TODO(gram): We should be buffering the data and only outputting
 // it when we see a '\n'.
@@ -18,3 +21,4 @@
   __android_log_vprint(ANDROID_LOG_ERROR, "Dart", format, args);
 }
 
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/log_linux.cc b/runtime/bin/log_linux.cc
index 1b99c70..0b825af 100644
--- a/runtime/bin/log_linux.cc
+++ b/runtime/bin/log_linux.cc
@@ -2,9 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "bin/log.h"
 
-#include <stdio.h>
+#include <stdio.h>  // NOLINT
 
 void Log::VPrint(const char* format, va_list args) {
   vfprintf(stdout, format, args);
@@ -16,3 +19,4 @@
   fflush(stdout);
 }
 
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/log_macos.cc b/runtime/bin/log_macos.cc
index 2f0d371..87c9075 100644
--- a/runtime/bin/log_macos.cc
+++ b/runtime/bin/log_macos.cc
@@ -2,9 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
 #include "bin/log.h"
 
-#include <stdio.h>
+#include <stdio.h>  // NOLINT
 
 void Log::VPrint(const char* format, va_list args) {
   vfprintf(stdout, format, args);
@@ -15,3 +18,5 @@
   vfprintf(stderr, format, args);
   fflush(stderr);
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/log_win.cc b/runtime/bin/log_win.cc
index 2f0d371..30c265d 100644
--- a/runtime/bin/log_win.cc
+++ b/runtime/bin/log_win.cc
@@ -2,9 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "bin/log.h"
 
-#include <stdio.h>
+#include <stdio.h>  // NOLINT
 
 void Log::VPrint(const char* format, va_list args) {
   vfprintf(stdout, format, args);
@@ -15,3 +18,5 @@
   vfprintf(stderr, format, args);
   fflush(stderr);
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 6d263ef..6a06bf3 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -463,7 +463,8 @@
     use_script_snapshot = false;  // No further usage of script snapshots.
   } else {
     // Prepare builtin and its dependent libraries for use to resolve URIs.
-    Dart_Handle uri_lib = Builtin::LoadAndCheckLibrary(Builtin::kUriLibrary);
+    Dart_Handle uri_url = DartUtils::NewString(DartUtils::kUriLibURL);
+    Dart_Handle uri_lib = Dart_LookupLibrary(uri_url);
     CHECK_RESULT(uri_lib);
     Dart_Handle builtin_lib =
         Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
diff --git a/runtime/bin/native_service.cc b/runtime/bin/native_service.cc
new file mode 100644
index 0000000..9d4c3e8
--- /dev/null
+++ b/runtime/bin/native_service.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "bin/native_service.h"
+
+#include "platform/globals.h"
+#include "bin/thread.h"
+
+
+NativeService::NativeService(const char* name,
+                             Dart_NativeMessageHandler handler,
+                             int number_of_ports)
+    : name_(name),
+      handler_(handler),
+      service_ports_size_(number_of_ports),
+      service_ports_index_(0) {
+  service_ports_ = new Dart_Port[service_ports_size_];
+  for (int i = 0; i < service_ports_size_; i++) {
+    service_ports_[i] = ILLEGAL_PORT;
+  }
+}
+
+
+NativeService::~NativeService() {
+  delete[] service_ports_;
+}
+
+
+Dart_Port NativeService::GetServicePort() {
+  MutexLocker lock(&mutex_);
+  Dart_Port result = service_ports_[service_ports_index_];
+  if (result == ILLEGAL_PORT) {
+    result = Dart_NewNativePort(name_, handler_, true);
+    ASSERT(result != ILLEGAL_PORT);
+    service_ports_[service_ports_index_] = result;
+  }
+  service_ports_index_ = (service_ports_index_ + 1) % service_ports_size_;
+  return result;
+}
diff --git a/runtime/bin/native_service.h b/runtime/bin/native_service.h
new file mode 100644
index 0000000..8bb4330
--- /dev/null
+++ b/runtime/bin/native_service.h
@@ -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.
+
+#ifndef BIN_NATIVE_SERVICE_H_
+#define BIN_NATIVE_SERVICE_H_
+
+#include "include/dart_api.h"
+#include "platform/globals.h"
+#include "platform/thread.h"
+
+// Utility class to set up a native service and allocate Dart native
+// ports to interact with it from Dart code. The number of native ports
+// allocated for each service is limited.
+class NativeService {
+ public:
+  // Create a native service with the given name and handler. Allow
+  // the creation of [number_of_ports] native ports for the service.
+  // If GetServicePort is called more than [number_of_ports] times
+  // one of the already allocated native ports will be reused.
+  NativeService(const char* name,
+                Dart_NativeMessageHandler handler,
+                int number_of_ports);
+
+  ~NativeService();
+
+  // Get a Dart native port for this native service.
+  Dart_Port GetServicePort();
+
+ private:
+  // Name and handler for the native service.
+  const char* name_;
+  Dart_NativeMessageHandler handler_;
+
+  // Allocated native ports for the service. Mutex protected since
+  // the service can be used from multiple isolates.
+  dart::Mutex mutex_;
+  int service_ports_size_;
+  Dart_Port* service_ports_;
+  int service_ports_index_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(NativeService);
+};
+
+#endif  // BIN_NATIVE_SERVICE_H_
diff --git a/runtime/bin/platform_android.cc b/runtime/bin/platform_android.cc
index a05de34..435f16b 100644
--- a/runtime/bin/platform_android.cc
+++ b/runtime/bin/platform_android.cc
@@ -2,11 +2,14 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "bin/platform.h"
 
-#include <signal.h>
-#include <string.h>
-#include <unistd.h>
+#include <signal.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 
 bool Platform::Initialize() {
@@ -65,3 +68,5 @@
 void Platform::FreeEnvironment(char** env, intptr_t count) {
   delete[] env;
 }
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/platform_linux.cc b/runtime/bin/platform_linux.cc
index da91bc5..48f6154 100644
--- a/runtime/bin/platform_linux.cc
+++ b/runtime/bin/platform_linux.cc
@@ -2,11 +2,14 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "bin/platform.h"
 
-#include <signal.h>
-#include <string.h>
-#include <unistd.h>
+#include <signal.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 
 bool Platform::Initialize() {
@@ -65,3 +68,5 @@
 void Platform::FreeEnvironment(char** env, intptr_t count) {
   delete[] env;
 }
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc
index 87e8c6f..d538eb7 100644
--- a/runtime/bin/platform_macos.cc
+++ b/runtime/bin/platform_macos.cc
@@ -2,12 +2,15 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
 #include "bin/platform.h"
 
-#include <crt_externs.h>
-#include <signal.h>
-#include <string.h>
-#include <unistd.h>
+#include <crt_externs.h>  // NOLINT
+#include <signal.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 
 bool Platform::Initialize() {
@@ -70,3 +73,5 @@
 void Platform::FreeEnvironment(char** env, intptr_t count) {
   delete[] env;
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/platform_win.cc b/runtime/bin/platform_win.cc
index 090fcf2..a71a455 100644
--- a/runtime/bin/platform_win.cc
+++ b/runtime/bin/platform_win.cc
@@ -2,6 +2,9 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "bin/platform.h"
 #include "bin/log.h"
 #include "bin/socket.h"
@@ -25,12 +28,7 @@
 
 
 bool Platform::LocalHostname(char *buffer, intptr_t buffer_length) {
-  static bool socket_initialized = false;
-  if (!socket_initialized) {
-    // Initialize Socket for gethostname.
-    if (!Socket::Initialize()) return false;
-    socket_initialized = true;
-  }
+  if (!Socket::Initialize()) return false;
   return gethostname(buffer, buffer_length) == 0;
 }
 
@@ -60,3 +58,5 @@
   for (int i = 0; i < count; i++) free(env[i]);
   delete[] env;
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index 81715ba..ac75854 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -58,9 +58,9 @@
 void FUNCTION_NAME(Process_Start)(Dart_NativeArguments args) {
   Dart_EnterScope();
   Dart_Handle process =  Dart_GetNativeArgument(args, 0);
-  intptr_t in;
-  intptr_t out;
-  intptr_t err;
+  intptr_t process_stdin;
+  intptr_t process_stdout;
+  intptr_t process_stderr;
   intptr_t exit_event;
   Dart_Handle status_handle = Dart_GetNativeArgument(args, 9);
   Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
@@ -119,9 +119,9 @@
       return;
     }
   }
-  Dart_Handle in_handle = Dart_GetNativeArgument(args, 5);
-  Dart_Handle out_handle = Dart_GetNativeArgument(args, 6);
-  Dart_Handle err_handle = Dart_GetNativeArgument(args, 7);
+  Dart_Handle stdin_handle = Dart_GetNativeArgument(args, 5);
+  Dart_Handle stdout_handle = Dart_GetNativeArgument(args, 6);
+  Dart_Handle stderr_handle = Dart_GetNativeArgument(args, 7);
   Dart_Handle exit_handle = Dart_GetNativeArgument(args, 8);
   intptr_t pid = -1;
   char* os_error_message = NULL;
@@ -132,16 +132,16 @@
                                   working_directory,
                                   string_environment,
                                   environment_length,
-                                  &in,
-                                  &out,
-                                  &err,
+                                  &process_stdout,
+                                  &process_stdin,
+                                  &process_stderr,
                                   &pid,
                                   &exit_event,
                                   &os_error_message);
   if (error_code == 0) {
-    Socket::SetSocketIdNativeField(in_handle, in);
-    Socket::SetSocketIdNativeField(out_handle, out);
-    Socket::SetSocketIdNativeField(err_handle, err);
+    Socket::SetSocketIdNativeField(stdin_handle, process_stdin);
+    Socket::SetSocketIdNativeField(stdout_handle, process_stdout);
+    Socket::SetSocketIdNativeField(stderr_handle, process_stderr);
     Socket::SetSocketIdNativeField(exit_handle, exit_event);
     Process::SetProcessIdNativeField(process, pid);
   } else {
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index f38e100..066539a 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -2,17 +2,20 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "bin/process.h"
 
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/wait.h>
-#include <unistd.h>
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
+#include <poll.h>  // NOLINT
+#include <signal.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/wait.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/fdutils.h"
 #include "bin/log.h"
@@ -566,3 +569,5 @@
 intptr_t Process::CurrentProcessId() {
   return static_cast<intptr_t>(getpid());
 }
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index cd71267..3522385 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -2,17 +2,20 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "bin/process.h"
 
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/wait.h>
-#include <unistd.h>
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
+#include <poll.h>  // NOLINT
+#include <signal.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/wait.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/fdutils.h"
 #include "bin/log.h"
@@ -562,3 +565,5 @@
 intptr_t Process::CurrentProcessId() {
   return static_cast<intptr_t>(getpid());
 }
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index f2d5ca3..67a7102 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -2,16 +2,19 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
 #include "bin/process.h"
 
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
+#include <errno.h>  // NOLINT
+#include <fcntl.h>  // NOLINT
+#include <poll.h>  // NOLINT
+#include <signal.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/fdutils.h"
 #include "bin/log.h"
@@ -293,7 +296,7 @@
     FDUtils::WriteToBlocking(
         exec_control_fd, os_error_message, strlen(os_error_message) + 1);
   }
-  TEMP_FAILURE_RETRY(close(exec_control_fd));
+  VOID_TEMP_FAILURE_RETRY(close(exec_control_fd));
   exit(1);
 }
 
@@ -335,8 +338,8 @@
   result = TEMP_FAILURE_RETRY(pipe(read_err));
   if (result < 0) {
     SetChildOsErrorMessage(os_error_message);
-    TEMP_FAILURE_RETRY(close(read_in[0]));
-    TEMP_FAILURE_RETRY(close(read_in[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
     Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message);
     return errno;
   }
@@ -344,10 +347,10 @@
   result = TEMP_FAILURE_RETRY(pipe(write_out));
   if (result < 0) {
     SetChildOsErrorMessage(os_error_message);
-    TEMP_FAILURE_RETRY(close(read_in[0]));
-    TEMP_FAILURE_RETRY(close(read_in[1]));
-    TEMP_FAILURE_RETRY(close(read_err[0]));
-    TEMP_FAILURE_RETRY(close(read_err[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
     Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message);
     return errno;
   }
@@ -355,12 +358,12 @@
   result = TEMP_FAILURE_RETRY(pipe(exec_control));
   if (result < 0) {
     SetChildOsErrorMessage(os_error_message);
-    TEMP_FAILURE_RETRY(close(read_in[0]));
-    TEMP_FAILURE_RETRY(close(read_in[1]));
-    TEMP_FAILURE_RETRY(close(read_err[0]));
-    TEMP_FAILURE_RETRY(close(read_err[1]));
-    TEMP_FAILURE_RETRY(close(write_out[0]));
-    TEMP_FAILURE_RETRY(close(write_out[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[1]));
     Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message);
     return errno;
   }
@@ -372,14 +375,14 @@
             TEMP_FAILURE_RETRY(fcntl(exec_control[1], F_GETFD)) | FD_CLOEXEC));
   if (result < 0) {
     SetChildOsErrorMessage(os_error_message);
-    TEMP_FAILURE_RETRY(close(read_in[0]));
-    TEMP_FAILURE_RETRY(close(read_in[1]));
-    TEMP_FAILURE_RETRY(close(read_err[0]));
-    TEMP_FAILURE_RETRY(close(read_err[1]));
-    TEMP_FAILURE_RETRY(close(write_out[0]));
-    TEMP_FAILURE_RETRY(close(write_out[1]));
-    TEMP_FAILURE_RETRY(close(exec_control[0]));
-    TEMP_FAILURE_RETRY(close(exec_control[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[1]));
+    VOID_TEMP_FAILURE_RETRY(close(exec_control[0]));
+    VOID_TEMP_FAILURE_RETRY(close(exec_control[1]));
     Log::PrintErr("fcntl failed: %s\n", *os_error_message);
     return errno;
   }
@@ -411,14 +414,14 @@
   if (pid < 0) {
     SetChildOsErrorMessage(os_error_message);
     delete[] program_arguments;
-    TEMP_FAILURE_RETRY(close(read_in[0]));
-    TEMP_FAILURE_RETRY(close(read_in[1]));
-    TEMP_FAILURE_RETRY(close(read_err[0]));
-    TEMP_FAILURE_RETRY(close(read_err[1]));
-    TEMP_FAILURE_RETRY(close(write_out[0]));
-    TEMP_FAILURE_RETRY(close(write_out[1]));
-    TEMP_FAILURE_RETRY(close(exec_control[0]));
-    TEMP_FAILURE_RETRY(close(exec_control[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[1]));
+    VOID_TEMP_FAILURE_RETRY(close(exec_control[0]));
+    VOID_TEMP_FAILURE_RETRY(close(exec_control[1]));
     return errno;
   } else if (pid == 0) {
     // Wait for parent process before setting up the child process.
@@ -429,25 +432,25 @@
       exit(1);
     }
 
-    TEMP_FAILURE_RETRY(close(write_out[1]));
-    TEMP_FAILURE_RETRY(close(read_in[0]));
-    TEMP_FAILURE_RETRY(close(read_err[0]));
-    TEMP_FAILURE_RETRY(close(exec_control[0]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
+    VOID_TEMP_FAILURE_RETRY(close(exec_control[0]));
 
     if (TEMP_FAILURE_RETRY(dup2(write_out[0], STDIN_FILENO)) == -1) {
       ReportChildError(exec_control[1]);
     }
-    TEMP_FAILURE_RETRY(close(write_out[0]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
 
     if (TEMP_FAILURE_RETRY(dup2(read_in[1], STDOUT_FILENO)) == -1) {
       ReportChildError(exec_control[1]);
     }
-    TEMP_FAILURE_RETRY(close(read_in[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
 
     if (TEMP_FAILURE_RETRY(dup2(read_err[1], STDERR_FILENO)) == -1) {
       ReportChildError(exec_control[1]);
     }
-    TEMP_FAILURE_RETRY(close(read_err[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
 
     if (working_directory != NULL &&
         TEMP_FAILURE_RETRY(chdir(working_directory)) == -1) {
@@ -458,7 +461,7 @@
       environ = program_environment;
     }
 
-    TEMP_FAILURE_RETRY(
+    VOID_TEMP_FAILURE_RETRY(
         execvp(path, const_cast<char* const*>(program_arguments)));
 
     ReportChildError(exec_control[1]);
@@ -473,12 +476,12 @@
   result = TEMP_FAILURE_RETRY(pipe(event_fds));
   if (result < 0) {
     SetChildOsErrorMessage(os_error_message);
-    TEMP_FAILURE_RETRY(close(read_in[0]));
-    TEMP_FAILURE_RETRY(close(read_in[1]));
-    TEMP_FAILURE_RETRY(close(read_err[0]));
-    TEMP_FAILURE_RETRY(close(read_err[1]));
-    TEMP_FAILURE_RETRY(close(write_out[0]));
-    TEMP_FAILURE_RETRY(close(write_out[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[1]));
     Log::PrintErr("Error pipe creation failed: %s\n", *os_error_message);
     return errno;
   }
@@ -499,7 +502,7 @@
   // Read exec result from child. If no data is returned the exec was
   // successful and the exec call closed the pipe. Otherwise the errno
   // is written to the pipe.
-  TEMP_FAILURE_RETRY(close(exec_control[1]));
+  VOID_TEMP_FAILURE_RETRY(close(exec_control[1]));
   int child_errno;
   int bytes_read = -1;
   ASSERT(sizeof(child_errno) == sizeof(errno));
@@ -515,16 +518,16 @@
     message[kMaxMessageSize - 1] = '\0';
     *os_error_message = message;
   }
-  TEMP_FAILURE_RETRY(close(exec_control[0]));
+  VOID_TEMP_FAILURE_RETRY(close(exec_control[0]));
 
   // Return error code if any failures.
   if (bytes_read != 0) {
-    TEMP_FAILURE_RETRY(close(read_in[0]));
-    TEMP_FAILURE_RETRY(close(read_in[1]));
-    TEMP_FAILURE_RETRY(close(read_err[0]));
-    TEMP_FAILURE_RETRY(close(read_err[1]));
-    TEMP_FAILURE_RETRY(close(write_out[0]));
-    TEMP_FAILURE_RETRY(close(write_out[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[0]));
+    VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
+    VOID_TEMP_FAILURE_RETRY(close(write_out[1]));
     if (bytes_read == -1) {
       return errno;  // Read failed.
     } else {
@@ -534,13 +537,13 @@
 
   FDUtils::SetNonBlocking(read_in[0]);
   *in = read_in[0];
-  TEMP_FAILURE_RETRY(close(read_in[1]));
+  VOID_TEMP_FAILURE_RETRY(close(read_in[1]));
   FDUtils::SetNonBlocking(write_out[1]);
   *out = write_out[1];
-  TEMP_FAILURE_RETRY(close(write_out[0]));
+  VOID_TEMP_FAILURE_RETRY(close(write_out[0]));
   FDUtils::SetNonBlocking(read_err[0]);
   *err = read_err[0];
-  TEMP_FAILURE_RETRY(close(read_err[1]));
+  VOID_TEMP_FAILURE_RETRY(close(read_err[1]));
 
   *id = pid;
   return 0;
@@ -560,3 +563,5 @@
 intptr_t Process::CurrentProcessId() {
   return static_cast<intptr_t>(getpid());
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index edc29e2..29913b1 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -25,7 +25,7 @@
   /* patch */ static Future<ProcessResult> run(String executable,
                                                List<String> arguments,
                                                [ProcessOptions options]) {
-    return new _NonInteractiveProcess(executable, arguments, options)._result;
+    return _runNonInteractiveProcess(executable, arguments, options);
   }
 }
 
@@ -88,13 +88,15 @@
       });
     }
 
-    _in = new _Socket._internalReadOnly();  // stdout coming from process.
-    _out = new _Socket._internalWriteOnly();  // stdin going to process.
-    _err = new _Socket._internalReadOnly();  // stderr coming from process.
-    _exitHandler = new _Socket._internalReadOnly();
+    // stdin going to process.
+    _stdin = new _Socket._writePipe();
+    // stdout coming from process.
+    _stdout = new _Socket._readPipe();
+    // stderr coming from process.
+    _stderr = new _Socket._readPipe();
+    _exitHandler = new _Socket._readPipe();
     _ended = false;
     _started = false;
-    _onExit = null;
   }
 
   String _windowsArgumentEscape(String argument) {
@@ -160,16 +162,12 @@
                                   _arguments,
                                   _workingDirectory,
                                   _environment,
-                                  _in,
-                                  _out,
-                                  _err,
-                                  _exitHandler,
+                                  _stdin._nativeSocket,
+                                  _stdout._nativeSocket,
+                                  _stderr._nativeSocket,
+                                  _exitHandler._nativeSocket,
                                   status);
       if (!success) {
-        _in.close();
-        _out.close();
-        _err.close();
-        _exitHandler.close();
         completer.completeError(
             new ProcessException(_path,
                                  _arguments,
@@ -179,23 +177,12 @@
       }
       _started = true;
 
-      _in._closed = false;
-      _out._closed = false;
-      _err._closed = false;
-      _exitHandler._closed = false;
-
-      // Make sure to activate socket handlers now that the file
-      // descriptors have been set.
-      _in._activateHandlers();
-      _out._activateHandlers();
-      _err._activateHandlers();
-
       // Setup an exit handler to handle internal cleanup and possible
       // callback when a process terminates.
       int exitDataRead = 0;
       final int EXIT_DATA_SIZE = 8;
       List<int> exitDataBuffer = new List<int>.fixedLength(EXIT_DATA_SIZE);
-      _exitHandler.inputStream.onData = () {
+      _exitHandler.listen((data) {
 
         int exitCode(List<int> ints) {
           var code = _intFromBytes(ints, 0);
@@ -206,18 +193,17 @@
 
         void handleExit() {
           _ended = true;
-          _exitCode = exitCode(exitDataBuffer);
-          if (_onExit != null) _onExit(_exitCode);
-          _out.close();
+          _exitCode.complete(exitCode(exitDataBuffer));
+          // Kill stdin, helping hand if the user forgot to do it.
+          _stdin.destroy();
         }
 
-        exitDataRead += _exitHandler.inputStream.readInto(
-            exitDataBuffer, exitDataRead, EXIT_DATA_SIZE - exitDataRead);
+        exitDataBuffer.setRange(exitDataRead, data.length, data);
+        exitDataRead += data.length;
         if (exitDataRead == EXIT_DATA_SIZE) {
-          _exitHandler.close();
           handleExit();
         }
-      };
+      });
 
       completer.complete(this);
     });
@@ -228,24 +214,29 @@
                     List<String> arguments,
                     String workingDirectory,
                     List<String> environment,
-                    Socket input,
-                    Socket output,
-                    Socket error,
-                    Socket exitHandler,
+                    _NativeSocket stdin,
+                    _NativeSocket stdout,
+                    _NativeSocket stderr,
+                    _NativeSocket exitHandler,
                     _ProcessStartStatus status) native "Process_Start";
 
-  InputStream get stdout {
-    return _in.inputStream;
+  Stream<List<int>> get stdout {
+    // TODO(ajohnsen): Get stream object only.
+    return _stdout;
   }
 
-  InputStream get stderr {
-    return _err.inputStream;
+  Stream<List<int>> get stderr {
+    // TODO(ajohnsen): Get stream object only.
+    return _stderr;
   }
 
-  OutputStream get stdin {
-    return _out.outputStream;
+  IOSink get stdin {
+    // TODO(ajohnsen): Get consumer object only.
+    return _stdin;
   }
 
+  Future<int> get exitCode => _exitCode.future;
+
   bool kill([ProcessSignal signal = ProcessSignal.SIGTERM]) {
     if (signal is! ProcessSignal) {
       throw new ArgumentError(
@@ -258,24 +249,18 @@
 
   bool _kill(Process p, int signal) native "Process_Kill";
 
-  void set onExit(void callback(int exitCode)) {
-    if (_ended) callback(_exitCode);
-    _onExit = callback;
-  }
-
   String _path;
   List<String> _arguments;
   String _workingDirectory;
   List<String> _environment;
-  // Private methods of _Socket are used by _in, _out, and _err.
-  _Socket _in;
-  _Socket _out;
-  _Socket _err;
+  // Private methods of Socket are used by _in, _out, and _err.
+  Socket _stdin;
+  Socket _stdout;
+  Socket _stderr;
   Socket _exitHandler;
-  int _exitCode;
   bool _ended;
   bool _started;
-  Function _onExit;
+  final Completer<int> _exitCode = new Completer<int>();
 }
 
 
@@ -283,88 +268,59 @@
 // that buffers output so it can be delivered when the process exits.
 // _NonInteractiveProcess is used to implement the Process.run
 // method.
-class _NonInteractiveProcess {
-  _NonInteractiveProcess(String path,
-                         List<String> arguments,
-                         ProcessOptions options) {
-    _completer = new Completer<ProcessResult>();
-    // Extract output encoding options and verify arguments.
-    var stdoutEncoding = Encoding.SYSTEM;
-    var stderrEncoding = Encoding.SYSTEM;
-    if (options != null) {
-      if (options.stdoutEncoding != null) {
-        stdoutEncoding = options.stdoutEncoding;
-        if (stdoutEncoding is !Encoding) {
-          throw new ArgumentError(
-              'stdoutEncoding option is not an encoding: $stdoutEncoding');
-        }
-      }
-      if (options.stderrEncoding != null) {
-        stderrEncoding = options.stderrEncoding;
-        if (stderrEncoding is !Encoding) {
-          throw new ArgumentError(
-              'stderrEncoding option is not an encoding: $stderrEncoding');
-        }
+Future<ProcessResult> _runNonInteractiveProcess(String path,
+                                                List<String> arguments,
+                                                ProcessOptions options) {
+  // Extract output encoding options and verify arguments.
+  var stdoutEncoding = Encoding.SYSTEM;
+  var stderrEncoding = Encoding.SYSTEM;
+  if (options != null) {
+    if (options.stdoutEncoding != null) {
+      stdoutEncoding = options.stdoutEncoding;
+      if (stdoutEncoding is !Encoding) {
+        throw new ArgumentError(
+            'stdoutEncoding option is not an encoding: $stdoutEncoding');
       }
     }
+    if (options.stderrEncoding != null) {
+      stderrEncoding = options.stderrEncoding;
+      if (stderrEncoding is !Encoding) {
+        throw new ArgumentError(
+            'stderrEncoding option is not an encoding: $stderrEncoding');
+      }
+    }
+  }
 
-    // Start the underlying process.
-    var processFuture = new _ProcessImpl(path, arguments, options)._start();
+  // Start the underlying process.
+  return Process.start(path, arguments, options).then((Process p) {
+    // Make sure the process stdin is closed.
+    p.stdin.close();
 
-    processFuture.then((Process p) {
-      // Make sure the process stdin is closed.
-      p.stdin.close();
+    // Setup stdout handling.
+    Future<StringBuffer> stdout = p.stdout
+        .transform(new StringDecoder(stdoutEncoding))
+        .reduce(
+            new StringBuffer(),
+            (buf, data) {
+              buf.add(data);
+              return buf;
+            });
 
-      // Setup process exit handling.
-      p.onExit = (exitCode) {
-        _exitCode = exitCode;
-        _checkDone();
-      };
+    Future<StringBuffer> stderr = p.stderr
+        .transform(new StringDecoder(stderrEncoding))
+        .reduce(
+            new StringBuffer(),
+            (buf, data) {
+              buf.add(data);
+              return buf;
+            });
 
-      // Setup stdout handling.
-      _stdoutBuffer = new StringBuffer();
-      var stdoutStream = new StringInputStream(p.stdout, stdoutEncoding);
-      stdoutStream.onData = () {
-        var data = stdoutStream.read();
-        if (data != null) _stdoutBuffer.add(data);
-      };
-      stdoutStream.onClosed = () {
-        _stdoutClosed = true;
-        _checkDone();
-      };
-
-      // Setup stderr handling.
-      _stderrBuffer = new StringBuffer();
-      var stderrStream = new StringInputStream(p.stderr, stderrEncoding);
-      stderrStream.onData = () {
-        var data = stderrStream.read();
-        if (data != null) _stderrBuffer.add(data);
-      };
-      stderrStream.onClosed = () {
-        _stderrClosed = true;
-        _checkDone();
-      };
-    }).catchError((error) {
-      _completer.completeError(error.error);
+    return Future.wait([p.exitCode, stdout, stderr]).then((result) {
+      return new _ProcessResult(result[0],
+                                result[1].toString(),
+                                result[2].toString());
     });
-  }
-
-  void _checkDone() {
-    if (_exitCode != null && _stderrClosed && _stdoutClosed) {
-      _completer.complete(new _ProcessResult(_exitCode,
-                                             _stdoutBuffer.toString(),
-                                             _stderrBuffer.toString()));
-    }
-  }
-
-  Future<ProcessResult> get _result => _completer.future;
-
-  Completer<ProcessResult> _completer;
-  StringBuffer _stdoutBuffer;
-  StringBuffer _stderrBuffer;
-  int _exitCode;
-  bool _stdoutClosed = false;
-  bool _stderrClosed = false;
+  });
 }
 
 
diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc
index a073717..407dd37 100644
--- a/runtime/bin/process_win.cc
+++ b/runtime/bin/process_win.cc
@@ -2,7 +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 <process.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
+#include <process.h>  // NOLINT
 
 #include "bin/builtin.h"
 #include "bin/process.h"
@@ -10,7 +13,6 @@
 #include "bin/log.h"
 #include "bin/thread.h"
 #include "bin/utils.h"
-#include "platform/globals.h"
 
 static const int kReadHandle = 0;
 static const int kWriteHandle = 1;
@@ -660,3 +662,5 @@
 intptr_t Process::CurrentProcessId() {
   return static_cast<intptr_t>(GetCurrentProcessId());
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 603a4c0..0f9140b 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -312,7 +312,7 @@
         Dart_NewPersistentHandle(Dart_ListGetAt(dart_buffers_object, i)));
     buffers_[i] = new uint8_t[size];
     Dart_Handle data = ThrowIfError(
-      Dart_NewExternalByteArray(buffers_[i], size, NULL, NULL));
+        Dart_NewExternalTypedData(kUint8, buffers_[i], size, NULL, NULL));
     ThrowIfError(Dart_SetField(dart_buffer_objects_[i],
                                data_identifier,
                                data));
@@ -340,7 +340,6 @@
                                   bool report_duplicate_initialization) {
   MutexLocker locker(&mutex_);
   if (!library_initialized_) {
-    library_initialized_ = true;
     password_ = strdup(password);  // This one copy persists until Dart exits.
     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
     // TODO(whesse): Verify there are no UTF-8 issues here.
@@ -362,20 +361,25 @@
                                       SECMOD_DB,
                                       init_flags);
     if (status != SECSuccess) {
+      mutex_.Unlock();  // MutexLocker destructor not called when throwing.
       ThrowPRException("Failed NSS_Init call.");
     }
+    library_initialized_ = true;
 
     status = NSS_SetDomesticPolicy();
     if (status != SECSuccess) {
+      mutex_.Unlock();  // MutexLocker destructor not called when throwing.
       ThrowPRException("Failed NSS_SetDomesticPolicy call.");
     }
     // Enable TLS, as well as SSL3 and SSL2.
     status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
     if (status != SECSuccess) {
+      mutex_.Unlock();  // MutexLocker destructor not called when throwing.
       ThrowPRException("Failed SSL_OptionSetDefault enable TLS call.");
     }
     status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL);
     if (status != SECSuccess) {
+      mutex_.Unlock();  // MutexLocker destructor not called when throwing.
       ThrowPRException("Failed SSL_ConfigServerSessionIDCache call.");
     }
 
@@ -442,17 +446,28 @@
   SECStatus status;
   if (is_server) {
     PK11_SetPasswordFunc(PasswordCallback);
-    CERTCertDBHandle* certificate_database = CERT_GetDefaultCertDB();
-    if (certificate_database == NULL) {
-      ThrowPRException("Certificate database cannot be loaded");
-    }
-    // TODO(whesse): Switch to a function that looks up certs by nickname,
-    // so that server and client uses of certificateName agree.
-    CERTCertificate* certificate = CERT_FindCertByNameString(
-        certificate_database,
-        const_cast<char*>(certificate_name));
-    if (certificate == NULL) {
-      ThrowPRException("Cannot find server certificate by name");
+
+    CERTCertificate* certificate = NULL;
+    if (strstr(certificate_name, "CN=") != NULL) {
+      // Look up certificate using the distinguished name (DN) certificate_name.
+      CERTCertDBHandle* certificate_database = CERT_GetDefaultCertDB();
+      if (certificate_database == NULL) {
+        ThrowPRException("Certificate database cannot be loaded");
+      }
+      certificate = CERT_FindCertByNameString(certificate_database,
+          const_cast<char*>(certificate_name));
+      if (certificate == NULL) {
+        ThrowPRException(
+            "Cannot find server certificate by distinguished name");
+      }
+    } else {
+      // Look up certificate using the nickname certificate_name.
+      certificate = PK11_FindCertFromNickname(
+          const_cast<char*>(certificate_name),
+          static_cast<void*>(const_cast<char*>(password_)));
+      if (certificate == NULL) {
+        ThrowPRException("Cannot find server certificate by nickname");
+      }
     }
     SECKEYPrivateKey* key = PK11_FindKeyByAnyCert(
         certificate,
diff --git a/runtime/bin/secure_socket_patch.dart b/runtime/bin/secure_socket_patch.dart
index 9e79c86..a52647c 100644
--- a/runtime/bin/secure_socket_patch.dart
+++ b/runtime/bin/secure_socket_patch.dart
@@ -28,8 +28,8 @@
     extends NativeFieldWrapperClass1
     implements _SecureFilter {
   _SecureFilterImpl() {
-    buffers = new List<_ExternalBuffer>(_SecureSocket.NUM_BUFFERS);
-    for (int i = 0; i < _SecureSocket.NUM_BUFFERS; ++i) {
+    buffers = new List<_ExternalBuffer>(_RawSecureSocket.NUM_BUFFERS);
+    for (int i = 0; i < _RawSecureSocket.NUM_BUFFERS; ++i) {
       buffers[i] = new _ExternalBuffer();
     }
   }
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index dfde8f3..d9c20e7 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -29,7 +29,8 @@
   if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 2), &port)) {
     intptr_t socket = Socket::CreateConnect(host, port);
     if (socket >= 0) {
-      Socket::SetSocketIdNativeField(socket_obj, socket);
+      Dart_Handle err = Socket::SetSocketIdNativeField(socket_obj, socket);
+      if (Dart_IsError(err)) Dart_PropagateError(err);
       Dart_SetReturnValue(args, Dart_True());
     } else {
       Dart_SetReturnValue(args, DartUtils::NewDartOSError());
@@ -48,7 +49,8 @@
   Dart_EnterScope();
   Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
   intptr_t socket = 0;
-  Socket::GetSocketIdNativeField(socket_obj, &socket);
+  Dart_Handle err = Socket::GetSocketIdNativeField(socket_obj, &socket);
+  if (Dart_IsError(err)) Dart_PropagateError(err);
   intptr_t available = Socket::Available(socket);
   if (available >= 0) {
     Dart_SetReturnValue(args, Dart_NewInteger(available));
@@ -63,7 +65,8 @@
   Dart_EnterScope();
   Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
   intptr_t socket = 0;
-  Socket::GetSocketIdNativeField(socket_obj, &socket);
+  Dart_Handle err = Socket::GetSocketIdNativeField(socket_obj, &socket);
+  if (Dart_IsError(err)) Dart_PropagateError(err);
   intptr_t available = Socket::Available(socket);
   if (available > 0) {
     int64_t length = 0;
@@ -110,7 +113,8 @@
   static bool short_socket_reads = Dart_IsVMFlagSet("short_socket_read");
   Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
   intptr_t socket = 0;
-  Socket::GetSocketIdNativeField(socket_obj, &socket);
+  Dart_Handle err = Socket::GetSocketIdNativeField(socket_obj, &socket);
+  if (Dart_IsError(err)) Dart_PropagateError(err);
   Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
   int64_t offset = 0;
   int64_t length = 0;
@@ -160,7 +164,8 @@
   static bool short_socket_writes = Dart_IsVMFlagSet("short_socket_write");
   Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
   intptr_t socket = 0;
-  Socket::GetSocketIdNativeField(socket_obj, &socket);
+  Dart_Handle err = Socket::GetSocketIdNativeField(socket_obj, &socket);
+  if (Dart_IsError(err)) Dart_PropagateError(err);
   Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
   ASSERT(Dart_IsList(buffer_obj));
   intptr_t offset =
@@ -180,20 +185,21 @@
 
   intptr_t total_bytes_written = 0;
   intptr_t bytes_written = 0;
-  if (Dart_IsByteArrayExternal(buffer_obj)) {
-    void* buffer = NULL;
-    result = Dart_ExternalByteArrayGetData(buffer_obj, &buffer);
-    if (Dart_IsError(result)) {
-      Dart_PropagateError(result);
-    }
-    buffer = static_cast<void*>((static_cast<uint8_t*>(buffer) + offset));
+  Dart_TypedData_Type type;
+  uint8_t* buffer = NULL;
+  intptr_t len;
+  result = Dart_TypedDataAcquireData(buffer_obj, &type,
+                                     reinterpret_cast<void**>(&buffer), &len);
+  if (!Dart_IsError(result)) {
+    buffer += offset;
     bytes_written = Socket::Write(socket, buffer, length);
     if (bytes_written > 0) total_bytes_written = bytes_written;
+    Dart_TypedDataReleaseData(buffer_obj);
   } else {
     // Send data in chunks of maximum 16KB.
     const intptr_t max_chunk_length =
         dart::Utils::Minimum(length, static_cast<intptr_t>(16 * KB));
-    uint8_t* buffer = new uint8_t[max_chunk_length];
+    buffer = new uint8_t[max_chunk_length];
     do {
       intptr_t chunk_length =
           dart::Utils::Minimum(max_chunk_length, length - total_bytes_written);
@@ -224,7 +230,8 @@
   Dart_EnterScope();
   Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
   intptr_t socket = 0;
-  Socket::GetSocketIdNativeField(socket_obj, &socket);
+  Dart_Handle err = Socket::GetSocketIdNativeField(socket_obj, &socket);
+  if (Dart_IsError(err)) Dart_PropagateError(err);
   OSError os_error;
   intptr_t port = Socket::GetPort(socket);
   if (port > 0) {
@@ -240,7 +247,8 @@
   Dart_EnterScope();
   Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
   intptr_t socket = 0;
-  Socket::GetSocketIdNativeField(socket_obj, &socket);
+  Dart_Handle err = Socket::GetSocketIdNativeField(socket_obj, &socket);
+  if (Dart_IsError(err)) Dart_PropagateError(err);
   OSError os_error;
   intptr_t port = 0;
   char host[INET_ADDRSTRLEN];
@@ -260,7 +268,8 @@
   Dart_EnterScope();
   Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
   intptr_t socket = 0;
-  Socket::GetSocketIdNativeField(socket_obj, &socket);
+  Dart_Handle err = Socket::GetSocketIdNativeField(socket_obj, &socket);
+  if (Dart_IsError(err)) Dart_PropagateError(err);
   OSError os_error;
   Socket::GetError(socket, &os_error);
   Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
@@ -291,7 +300,8 @@
       DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
   ASSERT(num == 0 || num == 1 || num == 2);
   intptr_t socket = Socket::GetStdioHandle(num);
-  Socket::SetSocketIdNativeField(socket_obj, socket);
+  Dart_Handle err = Socket::SetSocketIdNativeField(socket_obj, socket);
+  if (Dart_IsError(err)) Dart_PropagateError(err);
   Dart_SetReturnValue(args, Dart_NewBoolean(socket >= 0));
   Dart_ExitScope();
 }
@@ -312,7 +322,8 @@
     intptr_t socket =
         ServerSocket::CreateBindListen(bind_address, port, backlog);
     if (socket >= 0) {
-      Socket::SetSocketIdNativeField(socket_obj, socket);
+      Dart_Handle err = Socket::SetSocketIdNativeField(socket_obj, socket);
+      if (Dart_IsError(err)) Dart_PropagateError(err);
       Dart_SetReturnValue(args, Dart_True());
     } else {
       if (socket == -5) {
@@ -336,11 +347,14 @@
   Dart_EnterScope();
   Dart_Handle socket_obj = Dart_GetNativeArgument(args, 0);
   intptr_t socket = 0;
-  Socket::GetSocketIdNativeField(socket_obj, &socket);
+  Dart_Handle err = Socket::GetSocketIdNativeField(socket_obj, &socket);
+  if (Dart_IsError(err)) Dart_PropagateError(err);
   Dart_Handle result_socket_obj = Dart_GetNativeArgument(args, 1);
   intptr_t new_socket = ServerSocket::Accept(socket);
   if (new_socket >= 0) {
-    Socket::SetSocketIdNativeField(result_socket_obj, new_socket);
+    Dart_Handle err = Socket::SetSocketIdNativeField(result_socket_obj,
+                                                     new_socket);
+    if (Dart_IsError(err)) Dart_PropagateError(err);
     Dart_SetReturnValue(args, Dart_True());
   } else if (new_socket == ServerSocket::kTemporaryFailure) {
     Dart_SetReturnValue(args, Dart_False());
@@ -374,7 +388,7 @@
 void SocketService(Dart_Port dest_port_id,
                    Dart_Port reply_port_id,
                    Dart_CObject* message) {
-  CObject* response = CObject::False();
+  CObject* response = CObject::IllegalArgumentError();
   CObjectArray request(message);
   if (message->type == Dart_CObject::kArray) {
     if (request.Length() > 1 && request[0]->IsInt32()) {
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index 3e41242..8bd9683 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -2,11 +2,14 @@
 // 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
+#include <errno.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/socket.h"
 #include "bin/fdutils.h"
@@ -260,3 +263,5 @@
     Log::PrintErr("%s\n", error_message);
   }
 }
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index ff6c191..746adcf 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -2,12 +2,15 @@
 // 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
+#include <errno.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/fdutils.h"
 #include "bin/file.h"
@@ -201,10 +204,7 @@
   }
 
   fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
-  if (fd < 0) {
-    Log::PrintErr("Error CreateBind: %s\n", strerror(errno));
-    return -1;
-  }
+  if (fd < 0) return -1;
 
   FDUtils::SetCloseOnExec(fd);
 
@@ -222,12 +222,11 @@
                reinterpret_cast<struct sockaddr *>(&server_address),
                sizeof(server_address))) < 0) {
     TEMP_FAILURE_RETRY(close(fd));
-    Log::PrintErr("Error Bind: %s\n", strerror(errno));
     return -1;
   }
 
-  if (TEMP_FAILURE_RETRY(listen(fd, backlog)) != 0) {
-    Log::PrintErr("Error Listen: %s\n", strerror(errno));
+  if (TEMP_FAILURE_RETRY(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
+    TEMP_FAILURE_RETRY(close(fd));
     return -1;
   }
 
@@ -276,3 +275,5 @@
     Log::PrintErr("%s\n", error_message);
   }
 }
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index 20364cb..50ad16f 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -2,12 +2,15 @@
 // 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
+#include <errno.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
+#include <string.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "bin/fdutils.h"
 #include "bin/file.h"
@@ -37,7 +40,7 @@
 
   server = gethostbyname(host);
   if (server == NULL) {
-    TEMP_FAILURE_RETRY(close(fd));
+    VOID_TEMP_FAILURE_RETRY(close(fd));
     Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
     return -1;
   }
@@ -197,15 +200,12 @@
   }
 
   fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
-  if (fd < 0) {
-    Log::PrintErr("Error CreateBind: %s\n", strerror(errno));
-    return -1;
-  }
+  if (fd < 0) return -1;
 
   FDUtils::SetCloseOnExec(fd);
 
   int optval = 1;
-  TEMP_FAILURE_RETRY(
+  VOID_TEMP_FAILURE_RETRY(
       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
 
   server_address.sin_family = AF_INET;
@@ -217,13 +217,12 @@
           bind(fd,
                reinterpret_cast<struct sockaddr *>(&server_address),
                sizeof(server_address))) < 0) {
-    TEMP_FAILURE_RETRY(close(fd));
-    Log::PrintErr("Error Bind: %s\n", strerror(errno));
+    VOID_TEMP_FAILURE_RETRY(close(fd));
     return -1;
   }
 
-  if (TEMP_FAILURE_RETRY(listen(fd, backlog)) != 0) {
-    Log::PrintErr("Error Listen: %s\n", strerror(errno));
+  if (TEMP_FAILURE_RETRY(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
+    TEMP_FAILURE_RETRY(close(fd));
     return -1;
   }
 
@@ -262,3 +261,5 @@
     Log::PrintErr("%s\n", error_message);
   }
 }
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index bc91a32..15dd4c7 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -1,20 +1,25 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
-patch class ServerSocket {
-  /* patch */ factory ServerSocket(String bindAddress, int port, int backlog) {
-    return new _ServerSocket(bindAddress, port, backlog);
+patch class RawServerSocket  {
+  /* patch */ static Future<RawServerSocket> bind([String address = "127.0.0.1",
+                                                   int port = 0,
+                                                   int backlog = 0]) {
+    return _RawServerSocket.bind(address, port, backlog);
   }
 }
 
 
-patch class Socket {
-  /* patch */ factory Socket(String host, int port) => new _Socket(host, port);
+patch class RawSocket {
+  /* patch */ static Future<RawSocket> connect(String host, int port) {
+    return _RawSocket.connect(host, port);
+  }
 }
 
 
-class _SocketBase extends NativeFieldWrapperClass1 {
+// The _NativeSocket class encapsulates an OS socket.
+class _NativeSocket extends NativeFieldWrapperClass1 {
   // Bit flags used when communicating between the eventhandler and
   // dart code. The EVENT flags are used to indicate events of
   // interest when sending a message from dart code to the
@@ -24,584 +29,895 @@
   // eventhandler. COMMAND flags are never received from the
   // eventhandler. Additional flags are used to communicate other
   // information.
-  static const int _IN_EVENT = 0;
-  static const int _OUT_EVENT = 1;
-  static const int _ERROR_EVENT = 2;
-  static const int _CLOSE_EVENT = 3;
+  static const int READ_EVENT = 0;
+  static const int WRITE_EVENT = 1;
+  static const int ERROR_EVENT = 2;
+  static const int CLOSED_EVENT = 3;
+  static const int FIRST_EVENT = READ_EVENT;
+  static const int LAST_EVENT = CLOSED_EVENT;
+  static const int EVENT_COUNT = LAST_EVENT - FIRST_EVENT + 1;
 
-  static const int _CLOSE_COMMAND = 8;
-  static const int _SHUTDOWN_READ_COMMAND = 9;
-  static const int _SHUTDOWN_WRITE_COMMAND = 10;
+  static const int CLOSE_COMMAND = 8;
+  static const int SHUTDOWN_READ_COMMAND = 9;
+  static const int SHUTDOWN_WRITE_COMMAND = 10;
+  static const int FIRST_COMMAND = CLOSE_COMMAND;
+  static const int LAST_COMMAND = SHUTDOWN_WRITE_COMMAND;
 
-  // Flag send to the eventhandler providing additional information on
-  // the type of the file descriptor.
-  static const int _LISTENING_SOCKET = 16;
-  static const int _PIPE = 17;
+  // Type flag send to the eventhandler providing additional
+  // information on the type of the file descriptor.
+  static const int LISTENING_SOCKET = 16;
+  static const int PIPE_SOCKET = 17;
+  static const int TYPE_NORMAL_SOCKET = 0;
+  static const int TYPE_LISTENING_SOCKET = 1 << LISTENING_SOCKET;
+  static const int TYPE_PIPE = 1 << PIPE_SOCKET;
 
-  static const int _FIRST_EVENT = _IN_EVENT;
-  static const int _LAST_EVENT = _CLOSE_EVENT;
-
-  static const int _FIRST_COMMAND = _CLOSE_COMMAND;
-  static const int _LAST_COMMAND = _SHUTDOWN_WRITE_COMMAND;
-
-  _SocketBase () {
-    _handlerMap = new List.fixedLength(_LAST_EVENT + 1);
-    _handlerMask = 0;
-    _canActivateHandlers = true;
-    _closed = true;
-    _EventHandler._start();
-    _hashCode = _nextHashCode;
-    _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF;
-  }
-
-  // Multiplexes socket events to the socket handlers.
-  void _multiplex(int event_mask) {
-    _canActivateHandlers = false;
-    for (int i = _FIRST_EVENT; i <= _LAST_EVENT; i++) {
-      if (((event_mask & (1 << i)) != 0)) {
-        if ((i == _CLOSE_EVENT) && this is _Socket && !_closed) {
-          _closedRead = true;
-          if (_closedWrite) _close();
-        }
-
-        var eventHandler = _handlerMap[i];
-        if (eventHandler != null || i == _ERROR_EVENT) {
-          // Unregister the out handler before executing it. There is
-          // no need to notify the eventhandler as handlers are
-          // disabled while the event is handled.
-          if (i == _OUT_EVENT) _setHandler(i, null, notifyEventhandler: false);
-
-          // Don't call the in handler if there is no data available
-          // after all.
-          if ((i == _IN_EVENT) && (this is _Socket) && (available() == 0)) {
-            continue;
-          }
-          if (i == _ERROR_EVENT) {
-            _reportError(_getError(), "");
-            close();
-          } else {
-            eventHandler();
-          }
-        }
-      }
-    }
-    _canActivateHandlers = true;
-    _activateHandlers();
-  }
-
-  void _setHandler(int event,
-                   Function callback,
-                   {bool notifyEventhandler: true}) {
-    if (callback == null) {
-      _handlerMask &= ~(1 << event);
-    } else {
-      _handlerMask |= (1 << event);
-    }
-    _handlerMap[event] = callback;
-    // If the socket is only for writing then close the receive port
-    // when not waiting for any events.
-    if (this is _Socket &&
-        _closedRead &&
-        _handlerMask == 0 &&
-        _handler != null) {
-      _handler.close();
-      _handler = null;
-    } else {
-      if (notifyEventhandler) _activateHandlers();
-    }
-  }
-
-  OSError _getError() native "Socket_GetError";
-
-  int _getPort() native "Socket_GetPort";
-
-  void set onError(void callback(e)) {
-    _setHandler(_ERROR_EVENT, callback);
-  }
-
-  void _activateHandlers() {
-    if (_canActivateHandlers && !_closed) {
-      if (_handlerMask == 0) {
-        if (_handler != null) {
-          _handler.close();
-          _handler = null;
-        }
-        return;
-      }
-      int data = _handlerMask;
-      if (_isListenSocket()) {
-        data |= (1 << _LISTENING_SOCKET);
-      } else {
-        if (_closedRead) { data &= ~(1 << _IN_EVENT); }
-        if (_closedWrite) { data &= ~(1 << _OUT_EVENT); }
-        if (_isPipe()) data |= (1 << _PIPE);
-      }
-      _sendToEventHandler(data);
-    }
-  }
-
-  int get port {
-    if (_port == null) {
-      _port = _getPort();
-    }
-    return _port;
-  }
-
-  void close([bool halfClose = false]) {
-    if (!_closed) {
-      if (halfClose) {
-        _closeWrite();
-      } else {
-        _close();
-      }
-    } else if (_handler != null) {
-      // This is to support closing sockets created but never assigned
-      // any actual socket.
-      _handler.close();
-      _handler = null;
-    }
-  }
-
-  void _closeWrite() {
-    if (!_closed) {
-      if (_closedRead) {
-        _close();
-      } else {
-        _sendToEventHandler(1 << _SHUTDOWN_WRITE_COMMAND);
-      }
-      _closedWrite = true;
-    }
-  }
-
-  void _closeRead() {
-    if (!_closed) {
-      if (_closedWrite) {
-        _close();
-      } else {
-        _sendToEventHandler(1 << _SHUTDOWN_READ_COMMAND);
-      }
-      _closedRead = true;
-    }
-  }
-
-  void _close() {
-    if (!_closed) {
-      _sendToEventHandler(1 << _CLOSE_COMMAND);
-      _handler.close();
-      _handler = null;
-      _closed = true;
-    }
-  }
-
-  void _sendToEventHandler(int data) {
-    if (_handler == null) {
-      _handler = new ReceivePort();
-      _handler.receive((var message, ignored) { _multiplex(message); });
-    }
-    assert(!_closed);
-    _EventHandler._sendData(this, _handler, data);
-  }
-
-  bool _reportError(error, String message) {
-    void doReportError(Exception e) {
-      // Invoke the socket error callback if any.
-      bool reported = false;
-      if (_handlerMap[_ERROR_EVENT] != null) {
-        _handlerMap[_ERROR_EVENT](e);
-        reported = true;
-      }
-      // Propagate the error to any additional listeners.
-      reported = reported || _propagateError(e);
-      if (!reported) throw e;
-    }
-
-    // For all errors we close the socket, call the error handler and
-    // disable further calls of the error handler.
-    close();
-    if (error is OSError) {
-      doReportError(new SocketIOException(message, error));
-    } else if (error is List) {
-      assert(_isErrorResponse(error));
-      switch (error[0]) {
-        case _ILLEGAL_ARGUMENT_RESPONSE:
-          doReportError(new ArgumentError());
-          break;
-        case _OSERROR_RESPONSE:
-          doReportError(new SocketIOException(
-              message, new OSError(error[2], error[1])));
-          break;
-        default:
-          doReportError(new Exception("Unknown error"));
-          break;
-      }
-    } else {
-      doReportError(new SocketIOException(message));
-    }
-  }
-
-  int get hashCode => _hashCode;
-
-  bool _propagateError(Exception e) => false;
-
-  bool _isListenSocket();
-  bool _isPipe();
-
-  // Is this socket closed.
-  bool _closed;
-
-  // Dedicated ReceivePort for socket events.
-  ReceivePort _handler;
-
-  // Poll event to handler map.
-  List _handlerMap;
-
-  // Indicates for which poll events the socket registered handlers.
-  int _handlerMask;
-
-  // Indicates if native interrupts can be activated.
-  bool _canActivateHandlers;
-
-  // Holds the port of the socket, null if not known.
-  int _port;
-
-  // Hash code for the socket. Currently this is just a counter.
-  int _hashCode;
-  static int _nextHashCode = 0;
-  bool _closedRead = false;
-  bool _closedWrite = false;
-}
-
-
-class _ServerSocket extends _SocketBase implements ServerSocket {
-  // Constructor for server socket. First a socket object is allocated
-  // in which the native socket is stored. After that _createBind
-  // is called which creates a file descriptor and binds the given address
-  // and port to the socket. Null is returned if file descriptor creation or
-  // bind failed.
-  factory _ServerSocket(String bindAddress, int port, int backlog) {
-    _ServerSocket socket = new _ServerSocket._internal();
-    var result = socket._createBindListen(bindAddress, port, backlog);
-    if (result is OSError) {
-      socket.close();
-      throw new SocketIOException("Failed to create server socket", result);
-    }
-    socket._closed = false;
-    assert(result);
-    if (port != 0) {
-      socket._port = port;
-    }
-    return socket;
-  }
-
-  _ServerSocket._internal();
-
-  _accept(Socket socket) native "ServerSocket_Accept";
-
-  _createBindListen(String bindAddress, int port, int backlog)
-      native "ServerSocket_CreateBindListen";
-
-  void set onConnection(void callback(Socket connection)) {
-    _clientConnectionHandler = callback;
-    _setHandler(_SocketBase._IN_EVENT,
-                _clientConnectionHandler != null ? _connectionHandler : null);
-  }
-
-  void _connectionHandler() {
-    if (!_closed) {
-      _Socket socket = new _Socket._internal();
-      var result = _accept(socket);
-      if (result is OSError) {
-        _reportError(result, "Accept failed");
-      } else if (result) {
-        socket._closed = false;
-        _clientConnectionHandler(socket);
-      } else {
-        // Temporary failure accepting the connection. Ignoring
-        // temporary failures lets us retry when we wake up with data
-        // on the listening socket again.
-      }
-    }
-  }
-
-  bool _isListenSocket() => true;
-  bool _isPipe() => false;
-
-  var _clientConnectionHandler;
-}
-
-
-class _Socket extends _SocketBase implements Socket {
+  // Native port messages.
   static const HOST_NAME_LOOKUP = 0;
 
-  // Constructs a new socket. During the construction an asynchronous
-  // host name lookup is initiated. The returned socket is not yet
-  // connected but ready for registration of callbacks.
-  factory _Socket(String host, int port) {
-    Socket socket = new _Socket._internal();
-    _ensureSocketService();
-    List request = new List.fixedLength(2);
-    request[0] = HOST_NAME_LOOKUP;
-    request[1] = host;
-    _socketService.call(request).then((response) {
-      if (socket._isErrorResponse(response)) {
-        socket._reportError(response, "Failed host name lookup");
-      } else{
-        var result = socket._createConnect(response, port);
+  // Socket close state
+  bool isClosed = false;
+  bool isClosedRead = false;
+  bool isClosedWrite = false;
+  Completer closeCompleter = new Completer();
+
+  // Handlers and receive port for socket events from the event handler.
+  int eventMask = 0;
+  List eventHandlers;
+  ReceivePort eventPort;
+
+  // Indicates if native interrupts can be activated.
+  bool canActivateEvents = true;
+
+  // The type flags for this socket.
+  final int typeFlags;
+
+  // Holds the port of the socket, null if not known.
+  int localPort;
+
+  // Native port for socket services.
+  static SendPort socketService;
+
+  static Future<_NativeSocket> connect(String host, int port) {
+    var completer = new Completer();
+    ensureSocketService();
+    socketService.call([HOST_NAME_LOOKUP, host]).then((response) {
+      if (isErrorResponse(response)) {
+        completer.completeError(
+            createError(response, "Failed host name lookup"));
+      } else {
+        var socket = new _NativeSocket.normal();
+        var result = socket.nativeCreateConnect(response, port);
         if (result is OSError) {
-          socket.close();
-          socket._reportError(result, "Connection failed");
+          completer.completeError(createError(result, "Connection failed"));
         } else {
-          socket._closed = false;
-          socket._activateHandlers();
+          // Setup handlers for receiving the first write event which
+          // indicate that the socket is fully connected.
+          socket.setHandlers(
+              write: () {
+                socket.setListening(read: false, write: false);
+                completer.complete(socket);
+              },
+              error: (e) {
+                socket.close();
+                completer.completeError(createError(e, "Connection failed"));
+              }
+          );
+          socket.setListening(read: false, write: true);
         }
       }
     });
-    return socket;
+    return completer.future;
   }
 
-  _Socket._internal();
-  _Socket._internalReadOnly() : _pipe = true { super._closedWrite = true; }
-  _Socket._internalWriteOnly() : _pipe = true { super._closedRead = true; }
+  static Future<_NativeSocket> bind(String address,
+                                    int port,
+                                    int backlog) {
+    var socket = new _NativeSocket.listen();
+    var result = socket.nativeCreateBindListen(address, port, backlog);
+    if (result is OSError) {
+      return new Future.immediateError(
+          new SocketIOException("Failed to create server socket", result));
+    }
+    if (port != 0) socket.localPort = port;
+    return new Future.immediate(socket);
+  }
+
+  _NativeSocket.normal() : typeFlags = TYPE_NORMAL_SOCKET {
+    eventHandlers = new List.fixedLength(EVENT_COUNT + 1);
+    _EventHandler._start();
+  }
+
+  _NativeSocket.listen() : typeFlags = TYPE_LISTENING_SOCKET {
+    eventHandlers = new List.fixedLength(EVENT_COUNT + 1);
+    _EventHandler._start();
+  }
+
+  _NativeSocket.pipe() : typeFlags = TYPE_PIPE {
+    eventHandlers = new List.fixedLength(EVENT_COUNT + 1);
+    _EventHandler._start();
+  }
 
   int available() {
-    if (!_closed) {
-      var result = _available();
-      if (result is OSError) {
-        _reportError(result, "Available failed");
-        return 0;
-      } else {
-        return result;
-      }
+    if (isClosed) return 0;
+    var result = nativeAvailable();
+    if (result is OSError) {
+      reportError(result, "Available failed");
+      return 0;
+    } else {
+      return result;
     }
-    throw new
-        SocketIOException("Error: available failed - invalid socket handle");
   }
 
-  _available() native "Socket_Available";
-
-  List<int> read([int len]) {
+  List<int> read(int len) {
     if (len != null && len <= 0) {
-      throw new SocketIOException("Illegal length $len");
+      throw new ArgumentError("Illegal length $len");
     }
-    var result = _read(len == null ? -1 : len);
+    var result = nativeRead(len == null ? -1 : len);
     if (result is OSError) {
-      _reportError(result, "Read failed");
+      reportError(result, "Read failed");
       return null;
     }
     return result;
   }
 
-  _read(int len) native "Socket_Read";
-
-  int readList(List<int> buffer, int offset, int bytes) {
-    if (!_closed) {
-      if (bytes == 0) {
-        return 0;
-      }
-      if (offset < 0) {
-        throw new RangeError.value(offset);
-      }
-      if (bytes < 0) {
-        throw new RangeError.value(bytes);
-      }
-      if ((offset + bytes) > buffer.length) {
-        throw new RangeError.value(offset + bytes);
-      }
-      var result = _readList(buffer, offset, bytes);
-      if (result is OSError) {
-        _reportError(result, "Read failed");
-        return -1;
-      }
-      return result;
+  int write(List<int> buffer, int offset, int bytes) {
+    if (buffer is! List) throw new ArgumentError();
+    if (offset == null) offset = 0;
+    if (bytes == null) bytes = buffer.length;
+    if (offset < 0) throw new RangeError.value(offset);
+    if (bytes < 0) throw new RangeError.value(bytes);
+    if ((offset + bytes) > buffer.length) {
+      throw new RangeError.value(offset + bytes);
     }
-    throw new
-        SocketIOException("Error: readList failed - invalid socket handle");
-  }
-
-  _readList(List<int> buffer, int offset, int bytes) native "Socket_ReadList";
-
-  int writeList(List<int> buffer, int offset, int bytes) {
-    if (buffer is! List || offset is! int || bytes is! int) {
-      throw new ArgumentError(
-          "Invalid arguments to writeList on Socket");
+    if (offset is! int || bytes is! int) {
+      throw new ArgumentError("Invalid arguments to write on Socket");
     }
-    if (!_closed) {
-      if (bytes == 0) {
-        return 0;
-      }
-      if (offset < 0) {
-        throw new RangeError.value(offset);
-      }
-      if (bytes < 0) {
-        throw new RangeError.value(bytes);
-      }
-      if ((offset + bytes) > buffer.length) {
-        throw new RangeError.value(offset + bytes);
-      }
-      _BufferAndOffset bufferAndOffset =
-          _ensureFastAndSerializableBuffer(buffer, offset, bytes);
-      var result =
-          _writeList(bufferAndOffset.buffer, bufferAndOffset.offset, bytes);
-      if (result is OSError) {
-        _reportError(result, "Write failed");
-        // If writing fails we return 0 as the number of bytes and
-        // report the error on the error handler.
-        result = 0;
-      }
-      return result;
+    if (isClosed) return 0;
+    if (bytes == 0) return 0;
+    _BufferAndOffset bufferAndOffset =
+        _ensureFastAndSerializableBuffer(buffer, offset, bytes);
+    var result =
+        nativeWrite(bufferAndOffset.buffer, bufferAndOffset.offset, bytes);
+    if (result is OSError) {
+      reportError(result, "Write failed");
+      result = 0;
     }
-    throw new SocketIOException("writeList failed - invalid socket handle");
+    return result;
   }
 
-  _writeList(List<int> buffer, int offset, int bytes) native "Socket_WriteList";
-
-  bool _isErrorResponse(response) {
-    return response is List && response[0] != _SUCCESS_RESPONSE;
+  _NativeSocket accept() {
+    var socket = new _NativeSocket.normal();
+    if (nativeAccept(socket) != true) return null;
+    return socket;
   }
 
-  bool _createConnect(String host, int port) native "Socket_CreateConnect";
-
-  void set onWrite(void callback()) {
-    if (_outputStream != null) throw new StreamException(
-            "Cannot set write handler when output stream is used");
-    _clientWriteHandler = callback;
-    _updateOutHandler();
-  }
-
-  void set onConnect(void callback()) {
-    if (_seenFirstOutEvent) {
-      throw new StreamException(
-          "Cannot set connect handler when already connected");
-    }
-    _clientConnectHandler = callback;
-    _updateOutHandler();
-  }
-
-  void set onData(void callback()) {
-    if (_inputStream != null) throw new StreamException(
-            "Cannot set data handler when input stream is used");
-    _onData = callback;
-  }
-
-  void set onClosed(void callback()) {
-    if (_inputStream != null) throw new StreamException(
-           "Cannot set close handler when input stream is used");
-    _onClosed = callback;
-  }
-
-  bool _isListenSocket() => false;
-
-  bool _isPipe() => _pipe;
-
-  InputStream get inputStream {
-    if (_inputStream == null) {
-      if (_handlerMap[_SocketBase._IN_EVENT] != null ||
-          _handlerMap[_SocketBase._CLOSE_EVENT] != null) {
-        throw new StreamException(
-            "Cannot get input stream when socket handlers are used");
-      }
-      _inputStream = new _SocketInputStream(this);
-    }
-    return _inputStream;
-  }
-
-  OutputStream get outputStream {
-    if (_outputStream == null) {
-      if (_clientWriteHandler != null) {
-        throw new StreamException(
-            "Cannot get output stream when socket handlers are used");
-      }
-      _outputStream = new _SocketOutputStream(this);
-    }
-    return _outputStream;
-  }
-
-  void set _onWrite(void callback()) {
-    _setHandler(_SocketBase._OUT_EVENT, callback);
-  }
-
-  void set _onData(void callback()) {
-    _setHandler(_SocketBase._IN_EVENT, callback);
-  }
-
-  void set _onClosed(void callback()) {
-    _setHandler(_SocketBase._CLOSE_EVENT, callback);
-  }
-
-  bool _propagateError(Exception e) {
-    bool reported = false;
-    if (_inputStream != null) {
-      reported = reported || _inputStream._onSocketError(e);
-    }
-    if (_outputStream != null) {
-      reported = reported || _outputStream._onSocketError(e);
-    }
-    return reported;
-  }
-
-  void _updateOutHandler() {
-    void firstWriteHandler() {
-      assert(!_seenFirstOutEvent);
-      _seenFirstOutEvent = true;
-
-      // From now on the write handler is only the client write
-      // handler (connect handler cannot be called again). Change this
-      // before calling any handlers as handlers can change the
-      // handlers.
-      if (_clientWriteHandler == null) _onWrite = _clientWriteHandler;
-
-      // First out event is socket connected event.
-      if (_clientConnectHandler != null) _clientConnectHandler();
-      _clientConnectHandler = null;
-
-      // Always (even for the first out event) call the write handler.
-      if (_clientWriteHandler != null) _clientWriteHandler();
-    }
-
-    if (_clientConnectHandler == null && _clientWriteHandler == null) {
-      _onWrite = null;
-    } else {
-      if (_seenFirstOutEvent) {
-        _onWrite = _clientWriteHandler;
-      } else {
-        _onWrite = firstWriteHandler;
-      }
-    }
+  int get port {
+    if (localPort != null) return localPort;
+    return localPort = nativeGetPort();
   }
 
   int get remotePort {
-    if (_remotePort == null) {
-      remoteHost;
-    }
-    return _remotePort;
+    return nativeGetRemotePeer()[1];
   }
 
   String get remoteHost {
-    if (_remoteHost == null) {
-      List peer = _getRemotePeer();
-      _remoteHost = peer[0];
-      _remotePort = peer[1];
-    }
-    return _remoteHost;
+    return nativeGetRemotePeer()[0];
   }
 
-  List _getRemotePeer() native "Socket_GetRemotePeer";
+  // Multiplexes socket events to the socket handlers.
+  void multiplex(int events) {
+    canActivateEvents = false;
+    for (int i = FIRST_EVENT; i <= LAST_EVENT; i++) {
+      if (((events & (1 << i)) != 0)) {
+        if (i == CLOSED_EVENT &&
+            typeFlags != TYPE_LISTENING_SOCKET &&
+            !isClosed) {
+          isClosedRead = true;
+        }
 
-  static SendPort _newServicePort() native "Socket_NewServicePort";
+        var handler = eventHandlers[i];
+        assert(handler != null);
+        if (i == WRITE_EVENT) {
+          // If the event was disabled before we had a chance to fire the event,
+          // discard it. If we register again, we'll get a new one.
+          if ((eventMask & (1 << i)) == 0) continue;
+          // Unregister the out handler before executing it. There is
+          // no need to notify the eventhandler as handlers are
+          // disabled while the event is handled.
+          eventMask &= ~(1 << i);
+        }
 
-  static void _ensureSocketService() {
-    if (_socketService == null) {
-      _socketService = _Socket._newServicePort();
+        // Don't call the in handler if there is no data available
+        // after all.
+        if (i == READ_EVENT &&
+            typeFlags != TYPE_LISTENING_SOCKET &&
+            available() == 0) {
+          continue;
+        }
+        if (i == ERROR_EVENT) {
+          reportError(nativeGetError(), "");
+        } else if (!isClosed) {
+          handler();
+        }
+      }
+    }
+    if (isClosedRead && isClosedWrite) close();
+    canActivateEvents = true;
+    activateHandlers();
+  }
+
+  void setHandlers({read: null, write: null, error: null, closed: null}) {
+    eventHandlers[READ_EVENT] = read;
+    eventHandlers[WRITE_EVENT] = write;
+    eventHandlers[ERROR_EVENT] = error;
+    eventHandlers[CLOSED_EVENT] = closed;
+  }
+
+  void setListening({read: true, write: true}) {
+    eventMask = (1 << CLOSED_EVENT) | (1 << ERROR_EVENT);
+    if (read) eventMask |= (1 << READ_EVENT);
+    if (write) eventMask |= (1 << WRITE_EVENT);
+    activateHandlers();
+  }
+
+  Future get closeFuture => closeCompleter.future;
+
+  void activateHandlers() {
+    if (canActivateEvents && !isClosed) {
+      // If we don't listen for either read or write, disconnect as we won't
+      // get close and error events anyway.
+      if ((eventMask & ((1 << READ_EVENT) | (1 << WRITE_EVENT))) == 0) {
+        if (eventPort != null) disconnectFromEventHandler();
+      } else {
+        int data = eventMask;
+        data |= typeFlags;
+        if (isClosedRead) data &= ~(1 << READ_EVENT);
+        if (isClosedWrite) data &= ~(1 << WRITE_EVENT);
+        sendToEventHandler(data);
+      }
     }
   }
 
-  bool _seenFirstOutEvent = false;
-  bool _pipe = false;
-  Function _clientConnectHandler;
-  Function _clientWriteHandler;
-  _SocketInputStream _inputStream;
-  _SocketOutputStream _outputStream;
-  String _remoteHost;
-  int _remotePort;
-  static SendPort _socketService;
+  void close() {
+    if (!isClosed) {
+      sendToEventHandler(1 << CLOSE_COMMAND);
+      isClosed = true;
+      closeCompleter.complete(this);
+    }
+    // Outside the if support closing sockets created but never
+    // assigned any actual socket.
+    disconnectFromEventHandler();
+  }
+
+  void shutdown(SocketDirection direction) {
+    if (!isClosed) {
+      switch (direction) {
+        case SocketDirection.RECEIVE:
+          shutdownRead();
+          break;
+        case SocketDirection.SEND:
+          shutdownWrite();
+          break;
+        case SocketDirection.BOTH:
+          close();
+          break;
+        default:
+          throw new ArgumentError(direction);
+      }
+    }
+  }
+
+  void shutdownWrite() {
+    if (!isClosed) {
+      if (isClosedRead) {
+        close();
+      } else {
+        sendToEventHandler(1 << SHUTDOWN_WRITE_COMMAND);
+      }
+      isClosedWrite = true;
+    }
+  }
+
+  void shutdownRead() {
+    if (!isClosed) {
+      if (isClosedWrite) {
+        close();
+      } else {
+        sendToEventHandler(1 << SHUTDOWN_READ_COMMAND);
+      }
+      isClosedRead = true;
+    }
+  }
+
+  void sendToEventHandler(int data) {
+    connectToEventHandler();
+    assert(!isClosed);
+    _EventHandler._sendData(this, eventPort, data);
+  }
+
+  void connectToEventHandler() {
+    if (eventPort == null) {
+      eventPort = new ReceivePort();
+      eventPort.receive ((var message, _) => multiplex(message));
+    }
+  }
+
+  void disconnectFromEventHandler() {
+    if (eventPort != null) {
+      eventPort.close();
+      eventPort = null;
+    }
+  }
+
+  static void ensureSocketService() {
+    if (socketService == null) {
+      socketService = _NativeSocket.newServicePort();
+    }
+  }
+
+  // Check whether this is an error response from a native port call.
+  static bool isErrorResponse(response) {
+    return response is List && response[0] != _SUCCESS_RESPONSE;
+  }
+
+  // Create the appropriate error/exception from different returned
+  // error objects.
+  static createError(error, String message) {
+    if (error is OSError) {
+      return new SocketIOException(message, error);
+    } else if (error is List) {
+      assert(isErrorResponse(error));
+      switch (error[0]) {
+        case _ILLEGAL_ARGUMENT_RESPONSE:
+          return new ArgumentError();
+        case _OSERROR_RESPONSE:
+          return new SocketIOException(
+              message, new OSError(error[2], error[1]));
+        default:
+          return new Exception("Unknown error");
+      }
+    } else {
+      return new SocketIOException(message);
+    }
+  }
+
+  void reportError(error, String message) {
+    var e = createError(error, message);
+    // Invoke the error handler if any.
+    if (eventHandlers[ERROR_EVENT] != null) {
+      eventHandlers[ERROR_EVENT](e);
+    }
+    // For all errors we close the socket
+    close();
+  }
+
+  nativeAvailable() native "Socket_Available";
+  nativeRead(int len) native "Socket_Read";
+  nativeWrite(List<int> buffer, int offset, int bytes)
+      native "Socket_WriteList";
+  bool nativeCreateConnect(String host, int port) native "Socket_CreateConnect";
+  nativeCreateBindListen(String address, int port, int backlog)
+      native "ServerSocket_CreateBindListen";
+  nativeAccept(_NativeSocket socket) native "ServerSocket_Accept";
+  int nativeGetPort() native "Socket_GetPort";
+  List nativeGetRemotePeer() native "Socket_GetRemotePeer";
+  OSError nativeGetError() native "Socket_GetError";
+
+  static SendPort newServicePort() native "Socket_NewServicePort";
+}
+
+
+class _RawServerSocket extends Stream<RawSocket>
+                       implements RawServerSocket {
+  final _NativeSocket _socket;
+  StreamController<RawSocket> _controller;
+
+  static Future<_RawServerSocket> bind(String address,
+                                       int port,
+                                       int backlog) {
+    if (port < 0 || port > 0xFFFF)
+      throw new ArgumentError("Invalid port $port");
+    if (backlog < 0) throw new ArgumentError("Invalid backlog $backlog");
+    return _NativeSocket.bind(address, port, backlog)
+        .then((socket) => new _RawServerSocket(socket));
+  }
+
+  _RawServerSocket(this._socket) {
+    _controller = new StreamController(
+        onSubscriptionStateChange: _onSubscriptionStateChange,
+        onPauseStateChange: _onPauseStateChange);
+    _socket.closeFuture.then((_) => _controller.close());
+    _socket.setHandlers(
+      read: () {
+        var socket = _socket.accept();
+        if (socket != null) _controller.add(new _RawSocket(socket));
+      },
+      error: (e) {
+        _controller.signalError(new AsyncError(e));
+        _controller.close();
+      }
+    );
+  }
+
+  StreamSubscription<RawSocket> listen(void onData(RawSocket event),
+                                       {void onError(AsyncError error),
+                                        void onDone(),
+                                        bool unsubscribeOnError}) {
+    return _controller.stream.listen(
+        onData,
+        onError: onError,
+        onDone: onDone,
+        unsubscribeOnError: unsubscribeOnError);
+  }
+
+  int get port => _socket.port;
+
+  void close() => _socket.close();
+
+  void _pause() {
+    _socket.setListening(read: false, write: false);
+  }
+
+  void _resume() {
+    _socket.setListening(read: true, write: false);
+  }
+
+  void _onSubscriptionStateChange() {
+    if (_controller.hasSubscribers) {
+      _resume();
+    } else {
+      close();
+    }
+  }
+  void _onPauseStateChange() {
+    if (_controller.isPaused) {
+      _pause();
+    } else {
+      _resume();
+    }
+  }
+}
+
+
+class _RawSocket extends Stream<RawSocketEvent>
+                 implements RawSocket {
+  final _NativeSocket _socket;
+  StreamController<RawSocketEvent> _controller;
+  bool _readEventsEnabled = true;
+  bool _writeEventsEnabled = true;
+
+  static Future<RawSocket> connect(String host, int port) {
+    return _NativeSocket.connect(host, port)
+        .then((socket) => new _RawSocket(socket));
+  }
+
+  _RawSocket(this._socket) {
+    _controller = new StreamController(
+        onSubscriptionStateChange: _onSubscriptionStateChange,
+        onPauseStateChange: _onPauseStateChange);
+    _socket.closeFuture.then((_) => _controller.close());
+    _socket.setHandlers(
+      read: () => _controller.add(RawSocketEvent.READ),
+      write: () {
+        // The write event handler is automatically disabled by the
+        // event handler when it fires.
+        _writeEventsEnabled = false;
+        _controller.add(RawSocketEvent.WRITE);
+      },
+      closed: () => _controller.add(RawSocketEvent.READ_CLOSED),
+      error: (e) {
+        _controller.signalError(new AsyncError(e));
+        close();
+      }
+    );
+  }
+
+  factory _RawSocket._writePipe(int fd) {
+    var native = new _NativeSocket.pipe();
+    native.isClosedRead = true;
+    if (fd != null) _getStdioHandle(native, fd);
+    return new _RawSocket(native);
+  }
+
+  factory _RawSocket._readPipe(int fd) {
+    var native = new _NativeSocket.pipe();
+    native.isClosedWrite = true;
+    if (fd != null) _getStdioHandle(native, fd);
+    return new _RawSocket(native);
+  }
+
+  StreamSubscription<RawSocketEvent> listen(void onData(RawSocketEvent event),
+                                            {void onError(AsyncError error),
+                                             void onDone(),
+                                             bool unsubscribeOnError}) {
+    return _controller.stream.listen(
+        onData,
+        onError: onError,
+        onDone: onDone,
+        unsubscribeOnError: unsubscribeOnError);
+  }
+
+  int available() => _socket.available();
+
+  List<int> read([int len]) => _socket.read(len);
+
+  int write(List<int> buffer, [int offset, int count]) =>
+      _socket.write(buffer, offset, count);
+
+  void close() => _socket.close();
+
+  void shutdown(SocketDirection direction) => _socket.shutdown(direction);
+
+  int get port => _socket.port;
+
+  int get remotePort => _socket.remotePort;
+
+  String get remoteHost => _socket.remoteHost;
+
+  bool get readEventsEnabled => _readEventsEnabled;
+  void set readEventsEnabled(bool value) {
+    if (value != _readEventsEnabled) {
+      _readEventsEnabled = value;
+      if (!_controller.isPaused) _resume();
+    }
+  }
+
+  bool get writeEventsEnabled => _writeEventsEnabled;
+  void set writeEventsEnabled(bool value) {
+    if (value != _writeEventsEnabled) {
+      _writeEventsEnabled = value;
+      if (!_controller.isPaused) _resume();
+    }
+  }
+
+  _pause() {
+    _socket.setListening(read: false, write: false);
+  }
+
+  void _resume() {
+    _socket.setListening(read: _readEventsEnabled, write: _writeEventsEnabled);
+  }
+
+  void _onPauseStateChange() {
+    if (_controller.isPaused) {
+      _pause();
+    } else {
+      _resume();
+    }
+  }
+
+  void _onSubscriptionStateChange() {
+    if (_controller.hasSubscribers) {
+      _resume();
+    } else {
+      close();
+    }
+  }
+}
+
+
+patch class ServerSocket {
+  /* patch */ static Future<ServerSocket> bind([String address = "127.0.0.1",
+                                                int port = 0,
+                                                int backlog = 0]) {
+    return _ServerSocket.bind(address, port, backlog);
+  }
+}
+
+class _ServerSocket extends Stream<Socket>
+                    implements ServerSocket {
+  final _socket;
+
+  static Future<_ServerSocket> bind(String address,
+                                    int port,
+                                    int backlog) {
+    return _RawServerSocket.bind(address, port, backlog)
+        .then((socket) => new _ServerSocket(socket));
+  }
+
+  _ServerSocket(this._socket);
+
+  StreamSubscription<Socket> listen(void onData(Socket event),
+                                    {void onError(AsyncError error),
+                                     void onDone(),
+                                     bool unsubscribeOnError}) {
+    return _socket.map((rawSocket) => new _Socket(rawSocket)).listen(
+        onData,
+        onError: onError,
+        onDone: onDone,
+        unsubscribeOnError: unsubscribeOnError);
+  }
+
+  int get port => _socket.port;
+
+  void close() => _socket.close();
+}
+
+
+patch class Socket {
+  /* patch */ static Future<Socket> connect(String host, int port) {
+    return RawSocket.connect(host, port).then(
+        (socket) => new _Socket(socket));
+  }
+}
+
+
+patch class SecureSocket {
+  /* patch */ factory SecureSocket._(RawSecureSocket rawSocket) =>
+      new _SecureSocket(rawSocket);
+}
+
+
+class _SocketStreamConsumer extends StreamConsumer<List<int>, Socket> {
+  StreamSubscription subscription;
+  final _Socket socket;
+  int offset;
+  List<int> buffer;
+  bool paused = false;
+
+  _SocketStreamConsumer(this.socket);
+
+  Future<Socket> consume(Stream<List<int>> stream) {
+    subscription = stream.listen(
+        (data) {
+          assert(!paused);
+          assert(buffer == null);
+          buffer = data;
+          offset = 0;
+          write();
+        },
+        onDone: () {
+          socket._consumerDone();
+        });
+    return socket._doneFuture;
+  }
+
+  void write() {
+    try {
+      if (subscription == null) return;
+      assert(buffer != null);
+      // Write as much as possible.
+      offset += socket._write(buffer, offset, buffer.length - offset);
+      if (offset < buffer.length) {
+        if (!paused) {
+          paused = true;
+          // TODO(ajohnsen): It would be nice to avoid this check.
+          // Some info: socket._write can emit an event, if it fails to write.
+          // If the user closes the socket in that event, stop() will be called
+          // before we get a change to pause.
+          if (subscription == null) return;
+          subscription.pause();
+        }
+        socket._enableWriteEvent();
+      } else {
+        buffer = null;
+        if (paused) {
+          paused = false;
+          subscription.resume();
+        }
+      }
+    } catch (e) {
+      socket._consumerDone(e);
+    }
+  }
+
+  void stop() {
+    if (subscription == null) return;
+    subscription.cancel();
+    subscription = null;
+    socket._disableWriteEvent();
+  }
+}
+
+
+class _Socket extends Stream<List<int>> implements Socket {
+  RawSocket _raw;  // Set to null when the raw socket is closed.
+  bool _closed = false;  // Set to true when the raw socket is closed.
+  StreamController _controller;
+  bool _controllerClosed = false;
+  _SocketStreamConsumer _consumer;
+  IOSink<Socket> _sink;
+  Completer _doneCompleter;
+  var _subscription;
+
+  _Socket(RawSocket this._raw) {
+    _controller = new StreamController<List<int>>(
+        onSubscriptionStateChange: _onSubscriptionStateChange,
+        onPauseStateChange: _onPauseStateChange);
+    _consumer = new _SocketStreamConsumer(this);
+    _sink = new IOSink(_consumer);
+
+    // Disable read events until there is a subscription.
+    _raw.readEventsEnabled = false;
+
+    // Disable write events until the consumer needs it for pending writes.
+    _raw.writeEventsEnabled = false;
+  }
+
+  factory _Socket._writePipe([int fd]) {
+    return new _Socket(new _RawSocket._writePipe(fd));
+  }
+
+  factory _Socket._readPipe([int fd]) {
+    return new _Socket(new _RawSocket._readPipe(fd));
+  }
+
+  _NativeSocket get _nativeSocket => _raw._socket;
+
+  StreamSubscription<List<int>> listen(void onData(List<int> event),
+                                       {void onError(AsyncError error),
+                                        void onDone(),
+                                        bool unsubscribeOnError}) {
+    return _controller.stream.listen(
+        onData,
+        onError: onError,
+        onDone: onDone,
+        unsubscribeOnError: unsubscribeOnError);
+  }
+
+  Future<Socket> consume(Stream<List<int>> stream) {
+    return _sink.consume(stream);
+  }
+
+  Future<Socket> addStream(Stream<List<int>> stream) {
+    return _sink.addStream(stream);
+  }
+
+  void add(List<int> data) {
+    return _sink.add(data);
+  }
+
+  void addString(String string, [Encoding encoding = Encoding.UTF_8]) {
+    return _sink.addString(string, encoding);
+  }
+
+  close() => _sink.close();
+
+  Future<Socket> get done => _sink.done;
+
+  void destroy() {
+    // Destroy can always be called to get rid of a socket.
+    if (_raw == null) return;
+    _closeRawSocket();
+    _consumer.stop();
+    _controllerClosed = true;
+    _controller.close();
+  }
+
+  int get port => _raw.port;
+  String get remoteHost => _raw.remoteHost;
+  int get remotePort => _raw.remotePort;
+
+  // Ensure a subscription on the raw socket. Both the stream and the
+  // consumer needs a subscription as they share the error and done
+  // events from the raw socket.
+  void _ensureRawSocketSubscription() {
+    if (_subscription == null) {
+      _subscription = _raw.listen(_onData,
+                                  onError: _onError,
+                                  onDone: _onDone,
+                                  unsubscribeOnError: true);
+    }
+  }
+
+  _closeRawSocket() {
+    var tmp = _raw;
+    _raw = null;
+    _closed = true;
+    tmp.close();
+  }
+
+  void _onSubscriptionStateChange() {
+    if (_controller.hasSubscribers) {
+      _ensureRawSocketSubscription();
+      // Enable read events for providing data to subscription.
+      if (_raw != null) {
+        _raw.readEventsEnabled = true;
+      }
+    } else {
+      _controllerClosed = true;
+      if (_raw != null) {
+        _raw.shutdown(SocketDirection.RECEIVE);
+      }
+    }
+  }
+
+  void _onPauseStateChange() {
+    if (_raw != null) {
+      _raw.readEventsEnabled = !_controller.isPaused;
+    }
+  }
+
+  void _onData(event) {
+    switch (event) {
+      case RawSocketEvent.READ:
+        var buffer = _raw.read();
+        if (buffer != null) _controller.add(buffer);
+        break;
+      case RawSocketEvent.WRITE:
+        _consumer.write();
+        break;
+      case RawSocketEvent.READ_CLOSED:
+        _controllerClosed = true;
+        _controller.close();
+        break;
+    }
+  }
+
+  void _onDone() {
+    if (!_controllerClosed) {
+      _controllerClosed = true;
+      _controller.close();
+    }
+    _done();
+  }
+
+  void _onError(error) {
+    if (!_controllerClosed) {
+      _controllerClosed = true;
+      _controller.signalError(error);
+      _controller.close();
+    }
+    _done(error);
+  }
+
+  get _doneFuture {
+    if (_doneCompleter == null) {
+      _ensureRawSocketSubscription();
+      _doneCompleter = new Completer();
+    }
+    return _doneCompleter.future;
+  }
+
+  void _done([error]) {
+    if (_doneCompleter != null) {
+      var tmp = _doneCompleter;
+      _doneCompleter = null;
+      if (error != null) {
+        tmp.completeError(error);
+      } else {
+        tmp.complete(this);
+      }
+    }
+  }
+
+  int _write(List<int> data, int offset, int length) =>
+      _raw.write(data, offset, length);
+
+  void _enableWriteEvent() {
+    _raw.writeEventsEnabled = true;
+  }
+
+  void _disableWriteEvent() {
+    if (_raw != null) {
+      _raw.writeEventsEnabled = false;
+    }
+  }
+
+  void _consumerDone([error]) {
+    if (_raw != null) {
+      _raw.shutdown(SocketDirection.SEND);
+      _disableWriteEvent();
+    }
+    _done(error);
+  }
+}
+
+
+class _SecureSocket extends _Socket implements SecureSocket {
+  _SecureSocket(RawSecureSocket raw) : super(raw);
+
+  void set onBadCertificate(bool callback(X509Certificate certificate)) {
+    if (_raw == null) {
+      throw new StateError("onBadCertificate called on destroyed SecureSocket");
+    }
+    _raw.onBadCertificate = callback;
+  }
+
+  X509Certificate get peerCertificate {
+    if (_raw == null) {
+     throw new StateError("peerCertificate called on destroyed SecureSocket");
+    }
+    return _raw.peerCertificate;
+  }
 }
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index a33d703..a60f1e4 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -2,6 +2,9 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "bin/builtin.h"
 #include "bin/eventhandler.h"
 #include "bin/file.h"
@@ -9,11 +12,15 @@
 #include "bin/socket.h"
 
 bool Socket::Initialize() {
+  static bool socket_initialized = false;
+  if (socket_initialized) return true;
   int err;
   WSADATA winsock_data;
-  WORD version_requested = MAKEWORD(1, 0);
+  WORD version_requested = MAKEWORD(2, 2);
   err = WSAStartup(version_requested, &winsock_data);
-  if (err != 0) {
+  if (err == 0) {
+    socket_initialized = true;
+  } else {
     Log::PrintErr("Unable to initialize Winsock: %d\n", WSAGetLastError());
   }
   return err == 0;
@@ -187,6 +194,7 @@
 
 const char* Socket::LookupIPv4Address(char* host, OSError** os_error) {
   // Perform a name lookup for an IPv4 address.
+  Initialize();
   struct addrinfo hints;
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = AF_INET;
@@ -262,7 +270,7 @@
     return -1;
   }
 
-  status = listen(s, backlog);
+  status = listen(s, backlog > 0 ? backlog : SOMAXCONN);
   if (status == SOCKET_ERROR) {
     DWORD rc = WSAGetLastError();
     closesocket(s);
@@ -277,5 +285,7 @@
 
 void Socket::Close(intptr_t fd) {
   ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(fd);
-  client_socket->close();
+  client_socket->Close();
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/stdio_patch.dart b/runtime/bin/stdio_patch.dart
index 9ec2d52..38c488d 100644
--- a/runtime/bin/stdio_patch.dart
+++ b/runtime/bin/stdio_patch.dart
@@ -3,45 +3,39 @@
 // BSD-style license that can be found in the LICENSE file.
 
 patch class _StdIOUtils {
-  static InputStream _getStdioInputStream() {
+  static Stream<List<int>> _getStdioInputStream() {
     switch (_getStdioHandleType(0)) {
       case _STDIO_HANDLE_TYPE_TERMINAL:
       case _STDIO_HANDLE_TYPE_PIPE:
       case _STDIO_HANDLE_TYPE_SOCKET:
-        Socket s = new _Socket._internalReadOnly();
-        _getStdioHandle(s, 0);
-        s._closed = false;
-        return s.inputStream;
+        return new _Socket._readPipe(0);
       case _STDIO_HANDLE_TYPE_FILE:
-        return new _FileInputStream.fromStdio(0);
+        return new _FileStream.forStdin();
       default:
         throw new FileIOException("Unsupported stdin type");
     }
   }
 
-  static OutputStream _getStdioOutputStream(int fd) {
+  static IOSink _getStdioOutputStream(int fd) {
     assert(fd == 1 || fd == 2);
     switch (_getStdioHandleType(fd)) {
       case _STDIO_HANDLE_TYPE_TERMINAL:
       case _STDIO_HANDLE_TYPE_PIPE:
       case _STDIO_HANDLE_TYPE_SOCKET:
-        Socket s = new _Socket._internalWriteOnly();
-        _getStdioHandle(s, fd);
-        s._closed = false;
-        return s.outputStream;
+        return new _Socket._writePipe(fd);
       case _STDIO_HANDLE_TYPE_FILE:
-        return new _FileOutputStream.fromStdio(fd);
+        return new IOSink(new _FileStreamConsumer.fromStdio(fd));
       default:
         throw new FileIOException("Unsupported stdin type");
     }
   }
 
-  static int _socketType(Socket socket) {
-    return _getSocketType(socket);
+  static int _socketType(nativeSocket) {
+    return _getSocketType(nativeSocket);
   }
 }
 
 
-_getStdioHandle(Socket socket, int num) native "Socket_GetStdioHandle";
+_getStdioHandle(_NativeSocket socket, int num) native "Socket_GetStdioHandle";
 _getStdioHandleType(int num) native "File_GetStdioHandleType";
-_getSocketType(Socket socket) native "Socket_GetType";
+_getSocketType(_NativeSocket nativeSocket) native "Socket_GetType";
diff --git a/runtime/bin/test_extension_dllmain_win.cc b/runtime/bin/test_extension_dllmain_win.cc
index fdbd17e..ba2199a 100644
--- a/runtime/bin/test_extension_dllmain_win.cc
+++ b/runtime/bin/test_extension_dllmain_win.cc
@@ -2,11 +2,16 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #define WIN32_LEAN_AND_MEAN
-#include <windows.h>
+#include <windows.h>  // NOLINT
 
 BOOL APIENTRY DllMain(HMODULE module,
                       DWORD  reason,
                       LPVOID reserved) {
   return true;
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/utf_sources.gypi b/runtime/bin/utf_sources.gypi
deleted file mode 100644
index a8fc95b..0000000
--- a/runtime/bin/utf_sources.gypi
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# This file contains all sources for the dart:utf library.
-#
-# TODO(ager): ../lib/utf/utf_vm.dart should be removed when the
-# VM can use the #source directive for libraries.  At that point
-# ../../sdk/lib/utf/utf.dart should be the only utf library file.
-{
-  'sources': [
-    # The utf_vm.dart file needs to be the first source file. It contains
-    # the library and import directives for the dart:utf library. The
-    # dart:utf library is created by concatenating the files listed here
-    # in the order they are listed.
-    '../lib/utf/utf_vm.dart',
-
-    '../../sdk/lib/utf/utf_core.dart',
-    '../../sdk/lib/utf/utf8.dart',
-    '../../sdk/lib/utf/utf16.dart',
-    '../../sdk/lib/utf/utf32.dart',
-  ],
-}
diff --git a/runtime/bin/utils.h b/runtime/bin/utils.h
index ba236eb..470f26a 100644
--- a/runtime/bin/utils.h
+++ b/runtime/bin/utils.h
@@ -78,4 +78,10 @@
   static void FreeUnicodeArgv(wchar_t** argv);
 };
 
+class TimerUtils {
+ public:
+  static int64_t GetCurrentTimeMicros();
+  static int64_t GetCurrentTimeMilliseconds();
+};
+
 #endif  // BIN_UTILS_H_
diff --git a/runtime/bin/utils_android.cc b/runtime/bin/utils_android.cc
index 81b96179..89becdc 100644
--- a/runtime/bin/utils_android.cc
+++ b/runtime/bin/utils_android.cc
@@ -2,8 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-#include <errno.h>
-#include <netdb.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
+#include <errno.h>  // NOLINT
+#include <netdb.h>  // NOLINT
+#include <sys/time.h>  // NOLINT
 
 #include "bin/utils.h"
 #include "platform/assert.h"
@@ -69,3 +73,18 @@
 
 void ShellUtils::FreeUnicodeArgv(wchar_t** argv) {
 }
+
+int64_t TimerUtils::GetCurrentTimeMilliseconds() {
+  return GetCurrentTimeMicros() / 1000;
+}
+
+int64_t TimerUtils::GetCurrentTimeMicros() {
+  struct timeval tv;
+  if (gettimeofday(&tv, NULL) < 0) {
+    UNREACHABLE();
+    return 0;
+  }
+  return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
+}
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/utils_linux.cc b/runtime/bin/utils_linux.cc
index 81b96179..39dcce6 100644
--- a/runtime/bin/utils_linux.cc
+++ b/runtime/bin/utils_linux.cc
@@ -2,8 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-#include <errno.h>
-#include <netdb.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
+#include <errno.h>  // NOLINT
+#include <netdb.h>  // NOLINT
+#include <sys/time.h>  // NOLINT
 
 #include "bin/utils.h"
 #include "platform/assert.h"
@@ -69,3 +73,18 @@
 
 void ShellUtils::FreeUnicodeArgv(wchar_t** argv) {
 }
+
+int64_t TimerUtils::GetCurrentTimeMilliseconds() {
+  return GetCurrentTimeMicros() / 1000;
+}
+
+int64_t TimerUtils::GetCurrentTimeMicros() {
+  struct timeval tv;
+  if (gettimeofday(&tv, NULL) < 0) {
+    UNREACHABLE();
+    return 0;
+  }
+  return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
+}
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/utils_macos.cc b/runtime/bin/utils_macos.cc
index 81b96179..1c79c0d 100644
--- a/runtime/bin/utils_macos.cc
+++ b/runtime/bin/utils_macos.cc
@@ -2,8 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-#include <errno.h>
-#include <netdb.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
+#include <errno.h>  // NOLINT
+#include <netdb.h>  // NOLINT
+#include <sys/time.h>  // NOLINT
 
 #include "bin/utils.h"
 #include "platform/assert.h"
@@ -69,3 +73,18 @@
 
 void ShellUtils::FreeUnicodeArgv(wchar_t** argv) {
 }
+
+int64_t TimerUtils::GetCurrentTimeMilliseconds() {
+  return GetCurrentTimeMicros() / 1000;
+}
+
+int64_t TimerUtils::GetCurrentTimeMicros() {
+  struct timeval tv;
+  if (gettimeofday(&tv, NULL) < 0) {
+    UNREACHABLE();
+    return 0;
+  }
+  return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
+}
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/utils_win.cc b/runtime/bin/utils_win.cc
index 75cc496..2c41278 100644
--- a/runtime/bin/utils_win.cc
+++ b/runtime/bin/utils_win.cc
@@ -2,7 +2,11 @@
 // 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 <errno.h>
+#include "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
+#include <errno.h>  // NOLINT
+#include <time.h>  // NOLINT
 
 #include "bin/utils.h"
 #include "bin/log.h"
@@ -113,3 +117,28 @@
 void ShellUtils::FreeUnicodeArgv(wchar_t** argv) {
   LocalFree(argv);
 }
+
+int64_t TimerUtils::GetCurrentTimeMilliseconds() {
+  return GetCurrentTimeMicros() / 1000;
+}
+
+int64_t TimerUtils::GetCurrentTimeMicros() {
+  static const int64_t kTimeEpoc = 116444736000000000LL;
+  static const int64_t kTimeScaler = 10;  // 100 ns to us.
+
+  // Although win32 uses 64-bit integers for representing timestamps,
+  // these are packed into a FILETIME structure. The FILETIME
+  // structure is just a struct representing a 64-bit integer. The
+  // TimeStamp union allows access to both a FILETIME and an integer
+  // representation of the timestamp. The Windows timestamp is in
+  // 100-nanosecond intervals since January 1, 1601.
+  union TimeStamp {
+    FILETIME ft_;
+    int64_t t_;
+  };
+  TimeStamp time;
+  GetSystemTimeAsFileTime(&time.ft_);
+  return (time.t_ - kTimeEpoc) / kTimeScaler;
+}
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/dart-runtime.gyp b/runtime/dart-runtime.gyp
index 45f4967..db2f10f 100644
--- a/runtime/dart-runtime.gyp
+++ b/runtime/dart-runtime.gyp
@@ -9,7 +9,6 @@
     'bin/bin.gypi',
     'third_party/double-conversion/src/double-conversion.gypi',
     'third_party/jscre/jscre.gypi',
-    '../tools/gyp/source_filter.gypi',
   ],
   'variables': {
     'version_in_cc_file': 'vm/version_in.cc',
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 2e53b34..96ca096 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -1631,10 +1631,10 @@
                                             uint8_t* native_array,
                                             intptr_t length);
 
-// --- Scalar Lists ---
+// --- Typed Data ---
 
 typedef enum {
-  kByteArray = 0,
+  kByteData = 0,
   kInt8,
   kUint8,
   kUint8Clamped,
@@ -1645,92 +1645,73 @@
   kInt64,
   kUint64,
   kFloat32,
-  kFloat64
-} Dart_Scalar_Type;
+  kFloat64,
+  kInvalid
+} Dart_TypedData_Type;
 
 /**
- * Is this object a ByteArray?
+ * Return type if this object is a TypedData object.
+ *
+ * \return kInvalid if the object is not a TypedData object or the appropriate
+ *   Dart_TypedData_Type.
  */
-DART_EXPORT bool Dart_IsByteArray(Dart_Handle object);
+DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object);
 
 /**
- * Is this object an external ByteArray?
+ * Return type if this object is an external TypedData object.
  *
- * An external ByteArray is a ByteArray which references a fixed array of
- * bytes which is external to the Dart heap.
+ * \return kInvalid if the object is not an external TypedData object or
+ *   the appropriate Dart_TypedData_Type.
  */
-DART_EXPORT bool Dart_IsByteArrayExternal(Dart_Handle object);
+DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfExternalTypedData(
+    Dart_Handle object);
 
 /**
- * Returns a ByteArray of the desired length.
+ * Returns a TypedData object of the desired length and type.
  *
- * \param length The length of the array.
+ * \param type The type of the TypedData object.
+ * \param length The length of the TypedData object (length in type units).
  *
- * \return The ByteArray object if no error occurs. Otherwise returns
+ * \return The TypedData object if no error occurs. Otherwise returns
  *   an error handle.
  */
-DART_EXPORT Dart_Handle Dart_NewByteArray(intptr_t length);
+DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type,
+                                          intptr_t length);
 
 /**
- * Returns a ByteArray which references an external array of 8-bit bytes.
+ * Returns a TypedData object which references an external data array.
  *
- * \param value An array of 8-bit bytes. This array must not move.
- * \param length The length of the array.
- * \param peer An external pointer to associate with this byte array.
+ * \param type The type of the data array.
+ * \param value A data array. This array must not move.
+ * \param length The length of the data array (length in type units).
+ * \param peer An external pointer to associate with this array.
  *
- * \return The ByteArray object if no error occurs. Otherwise returns
- *   an error handle. The ByteArray object is returned in a
+ * \return The TypedData object if no error occurs. Otherwise returns
+ *   an error handle. The TypedData object is returned in a
  *   WeakPersistentHandle which needs to be deleted in the specified callback
  *   using Dart_DeletePersistentHandle.
  */
-DART_EXPORT Dart_Handle Dart_NewExternalByteArray(
-    uint8_t* data,
+DART_EXPORT Dart_Handle Dart_NewExternalTypedData(
+    Dart_TypedData_Type type,
+    void* data,
     intptr_t length,
     void* peer,
     Dart_WeakPersistentHandleFinalizer callback);
 
 /**
- * Returns a clamped ByteArray which references an external array of
- * 8-bit bytes.
- * A clamped ByteArray differs from ByteArray above in the indexed store
- * operation where negative values are clamped to 0 and values above 255 are
- * clamped to 255.
- *
- * \param value An array of 8-bit bytes. This array must not move.
- * \param length The length of the array.
- * \param peer An external pointer to associate with this byte array.
- *
- * \return The clamped ByteArray object if no error occurs. Otherwise returns
- *   an error handle. The clamped ByteArray object is returned in a
- *   WeakPersistentHandle which needs to be deleted in the specified callback
- *   using Dart_DeletePersistentHandle.
+ * Retrieves the peer pointer associated with an external TypedData object.
  */
-DART_EXPORT Dart_Handle Dart_NewExternalClampedByteArray(
-    uint8_t* data,
-    intptr_t length,
-    void* peer,
-    Dart_WeakPersistentHandleFinalizer callback);
-
-/**
- * Retrieves the data pointer associated with an external ByteArray.
- */
-DART_EXPORT Dart_Handle Dart_ExternalByteArrayGetData(Dart_Handle object,
-                                                      void** data);
-
-/**
- * Retrieves the peer pointer associated with an external ByteArray.
- */
-DART_EXPORT Dart_Handle Dart_ExternalByteArrayGetPeer(Dart_Handle object,
+DART_EXPORT Dart_Handle Dart_ExternalTypedDataGetPeer(Dart_Handle object,
                                                       void** peer);
 
 /**
- * Acquires access to the internal data address of a scalar list object.
+ * Acquires access to the internal data address of a TypedData object.
  *
- * \param array The scalar list object whose internal data address is to
+ * \param object The typed data object whose internal data address is to
  *    be accessed.
- * \param type The scalar type of the object is returned here.
+ * \param type The type of the object is returned here.
  * \param data The internal data address is returned here.
- * \param len Size of the byte array is returned here.
+ * \param len Size of the typed array is returned here.
  *
  * Note: When the internal address of the object is acquired any calls to a
  *       Dart API function that could potentially allocate an object or run
@@ -1739,22 +1720,22 @@
  * \return Success if the internal data address is acquired successfully.
  *   Otherwise, returns an error handle.
  */
-DART_EXPORT Dart_Handle Dart_ScalarListAcquireData(Dart_Handle array,
-                                                   Dart_Scalar_Type* type,
-                                                   void** data,
-                                                   intptr_t* len);
+DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object,
+                                                  Dart_TypedData_Type* type,
+                                                  void** data,
+                                                  intptr_t* len);
 
 /**
  * Releases access to the internal data address that was acquired earlier using
- * Dart_ByteArrayAcquireData.
+ * Dart_TypedDataAcquireData.
  *
- * \param array The scalar list object whose internal data address is to be
+ * \param object The typed data object whose internal data address is to be
  *   released.
  *
  * \return Success if the internal data address is released successfully.
  *   Otherwise, returns an error handle.
  */
-DART_EXPORT Dart_Handle Dart_ScalarListReleaseData(Dart_Handle array);
+DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle array);
 
 
 // --- Closures ---
diff --git a/runtime/lib/async_sources.gypi b/runtime/lib/async_sources.gypi
index d1c0711..a64243d 100644
--- a/runtime/lib/async_sources.gypi
+++ b/runtime/lib/async_sources.gypi
@@ -6,5 +6,6 @@
 {
   'sources': [
     'timer_patch.dart',
+    'deferred_load_patch.dart',
   ],
 }
diff --git a/runtime/lib/deferred_load_patch.dart b/runtime/lib/deferred_load_patch.dart
new file mode 100644
index 0000000..8d0a9ff
--- /dev/null
+++ b/runtime/lib/deferred_load_patch.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.
+
+final Set<String> _loadedLibraries = new Set<String>();
+
+patch class DeferredLibrary {
+  /* patch */ Future<bool> load() {
+    // Dummy implementation that should eventually be replaced by real
+    // implementation.
+    Future future =
+        new Future<bool>.immediate(!_loadedLibraries.contains(libraryName));
+    _loadedLibraries.add(libraryName);
+    return future;
+  }
+}
diff --git a/runtime/lib/errors_patch.dart b/runtime/lib/errors_patch.dart
index 5fd3e50..783a17d 100644
--- a/runtime/lib/errors_patch.dart
+++ b/runtime/lib/errors_patch.dart
@@ -14,6 +14,7 @@
   // unresolved method.
   static void _throwNew(Object receiver,
                         String memberName,
+                        int invocation_type,
                         List arguments,
                         List argumentNames,
                         List existingArgumentNames) {
@@ -31,10 +32,121 @@
       var arg_value = arguments[numPositionalArguments + i];
       namedArguments[argumentNames[i]] = arg_value;
     }
-    throw new NoSuchMethodError(receiver,
+    throw new NoSuchMethodError._withType(receiver,
                                 memberName,
+                                invocation_type,
                                 positionalArguments,
                                 namedArguments,
                                 existingArgumentNames);
   }
+
+  // Remember the type from the invocation mirror or static compilation
+  // analysis when thrown directly with _throwNew. A negative value means
+  // that no information is available.
+  final int _invocation_type;
+
+  const NoSuchMethodError(Object this._receiver,
+                          String this._memberName,
+                          List this._arguments,
+                          Map<String,dynamic> this._namedArguments,
+                          [List existingArgumentNames = null])
+      : this._existingArgumentNames = existingArgumentNames,
+        this._invocation_type = -1;
+
+  const NoSuchMethodError._withType(Object this._receiver,
+                                    String this._memberName,
+                                    this._invocation_type,
+                                    List this._arguments,
+                                    Map<String,dynamic> this._namedArguments,
+                                    [List existingArgumentNames = null])
+      : this._existingArgumentNames = existingArgumentNames;
+
+
+  String _developerMessage(args_mismatch) {
+    if (_invocation_type < 0) {
+      return "";
+    }
+    var type = _invocation_type & _InvocationMirror._TYPE_MASK;
+    var level = (_invocation_type >> _InvocationMirror._CALL_SHIFT) &
+         _InvocationMirror._CALL_MASK;
+    var type_str =
+        (const ["method", "getter", "setter", "getter or setter"])[type];
+    var args_message = args_mismatch ? " with matching arguments" : "";
+    var msg;
+    switch (level) {
+      case _InvocationMirror._DYNAMIC: {
+        if (_receiver == null) {
+          msg = "The null object does not have a $type_str '$_memberName'"
+              "$args_message.";
+        } else {
+          msg = "Class '${_receiver.runtimeType}' has no instance $type_str "
+              "'$_memberName'$args_message.";
+        }
+        break;
+      }
+      case _InvocationMirror._STATIC: {
+        msg = "No static $type_str '$_memberName' declared in class "
+            "'$_receiver'.";
+        break;
+      }
+      case _InvocationMirror._CONSTRUCTOR: {
+        msg = "No constructor '$_memberName' declared in class '$_receiver'.";
+        break;
+      }
+      case _InvocationMirror._TOP_LEVEL: {
+        msg = "No top-level $type_str '$_memberName' declared.";
+        break;
+      }
+    }
+    return "$msg\n\n";
+  }
+
+  /* patch */ String toString() {
+    StringBuffer actual_buf = new StringBuffer();
+    int i = 0;
+    if (_arguments != null) {
+      for (; i < _arguments.length; i++) {
+        if (i > 0) {
+          actual_buf.add(", ");
+        }
+        actual_buf.add(Error.safeToString(_arguments[i]));
+      }
+    }
+    if (_namedArguments != null) {
+      _namedArguments.forEach((String key, var value) {
+        if (i > 0) {
+          actual_buf.add(", ");
+        }
+        actual_buf.add(key);
+        actual_buf.add(": ");
+        actual_buf.add(Error.safeToString(value));
+        i++;
+      });
+    }
+    var args_mismatch = _existingArgumentNames != null;
+    StringBuffer msg_buf = new StringBuffer(_developerMessage(args_mismatch));
+    if (!args_mismatch) {
+      msg_buf.add(
+          "NoSuchMethodError : method not found: '$_memberName'\n"
+          "Receiver: ${Error.safeToString(_receiver)}\n"
+          "Arguments: [$actual_buf]");
+    } else {
+      String actualParameters = actual_buf.toString();
+      StringBuffer formal_buf = new StringBuffer();
+      for (int i = 0; i < _existingArgumentNames.length; i++) {
+        if (i > 0) {
+          formal_buf.add(", ");
+        }
+        formal_buf.add(_existingArgumentNames[i]);
+      }
+      String formalParameters = formal_buf.toString();
+      msg_buf.add( 
+          "NoSuchMethodError: incorrect number of arguments passed to "
+          "method named '$_memberName'\n"
+          "Receiver: ${Error.safeToString(_receiver)}\n"
+          "Tried calling: $_memberName($actualParameters)\n"
+          "Found: $_memberName($formalParameters)");
+    }
+    return msg_buf.toString();
+  }
 }
diff --git a/runtime/lib/invocation_mirror.h b/runtime/lib/invocation_mirror.h
new file mode 100644
index 0000000..af0d24c
--- /dev/null
+++ b/runtime/lib/invocation_mirror.h
@@ -0,0 +1,48 @@
+// 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 LIB_INVOCATION_MIRROR_H_
+#define LIB_INVOCATION_MIRROR_H_
+
+#include "vm/allocation.h"
+
+namespace dart {
+
+class InvocationMirror : public AllStatic {
+ public:
+  // These enum correspond to the constants in invocation_mirror_patch.dart.
+  // It is used to communicate the reason for statically thrown
+  // NoSuchMethodErrors by the compiler.
+  enum Type {
+    // Constants describing the invocation type.
+    // kField cannot be generated by regular invocation mirrors.
+    kMethod = 0,
+    kGetter = 1,
+    kSetter = 2,
+    kField  = 3,
+    kTypeShift = 0,
+    kTypeBits = 2,
+    kTypeMask = (1 << kTypeBits) - 1
+  };
+
+  enum Call {
+    // These values, except kDynamic, are only used when throwing
+    // NoSuchMethodError for compile-time resolution failures.
+    kDynamic = 0,
+    kStatic  = 1,
+    kConstructor = 2,
+    kTopLevel = 3,
+    kCallShift = kTypeBits,
+    kCallBits = 2,
+    kCallMask = (1 << kCallBits) - 1
+  };
+
+  static int EncodeType(Call call, Type type) {
+    return (call << kCallShift) | type;
+  }
+};
+
+}  // namespace dart
+
+#endif  // LIB_INVOCATION_MIRROR_H_
diff --git a/runtime/lib/invocation_mirror_patch.dart b/runtime/lib/invocation_mirror_patch.dart
index 840b6f0..3f53feb 100644
--- a/runtime/lib/invocation_mirror_patch.dart
+++ b/runtime/lib/invocation_mirror_patch.dart
@@ -4,9 +4,24 @@
 
 class _InvocationMirror implements InvocationMirror {
   // Constants describing the invocation type.
-  static final int _METHOD = 0;
-  static final int _GETTER = 1;
-  static final int _SETTER = 2;
+  // _FIELD cannot be generated by regular invocation mirrors.
+  static const int _METHOD = 0;
+  static const int _GETTER = 1;
+  static const int _SETTER = 2;
+  static const int _FIELD = 3;
+  static const int _TYPE_SHIFT = 0;
+  static const int _TYPE_BITS = 2;
+  static const int _TYPE_MASK = (1 << _TYPE_BITS) - 1;
+
+  // These values, except _DYNAMIC, are only used when throwing
+  // NoSuchMethodError for compile-time resolution failures.
+  static const int _DYNAMIC = 0;
+  static const int _STATIC = 1;
+  static const int _CONSTRUCTOR = 2;
+  static const int _TOP_LEVEL = 3;
+  static const int _CALL_SHIFT = _TYPE_BITS;
+  static const int _CALL_BITS = 2;
+  static const int _CALL_MASK = (1 << _CALL_BITS) - 1;
 
   // Internal representation of the invocation mirror.
   final String _functionName;
diff --git a/runtime/lib/lib_sources.gypi b/runtime/lib/lib_sources.gypi
index 18b74fe..f5b6c04 100644
--- a/runtime/lib/lib_sources.gypi
+++ b/runtime/lib/lib_sources.gypi
@@ -31,6 +31,7 @@
     'integers.dart',
     'integers_patch.dart',
     'invocation_mirror.cc',
+    'invocation_mirror.h',
     'invocation_mirror_patch.dart',
     'map_patch.dart',
     'object.cc',
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index fc50c04..48dacdf 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -19,18 +19,20 @@
 }
 
 
-DEFINE_NATIVE_ENTRY(Object_noSuchMethod, 5) {
+DEFINE_NATIVE_ENTRY(Object_noSuchMethod, 6) {
   const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Bool, is_method, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(String, member_name, arguments->NativeArgAt(2));
-  GET_NON_NULL_NATIVE_ARGUMENT(Instance, func_args, arguments->NativeArgAt(3));
+  GET_NON_NULL_NATIVE_ARGUMENT(Smi, invocation_type, arguments->NativeArgAt(3));
+  GET_NON_NULL_NATIVE_ARGUMENT(Instance, func_args, arguments->NativeArgAt(4));
   GET_NON_NULL_NATIVE_ARGUMENT(
-      Instance, func_named_args, arguments->NativeArgAt(4));
-  const Array& dart_arguments = Array::Handle(Array::New(5));
+      Instance, func_named_args, arguments->NativeArgAt(5));
+  const Array& dart_arguments = Array::Handle(Array::New(6));
   dart_arguments.SetAt(0, instance);
   dart_arguments.SetAt(1, member_name);
-  dart_arguments.SetAt(2, func_args);
-  dart_arguments.SetAt(3, func_named_args);
+  dart_arguments.SetAt(2, invocation_type);
+  dart_arguments.SetAt(3, func_args);
+  dart_arguments.SetAt(4, func_named_args);
 
   if (is_method.value()) {
     // Report if a function with same name (but different arguments) has been
@@ -50,7 +52,7 @@
       for (int i = 1; i < total_num_parameters; i++) {
         array.SetAt(i - 1, String::Handle(function.ParameterNameAt(i)));
       }
-      dart_arguments.SetAt(4, array);
+      dart_arguments.SetAt(5, array);
     }
   }
   Exceptions::ThrowByType(Exceptions::kNoSuchMethod, dart_arguments);
diff --git a/runtime/lib/object_patch.dart b/runtime/lib/object_patch.dart
index a1ebe00..2c0c0a3 100644
--- a/runtime/lib/object_patch.dart
+++ b/runtime/lib/object_patch.dart
@@ -28,6 +28,7 @@
 
   _noSuchMethod(bool isMethod,
                 String memberName,
+                int type,
                 List arguments,
                 Map<String, dynamic> namedArguments)
       native "Object_noSuchMethod";
@@ -35,6 +36,7 @@
   /* patch */ noSuchMethod(InvocationMirror invocation) {
     return _noSuchMethod(invocation.isMethod,
                          invocation.memberName,
+                         invocation._type,
                          invocation.positionalArguments,
                          invocation.namedArguments);
   }
diff --git a/runtime/lib/utf/utf_vm.dart b/runtime/lib/utf/utf_vm.dart
deleted file mode 100644
index a3d8151..0000000
--- a/runtime/lib/utf/utf_vm.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// TODO(dgrove) - once the VM has a new way to include whole libraries,
-// remove this file and update runtime/bin/utf_sources.gypi .
-
-library utf;
diff --git a/runtime/platform/floating_point_win.cc b/runtime/platform/floating_point_win.cc
index 82aee16..27d6c25 100644
--- a/runtime/platform/floating_point_win.cc
+++ b/runtime/platform/floating_point_win.cc
@@ -2,10 +2,11 @@
 // 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 <math.h>
-#include <limits>
-
 #include "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
+#include <math.h>  // NOLINT
+#include <limits>  // NOLINT
 
 // Taken from third_party/v8/src/platform-win32.cc
 double fmod_ieee(double x, double y) {
@@ -44,3 +45,5 @@
     return atan2(x, y);
   }
 }
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 176246e..4c5d053 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -61,7 +61,7 @@
 //   - http://msdn.microsoft.com/en-us/library/b0084kay.aspx
 //   - with gcc, run: "echo | gcc -E -dM -"
 #if defined(__ANDROID__)
-#define TARGET_OS_ANDROID
+#define TARGET_OS_ANDROID 1
 #elif defined(__linux__) || defined(__FreeBSD__)
 #define TARGET_OS_LINUX 1
 #elif defined(__APPLE__)
@@ -391,22 +391,28 @@
 #define strtok_r strtok_s
 #endif
 
-#if !defined(TARGET_OS_WINDOWS) && !defined(TEMP_FAILURE_RETRY)
+#if !defined(TARGET_OS_WINDOWS)
+#if !defined(TEMP_FAILURE_RETRY)
 // TEMP_FAILURE_RETRY is defined in unistd.h on some platforms. The
 // definition below is copied from Linux and adapted to avoid lint
 // errors (type long int changed to int64_t and do/while split on
 // separate lines with body in {}s).
-# define TEMP_FAILURE_RETRY(expression)                                        \
+#define TEMP_FAILURE_RETRY(expression)                                         \
     ({ int64_t __result;                                                       \
        do {                                                                    \
-         __result = (int64_t) (expression);                                    \
+         __result = static_cast<int64_t>(expression);                          \
        } while (__result == -1L && errno == EINTR);                            \
        __result; })
-#endif
+#endif  // !defined(TEMP_FAILURE_RETRY)
 
+// This is a version of TEMP_FAILURE_RETRY which does not use the value
+// returned from the expression.
+#define VOID_TEMP_FAILURE_RETRY(expression)                                    \
+    (static_cast<void>(TEMP_FAILURE_RETRY(expression)))
+
+#endif  // !defined(TARGET_OS_WINDOWS)
 
 #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_MACOS)
-//
 // Tell the compiler to do printf format string checking if the
 // compiler supports it; see the 'format' attribute in
 // <http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Attributes.html>.
@@ -414,7 +420,6 @@
 // N.B.: As the GCC manual states, "[s]ince non-static C++ methods
 // have an implicit 'this' argument, the arguments of such methods
 // should be counted from two, not one."
-//
 #define PRINTF_ATTRIBUTE(string_index, first_to_check) \
   __attribute__((__format__(__printf__, string_index, first_to_check)))
 #else
diff --git a/runtime/platform/thread_android.cc b/runtime/platform/thread_android.cc
index da00de1..e789c01 100644
--- a/runtime/platform/thread_android.cc
+++ b/runtime/platform/thread_android.cc
@@ -2,10 +2,13 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "platform/thread.h"
 
-#include <errno.h>
-#include <sys/time.h>
+#include <errno.h>  // NOLINT
+#include <sys/time.h>  // NOLINT
 
 #include "platform/assert.h"
 
@@ -277,3 +280,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/platform/thread_linux.cc b/runtime/platform/thread_linux.cc
index 8ac046a..dd02a38 100644
--- a/runtime/platform/thread_linux.cc
+++ b/runtime/platform/thread_linux.cc
@@ -2,10 +2,13 @@
 // 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 "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "platform/thread.h"
 
-#include <errno.h>
-#include <sys/time.h>
+#include <errno.h>  // NOLINT
+#include <sys/time.h>  // NOLINT
 
 #include "platform/assert.h"
 
@@ -279,3 +282,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/platform/thread_macos.cc b/runtime/platform/thread_macos.cc
index 71f025d..29059fe 100644
--- a/runtime/platform/thread_macos.cc
+++ b/runtime/platform/thread_macos.cc
@@ -2,9 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
 #include "platform/thread.h"
 
-#include <sys/errno.h>
+#include <sys/errno.h>  // NOLINT
 
 #include "platform/assert.h"
 
@@ -259,3 +262,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/platform/thread_win.cc b/runtime/platform/thread_win.cc
index 6fffe93..18ec6d0 100644
--- a/runtime/platform/thread_win.cc
+++ b/runtime/platform/thread_win.cc
@@ -2,9 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "platform/thread.h"
 
-#include <process.h>
+#include <process.h>  // NOLINT
 
 #include "platform/assert.h"
 
@@ -336,3 +339,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/tests/vm/dart/byte_array_test.dart b/runtime/tests/vm/dart/byte_array_test.dart
index 8ebe03c..0eab243 100644
--- a/runtime/tests/vm/dart/byte_array_test.dart
+++ b/runtime/tests/vm/dart/byte_array_test.dart
@@ -179,6 +179,82 @@
     testUint8ListImpl(array);
   }
 
+  static testUint8ClampedListImpl(Uint8ClampedList array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(10, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(10, array.lengthInBytes());
+    Expect.listEquals([0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0],
+                      array);
+    Expect.throws(() { array[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -1 + i;
+    }
+    Expect.listEquals([0, 0, 1, 2, 3, 4, 5, 6, 7, 8], array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x100 + i;
+    }
+    Expect.listEquals([255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xFF - i;
+    }
+    Expect.listEquals([0xFF, 0xFE, 0xFD, 0xFC, 0xFB,
+                       0xFA, 0xF9, 0xF8, 0xF7, 0xF6],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Uint8ClampedList);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Uint8ClampedList);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    array.setRange(3, 4, [257, 0, 1, 255]);
+    Expect.listEquals([0, 1, 2, 255, 0, 1, 255, 7, 8, 9], array);
+  }
+
+  static testUint8ClampedList() {
+    Expect.throws(() { new Uint8ClampedList(-1); },
+                  (e) { return e is ArgumentError; });
+    Expect.throws(() { new Uint8ClampedList.transferable(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Uint8ClampedList(10);
+    testUint8ClampedListImpl(array);
+    array = new Uint8ClampedList.transferable(10);
+    testUint8ClampedListImpl(array);
+  }
+
   static testInt16ListImpl(Int16List array) {
     Expect.isTrue(array is List<int>);
     Expect.equals(10, array.length);
@@ -2382,6 +2458,7 @@
   static testMain() {
     testInt8List();
     testUint8List();
+    testUint8ClampedList();
     testInt16List();
     testUint16List();
     testInt32List();
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 5d7f315..c4537b6 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -58,7 +58,6 @@
 
 [ $arch == simarm ]
 # Tests needing an assembler.
-cc/Call: Skip
 cc/CallLeafRuntimeStubCode: Skip
 cc/CallRuntimeStubCode: Skip
 cc/Dart2JSCompileAll: Skip
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 183e164..2bd4737 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -7,9 +7,12 @@
 
 #include "vm/assembler.h"
 
+#include "vm/stub_code.h"
+
 namespace dart {
 
-DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
+// TODO(regis): Enable this flag after PrintStopMessage stub is implemented.
+DEFINE_FLAG(bool, print_stop_message, false, "Print stop message.");
 
 
 // Instruction encoding bits.
@@ -1036,11 +1039,11 @@
   const int32_t offset =
       Array::data_offset() + 4*AddObject(object) - kHeapObjectTag;
   if (Address::CanHoldLoadOffset(kLoadWord, offset)) {
-    ldr(rd, Address(CP, offset));
+    ldr(rd, Address(PP, offset));
   } else {
     int32_t offset12_hi = offset & ~kOffset12Mask;  // signed
     uint32_t offset12_lo = offset & kOffset12Mask;  // unsigned
-    AddConstant(rd, CP, offset12_hi);
+    AddConstant(rd, PP, offset12_hi);
     ldr(rd, Address(rd, offset12_lo));
   }
 }
@@ -1167,28 +1170,34 @@
 
 
 void Assembler::BranchLink(const ExternalLabel* label) {
-  // TODO(regis): Make sure that CodePatcher is able to patch the label referred
+  LoadImmediate(IP, label->address());  // Target address is never patched.
+  blx(IP);  // Use blx instruction so that the return branch prediction works.
+}
+
+
+void Assembler::BranchLinkPatchable(const ExternalLabel* label) {
+  // Make sure that class CallPattern is able to patch the label referred
   // to by this code sequence.
   // For added code robustness, use 'blx lr' in a patchable sequence and
   // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors).
   const int32_t offset =
       Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag;
   if (Address::CanHoldLoadOffset(kLoadWord, offset)) {
-    ldr(LR, Address(CP, offset));
+    ldr(LR, Address(PP, offset));
   } else {
     int32_t offset12_hi = offset & ~kOffset12Mask;  // signed
     uint32_t offset12_lo = offset & kOffset12Mask;  // unsigned
     // Inline a simplified version of AddConstant(LR, CP, offset12_hi).
     ShifterOperand shifter_op;
     if (ShifterOperand::CanHold(offset12_hi, &shifter_op)) {
-      add(LR, CP, shifter_op);
+      add(LR, PP, shifter_op);
     } else {
       movw(LR, Utils::Low16Bits(offset12_hi));
       const uint16_t value_high = Utils::High16Bits(offset12_hi);
       if (value_high != 0) {
         movt(LR, value_high);
       }
-      add(LR, CP, ShifterOperand(LR));
+      add(LR, PP, ShifterOperand(LR));
     }
     ldr(LR, Address(LR, offset12_lo));
   }
@@ -1500,7 +1509,11 @@
 
 void Assembler::Stop(const char* message) {
   if (FLAG_print_stop_message) {
-    UNIMPLEMENTED();  // Emit call to StubCode::PrintStopMessage().
+    PushList((1 << R0) | (1 << IP) | (1 << LR));  // Preserve R0, IP, LR.
+    LoadImmediate(R0, reinterpret_cast<int32_t>(message));
+    // PrintStopMessage() preserves all registers.
+    BranchLink(&StubCode::PrintStopMessageLabel());  // Passing message in R0.
+    PopList((1 << R0) | (1 << IP) | (1 << LR));  // Restore R0, IP, LR.
   }
   // Emit the message address before the svc instruction, so that we can
   // 'unstop' and continue execution in the simulator or jump to the next
@@ -1533,25 +1546,35 @@
 
 
 int32_t Assembler::AddObject(const Object& obj) {
+  if (object_pool_.IsNull()) {
+    // The object pool cannot be used in the vm isolate.
+    ASSERT(Isolate::Current() != Dart::vm_isolate());
+    object_pool_ = GrowableObjectArray::New();
+  }
   for (int i = 0; i < object_pool_.Length(); i++) {
     if (object_pool_.At(i) == obj.raw()) {
       return i;
     }
   }
   object_pool_.Add(obj);
-  return object_pool_.Length();
+  return object_pool_.Length() - 1;
 }
 
 
 int32_t Assembler::AddExternalLabel(const ExternalLabel* label) {
-  const uword address = label->address();
+  if (object_pool_.IsNull()) {
+    // The object pool cannot be used in the vm isolate.
+    ASSERT(Isolate::Current() != Dart::vm_isolate());
+    object_pool_ = GrowableObjectArray::New();
+  }
+  const word address = label->address();
   ASSERT(Utils::IsAligned(address, 4));
   // The address is stored in the object array as a RawSmi.
   const Smi& smi = Smi::Handle(Smi::New(address >> kSmiTagShift));
   // Do not reuse an existing entry, since each reference may be patched
   // independently.
   object_pool_.Add(smi);
-  return object_pool_.Length();
+  return object_pool_.Length() - 1;
 }
 
 }  // namespace dart
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 1b45703..76f20a1 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -73,7 +73,7 @@
 class ShifterOperand : public ValueObject {
  public:
   // Data-processing operands - Uninitialized.
-  ShifterOperand() : type_(-1) { }
+  ShifterOperand() : type_(-1), encoding_(-1) { }
 
   // Data-processing operands - Copy constructor.
   ShifterOperand(const ShifterOperand& other)
@@ -264,7 +264,7 @@
  public:
   Assembler()
       : buffer_(),
-        object_pool_(GrowableObjectArray::Handle(GrowableObjectArray::New())),
+        object_pool_(GrowableObjectArray::Handle()),
         prologue_offset_(-1),
         comments_() { }
   ~Assembler() { }
@@ -280,13 +280,10 @@
     ASSERT(buffer_.pointer_offsets().length() == 0);  // No pointers in code.
     return buffer_.pointer_offsets();
   }
-  const GrowableObjectArray& object_pool() const {
-    return object_pool_;
-  }
+  const GrowableObjectArray& object_pool() const { return object_pool_; }
 
   void FinalizeInstructions(const MemoryRegion& region) {
     buffer_.FinalizeInstructions(region);
-    ASSERT(object_pool_.Length() == 0);  // TODO(regis): Otherwise, more work.
   }
 
   // Debugging and bringup support.
@@ -459,14 +456,20 @@
   void blx(Register rm, Condition cond = AL);
 
   // Macros.
-  // Branch to an entry address that can be patched at runtime.
+  // Branch to an entry address. Call sequence is never patched.
   void Branch(const ExternalLabel* label);
+
+  // Branch and link to an entry address. Call sequence is never patched.
   void BranchLink(const ExternalLabel* label);
 
-  // Branch to entry after setting LR and storing LR at ad.
+  // Branch and link to an entry address. Call sequence can be patched.
+  void BranchLinkPatchable(const ExternalLabel* label);
+
+  // Branch and link to entry after storing return address at ad.
+  // Call sequence is never patched.
   void BranchLinkStore(const ExternalLabel* label, Address ad);
 
-  // Branch to [base + offset] after setting LR.
+  // Branch and link to [base + offset]. Call sequence is never patched.
   void BranchLinkOffset(Register base, int offset);
 
   // Add signed constant value to rd. May clobber IP.
@@ -533,7 +536,7 @@
 
  private:
   AssemblerBuffer buffer_;  // Contains position independent code.
-  const GrowableObjectArray& object_pool_;  // Objects and jump targets.
+  GrowableObjectArray& object_pool_;  // Objects and patchable jump targets.
   int32_t prologue_offset_;
 
   int32_t AddObject(const Object& obj);
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 9d92c48..1c6297e 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -21,11 +21,902 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Simple, entry) {
+ASSEMBLER_TEST_RUN(Simple, test) {
   typedef int (*SimpleCode)();
-  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, entry));
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
 }
 
+
+ASSEMBLER_TEST_GENERATE(MoveNegated, assembler) {
+  __ mvn(R0, ShifterOperand(42));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(MoveNegated, test) {
+  EXPECT(test != NULL);
+  typedef int (*MoveNegated)();
+  EXPECT_EQ(~42, EXECUTE_TEST_CODE_INT32(MoveNegated, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(MoveRotImm, assembler) {
+  ShifterOperand shifter_op;
+  EXPECT(ShifterOperand::CanHold(0x00550000, &shifter_op));
+  __ mov(R0, shifter_op);
+  EXPECT(ShifterOperand::CanHold(0x30000003, &shifter_op));
+  __ add(R0, R0, shifter_op);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(MoveRotImm, test) {
+  EXPECT(test != NULL);
+  typedef int (*MoveRotImm)();
+  EXPECT_EQ(0x30550003, EXECUTE_TEST_CODE_INT32(MoveRotImm, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(MovImm16, assembler) {
+  __ movw(R0, 0x5678);
+  __ movt(R0, 0x1234);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(MovImm16, test) {
+  EXPECT(test != NULL);
+  typedef int (*MovImm16)();
+  EXPECT_EQ(0x12345678, EXECUTE_TEST_CODE_INT32(MovImm16, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(LoadImmediate, assembler) {
+  __ mov(R0, ShifterOperand(0));
+  __ cmp(R0, ShifterOperand(0));
+  __ LoadImmediate(R0, 0x12345678, EQ);
+  __ LoadImmediate(R0, 0x87654321, NE);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(LoadImmediate, test) {
+  EXPECT(test != NULL);
+  typedef int (*LoadImmediate)();
+  EXPECT_EQ(0x12345678, EXECUTE_TEST_CODE_INT32(LoadImmediate, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Vmov, assembler) {
+  __ mov(R3, ShifterOperand(43));
+  __ mov(R1, ShifterOperand(41));
+  __ vmovsrr(S1, R1, R3);  // S1:S2 = 41:43
+  __ vmovs(S0, S2);  // S0 = S2, S0:S1 == 43:41
+  __ vmovd(D2, D0);  // D2 = D0, S4:S5 == 43:41
+  __ vmovrs(R3, S5);  // R3 = S5, R3 == 41
+  __ vmovrrs(R1, R2, S4);  // R1:R2 = S4:S5, R1:R2 == 43:41
+  __ vmovdrr(D3, R3, R2);  // D3 = R3:R2, S6:S7 == 41:41
+  __ vmovsr(S7, R1);  // S7 = R1, S6:S7 == 41:43
+  __ vmovrrd(R0, R1, D3);  // R0:R1 = D3, R0:R1 == 41:43
+  __ sub(R0, R1, ShifterOperand(R0));  // 43-41
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Vmov, test) {
+  EXPECT(test != NULL);
+  typedef int (*Vmov)();
+  EXPECT_EQ(2, EXECUTE_TEST_CODE_INT32(Vmov, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(SingleVLoadStore, assembler) {
+  __ LoadImmediate(R0, bit_cast<int32_t, float>(12.3f));
+  __ mov(R2, ShifterOperand(SP));
+  __ str(R0, Address(SP, (-kWordSize * 30), Address::PreIndex));
+  __ vldrs(S0, Address(R2, (-kWordSize * 30)));
+  __ vadds(S0, S0, S0);
+  __ vstrs(S0, Address(R2, (-kWordSize * 30)));
+  __ ldr(R0, Address(SP, (kWordSize * 30), Address::PostIndex));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(SingleVLoadStore, test) {
+  EXPECT(test != NULL);
+  typedef float (*SingleVLoadStore)();
+  float res = EXECUTE_TEST_CODE_FLOAT(SingleVLoadStore, test->entry());
+  EXPECT_FLOAT_EQ(2*12.3f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(DoubleVLoadStore, assembler) {
+  int64_t value = bit_cast<int64_t, double>(12.3);
+  __ LoadImmediate(R0, Utils::Low32Bits(value));
+  __ LoadImmediate(R1, Utils::High32Bits(value));
+  __ mov(R2, ShifterOperand(SP));
+  __ str(R0, Address(SP, (-kWordSize * 30), Address::PreIndex));
+  __ str(R1, Address(R2, (-kWordSize * 29)));
+  __ vldrd(D0, Address(R2, (-kWordSize * 30)));
+  __ vaddd(D0, D0, D0);
+  __ vstrd(D0, Address(R2, (-kWordSize * 30)));
+  __ ldr(R1, Address(R2, (-kWordSize * 29)));
+  __ ldr(R0, Address(SP, (kWordSize * 30), Address::PostIndex));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleVLoadStore, test) {
+  EXPECT(test != NULL);
+  typedef double (*DoubleVLoadStore)();
+  double res = EXECUTE_TEST_CODE_DOUBLE(DoubleVLoadStore, test->entry());
+  EXPECT_FLOAT_EQ(2*12.3, res, 0.001);
+}
+
+
+ASSEMBLER_TEST_GENERATE(SingleFPOperations, assembler) {
+  __ LoadSImmediate(S0, 12.3f);
+  __ LoadSImmediate(S1, 3.4f);
+  __ vnegs(S0, S0);  // -12.3f
+  __ vabss(S0, S0);  // 12.3f
+  __ vadds(S0, S0, S1);  // 15.7f
+  __ vmuls(S0, S0, S1);  // 53.38f
+  __ vsubs(S0, S0, S1);  // 49.98f
+  __ vdivs(S0, S0, S1);  // 14.7f
+  __ vsqrts(S0, S0);  // 3.8340579f
+  __ vmovrs(R0, S0);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(SingleFPOperations, test) {
+  EXPECT(test != NULL);
+  typedef float (*SingleFPOperations)();
+  float res = EXECUTE_TEST_CODE_FLOAT(SingleFPOperations, test->entry());
+  EXPECT_FLOAT_EQ(3.8340579f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(DoubleFPOperations, assembler) {
+  __ LoadDImmediate(D0, 12.3, R0);
+  __ LoadDImmediate(D1, 3.4, R0);
+  __ vnegd(D0, D0);  // -12.3
+  __ vabsd(D0, D0);  // 12.3
+  __ vaddd(D0, D0, D1);  // 15.7
+  __ vmuld(D0, D0, D1);  // 53.38
+  __ vsubd(D0, D0, D1);  // 49.98
+  __ vdivd(D0, D0, D1);  // 14.7
+  __ vsqrtd(D0, D0);  // 3.8340579
+  __ vmovrrd(R0, R1, D0);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleFPOperations, test) {
+  EXPECT(test != NULL);
+  typedef double (*DoubleFPOperations)();
+  double res = EXECUTE_TEST_CODE_DOUBLE(DoubleFPOperations, test->entry());
+  EXPECT_FLOAT_EQ(3.8340579, res, 0.001);
+}
+
+
+ASSEMBLER_TEST_GENERATE(IntToDoubleConversion, assembler) {
+  __ mov(R3, ShifterOperand(6));
+  __ vmovsr(S3, R3);
+  __ vcvtdi(D1, S3);
+  __ vmovrrd(R0, R1, D1);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(IntToDoubleConversion, test) {
+  typedef double (*IntToDoubleConversionCode)();
+  EXPECT(test != NULL);
+  double res = EXECUTE_TEST_CODE_DOUBLE(IntToDoubleConversionCode,
+                                        test->entry());
+  EXPECT_FLOAT_EQ(6.0, res, 0.001);
+}
+
+
+ASSEMBLER_TEST_GENERATE(LongToDoubleConversion, assembler) {
+  int64_t value = 60000000000LL;
+  __ LoadImmediate(R0, Utils::Low32Bits(value));
+  __ LoadImmediate(R1, Utils::High32Bits(value));
+  __ vmovsr(S0, R0);
+  __ vmovsr(S2, R1);
+  __ vcvtdu(D0, S0);
+  __ vcvtdi(D1, S2);
+  __ LoadDImmediate(D2, 1.0 * (1LL << 32), R0);
+  __ vmlad(D0, D1, D2);
+  __ vmovrrd(R0, R1, D0);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(LongToDoubleConversion, test) {
+  typedef double (*LongToDoubleConversionCode)();
+  EXPECT(test != NULL);
+  double res = EXECUTE_TEST_CODE_DOUBLE(LongToDoubleConversionCode,
+                                        test->entry());
+  EXPECT_FLOAT_EQ(60000000000.0, res, 0.001);
+}
+
+
+ASSEMBLER_TEST_GENERATE(IntToFloatConversion, assembler) {
+  __ mov(R3, ShifterOperand(6));
+  __ vmovsr(S3, R3);
+  __ vcvtsi(S1, S3);
+  __ vmovrs(R0, S1);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(IntToFloatConversion, test) {
+  typedef float (*IntToFloatConversionCode)();
+  EXPECT(test != NULL);
+  float res = EXECUTE_TEST_CODE_FLOAT(IntToFloatConversionCode, test->entry());
+  EXPECT_FLOAT_EQ(6.0, res, 0.001);
+}
+
+
+ASSEMBLER_TEST_GENERATE(FloatToIntConversion, assembler) {
+  __ vmovsr(S1, R0);
+  __ vcvtis(S0, S1);
+  __ vmovrs(R0, S0);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(FloatToIntConversion, test) {
+  typedef int (*FloatToIntConversion)(float arg);
+  EXPECT(test != NULL);
+  EXPECT_EQ(12,
+            EXECUTE_TEST_CODE_INT32_F(FloatToIntConversion, test->entry(),
+                                      12.8f));
+  EXPECT_EQ(INT_MIN,
+            EXECUTE_TEST_CODE_INT32_F(FloatToIntConversion, test->entry(),
+                                      -FLT_MAX));
+  EXPECT_EQ(INT_MAX,
+            EXECUTE_TEST_CODE_INT32_F(FloatToIntConversion, test->entry(),
+                                      FLT_MAX));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DoubleToIntConversion, assembler) {
+  __ vmovdrr(D1, R0, R1);
+  __ vcvtid(S0, D1);
+  __ vmovrs(R0, S0);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleToIntConversion, test) {
+  typedef int (*DoubleToIntConversion)(double arg);
+  EXPECT(test != NULL);
+  EXPECT_EQ(12,
+            EXECUTE_TEST_CODE_INT32_D(DoubleToIntConversion, test->entry(),
+                                      12.8));
+  EXPECT_EQ(INT_MIN,
+            EXECUTE_TEST_CODE_INT32_D(DoubleToIntConversion, test->entry(),
+                                      -DBL_MAX));
+  EXPECT_EQ(INT_MAX,
+            EXECUTE_TEST_CODE_INT32_D(DoubleToIntConversion, test->entry(),
+                                      DBL_MAX));
+}
+
+
+ASSEMBLER_TEST_GENERATE(FloatToDoubleConversion, assembler) {
+  __ LoadSImmediate(S1, 12.8f);
+  __ vcvtds(D2, S1);
+  __ vmovrrd(R0, R1, D2);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(FloatToDoubleConversion, test) {
+  typedef double (*FloatToDoubleConversionCode)();
+  EXPECT(test != NULL);
+  double res = EXECUTE_TEST_CODE_DOUBLE(FloatToDoubleConversionCode,
+                                        test->entry());
+  EXPECT_FLOAT_EQ(12.8, res, 0.001);
+}
+
+
+ASSEMBLER_TEST_GENERATE(DoubleToFloatConversion, assembler) {
+  __ LoadDImmediate(D1, 12.8, R0);
+  __ vcvtsd(S3, D1);
+  __ vmovrs(R0, S3);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleToFloatConversion, test) {
+  typedef float (*DoubleToFloatConversionCode)();
+  EXPECT(test != NULL);
+  float res = EXECUTE_TEST_CODE_FLOAT(DoubleToFloatConversionCode,
+                                      test->entry());
+  EXPECT_FLOAT_EQ(12.8, res, 0.001);
+}
+
+
+ASSEMBLER_TEST_GENERATE(FloatCompare, assembler) {
+  // Test 12.3f vs 12.5f.
+  __ LoadSImmediate(S0, 12.3f);
+  __ LoadSImmediate(S1, 12.5f);
+
+  // Count errors in R0. R0 is zero if no errors found.
+  __ mov(R0, ShifterOperand(0));
+  __ vcmps(S0, S1);
+  __ vmstat();
+  __ add(R0, R0, ShifterOperand(1), VS);  // Error if unordered (Nan).
+  __ add(R0, R0, ShifterOperand(2), GT);  // Error if greater.
+  __ add(R0, R0, ShifterOperand(4), EQ);  // Error if equal.
+  __ add(R0, R0, ShifterOperand(8), PL);  // Error if not less.
+
+  // Test NaN.
+  // Create NaN by dividing 0.0f/0.0f.
+  __ LoadSImmediate(S1, 0.0f);
+  __ vdivs(S1, S1, S1);
+  __ vcmps(S1, S1);
+  __ vmstat();
+  __ add(R0, R0, ShifterOperand(16), VC);  // Error if not unordered (not Nan).
+
+  // R0 is 0 if all tests passed.
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(FloatCompare, test) {
+  EXPECT(test != NULL);
+  typedef int (*FloatCompare)();
+  EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(FloatCompare, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DoubleCompare, assembler) {
+  // Test 12.3 vs 12.5.
+  __ LoadDImmediate(D0, 12.3, R1);
+  __ LoadDImmediate(D1, 12.5, R1);
+
+  // Count errors in R0. R0 is zero if no errors found.
+  __ mov(R0, ShifterOperand(0));
+  __ vcmpd(D0, D1);
+  __ vmstat();
+  __ add(R0, R0, ShifterOperand(1), VS);  // Error if unordered (Nan).
+  __ add(R0, R0, ShifterOperand(2), GT);  // Error if greater.
+  __ add(R0, R0, ShifterOperand(4), EQ);  // Error if equal.
+  __ add(R0, R0, ShifterOperand(8), PL);  // Error if not less.
+
+  // Test NaN.
+  // Create NaN by dividing 0.0/0.0.
+  __ LoadDImmediate(D1, 0.0, R1);
+  __ vdivd(D1, D1, D1);
+  __ vcmpd(D1, D1);
+  __ vmstat();
+  __ add(R0, R0, ShifterOperand(16), VC);  // Error if not unordered (not Nan).
+
+  // R0 is 0 if all tests passed.
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleCompare, test) {
+  EXPECT(test != NULL);
+  typedef int (*DoubleCompare)();
+  EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(DoubleCompare, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Loop, assembler) {
+  Label loop_entry;
+  __ mov(R0, ShifterOperand(1));
+  __ mov(R1, ShifterOperand(2));
+  __ Bind(&loop_entry);
+  __ mov(R0, ShifterOperand(R0, LSL, 1));
+  __ movs(R1, ShifterOperand(R1, LSR, 1));
+  __ b(&loop_entry, NE);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Loop, test) {
+  EXPECT(test != NULL);
+  typedef int (*Loop)();
+  EXPECT_EQ(4, EXECUTE_TEST_CODE_INT32(Loop, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(ForwardBranch, assembler) {
+  Label skip;
+  __ mov(R0, ShifterOperand(42));
+  __ b(&skip);
+  __ mov(R0, ShifterOperand(11));
+  __ Bind(&skip);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(ForwardBranch, test) {
+  EXPECT(test != NULL);
+  typedef int (*ForwardBranch)();
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(ForwardBranch, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(LoadStore, assembler) {
+  __ mov(R1, ShifterOperand(123));
+  __ Push(R1);
+  __ Pop(R0);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(LoadStore, test) {
+  EXPECT(test != NULL);
+  typedef int (*LoadStore)();
+  EXPECT_EQ(123, EXECUTE_TEST_CODE_INT32(LoadStore, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(AddSub, assembler) {
+  __ mov(R1, ShifterOperand(40));
+  __ sub(R1, R1, ShifterOperand(2));
+  __ add(R0, R1, ShifterOperand(4));
+  __ rsbs(R0, R0, ShifterOperand(100));
+  __ rsc(R0, R0, ShifterOperand(100));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(AddSub, test) {
+  EXPECT(test != NULL);
+  typedef int (*AddSub)();
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(AddSub, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Semaphore, assembler) {
+  __ mov(R0, ShifterOperand(40));
+  __ mov(R1, ShifterOperand(42));
+  __ Push(R0);
+  Label retry;
+  __ Bind(&retry);
+  __ ldrex(R0, SP);
+  __ strex(IP, R1, SP);  // IP == 0, success
+  __ tst(IP, ShifterOperand(0));
+  __ b(&retry, NE);  // NE if context switch occurred between ldrex and strex.
+  __ Pop(R0);  // 42
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Semaphore, test) {
+  EXPECT(test != NULL);
+  typedef int (*Semaphore)();
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Semaphore, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(FailedSemaphore, assembler) {
+  __ mov(R0, ShifterOperand(40));
+  __ mov(R1, ShifterOperand(42));
+  __ Push(R0);
+  __ ldrex(R0, SP);
+  __ clrex();  // Simulate a context switch.
+  __ strex(IP, R1, SP);  // IP == 1, failure
+  __ Pop(R0);  // 40
+  __ add(R0, R0, ShifterOperand(IP));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(FailedSemaphore, test) {
+  EXPECT(test != NULL);
+  typedef int (*FailedSemaphore)();
+  EXPECT_EQ(41, EXECUTE_TEST_CODE_INT32(FailedSemaphore, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(AndOrr, assembler) {
+  __ mov(R1, ShifterOperand(40));
+  __ mov(R2, ShifterOperand(0));
+  __ and_(R1, R2, ShifterOperand(R1));
+  __ mov(R3, ShifterOperand(42));
+  __ orr(R0, R1, ShifterOperand(R3));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(AndOrr, test) {
+  EXPECT(test != NULL);
+  typedef int (*AndOrr)();
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(AndOrr, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Orrs, assembler) {
+  __ mov(R0, ShifterOperand(0));
+  __ tst(R0, ShifterOperand(R1));  // Set zero-flag.
+  __ orrs(R0, R0, ShifterOperand(1));  // Clear zero-flag.
+  __ mov(PC, ShifterOperand(LR), EQ);
+  __ mov(R0, ShifterOperand(42));
+  __ mov(PC, ShifterOperand(LR), NE);  // Only this return should fire.
+  __ mov(R0, ShifterOperand(2));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Orrs, test) {
+  EXPECT(test != NULL);
+  typedef int (*Orrs)();
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Orrs, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Multiply, assembler) {
+  __ mov(R1, ShifterOperand(20));
+  __ mov(R2, ShifterOperand(40));
+  __ mul(R3, R2, R1);
+  __ mov(R0, ShifterOperand(R3));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Multiply, test) {
+  EXPECT(test != NULL);
+  typedef int (*Multiply)();
+  EXPECT_EQ(800, EXECUTE_TEST_CODE_INT32(Multiply, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(QuotientRemainder, assembler) {
+  __ vmovsr(S2, R0);
+  __ vmovsr(S4, R2);
+  __ vcvtdi(D1, S2);
+  __ vcvtdi(D2, S4);
+  __ vdivd(D0, D1, D2);
+  __ vcvtid(S0, D0);
+  __ vmovrs(R1, S0);  // r1 = r0/r2
+  __ mls(R0, R1, R2, R0);  // r0 = r0 - r1*r2
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(QuotientRemainder, test) {
+  EXPECT(test != NULL);
+  typedef int64_t (*QuotientRemainder)(int64_t dividend, int64_t divisor);
+  EXPECT_EQ(0x1000400000da8LL,
+            EXECUTE_TEST_CODE_INT64_LL(QuotientRemainder, test->entry(),
+                                       0x12345678, 0x1234));
+}
+
+
+ASSEMBLER_TEST_GENERATE(LongMultiply, assembler) {
+  __ Push(R4);
+  __ Mov(IP, R0);
+  __ mul(R4, R2, R1);
+  __ umull(R0, R1, R2, IP);
+  __ mla(R2, IP, R3, R4);
+  __ add(R1, R2, ShifterOperand(R1));
+  __ Pop(R4);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(LongMultiply, test) {
+  EXPECT(test != NULL);
+  typedef int64_t (*LongMultiply)(int64_t operand0, int64_t operand1);
+  EXPECT_EQ(6, EXECUTE_TEST_CODE_INT64_LL(LongMultiply, test->entry(), -3, -2));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Clz, assembler) {
+  Label error;
+
+  __ mov(R0, ShifterOperand(0));
+  __ clz(R1, R0);
+  __ cmp(R1, ShifterOperand(32));
+  __ b(&error, NE);
+  __ mov(R2, ShifterOperand(42));
+  __ clz(R2, R2);
+  __ cmp(R2, ShifterOperand(26));
+  __ b(&error, NE);
+  __ mvn(R0, ShifterOperand(0));
+  __ clz(R1, R0);
+  __ cmp(R1, ShifterOperand(0));
+  __ b(&error, NE);
+  __ Lsr(R0, R0, 3);
+  __ clz(R1, R0);
+  __ cmp(R1, ShifterOperand(3));
+  __ b(&error, NE);
+  __ mov(R0, ShifterOperand(0));
+  __ mov(PC, ShifterOperand(LR));
+  __ Bind(&error);
+  __ mov(R0, ShifterOperand(1));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Clz, test) {
+  EXPECT(test != NULL);
+  typedef int (*Clz)();
+  EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Clz, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Tst, assembler) {
+  Label skip;
+
+  __ mov(R0, ShifterOperand(42));
+  __ mov(R1, ShifterOperand(40));
+  __ tst(R1, ShifterOperand(0));
+  __ b(&skip, NE);
+  __ mov(R0, ShifterOperand(0));
+  __ Bind(&skip);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Tst, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Lsl, assembler) {
+  Label skip;
+
+  __ mov(R0, ShifterOperand(1));
+  __ mov(R0, ShifterOperand(R0, LSL, 1));
+  __ mov(R1, ShifterOperand(1));
+  __ mov(R0, ShifterOperand(R0, LSL, R1));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Lsl, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Lsr, assembler) {
+  Label skip;
+
+  __ mov(R0, ShifterOperand(4));
+  __ mov(R0, ShifterOperand(R0, LSR, 1));
+  __ mov(R1, ShifterOperand(1));
+  __ mov(R0, ShifterOperand(R0, LSR, R1));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Lsr, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Lsr1, assembler) {
+  Label skip;
+
+  __ mov(R0, ShifterOperand(1));
+  __ Lsl(R0, R0, 31);
+  __ Lsr(R0, R0, 31);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Lsr1, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Asr1, assembler) {
+  Label skip;
+
+  __ mov(R0, ShifterOperand(1));
+  __ Lsl(R0, R0, 31);
+  __ Asr(R0, R0, 31);
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Asr1, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(-1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Rsb, assembler) {
+  __ mov(R3, ShifterOperand(10));
+  __ rsb(R0, R3, ShifterOperand(42));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Rsb, test) {
+  EXPECT(test != NULL);
+  typedef int (*Rsb)();
+  EXPECT_EQ(32, EXECUTE_TEST_CODE_INT32(Rsb, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Ldrh, assembler) {
+  Label Test1;
+  Label Test2;
+  Label Done;
+
+  __ mov(R1, ShifterOperand(0x11));
+  __ mov(R2, ShifterOperand(SP));
+  __ str(R1, Address(SP, (-kWordSize * 30), Address::PreIndex));
+  __ ldrh(R0, Address(R2, (-kWordSize * 30)));
+  __ cmp(R0, ShifterOperand(0x11));
+  __ b(&Test1, EQ);
+  __ mov(R0, ShifterOperand(1));
+  __ b(&Done);
+  __ Bind(&Test1);
+
+  __ mov(R0, ShifterOperand(0));
+  __ strh(R0, Address(R2, (-kWordSize * 30)));
+  __ ldrh(R1, Address(R2, (-kWordSize * 30)));
+  __ cmp(R1, ShifterOperand(0));
+  __ b(&Test2, EQ);
+  __ mov(R0, ShifterOperand(1));
+  __ b(&Done);
+  __ Bind(&Test2);
+
+  __ mov(R0, ShifterOperand(0));
+  __ Bind(&Done);
+  __ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Ldrh, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Ldrsb, assembler) {
+  __ mov(R1, ShifterOperand(0xFF));
+  __ mov(R2, ShifterOperand(SP));
+  __ str(R1, Address(SP, (-kWordSize * 30), Address::PreIndex));
+  __ ldrsb(R0, Address(R2, (-kWordSize * 30)));
+  __ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Ldrsb, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(-1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Ldrb, assembler) {
+  __ mov(R1, ShifterOperand(0xFF));
+  __ mov(R2, ShifterOperand(SP));
+  __ str(R1, Address(SP, (-kWordSize * 30), Address::PreIndex));
+  __ ldrb(R0, Address(R2, (-kWordSize * 30)));
+  __ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Ldrb, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(0xff, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Ldrsh, assembler) {
+  __ mov(R1, ShifterOperand(0xFF));
+  __ mov(R2, ShifterOperand(SP));
+  __ str(R1, Address(SP, (-kWordSize * 30), Address::PreIndex));
+  __ ldrsh(R0, Address(R2, (-kWordSize * 30)));
+  __ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Ldrsh, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(0xff, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Ldrh1, assembler) {
+  __ mov(R1, ShifterOperand(0xFF));
+  __ mov(R2, ShifterOperand(SP));
+  __ str(R1, Address(SP, (-kWordSize * 30), Address::PreIndex));
+  __ ldrh(R0, Address(R2, (-kWordSize * 30)));
+  __ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Ldrh1, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(0xff, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Ldrd, assembler) {
+  __ Mov(IP, SP);
+  __ strd(R2, Address(SP, (-kWordSize * 30), Address::PreIndex));
+  __ strd(R0, Address(IP, (-kWordSize * 28)));
+  __ ldrd(R2, Address(IP, (-kWordSize * 28)));
+  __ ldrd(R0, Address(SP, (kWordSize * 30), Address::PostIndex));
+  __ sub(R0, R0, ShifterOperand(R2));
+  __ add(R1, R1, ShifterOperand(R3));
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Ldrd, test) {
+  EXPECT(test != NULL);
+  typedef int64_t (*Tst)(int64_t r0r1, int64_t r2r3);
+  EXPECT_EQ(0x0000444400002222LL, EXECUTE_TEST_CODE_INT64_LL(
+      Tst, test->entry(), 0x0000111100000000LL, 0x0000333300002222LL));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Ldm_stm_da, assembler) {
+  __ mov(R0, ShifterOperand(1));
+  __ mov(R1, ShifterOperand(7));
+  __ mov(R2, ShifterOperand(11));
+  __ mov(R3, ShifterOperand(31));
+  __ Push(R5);  // We use R5 as accumulator.
+  __ Push(R5);
+  __ Push(R5);
+  __ Push(R5);
+  __ Push(R5);
+  __ Push(R0);  // Make room, so we can decrement after.
+  __ stm(DA_W, SP, (1 << R0 | 1 << R1 | 1 << R2 | 1 << R3));
+  __ str(R2, Address(SP));                 // Should be a free slot.
+  __ ldr(R5, Address(SP, 1 * kWordSize));  // R0.  R5 = +1.
+  __ ldr(IP, Address(SP, 2 * kWordSize));  // R1.
+  __ sub(R5, R5, ShifterOperand(IP));      // -R1. R5 = -6.
+  __ ldr(IP, Address(SP, 3 * kWordSize));  // R2.
+  __ add(R5, R5, ShifterOperand(IP));      // +R2. R5 = +5.
+  __ ldr(IP, Address(SP, 4 * kWordSize));  // R3.
+  __ sub(R5, R5, ShifterOperand(IP));      // -R3. R5 = -26.
+  __ ldm(IB_W, SP, (1 << R0 | 1 << R1 | 1 << R2 | 1 << R3));
+  // Same operations again. But this time from the restore registers.
+  __ add(R5, R5, ShifterOperand(R0));
+  __ sub(R5, R5, ShifterOperand(R1));
+  __ add(R5, R5, ShifterOperand(R2));
+  __ sub(R0, R5, ShifterOperand(R3));  // R0 = result = -52.
+  __ Pop(R1);  // Remove storage slot.
+  __ Pop(R5);  // Restore R5.
+  __ Pop(R5);  // Restore R5.
+  __ Pop(R5);  // Restore R5.
+  __ Pop(R5);  // Restore R5.
+  __ Pop(R5);  // Restore R5.
+  __ mov(PC, ShifterOperand(LR));
+}
+
+
+ASSEMBLER_TEST_RUN(Ldm_stm_da, test) {
+  EXPECT(test != NULL);
+  typedef int (*Tst)();
+  EXPECT_EQ(-52, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+}
+
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 9fb8106..8ab5b0c 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -299,7 +299,11 @@
 
 class Assembler : public ValueObject {
  public:
-  Assembler() : buffer_(), prologue_offset_(-1), comments_() { }
+  Assembler()
+      : buffer_(),
+        object_pool_(GrowableObjectArray::Handle()),
+        prologue_offset_(-1),
+        comments_() { }
   ~Assembler() { }
 
   static const bool kNearJump = true;
@@ -674,6 +678,7 @@
   const ZoneGrowableArray<int>& GetPointerOffsets() const {
     return buffer_.pointer_offsets();
   }
+  const GrowableObjectArray& object_pool() const { return object_pool_; }
 
   void FinalizeInstructions(const MemoryRegion& region) {
     buffer_.FinalizeInstructions(region);
@@ -695,6 +700,7 @@
 
  private:
   AssemblerBuffer buffer_;
+  GrowableObjectArray& object_pool_;  // Object pool is not used on ia32.
   int prologue_offset_;
 
   class CodeComment : public ZoneAllocated {
diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc
index 2a2c33d..f3da046 100644
--- a/runtime/vm/assembler_ia32_test.cc
+++ b/runtime/vm/assembler_ia32_test.cc
@@ -21,9 +21,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Simple, entry) {
+ASSEMBLER_TEST_RUN(Simple, test) {
   typedef int (*SimpleCode)();
-  EXPECT_EQ(42, reinterpret_cast<SimpleCode>(entry)());
+  EXPECT_EQ(42, reinterpret_cast<SimpleCode>(test->entry())());
 }
 
 
@@ -33,10 +33,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(ReadArgument, entry) {
+ASSEMBLER_TEST_RUN(ReadArgument, test) {
   typedef int (*ReadArgumentCode)(int n);
-  EXPECT_EQ(42, reinterpret_cast<ReadArgumentCode>(entry)(42));
-  EXPECT_EQ(87, reinterpret_cast<ReadArgumentCode>(entry)(87));
+  EXPECT_EQ(42, reinterpret_cast<ReadArgumentCode>(test->entry())(42));
+  EXPECT_EQ(87, reinterpret_cast<ReadArgumentCode>(test->entry())(87));
 }
 
 
@@ -98,7 +98,7 @@
 }
 
 
-ASSEMBLER_TEST_RUN(AddressingModes, entry) {
+ASSEMBLER_TEST_RUN(AddressingModes, test) {
   // Avoid running the code since it is constructed to lead to crashes.
 }
 
@@ -124,11 +124,11 @@
 }
 
 
-ASSEMBLER_TEST_RUN(JumpAroundCrash, entry) {
-  Instr* instr = Instr::At(entry);
+ASSEMBLER_TEST_RUN(JumpAroundCrash, test) {
+  Instr* instr = Instr::At(test->entry());
   EXPECT(!instr->IsBreakPoint());
   typedef void (*JumpAroundCrashCode)();
-  reinterpret_cast<JumpAroundCrashCode>(entry)();
+  reinterpret_cast<JumpAroundCrashCode>(test->entry())();
 }
 
 
@@ -153,9 +153,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(NearJumpAroundCrash, entry) {
+ASSEMBLER_TEST_RUN(NearJumpAroundCrash, test) {
   typedef void (*NearJumpAroundCrashCode)();
-  reinterpret_cast<NearJumpAroundCrashCode>(entry)();
+  reinterpret_cast<NearJumpAroundCrashCode>(test->entry())();
 }
 
 
@@ -172,9 +172,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SimpleLoop, entry) {
+ASSEMBLER_TEST_RUN(SimpleLoop, test) {
   typedef int (*SimpleLoopCode)();
-  EXPECT_EQ(2 * 87, reinterpret_cast<SimpleLoopCode>(entry)());
+  EXPECT_EQ(2 * 87, reinterpret_cast<SimpleLoopCode>(test->entry())());
 }
 
 
@@ -190,9 +190,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Increment, entry) {
+ASSEMBLER_TEST_RUN(Increment, test) {
   typedef int (*IncrementCode)();
-  EXPECT_EQ(2, reinterpret_cast<IncrementCode>(entry)());
+  EXPECT_EQ(2, reinterpret_cast<IncrementCode>(test->entry())());
 }
 
 
@@ -208,9 +208,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Decrement, entry) {
+ASSEMBLER_TEST_RUN(Decrement, test) {
   typedef int (*DecrementCode)();
-  EXPECT_EQ(0, reinterpret_cast<DecrementCode>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<DecrementCode>(test->entry())());
 }
 
 
@@ -224,9 +224,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(AddressBinOp, entry) {
+ASSEMBLER_TEST_RUN(AddressBinOp, test) {
   typedef int (*AddressBinOpCode)(int a);
-  EXPECT_EQ((2 + 2 + 1 - 2) * 2, reinterpret_cast<AddressBinOpCode>(entry)(2));
+  EXPECT_EQ((2 + 2 + 1 - 2) * 2,
+            reinterpret_cast<AddressBinOpCode>(test->entry())(2));
 }
 
 
@@ -239,9 +240,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SignedMultiply, entry) {
+ASSEMBLER_TEST_RUN(SignedMultiply, test) {
   typedef int (*SignedMultiply)();
-  EXPECT_EQ(8000, reinterpret_cast<SignedMultiply>(entry)());
+  EXPECT_EQ(8000, reinterpret_cast<SignedMultiply>(test->entry())());
 }
 
 
@@ -255,9 +256,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(OverflowSignedMultiply, entry) {
+ASSEMBLER_TEST_RUN(OverflowSignedMultiply, test) {
   typedef int (*OverflowSignedMultiply)();
-  EXPECT_EQ(0, reinterpret_cast<OverflowSignedMultiply>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<OverflowSignedMultiply>(test->entry())());
 }
 
 
@@ -273,9 +274,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SignedMultiply1, entry) {
+ASSEMBLER_TEST_RUN(SignedMultiply1, test) {
   typedef int (*SignedMultiply1)();
-  EXPECT_EQ(8000, reinterpret_cast<SignedMultiply1>(entry)());
+  EXPECT_EQ(8000, reinterpret_cast<SignedMultiply1>(test->entry())());
 }
 
 
@@ -287,9 +288,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Negate, entry) {
+ASSEMBLER_TEST_RUN(Negate, test) {
   typedef int (*Negate)();
-  EXPECT_EQ(-42, reinterpret_cast<Negate>(entry)());
+  EXPECT_EQ(-42, reinterpret_cast<Negate>(test->entry())());
 }
 
 
@@ -306,9 +307,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(MoveExtend, entry) {
+ASSEMBLER_TEST_RUN(MoveExtend, test) {
   typedef int (*MoveExtend)();
-  EXPECT_EQ(0xff - 1 + 0xffff, reinterpret_cast<MoveExtend>(entry)());
+  EXPECT_EQ(0xff - 1 + 0xffff, reinterpret_cast<MoveExtend>(test->entry())());
 }
 
 
@@ -329,9 +330,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(MoveExtendMemory, entry) {
+ASSEMBLER_TEST_RUN(MoveExtendMemory, test) {
   typedef int (*MoveExtendMemory)();
-  EXPECT_EQ(0xff - 1 + 0xffff, reinterpret_cast<MoveExtendMemory>(entry)());
+  EXPECT_EQ(0xff - 1 + 0xffff,
+            reinterpret_cast<MoveExtendMemory>(test->entry())());
 }
 
 
@@ -351,9 +353,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Bitwise, entry) {
+ASSEMBLER_TEST_RUN(Bitwise, test) {
   typedef int (*Bitwise)();
-  EXPECT_EQ(256 + 1, reinterpret_cast<Bitwise>(entry)());
+  EXPECT_EQ(256 + 1, reinterpret_cast<Bitwise>(test->entry())());
 }
 
 
@@ -525,9 +527,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LogicalOps, entry) {
+ASSEMBLER_TEST_RUN(LogicalOps, test) {
   typedef int (*LogicalOpsCode)();
-  EXPECT_EQ(0, reinterpret_cast<LogicalOpsCode>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<LogicalOpsCode>(test->entry())());
 }
 
 
@@ -586,9 +588,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LogicalTest, entry) {
+ASSEMBLER_TEST_RUN(LogicalTest, test) {
   typedef int (*LogicalTestCode)();
-  EXPECT_EQ(0, reinterpret_cast<LogicalTestCode>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<LogicalTestCode>(test->entry())());
 }
 
 
@@ -604,9 +606,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(CompareSwapEQ, entry) {
+ASSEMBLER_TEST_RUN(CompareSwapEQ, test) {
   typedef int (*CompareSwapEQCode)();
-  EXPECT_EQ(0, reinterpret_cast<CompareSwapEQCode>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<CompareSwapEQCode>(test->entry())());
 }
 
 
@@ -622,9 +624,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(CompareSwapNEQ, entry) {
+ASSEMBLER_TEST_RUN(CompareSwapNEQ, test) {
   typedef int (*CompareSwapNEQCode)();
-  EXPECT_EQ(4, reinterpret_cast<CompareSwapNEQCode>(entry)());
+  EXPECT_EQ(4, reinterpret_cast<CompareSwapNEQCode>(test->entry())());
 }
 
 
@@ -638,9 +640,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SignedDivide, entry) {
+ASSEMBLER_TEST_RUN(SignedDivide, test) {
   typedef int (*SignedDivide)();
-  EXPECT_EQ(-87 / 42, reinterpret_cast<SignedDivide>(entry)());
+  EXPECT_EQ(-87 / 42, reinterpret_cast<SignedDivide>(test->entry())());
 }
 
 
@@ -653,9 +655,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Exchange, entry) {
+ASSEMBLER_TEST_RUN(Exchange, test) {
   typedef int (*Exchange)();
-  EXPECT_EQ(987654321 - 123456789, reinterpret_cast<Exchange>(entry)());
+  EXPECT_EQ(987654321 - 123456789, reinterpret_cast<Exchange>(test->entry())());
 }
 
 
@@ -694,9 +696,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(CallSimpleLeaf, entry) {
+ASSEMBLER_TEST_RUN(CallSimpleLeaf, test) {
   typedef int (*CallSimpleLeafCode)();
-  EXPECT_EQ(42 + 87, reinterpret_cast<CallSimpleLeafCode>(entry)());
+  EXPECT_EQ(42 + 87, reinterpret_cast<CallSimpleLeafCode>(test->entry())());
 }
 
 
@@ -713,9 +715,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(JumpSimpleLeaf, entry) {
+ASSEMBLER_TEST_RUN(JumpSimpleLeaf, test) {
   typedef int (*JumpSimpleLeafCode)();
-  EXPECT_EQ(42, reinterpret_cast<JumpSimpleLeafCode>(entry)());
+  EXPECT_EQ(42, reinterpret_cast<JumpSimpleLeafCode>(test->entry())());
 }
 
 
@@ -734,9 +736,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(JumpConditionalSimpleLeaf, entry) {
+ASSEMBLER_TEST_RUN(JumpConditionalSimpleLeaf, test) {
   typedef int (*JumpConditionalSimpleLeafCode)();
-  EXPECT_EQ(42, reinterpret_cast<JumpConditionalSimpleLeafCode>(entry)());
+  EXPECT_EQ(42,
+            reinterpret_cast<JumpConditionalSimpleLeafCode>(test->entry())());
 }
 
 
@@ -759,9 +762,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SingleFPMoves, entry) {
+ASSEMBLER_TEST_RUN(SingleFPMoves, test) {
   typedef float (*SingleFPMovesCode)();
-  float res = reinterpret_cast<SingleFPMovesCode>(entry)();
+  float res = reinterpret_cast<SingleFPMovesCode>(test->entry())();
   EXPECT_EQ(234.0f, res);
 }
 
@@ -783,9 +786,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SingleFPMoves2, entry) {
+ASSEMBLER_TEST_RUN(SingleFPMoves2, test) {
   typedef float (*SingleFPMoves2Code)();
-  float res = reinterpret_cast<SingleFPMoves2Code>(entry)();
+  float res = reinterpret_cast<SingleFPMoves2Code>(test->entry())();
   EXPECT_EQ(234.0f, res);
 }
 
@@ -803,9 +806,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SingleFPUStackMoves, entry) {
+ASSEMBLER_TEST_RUN(SingleFPUStackMoves, test) {
   typedef int (*SingleFPUStackMovesCode)();
-  int res = reinterpret_cast<SingleFPUStackMovesCode>(entry)();
+  int res = reinterpret_cast<SingleFPUStackMovesCode>(test->entry())();
   EXPECT_EQ(234.0f, (bit_cast<float, int>(res)));
 }
 
@@ -827,9 +830,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SingleFPOperations, entry) {
+ASSEMBLER_TEST_RUN(SingleFPOperations, test) {
   typedef float (*SingleFPOperationsCode)();
-  float res = reinterpret_cast<SingleFPOperationsCode>(entry)();
+  float res = reinterpret_cast<SingleFPOperationsCode>(test->entry())();
   EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
 }
 
@@ -855,9 +858,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedFPOperations, entry) {
+ASSEMBLER_TEST_RUN(PackedFPOperations, test) {
   typedef float (*PackedFPOperationsCode)();
-  float res = reinterpret_cast<PackedFPOperationsCode>(entry)();
+  float res = reinterpret_cast<PackedFPOperationsCode>(test->entry())();
   EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
 }
 
@@ -882,9 +885,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedFPOperations2, entry) {
+ASSEMBLER_TEST_RUN(PackedFPOperations2, test) {
   typedef float (*PackedFPOperations2Code)();
-  float res = reinterpret_cast<PackedFPOperations2Code>(entry)();
+  float res = reinterpret_cast<PackedFPOperations2Code>(test->entry())();
   EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
 }
 
@@ -902,9 +905,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareEQ, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareEQ, test) {
   typedef uint32_t (*PackedCompareEQCode)();
-  uint32_t res = reinterpret_cast<PackedCompareEQCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareEQCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0x0), res);
 }
 
@@ -922,9 +925,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareNEQ, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareNEQ, test) {
   typedef uint32_t (*PackedCompareNEQCode)();
-  uint32_t res = reinterpret_cast<PackedCompareNEQCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareNEQCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
 }
 
@@ -942,9 +945,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareLT, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareLT, test) {
   typedef uint32_t (*PackedCompareLTCode)();
-  uint32_t res = reinterpret_cast<PackedCompareLTCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareLTCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
 }
 
@@ -962,9 +965,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareLE, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareLE, test) {
   typedef uint32_t (*PackedCompareLECode)();
-  uint32_t res = reinterpret_cast<PackedCompareLECode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareLECode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
 }
 
@@ -982,9 +985,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareNLT, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareNLT, test) {
   typedef uint32_t (*PackedCompareNLTCode)();
-  uint32_t res = reinterpret_cast<PackedCompareNLTCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareNLTCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0x0), res);
 }
 
@@ -1002,9 +1005,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareNLE, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareNLE, test) {
   typedef uint32_t (*PackedCompareNLECode)();
-  uint32_t res = reinterpret_cast<PackedCompareNLECode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareNLECode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0x0), res);
 }
 
@@ -1024,9 +1027,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedNegate, entry) {
+ASSEMBLER_TEST_RUN(PackedNegate, test) {
   typedef float (*PackedNegateCode)();
-  float res = reinterpret_cast<PackedNegateCode>(entry)();
+  float res = reinterpret_cast<PackedNegateCode>(test->entry())();
   EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
 }
 
@@ -1046,9 +1049,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedAbsolute, entry) {
+ASSEMBLER_TEST_RUN(PackedAbsolute, test) {
   typedef float (*PackedAbsoluteCode)();
-  float res = reinterpret_cast<PackedAbsoluteCode>(entry)();
+  float res = reinterpret_cast<PackedAbsoluteCode>(test->entry())();
   EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
 }
 
@@ -1066,9 +1069,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedSetWZero, entry) {
+ASSEMBLER_TEST_RUN(PackedSetWZero, test) {
   typedef float (*PackedSetWZeroCode)();
-  float res = reinterpret_cast<PackedSetWZeroCode>(entry)();
+  float res = reinterpret_cast<PackedSetWZeroCode>(test->entry())();
   EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
 }
 
@@ -1086,9 +1089,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedMin, entry) {
+ASSEMBLER_TEST_RUN(PackedMin, test) {
   typedef float (*PackedMinCode)();
-  float res = reinterpret_cast<PackedMinCode>(entry)();
+  float res = reinterpret_cast<PackedMinCode>(test->entry())();
   EXPECT_FLOAT_EQ(2.0f, res, 0.001f);
 }
 
@@ -1106,9 +1109,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedMax, entry) {
+ASSEMBLER_TEST_RUN(PackedMax, test) {
   typedef float (*PackedMaxCode)();
-  float res = reinterpret_cast<PackedMaxCode>(entry)();
+  float res = reinterpret_cast<PackedMaxCode>(test->entry())();
   EXPECT_FLOAT_EQ(4.0f, res, 0.001f);
 }
 
@@ -1140,9 +1143,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedLogicalOr, entry) {
+ASSEMBLER_TEST_RUN(PackedLogicalOr, test) {
   typedef uint32_t (*PackedLogicalOrCode)();
-  uint32_t res = reinterpret_cast<PackedLogicalOrCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedLogicalOrCode>(test->entry())();
   EXPECT_EQ(0xFFFFFFFF, res);
 }
 
@@ -1173,9 +1176,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedLogicalAnd, entry) {
+ASSEMBLER_TEST_RUN(PackedLogicalAnd, test) {
   typedef uint32_t (*PackedLogicalAndCode)();
-  uint32_t res = reinterpret_cast<PackedLogicalAndCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedLogicalAndCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0x0000F000), res);
 }
 
@@ -1199,9 +1202,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedLogicalNot, entry) {
+ASSEMBLER_TEST_RUN(PackedLogicalNot, test) {
   typedef uint32_t (*PackedLogicalNotCode)();
-  uint32_t res = reinterpret_cast<PackedLogicalNotCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedLogicalNotCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0x0), res);
 }
 
@@ -1221,9 +1224,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SingleFPOperationsStack, entry) {
+ASSEMBLER_TEST_RUN(SingleFPOperationsStack, test) {
   typedef float (*SingleFPOperationsStackCode)(float f);
-  float res = reinterpret_cast<SingleFPOperationsStackCode>(entry)(3.4);
+  float res = reinterpret_cast<SingleFPOperationsStackCode>(test->entry())(3.4);
   EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
 }
 
@@ -1264,9 +1267,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleFPMoves, entry) {
+ASSEMBLER_TEST_RUN(DoubleFPMoves, test) {
   typedef double (*DoubleFPMovesCode)();
-  double res = reinterpret_cast<DoubleFPMovesCode>(entry)();
+  double res = reinterpret_cast<DoubleFPMovesCode>(test->entry())();
   EXPECT_FLOAT_EQ(1024.67, res, 0.0001);
 }
 
@@ -1286,9 +1289,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleFPUStackMoves, entry) {
+ASSEMBLER_TEST_RUN(DoubleFPUStackMoves, test) {
   typedef int64_t (*DoubleFPUStackMovesCode)();
-  int64_t res = reinterpret_cast<DoubleFPUStackMovesCode>(entry)();
+  int64_t res = reinterpret_cast<DoubleFPUStackMovesCode>(test->entry())();
   EXPECT_FLOAT_EQ(1024.67, (bit_cast<double, int64_t>(res)), 0.001);
 }
 
@@ -1320,9 +1323,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleFPOperations, entry) {
+ASSEMBLER_TEST_RUN(DoubleFPOperations, test) {
   typedef double (*DoubleFPOperationsCode)();
-  double res = reinterpret_cast<DoubleFPOperationsCode>(entry)();
+  double res = reinterpret_cast<DoubleFPOperationsCode>(test->entry())();
   EXPECT_FLOAT_EQ(14.7, res, 0.001);
 }
 
@@ -1352,9 +1355,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleFPOperationsStack, entry) {
+ASSEMBLER_TEST_RUN(DoubleFPOperationsStack, test) {
   typedef double (*DoubleFPOperationsStackCode)(double d);
-  double res = reinterpret_cast<DoubleFPOperationsStackCode>(entry)(3.4);
+  double res =
+      reinterpret_cast<DoubleFPOperationsStackCode>(test->entry())(3.4);
   EXPECT_FLOAT_EQ(14.7, res, 0.001);
 }
 
@@ -1372,9 +1376,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IntToDoubleConversion, entry) {
+ASSEMBLER_TEST_RUN(IntToDoubleConversion, test) {
   typedef double (*IntToDoubleConversionCode)();
-  double res = reinterpret_cast<IntToDoubleConversionCode>(entry)();
+  double res = reinterpret_cast<IntToDoubleConversionCode>(test->entry())();
   EXPECT_FLOAT_EQ(6.0, res, 0.001);
 }
 
@@ -1385,9 +1389,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IntToDoubleConversion2, entry) {
+ASSEMBLER_TEST_RUN(IntToDoubleConversion2, test) {
   typedef double (*IntToDoubleConversion2Code)(int i);
-  double res = reinterpret_cast<IntToDoubleConversion2Code>(entry)(3);
+  double res = reinterpret_cast<IntToDoubleConversion2Code>(test->entry())(3);
   EXPECT_FLOAT_EQ(3.0, res, 0.001);
 }
 
@@ -1403,9 +1407,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IntToFloatConversion, entry) {
+ASSEMBLER_TEST_RUN(IntToFloatConversion, test) {
   typedef float (*IntToFloatConversionCode)();
-  float res = reinterpret_cast<IntToFloatConversionCode>(entry)();
+  float res = reinterpret_cast<IntToFloatConversionCode>(test->entry())();
   EXPECT_FLOAT_EQ(6.0, res, 0.001);
 }
 
@@ -1418,11 +1422,12 @@
 }
 
 
-ASSEMBLER_TEST_RUN(FloatToIntConversionRound, entry) {
+ASSEMBLER_TEST_RUN(FloatToIntConversionRound, test) {
   typedef int (*FloatToIntConversionRoundCode)(float f);
-  int res = reinterpret_cast<FloatToIntConversionRoundCode>(entry)(12.3);
+  int res =
+      reinterpret_cast<FloatToIntConversionRoundCode>(test->entry())(12.3);
   EXPECT_EQ(12, res);
-  res = reinterpret_cast<FloatToIntConversionRoundCode>(entry)(12.8);
+  res = reinterpret_cast<FloatToIntConversionRoundCode>(test->entry())(12.8);
   EXPECT_EQ(13, res);
 }
 
@@ -1435,11 +1440,12 @@
 }
 
 
-ASSEMBLER_TEST_RUN(FloatToIntConversionTrunc, entry) {
+ASSEMBLER_TEST_RUN(FloatToIntConversionTrunc, test) {
   typedef int (*FloatToIntConversionTruncCode)(float f);
-  int res = reinterpret_cast<FloatToIntConversionTruncCode>(entry)(12.3);
+  int res =
+      reinterpret_cast<FloatToIntConversionTruncCode>(test->entry())(12.3);
   EXPECT_EQ(12, res);
-  res = reinterpret_cast<FloatToIntConversionTruncCode>(entry)(12.8);
+  res = reinterpret_cast<FloatToIntConversionTruncCode>(test->entry())(12.8);
   EXPECT_EQ(12, res);
 }
 
@@ -1459,9 +1465,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(FloatToDoubleConversion, entry) {
+ASSEMBLER_TEST_RUN(FloatToDoubleConversion, test) {
   typedef double (*FloatToDoubleConversionCode)();
-  double res = reinterpret_cast<FloatToDoubleConversionCode>(entry)();
+  double res = reinterpret_cast<FloatToDoubleConversionCode>(test->entry())();
   EXPECT_FLOAT_EQ(12.3, res, 0.001);
 }
 
@@ -1508,9 +1514,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(FloatCompare, entry) {
+ASSEMBLER_TEST_RUN(FloatCompare, test) {
   typedef int (*FloatCompareCode)();
-  int res = reinterpret_cast<FloatCompareCode>(entry)();
+  int res = reinterpret_cast<FloatCompareCode>(test->entry())();
   EXPECT_EQ(0, res);
 }
 
@@ -1579,9 +1585,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleCompare, entry) {
+ASSEMBLER_TEST_RUN(DoubleCompare, test) {
   typedef int (*DoubleCompareCode)();
-  int res = reinterpret_cast<DoubleCompareCode>(entry)();
+  int res = reinterpret_cast<DoubleCompareCode>(test->entry())();
   EXPECT_EQ(0, res);
 }
 
@@ -1602,9 +1608,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleToFloatConversion, entry) {
+ASSEMBLER_TEST_RUN(DoubleToFloatConversion, test) {
   typedef float (*DoubleToFloatConversionCode)();
-  float res = reinterpret_cast<DoubleToFloatConversionCode>(entry)();
+  float res = reinterpret_cast<DoubleToFloatConversionCode>(test->entry())();
   EXPECT_FLOAT_EQ(12.3f, res, 0.001);
 }
 
@@ -1616,11 +1622,12 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleToIntConversionRound, entry) {
+ASSEMBLER_TEST_RUN(DoubleToIntConversionRound, test) {
   typedef int (*DoubleToIntConversionRoundCode)(double d);
-  int res = reinterpret_cast<DoubleToIntConversionRoundCode>(entry)(12.3);
+  int res =
+      reinterpret_cast<DoubleToIntConversionRoundCode>(test->entry())(12.3);
   EXPECT_EQ(12, res);
-  res = reinterpret_cast<DoubleToIntConversionRoundCode>(entry)(12.8);
+  res = reinterpret_cast<DoubleToIntConversionRoundCode>(test->entry())(12.8);
   EXPECT_EQ(13, res);
 }
 
@@ -1632,11 +1639,12 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleToIntConversionTrunc, entry) {
+ASSEMBLER_TEST_RUN(DoubleToIntConversionTrunc, test) {
   typedef int (*DoubleToIntConversionTruncCode)(double d);
-  int res = reinterpret_cast<DoubleToIntConversionTruncCode>(entry)(12.3);
+  int res =
+      reinterpret_cast<DoubleToIntConversionTruncCode>(test->entry())(12.3);
   EXPECT_EQ(12, res);
-  res = reinterpret_cast<DoubleToIntConversionTruncCode>(entry)(12.8);
+  res = reinterpret_cast<DoubleToIntConversionTruncCode>(test->entry())(12.8);
   EXPECT_EQ(12, res);
 }
 
@@ -1654,15 +1662,15 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleToDoubleTrunc, entry) {
+ASSEMBLER_TEST_RUN(DoubleToDoubleTrunc, test) {
   typedef double (*DoubleToDoubleTruncCode)(double d);
-  double res = reinterpret_cast<DoubleToDoubleTruncCode>(entry)(12.3);
+  double res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(12.3);
   EXPECT_EQ(12.0, res);
-  res = reinterpret_cast<DoubleToDoubleTruncCode>(entry)(12.8);
+  res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(12.8);
   EXPECT_EQ(12.0, res);
-  res = reinterpret_cast<DoubleToDoubleTruncCode>(entry)(-12.3);
+  res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(-12.3);
   EXPECT_EQ(-12.0, res);
-  res = reinterpret_cast<DoubleToDoubleTruncCode>(entry)(-12.8);
+  res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(-12.8);
   EXPECT_EQ(-12.0, res);
 }
 
@@ -1680,27 +1688,31 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleToDoubleRound, entry) {
+ASSEMBLER_TEST_RUN(DoubleToDoubleRound, test) {
   typedef double (*DoubleToDoubleRoundCode)(double d);
-  double res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(12.3);
+  double res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(12.3);
   EXPECT_EQ(12.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(12.8);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(12.8);
   EXPECT_EQ(13.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(0.5);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(0.5);
   EXPECT_EQ(1.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(-12.3);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(-12.3);
   EXPECT_EQ(-12.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(-12.8);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(-12.8);
   EXPECT_EQ(-13.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(-0.5);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(-0.5);
   EXPECT_EQ(-1.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(0.49999999999999994);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(
+      test->entry())(0.49999999999999994);
   EXPECT_EQ(0.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(-0.49999999999999994);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(
+      test->entry())(-0.49999999999999994);
   EXPECT_EQ(-0.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(9007199254740991.0);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(
+      test->entry())(9007199254740991.0);
   EXPECT_EQ(9007199254740991.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(-9007199254740991.0);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(
+      test->entry())(-9007199254740991.0);
   EXPECT_EQ(-9007199254740991.0, res);
 }
 
@@ -1719,9 +1731,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(GlobalAddress, entry) {
+ASSEMBLER_TEST_RUN(GlobalAddress, test) {
   typedef double (*GlobalAddressCode)();
-  double res = reinterpret_cast<GlobalAddressCode>(entry)();
+  double res = reinterpret_cast<GlobalAddressCode>(test->entry())();
   EXPECT_FLOAT_EQ(kDoubleConst, res, 0.000001);
 }
 
@@ -1733,10 +1745,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Sine, entry) {
+ASSEMBLER_TEST_RUN(Sine, test) {
   typedef float (*SineCode)(float f);
   const float kFloatConst = 0.7;
-  float res = reinterpret_cast<SineCode>(entry)(kFloatConst);
+  float res = reinterpret_cast<SineCode>(test->entry())(kFloatConst);
   EXPECT_FLOAT_EQ(sin(kFloatConst), res, 0.0001);
 }
 
@@ -1748,10 +1760,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Cosine, entry) {
+ASSEMBLER_TEST_RUN(Cosine, test) {
   typedef float (*CosineCode)(float f);
   const float kFloatConst = 0.7;
-  float res = reinterpret_cast<CosineCode>(entry)(kFloatConst);
+  float res = reinterpret_cast<CosineCode>(test->entry())(kFloatConst);
   EXPECT_FLOAT_EQ(cos(kFloatConst), res, 0.0001);
 }
 
@@ -1765,10 +1777,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Tangent, entry) {
+ASSEMBLER_TEST_RUN(Tangent, test) {
   typedef double (*TangentCode)(double d);
   const double kDoubleConst = 0.6108652375000001;
-  double res = reinterpret_cast<TangentCode>(entry)(kDoubleConst);
+  double res = reinterpret_cast<TangentCode>(test->entry())(kDoubleConst);
   EXPECT_FLOAT_EQ(tan(kDoubleConst), res, 0.0001);
 }
 
@@ -1784,10 +1796,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SquareRootFloat, entry) {
+ASSEMBLER_TEST_RUN(SquareRootFloat, test) {
   typedef float (*SquareRootFloatCode)(float f);
   const float kFloatConst = 0.7;
-  float res = reinterpret_cast<SquareRootFloatCode>(entry)(kFloatConst);
+  float res = reinterpret_cast<SquareRootFloatCode>(test->entry())(kFloatConst);
   EXPECT_FLOAT_EQ(sqrt(kFloatConst), res, 0.0001);
 }
 
@@ -1805,10 +1817,11 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SquareRootDouble, entry) {
+ASSEMBLER_TEST_RUN(SquareRootDouble, test) {
   typedef double (*SquareRootDoubleCode)(double d);
   const double kDoubleConst = .7;
-  double res = reinterpret_cast<SquareRootDoubleCode>(entry)(kDoubleConst);
+  double res =
+      reinterpret_cast<SquareRootDoubleCode>(test->entry())(kDoubleConst);
   EXPECT_FLOAT_EQ(sqrt(kDoubleConst), res, 0.0001);
 }
 
@@ -1824,10 +1837,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(FloatNegate, entry) {
+ASSEMBLER_TEST_RUN(FloatNegate, test) {
   typedef float (*FloatNegateCode)(float f);
   const float kFloatConst = 12.345;
-  float res = reinterpret_cast<FloatNegateCode>(entry)(kFloatConst);
+  float res = reinterpret_cast<FloatNegateCode>(test->entry())(kFloatConst);
   EXPECT_FLOAT_EQ(-kFloatConst, res, 0.0001);
 }
 
@@ -1845,10 +1858,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleNegate, entry) {
+ASSEMBLER_TEST_RUN(DoubleNegate, test) {
   typedef double (*DoubleNegateCode)(double f);
   const double kDoubleConst = 12.345;
-  double res = reinterpret_cast<DoubleNegateCode>(entry)(kDoubleConst);
+  double res = reinterpret_cast<DoubleNegateCode>(test->entry())(kDoubleConst);
   EXPECT_FLOAT_EQ(-kDoubleConst, res, 0.0001);
 }
 
@@ -1861,12 +1874,12 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LongMulReg, entry) {
+ASSEMBLER_TEST_RUN(LongMulReg, test) {
   typedef int64_t (*LongMulRegCode)(int a, int b);
   const int a = -12;
   const int b = 13;
   const int64_t mul_res = a * b;
-  int64_t res = reinterpret_cast<LongMulRegCode>(entry)(a, b);
+  int64_t res = reinterpret_cast<LongMulRegCode>(test->entry())(a, b);
   EXPECT_EQ(mul_res, res);
 }
 
@@ -1878,12 +1891,12 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LongMulAddress, entry) {
+ASSEMBLER_TEST_RUN(LongMulAddress, test) {
   typedef int64_t (*LongMulAddressCode)(int a, int b);
   const int a = -12;
   const int b = 13;
   const int64_t mul_res = a * b;
-  int64_t res = reinterpret_cast<LongMulAddressCode>(entry)(a, b);
+  int64_t res = reinterpret_cast<LongMulAddressCode>(test->entry())(a, b);
   EXPECT_EQ(mul_res, res);
 }
 
@@ -1896,16 +1909,16 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LongUnsignedMulReg, entry) {
+ASSEMBLER_TEST_RUN(LongUnsignedMulReg, test) {
   typedef uint64_t (*LongUnsignedMulRegCode)(uint32_t a, uint32_t b);
   uint32_t a = 3;
   uint32_t b = 13;
   uint64_t mul_res = a * b;
-  uint64_t res = reinterpret_cast<LongUnsignedMulRegCode>(entry)(a, b);
+  uint64_t res = reinterpret_cast<LongUnsignedMulRegCode>(test->entry())(a, b);
   EXPECT_EQ(mul_res, res);
   a = 4021288948u;
   b = 13;
-  res = reinterpret_cast<LongUnsignedMulRegCode>(entry)(a, b);
+  res = reinterpret_cast<LongUnsignedMulRegCode>(test->entry())(a, b);
   mul_res =  static_cast<uint64_t>(a) * static_cast<uint64_t>(b);
   EXPECT_EQ(mul_res, res);
 }
@@ -1918,16 +1931,17 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LongUnsignedMulAddress, entry) {
+ASSEMBLER_TEST_RUN(LongUnsignedMulAddress, test) {
   typedef uint64_t (*LongUnsignedMulAddressCode)(uint32_t a, uint32_t b);
   uint32_t a = 12;
   uint32_t b = 13;
   uint64_t mul_res = a * b;
-  uint64_t res = reinterpret_cast<LongUnsignedMulAddressCode>(entry)(a, b);
+  uint64_t res =
+      reinterpret_cast<LongUnsignedMulAddressCode>(test->entry())(a, b);
   EXPECT_EQ(mul_res, res);
   a = 4294967284u;
   b = 13;
-  res = reinterpret_cast<LongUnsignedMulAddressCode>(entry)(a, b);
+  res = reinterpret_cast<LongUnsignedMulAddressCode>(test->entry())(a, b);
   mul_res =  static_cast<uint64_t>(a) * static_cast<uint64_t>(b);
   EXPECT_EQ(mul_res, res);
 }
@@ -1948,15 +1962,15 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LongAddReg, entry) {
+ASSEMBLER_TEST_RUN(LongAddReg, test) {
   typedef int64_t (*LongAddRegCode)(int64_t a, int64_t b);
   int64_t a = 12;
   int64_t b = 14;
-  int64_t res = reinterpret_cast<LongAddRegCode>(entry)(a, b);
+  int64_t res = reinterpret_cast<LongAddRegCode>(test->entry())(a, b);
   EXPECT_EQ((a + b), res);
   a = 2147483647;
   b = 600000;
-  res = reinterpret_cast<LongAddRegCode>(entry)(a, b);
+  res = reinterpret_cast<LongAddRegCode>(test->entry())(a, b);
   EXPECT_EQ((a + b), res);
 }
 
@@ -1971,15 +1985,15 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LongAddAddress, entry) {
+ASSEMBLER_TEST_RUN(LongAddAddress, test) {
   typedef int64_t (*LongAddAddressCode)(int64_t a, int64_t b);
   int64_t a = 12;
   int64_t b = 14;
-  int64_t res = reinterpret_cast<LongAddAddressCode>(entry)(a, b);
+  int64_t res = reinterpret_cast<LongAddAddressCode>(test->entry())(a, b);
   EXPECT_EQ((a + b), res);
   a = 2147483647;
   b = 600000;
-  res = reinterpret_cast<LongAddAddressCode>(entry)(a, b);
+  res = reinterpret_cast<LongAddAddressCode>(test->entry())(a, b);
   EXPECT_EQ((a + b), res);
 }
 
@@ -1999,15 +2013,15 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LongSubReg, entry) {
+ASSEMBLER_TEST_RUN(LongSubReg, test) {
   typedef int64_t (*LongSubRegCode)(int64_t a, int64_t b);
   int64_t a = 12;
   int64_t b = 14;
-  int64_t res = reinterpret_cast<LongSubRegCode>(entry)(a, b);
+  int64_t res = reinterpret_cast<LongSubRegCode>(test->entry())(a, b);
   EXPECT_EQ((a - b), res);
   a = 600000;
   b = 2147483647;
-  res = reinterpret_cast<LongSubRegCode>(entry)(a, b);
+  res = reinterpret_cast<LongSubRegCode>(test->entry())(a, b);
   EXPECT_EQ((a - b), res);
 }
 
@@ -2022,15 +2036,15 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LongSubAddress, entry) {
+ASSEMBLER_TEST_RUN(LongSubAddress, test) {
   typedef int64_t (*LongSubAddressCode)(int64_t a, int64_t b);
   int64_t a = 12;
   int64_t b = 14;
-  int64_t res = reinterpret_cast<LongSubAddressCode>(entry)(a, b);
+  int64_t res = reinterpret_cast<LongSubAddressCode>(test->entry())(a, b);
   EXPECT_EQ((a - b), res);
   a = 600000;
   b = 2147483647;
-  res = reinterpret_cast<LongSubAddressCode>(entry)(a, b);
+  res = reinterpret_cast<LongSubAddressCode>(test->entry())(a, b);
   EXPECT_EQ((a - b), res);
 }
 
@@ -2056,15 +2070,15 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LongSubAddress2, entry) {
+ASSEMBLER_TEST_RUN(LongSubAddress2, test) {
   typedef int64_t (*LongSubAddress2Code)(int64_t a, int64_t b);
   int64_t a = 12;
   int64_t b = 14;
-  int64_t res = reinterpret_cast<LongSubAddress2Code>(entry)(a, b);
+  int64_t res = reinterpret_cast<LongSubAddress2Code>(test->entry())(a, b);
   EXPECT_EQ((a - b), res);
   a = 600000;
   b = 2147483647;
-  res = reinterpret_cast<LongSubAddress2Code>(entry)(a, b);
+  res = reinterpret_cast<LongSubAddress2Code>(test->entry())(a, b);
   EXPECT_EQ((a - b), res);
 }
 
@@ -2090,15 +2104,15 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LongAddAddress2, entry) {
+ASSEMBLER_TEST_RUN(LongAddAddress2, test) {
   typedef int64_t (*LongAddAddress2Code)(int64_t a, int64_t b);
   int64_t a = 12;
   int64_t b = 14;
-  int64_t res = reinterpret_cast<LongAddAddress2Code>(entry)(a, b);
+  int64_t res = reinterpret_cast<LongAddAddress2Code>(test->entry())(a, b);
   EXPECT_EQ((a + b), res);
   a = 600000;
   b = 2147483647;
-  res = reinterpret_cast<LongAddAddress2Code>(entry)(a, b);
+  res = reinterpret_cast<LongAddAddress2Code>(test->entry())(a, b);
   EXPECT_EQ((a + b), res);
 }
 
@@ -2117,10 +2131,11 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IntegerToDoubleConversion, entry) {
+ASSEMBLER_TEST_RUN(IntegerToDoubleConversion, test) {
   typedef double (*IntegerToDoubleConversionCode)(int32_t);
   const int32_t val = -12;
-  double res = reinterpret_cast<IntegerToDoubleConversionCode>(entry)(val);
+  double res =
+      reinterpret_cast<IntegerToDoubleConversionCode>(test->entry())(val);
   EXPECT_FLOAT_EQ(static_cast<double>(val), res, 0.001);
 }
 
@@ -2146,19 +2161,19 @@
 }
 
 
-ASSEMBLER_TEST_RUN(FPUStoreLong, entry) {
+ASSEMBLER_TEST_RUN(FPUStoreLong, test) {
   typedef int64_t (*FPUStoreLongCode)(double d);
   double val = 12.2;
-  int64_t res = reinterpret_cast<FPUStoreLongCode>(entry)(val);
+  int64_t res = reinterpret_cast<FPUStoreLongCode>(test->entry())(val);
   EXPECT_EQ(static_cast<int64_t>(val), res);
   val = -12.2;
-  res = reinterpret_cast<FPUStoreLongCode>(entry)(val);
+  res = reinterpret_cast<FPUStoreLongCode>(test->entry())(val);
   EXPECT_EQ(static_cast<int64_t>(val), res);
   val = 12.8;
-  res = reinterpret_cast<FPUStoreLongCode>(entry)(val);
+  res = reinterpret_cast<FPUStoreLongCode>(test->entry())(val);
   EXPECT_EQ(static_cast<int64_t>(val), res);
   val = -12.8;
-  res = reinterpret_cast<FPUStoreLongCode>(entry)(val);
+  res = reinterpret_cast<FPUStoreLongCode>(test->entry())(val);
   EXPECT_EQ(static_cast<int64_t>(val), res);
 }
 
@@ -2176,9 +2191,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(XorpdZeroing, entry) {
+ASSEMBLER_TEST_RUN(XorpdZeroing, test) {
   typedef double (*XorpdZeroingCode)(double d);
-  double res = reinterpret_cast<XorpdZeroingCode>(entry)(12.56e3);
+  double res = reinterpret_cast<XorpdZeroingCode>(test->entry())(12.56e3);
   EXPECT_FLOAT_EQ(0.0, res, 0.0001);
 }
 
@@ -2196,9 +2211,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Pxor, entry) {
+ASSEMBLER_TEST_RUN(Pxor, test) {
   typedef double (*PxorCode)(double d);
-  double res = reinterpret_cast<PxorCode>(entry)(12.3456e3);
+  double res = reinterpret_cast<PxorCode>(test->entry())(12.3456e3);
   EXPECT_FLOAT_EQ(0.0, res, 0.0);
 }
 
@@ -2218,9 +2233,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Orpd, entry) {
+ASSEMBLER_TEST_RUN(Orpd, test) {
   typedef double (*OrpdCode)(double d);
-  double res = reinterpret_cast<OrpdCode>(entry)(12.56e3);
+  double res = reinterpret_cast<OrpdCode>(test->entry())(12.56e3);
   EXPECT_FLOAT_EQ(-12.56e3, res, 0.0);
 }
 
@@ -2234,10 +2249,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Pextrd0, entry) {
+ASSEMBLER_TEST_RUN(Pextrd0, test) {
   if (CPUFeatures::sse4_1_supported()) {
     typedef int32_t (*PextrdCode0)(double d);
-    int32_t res = reinterpret_cast<PextrdCode0>(entry)(123456789);
+    int32_t res = reinterpret_cast<PextrdCode0>(test->entry())(123456789);
     EXPECT_EQ(0x54000000, res);
   }
 }
@@ -2252,10 +2267,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Pextrd1, entry) {
+ASSEMBLER_TEST_RUN(Pextrd1, test) {
   if (CPUFeatures::sse4_1_supported()) {
     typedef int32_t (*PextrdCode1)(double d);
-    int32_t res = reinterpret_cast<PextrdCode1>(entry)(123456789);
+    int32_t res = reinterpret_cast<PextrdCode1>(test->entry())(123456789);
     EXPECT_EQ(0x419d6f34, res);
   }
 }
@@ -2271,10 +2286,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Pmovsxdq, entry) {
+ASSEMBLER_TEST_RUN(Pmovsxdq, test) {
   if (CPUFeatures::sse4_1_supported()) {
     typedef int32_t (*PmovsxdqCode)(double d);
-    int32_t res = reinterpret_cast<PmovsxdqCode>(entry)(123456789);
+    int32_t res = reinterpret_cast<PmovsxdqCode>(test->entry())(123456789);
     EXPECT_EQ(0, res);
   }
 }
@@ -2291,10 +2306,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Pcmpeqq, entry) {
+ASSEMBLER_TEST_RUN(Pcmpeqq, test) {
   if (CPUFeatures::sse4_1_supported()) {
     typedef int32_t (*PcmpeqqCode)(double d);
-    int32_t res = reinterpret_cast<PcmpeqqCode>(entry)(0);
+    int32_t res = reinterpret_cast<PcmpeqqCode>(test->entry())(0);
     EXPECT_EQ(-1, res);
   }
 }
@@ -2313,9 +2328,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(AndPd, entry) {
+ASSEMBLER_TEST_RUN(AndPd, test) {
   typedef double (*AndpdCode)(double d);
-  double res = reinterpret_cast<AndpdCode>(entry)(12.56e3);
+  double res = reinterpret_cast<AndpdCode>(test->entry())(12.56e3);
   EXPECT_FLOAT_EQ(12.56e3, res, 0.0);
 }
 
@@ -2330,9 +2345,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Movq, entry) {
+ASSEMBLER_TEST_RUN(Movq, test) {
   typedef double (*MovqCode)(double d);
-  double res = reinterpret_cast<MovqCode>(entry)(12.34e5);
+  double res = reinterpret_cast<MovqCode>(test->entry())(12.34e5);
   EXPECT_FLOAT_EQ(12.34e5, res, 0.0);
 }
 
@@ -2350,13 +2365,13 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleAbs, entry) {
+ASSEMBLER_TEST_RUN(DoubleAbs, test) {
   typedef double (*DoubleAbsCode)(double d);
   double val = -12.45;
-  double res =  reinterpret_cast<DoubleAbsCode>(entry)(val);
+  double res =  reinterpret_cast<DoubleAbsCode>(test->entry())(val);
   EXPECT_FLOAT_EQ(-val, res, 0.001);
   val = 12.45;
-  res =  reinterpret_cast<DoubleAbsCode>(entry)(val);
+  res =  reinterpret_cast<DoubleAbsCode>(test->entry())(val);
   EXPECT_FLOAT_EQ(val, res, 0.001);
 }
 
@@ -2369,13 +2384,13 @@
 }
 
 
-ASSEMBLER_TEST_RUN(ExtractSignBits, entry) {
+ASSEMBLER_TEST_RUN(ExtractSignBits, test) {
   typedef int (*ExtractSignBits)(double d);
-  int res = reinterpret_cast<ExtractSignBits>(entry)(1.0);
+  int res = reinterpret_cast<ExtractSignBits>(test->entry())(1.0);
   EXPECT_EQ(0, res);
-  res = reinterpret_cast<ExtractSignBits>(entry)(-1.0);
+  res = reinterpret_cast<ExtractSignBits>(test->entry())(-1.0);
   EXPECT_EQ(1, res);
-  res = reinterpret_cast<ExtractSignBits>(entry)(-0.0);
+  res = reinterpret_cast<ExtractSignBits>(test->entry())(-0.0);
   EXPECT_EQ(1, res);
 }
 
@@ -2400,11 +2415,11 @@
 }
 
 
-ASSEMBLER_TEST_RUN(ConditionalMovesSign, entry) {
+ASSEMBLER_TEST_RUN(ConditionalMovesSign, test) {
   typedef int (*ConditionalMovesSignCode)(int i);
-  int res = reinterpret_cast<ConditionalMovesSignCode>(entry)(785);
+  int res = reinterpret_cast<ConditionalMovesSignCode>(test->entry())(785);
   EXPECT_EQ(1, res);
-  res = reinterpret_cast<ConditionalMovesSignCode>(entry)(-12);
+  res = reinterpret_cast<ConditionalMovesSignCode>(test->entry())(-12);
   EXPECT_EQ(-1, res);
 }
 
@@ -2421,9 +2436,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestLoadDoubleConstant, entry) {
+ASSEMBLER_TEST_RUN(TestLoadDoubleConstant, test) {
   typedef double (*TestLoadDoubleConstantCode)();
-  double res = reinterpret_cast<TestLoadDoubleConstantCode>(entry)();
+  double res = reinterpret_cast<TestLoadDoubleConstantCode>(test->entry())();
   EXPECT_FLOAT_EQ(-12.34, res, 0.0001);
 }
 
@@ -2446,9 +2461,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestObjectCompare, entry) {
+ASSEMBLER_TEST_RUN(TestObjectCompare, test) {
   typedef bool (*TestObjectCompare)();
-  bool res = reinterpret_cast<TestObjectCompare>(entry)();
+  bool res = reinterpret_cast<TestObjectCompare>(test->entry())();
   EXPECT_EQ(true, res);
 }
 
@@ -2467,9 +2482,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestNop, entry) {
+ASSEMBLER_TEST_RUN(TestNop, test) {
   typedef int (*TestNop)();
-  int res = reinterpret_cast<TestNop>(entry)();
+  int res = reinterpret_cast<TestNop>(test->entry())();
   EXPECT_EQ(36, res);  // 36 nop bytes emitted.
 }
 
@@ -2481,9 +2496,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestAlign0, entry) {
+ASSEMBLER_TEST_RUN(TestAlign0, test) {
   typedef int (*TestAlign0)();
-  int res = reinterpret_cast<TestAlign0>(entry)();
+  int res = reinterpret_cast<TestAlign0>(test->entry())();
   EXPECT_EQ(0, res);  // 0 bytes emitted.
 }
 
@@ -2496,9 +2511,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestAlign1, entry) {
+ASSEMBLER_TEST_RUN(TestAlign1, test) {
   typedef int (*TestAlign1)();
-  int res = reinterpret_cast<TestAlign1>(entry)();
+  int res = reinterpret_cast<TestAlign1>(test->entry())();
   EXPECT_EQ(4, res);  // 4 bytes emitted.
 }
 
@@ -2511,9 +2526,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestAlign1Offset1, entry) {
+ASSEMBLER_TEST_RUN(TestAlign1Offset1, test) {
   typedef int (*TestAlign1Offset1)();
-  int res = reinterpret_cast<TestAlign1Offset1>(entry)();
+  int res = reinterpret_cast<TestAlign1Offset1>(test->entry())();
   EXPECT_EQ(3, res);  // 3 bytes emitted.
 }
 
@@ -2526,9 +2541,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestAlignLarge, entry) {
+ASSEMBLER_TEST_RUN(TestAlignLarge, test) {
   typedef int (*TestAlignLarge)();
-  int res = reinterpret_cast<TestAlignLarge>(entry)();
+  int res = reinterpret_cast<TestAlignLarge>(test->entry())();
   EXPECT_EQ(16, res);  // 16 bytes emitted.
 }
 
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 9ad8b88..1c72fd8 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -115,7 +115,11 @@
 
 class Assembler : public ValueObject {
  public:
-  Assembler() { UNIMPLEMENTED(); }
+  Assembler()
+      : buffer_(),
+        object_pool_(GrowableObjectArray::Handle()),
+        prologue_offset_(-1),
+        comments_() { }
   ~Assembler() { }
 
   void PopRegister(Register r) {
@@ -139,6 +143,10 @@
     UNIMPLEMENTED();
     return *pointer_offsets_;
   }
+  const GrowableObjectArray& object_pool() const {
+    UNIMPLEMENTED();
+    return object_pool_;
+  }
   void FinalizeInstructions(const MemoryRegion& region) {
     UNIMPLEMENTED();
   }
@@ -169,6 +177,7 @@
 
  private:
   AssemblerBuffer buffer_;
+  GrowableObjectArray& object_pool_;  // Objects and patchable jump targets.
   ZoneGrowableArray<int>* pointer_offsets_;
   int prologue_offset_;
 
diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc
index 8e263f5..dddd1f4 100644
--- a/runtime/vm/assembler_mips_test.cc
+++ b/runtime/vm/assembler_mips_test.cc
@@ -20,9 +20,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Simple, entry) {
+ASSEMBLER_TEST_RUN(Simple, test) {
   typedef int (*SimpleCode)();
-  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, entry));
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, test->entry()));
 }
 
 }  // namespace dart
diff --git a/runtime/vm/assembler_test.cc b/runtime/vm/assembler_test.cc
index 69228a1..8b1c602 100644
--- a/runtime/vm/assembler_test.cc
+++ b/runtime/vm/assembler_test.cc
@@ -14,11 +14,11 @@
 
 ASSEMBLER_TEST_EXTERN(StoreIntoObject);
 
-ASSEMBLER_TEST_RUN(StoreIntoObject, entry) {
+ASSEMBLER_TEST_RUN(StoreIntoObject, test) {
   typedef void (*StoreData)(RawContext* ctx,
                             RawObject* value,
                             RawObject* growable_array);
-  StoreData test_code = reinterpret_cast<StoreData>(entry);
+  StoreData test_code = reinterpret_cast<StoreData>(test->entry());
 
   const Array& old_array = Array::Handle(Array::New(3, Heap::kOld));
   const Array& new_array = Array::Handle(Array::New(3, Heap::kNew));
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 1bfabf2..64add15 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -312,7 +312,11 @@
 
 class Assembler : public ValueObject {
  public:
-  Assembler() : buffer_(), prologue_offset_(-1), comments_() { }
+  Assembler()
+      : buffer_(),
+        object_pool_(GrowableObjectArray::Handle()),
+        prologue_offset_(-1),
+        comments_() { }
   ~Assembler() { }
 
   static const bool kNearJump = true;
@@ -692,6 +696,7 @@
   const ZoneGrowableArray<int>& GetPointerOffsets() const {
     return buffer_.pointer_offsets();
   }
+  const GrowableObjectArray& object_pool() const { return object_pool_; }
 
   void FinalizeInstructions(const MemoryRegion& region) {
     buffer_.FinalizeInstructions(region);
@@ -711,6 +716,7 @@
 
  private:
   AssemblerBuffer buffer_;
+  GrowableObjectArray& object_pool_;  // Object pool is not used on x64.
   int prologue_offset_;
 
   class CodeComment : public ZoneAllocated {
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index 8e3f62a..b035b6e 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -23,9 +23,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(ReadArgument, entry) {
+ASSEMBLER_TEST_RUN(ReadArgument, test) {
   typedef int64_t (*ReadArgumentCode)(int64_t n);
-  ReadArgumentCode id = reinterpret_cast<ReadArgumentCode>(entry);
+  ReadArgumentCode id = reinterpret_cast<ReadArgumentCode>(test->entry());
   EXPECT_EQ(42, id(42));
   EXPECT_EQ(87, id(87));
   static const int64_t kLargeConstant = 0x1234567812345678LL;
@@ -203,7 +203,7 @@
 }
 
 
-ASSEMBLER_TEST_RUN(AddressingModes, entry) {
+ASSEMBLER_TEST_RUN(AddressingModes, test) {
   // Avoid running the code since it is constructed to lead to crashes.
 }
 
@@ -229,11 +229,11 @@
 }
 
 
-ASSEMBLER_TEST_RUN(JumpAroundCrash, entry) {
-  Instr* instr = Instr::At(entry);
+ASSEMBLER_TEST_RUN(JumpAroundCrash, test) {
+  Instr* instr = Instr::At(test->entry());
   EXPECT(!instr->IsBreakPoint());
   typedef void (*JumpAroundCrashCode)();
-  reinterpret_cast<JumpAroundCrashCode>(entry)();
+  reinterpret_cast<JumpAroundCrashCode>(test->entry())();
 }
 
 
@@ -250,9 +250,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SimpleLoop, entry) {
+ASSEMBLER_TEST_RUN(SimpleLoop, test) {
   typedef int (*SimpleLoopCode)();
-  EXPECT_EQ(2 * 87, reinterpret_cast<SimpleLoopCode>(entry)());
+  EXPECT_EQ(2 * 87, reinterpret_cast<SimpleLoopCode>(test->entry())());
 }
 
 
@@ -269,9 +269,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Increment, entry) {
+ASSEMBLER_TEST_RUN(Increment, test) {
   typedef int (*IncrementCode)();
-  EXPECT_EQ(3, reinterpret_cast<IncrementCode>(entry)());
+  EXPECT_EQ(3, reinterpret_cast<IncrementCode>(test->entry())());
 }
 
 
@@ -287,9 +287,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IncrementLong, entry) {
+ASSEMBLER_TEST_RUN(IncrementLong, test) {
   typedef int64_t (*IncrementCodeLong)();
-  EXPECT_EQ(0x100000001, reinterpret_cast<IncrementCodeLong>(entry)());
+  EXPECT_EQ(0x100000001, reinterpret_cast<IncrementCodeLong>(test->entry())());
 }
 
 
@@ -306,9 +306,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Decrement, entry) {
+ASSEMBLER_TEST_RUN(Decrement, test) {
   typedef int (*DecrementCode)();
-  EXPECT_EQ(0, reinterpret_cast<DecrementCode>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<DecrementCode>(test->entry())());
 }
 
 
@@ -324,9 +324,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DecrementLong, entry) {
+ASSEMBLER_TEST_RUN(DecrementLong, test) {
   typedef int64_t (*DecrementCodeLong)();
-  EXPECT_EQ(0xffffffff, reinterpret_cast<DecrementCodeLong>(entry)());
+  EXPECT_EQ(0xffffffff, reinterpret_cast<DecrementCodeLong>(test->entry())());
 }
 
 
@@ -339,9 +339,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SignedMultiply, entry) {
+ASSEMBLER_TEST_RUN(SignedMultiply, test) {
   typedef int (*SignedMultiply)();
-  EXPECT_EQ(8000, reinterpret_cast<SignedMultiply>(entry)());
+  EXPECT_EQ(8000, reinterpret_cast<SignedMultiply>(test->entry())());
 }
 
 
@@ -371,9 +371,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SignedMultiply64, entry) {
+ASSEMBLER_TEST_RUN(SignedMultiply64, test) {
   typedef int64_t (*SignedMultiply64)();
-  EXPECT_EQ(32, reinterpret_cast<SignedMultiply64>(entry)());
+  EXPECT_EQ(32, reinterpret_cast<SignedMultiply64>(test->entry())());
 }
 
 
@@ -396,10 +396,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SignedMultiplyLong, entry) {
+ASSEMBLER_TEST_RUN(SignedMultiplyLong, test) {
   typedef int64_t (*SignedMultiplyLong)();
   EXPECT_EQ(kProductLargeConstants,
-            reinterpret_cast<SignedMultiplyLong>(entry)());
+            reinterpret_cast<SignedMultiplyLong>(test->entry())());
 }
 
 
@@ -413,9 +413,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(OverflowSignedMultiply, entry) {
+ASSEMBLER_TEST_RUN(OverflowSignedMultiply, test) {
   typedef int (*OverflowSignedMultiply)();
-  EXPECT_EQ(0, reinterpret_cast<OverflowSignedMultiply>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<OverflowSignedMultiply>(test->entry())());
 }
 
 
@@ -429,9 +429,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SignedMultiply1, entry) {
+ASSEMBLER_TEST_RUN(SignedMultiply1, test) {
   typedef int (*SignedMultiply1)();
-  EXPECT_EQ(8000, reinterpret_cast<SignedMultiply1>(entry)());
+  EXPECT_EQ(8000, reinterpret_cast<SignedMultiply1>(test->entry())());
 }
 
 
@@ -445,9 +445,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SignedMultiply2, entry) {
+ASSEMBLER_TEST_RUN(SignedMultiply2, test) {
   typedef int (*SignedMultiply2)();
-  EXPECT_EQ(2000, reinterpret_cast<SignedMultiply2>(entry)());
+  EXPECT_EQ(2000, reinterpret_cast<SignedMultiply2>(test->entry())());
 }
 
 
@@ -461,9 +461,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SignedDivide, entry) {
+ASSEMBLER_TEST_RUN(SignedDivide, test) {
   typedef int32_t (*SignedDivide)();
-  EXPECT_EQ(-87 / 42, reinterpret_cast<SignedDivide>(entry)());
+  EXPECT_EQ(-87 / 42, reinterpret_cast<SignedDivide>(test->entry())());
 }
 
 
@@ -477,9 +477,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SignedDivideLong, entry) {
+ASSEMBLER_TEST_RUN(SignedDivideLong, test) {
   typedef int64_t (*SignedDivideLong)();
-  EXPECT_EQ(kLargeConstant / 42, reinterpret_cast<SignedDivideLong>(entry)());
+  EXPECT_EQ(kLargeConstant / 42,
+            reinterpret_cast<SignedDivideLong>(test->entry())());
 }
 
 
@@ -491,9 +492,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Negate, entry) {
+ASSEMBLER_TEST_RUN(Negate, test) {
   typedef int (*Negate)();
-  EXPECT_EQ(-42, reinterpret_cast<Negate>(entry)());
+  EXPECT_EQ(-42, reinterpret_cast<Negate>(test->entry())());
 }
 
 
@@ -508,9 +509,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(MoveExtend, entry) {
+ASSEMBLER_TEST_RUN(MoveExtend, test) {
   typedef int (*MoveExtend)();
-  EXPECT_EQ(0xff - 1 + 0xffff, reinterpret_cast<MoveExtend>(entry)());
+  EXPECT_EQ(0xff - 1 + 0xffff, reinterpret_cast<MoveExtend>(test->entry())());
 }
 
 
@@ -529,9 +530,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(MoveExtendMemory, entry) {
+ASSEMBLER_TEST_RUN(MoveExtendMemory, test) {
   typedef int (*MoveExtendMemory)();
-  EXPECT_EQ(0xff - 1 + 0xffff, reinterpret_cast<MoveExtendMemory>(entry)());
+  EXPECT_EQ(0xff - 1 + 0xffff,
+            reinterpret_cast<MoveExtendMemory>(test->entry())());
 }
 
 
@@ -547,9 +549,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(MoveWord, entry) {
+ASSEMBLER_TEST_RUN(MoveWord, test) {
   typedef int (*MoveWord)();
-  EXPECT_EQ(0xffff, reinterpret_cast<MoveWord>(entry)());
+  EXPECT_EQ(0xffff, reinterpret_cast<MoveWord>(test->entry())());
 }
 
 
@@ -566,9 +568,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(MoveWordRex, entry) {
+ASSEMBLER_TEST_RUN(MoveWordRex, test) {
   typedef int (*MoveWordRex)();
-  EXPECT_EQ(0xffff, reinterpret_cast<MoveWordRex>(entry)());
+  EXPECT_EQ(0xffff, reinterpret_cast<MoveWordRex>(test->entry())());
 }
 
 
@@ -587,9 +589,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Bitwise, entry) {
+ASSEMBLER_TEST_RUN(Bitwise, test) {
   typedef int (*Bitwise)();
-  EXPECT_EQ(256 + 1, reinterpret_cast<Bitwise>(entry)());
+  EXPECT_EQ(256 + 1, reinterpret_cast<Bitwise>(test->entry())());
 }
 
 
@@ -631,9 +633,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Bitwise64, entry) {
+ASSEMBLER_TEST_RUN(Bitwise64, test) {
   typedef int (*Bitwise64)();
-  EXPECT_EQ(256 + 1, reinterpret_cast<Bitwise64>(entry)());
+  EXPECT_EQ(256 + 1, reinterpret_cast<Bitwise64>(test->entry())());
 }
 
 
@@ -833,9 +835,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LogicalOps, entry) {
+ASSEMBLER_TEST_RUN(LogicalOps, test) {
   typedef int (*LogicalOpsCode)();
-  EXPECT_EQ(0, reinterpret_cast<LogicalOpsCode>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<LogicalOpsCode>(test->entry())());
 }
 
 
@@ -1023,9 +1025,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LogicalOps64, entry) {
+ASSEMBLER_TEST_RUN(LogicalOps64, test) {
   typedef int (*LogicalOpsCode)();
-  EXPECT_EQ(0, reinterpret_cast<LogicalOpsCode>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<LogicalOpsCode>(test->entry())());
 }
 
 
@@ -1073,9 +1075,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LogicalTestL, entry) {
+ASSEMBLER_TEST_RUN(LogicalTestL, test) {
   typedef int (*LogicalTestCode)();
-  EXPECT_EQ(0, reinterpret_cast<LogicalTestCode>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<LogicalTestCode>(test->entry())());
 }
 
 
@@ -1141,9 +1143,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LogicalTestQ, entry) {
+ASSEMBLER_TEST_RUN(LogicalTestQ, test) {
   typedef int (*LogicalTestCode)();
-  EXPECT_EQ(0, reinterpret_cast<LogicalTestCode>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<LogicalTestCode>(test->entry())());
 }
 
 
@@ -1159,9 +1161,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(CompareSwapEQ, entry) {
+ASSEMBLER_TEST_RUN(CompareSwapEQ, test) {
   typedef int (*CompareSwapEQCode)();
-  EXPECT_EQ(0, reinterpret_cast<CompareSwapEQCode>(entry)());
+  EXPECT_EQ(0, reinterpret_cast<CompareSwapEQCode>(test->entry())());
 }
 
 
@@ -1177,9 +1179,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(CompareSwapNEQ, entry) {
+ASSEMBLER_TEST_RUN(CompareSwapNEQ, test) {
   typedef int (*CompareSwapNEQCode)();
-  EXPECT_EQ(4, reinterpret_cast<CompareSwapNEQCode>(entry)());
+  EXPECT_EQ(4, reinterpret_cast<CompareSwapNEQCode>(test->entry())());
 }
 
 
@@ -1192,10 +1194,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Exchange, entry) {
+ASSEMBLER_TEST_RUN(Exchange, test) {
   typedef int64_t (*Exchange)();
   EXPECT_EQ(kAnotherLargeConstant - kLargeConstant,
-            reinterpret_cast<Exchange>(entry)());
+            reinterpret_cast<Exchange>(test->entry())());
 }
 
 
@@ -1205,9 +1207,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(LargeConstant, entry) {
+ASSEMBLER_TEST_RUN(LargeConstant, test) {
   typedef int64_t (*LargeConstantCode)();
-  EXPECT_EQ(kLargeConstant, reinterpret_cast<LargeConstantCode>(entry)());
+  EXPECT_EQ(kLargeConstant,
+            reinterpret_cast<LargeConstantCode>(test->entry())());
 }
 
 
@@ -1246,9 +1249,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(CallSimpleLeaf, entry) {
+ASSEMBLER_TEST_RUN(CallSimpleLeaf, test) {
   typedef int (*CallSimpleLeafCode)();
-  EXPECT_EQ(42 + 87, reinterpret_cast<CallSimpleLeafCode>(entry)());
+  EXPECT_EQ(42 + 87, reinterpret_cast<CallSimpleLeafCode>(test->entry())());
 }
 
 
@@ -1265,9 +1268,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(JumpSimpleLeaf, entry) {
+ASSEMBLER_TEST_RUN(JumpSimpleLeaf, test) {
   typedef int (*JumpSimpleLeafCode)();
-  EXPECT_EQ(42, reinterpret_cast<JumpSimpleLeafCode>(entry)());
+  EXPECT_EQ(42, reinterpret_cast<JumpSimpleLeafCode>(test->entry())());
 }
 
 
@@ -1326,9 +1329,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SingleFPMoves, entry) {
+ASSEMBLER_TEST_RUN(SingleFPMoves, test) {
   typedef float (*SingleFPMovesCode)();
-  EXPECT_EQ(234, reinterpret_cast<SingleFPMovesCode>(entry)());
+  EXPECT_EQ(234, reinterpret_cast<SingleFPMovesCode>(test->entry())());
 }
 
 
@@ -1352,9 +1355,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SingleFPMoves2, entry) {
+ASSEMBLER_TEST_RUN(SingleFPMoves2, test) {
   typedef float (*SingleFPMoves2Code)();
-  EXPECT_EQ(234, reinterpret_cast<SingleFPMoves2Code>(entry)());
+  EXPECT_EQ(234, reinterpret_cast<SingleFPMoves2Code>(test->entry())());
 }
 
 
@@ -1382,9 +1385,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SingleFPOperations, entry) {
+ASSEMBLER_TEST_RUN(SingleFPOperations, test) {
   typedef float (*SingleFPOperationsCode)();
-  float res = reinterpret_cast<SingleFPOperationsCode>(entry)();
+  float res = reinterpret_cast<SingleFPOperationsCode>(test->entry())();
   EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
 }
 
@@ -1405,9 +1408,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedFPOperations, entry) {
+ASSEMBLER_TEST_RUN(PackedFPOperations, test) {
   typedef float (*PackedFPOperationsCode)();
-  float res = reinterpret_cast<PackedFPOperationsCode>(entry)();
+  float res = reinterpret_cast<PackedFPOperationsCode>(test->entry())();
   EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
 }
 
@@ -1427,9 +1430,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedFPOperations2, entry) {
+ASSEMBLER_TEST_RUN(PackedFPOperations2, test) {
   typedef float (*PackedFPOperations2Code)();
-  float res = reinterpret_cast<PackedFPOperations2Code>(entry)();
+  float res = reinterpret_cast<PackedFPOperations2Code>(test->entry())();
   EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
 }
 
@@ -1445,9 +1448,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareEQ, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareEQ, test) {
   typedef uint32_t (*PackedCompareEQCode)();
-  uint32_t res = reinterpret_cast<PackedCompareEQCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareEQCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0x0), res);
 }
 
@@ -1463,9 +1466,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareNEQ, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareNEQ, test) {
   typedef uint32_t (*PackedCompareNEQCode)();
-  uint32_t res = reinterpret_cast<PackedCompareNEQCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareNEQCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
 }
 
@@ -1481,9 +1484,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareLT, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareLT, test) {
   typedef uint32_t (*PackedCompareLTCode)();
-  uint32_t res = reinterpret_cast<PackedCompareLTCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareLTCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
 }
 
@@ -1499,9 +1502,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareLE, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareLE, test) {
   typedef uint32_t (*PackedCompareLECode)();
-  uint32_t res = reinterpret_cast<PackedCompareLECode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareLECode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
 }
 
@@ -1517,9 +1520,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareNLT, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareNLT, test) {
   typedef uint32_t (*PackedCompareNLTCode)();
-  uint32_t res = reinterpret_cast<PackedCompareNLTCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareNLTCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0x0), res);
 }
 
@@ -1535,9 +1538,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedCompareNLE, entry) {
+ASSEMBLER_TEST_RUN(PackedCompareNLE, test) {
   typedef uint32_t (*PackedCompareNLECode)();
-  uint32_t res = reinterpret_cast<PackedCompareNLECode>(entry)();
+  uint32_t res = reinterpret_cast<PackedCompareNLECode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0x0), res);
 }
 
@@ -1552,9 +1555,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedNegate, entry) {
+ASSEMBLER_TEST_RUN(PackedNegate, test) {
   typedef float (*PackedNegateCode)();
-  float res = reinterpret_cast<PackedNegateCode>(entry)();
+  float res = reinterpret_cast<PackedNegateCode>(test->entry())();
   EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
 }
 
@@ -1569,9 +1572,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedAbsolute, entry) {
+ASSEMBLER_TEST_RUN(PackedAbsolute, test) {
   typedef float (*PackedAbsoluteCode)();
-  float res = reinterpret_cast<PackedAbsoluteCode>(entry)();
+  float res = reinterpret_cast<PackedAbsoluteCode>(test->entry())();
   EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
 }
 
@@ -1584,9 +1587,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedSetWZero, entry) {
+ASSEMBLER_TEST_RUN(PackedSetWZero, test) {
   typedef float (*PackedSetWZeroCode)();
-  float res = reinterpret_cast<PackedSetWZeroCode>(entry)();
+  float res = reinterpret_cast<PackedSetWZeroCode>(test->entry())();
   EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
 }
 
@@ -1599,9 +1602,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedMin, entry) {
+ASSEMBLER_TEST_RUN(PackedMin, test) {
   typedef float (*PackedMinCode)();
-  float res = reinterpret_cast<PackedMinCode>(entry)();
+  float res = reinterpret_cast<PackedMinCode>(test->entry())();
   EXPECT_FLOAT_EQ(2.0f, res, 0.001f);
 }
 
@@ -1614,9 +1617,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedMax, entry) {
+ASSEMBLER_TEST_RUN(PackedMax, test) {
   typedef float (*PackedMaxCode)();
-  float res = reinterpret_cast<PackedMaxCode>(entry)();
+  float res = reinterpret_cast<PackedMaxCode>(test->entry())();
   EXPECT_FLOAT_EQ(4.0f, res, 0.001f);
 }
 
@@ -1648,9 +1651,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedLogicalOr, entry) {
+ASSEMBLER_TEST_RUN(PackedLogicalOr, test) {
   typedef uint32_t (*PackedLogicalOrCode)();
-  uint32_t res = reinterpret_cast<PackedLogicalOrCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedLogicalOrCode>(test->entry())();
   EXPECT_EQ(0xFFFFFFFF, res);
 }
 
@@ -1681,9 +1684,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedLogicalAnd, entry) {
+ASSEMBLER_TEST_RUN(PackedLogicalAnd, test) {
   typedef uint32_t (*PackedLogicalAndCode)();
-  uint32_t res = reinterpret_cast<PackedLogicalAndCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedLogicalAndCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0x0000F000), res);
 }
 
@@ -1707,9 +1710,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(PackedLogicalNot, entry) {
+ASSEMBLER_TEST_RUN(PackedLogicalNot, test) {
   typedef uint32_t (*PackedLogicalNotCode)();
-  uint32_t res = reinterpret_cast<PackedLogicalNotCode>(entry)();
+  uint32_t res = reinterpret_cast<PackedLogicalNotCode>(test->entry())();
   EXPECT_EQ(static_cast<uword>(0x0), res);
 }
 
@@ -1768,9 +1771,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleFPMoves, entry) {
+ASSEMBLER_TEST_RUN(DoubleFPMoves, test) {
   typedef double (*DoubleFPMovesCode)();
-  EXPECT_FLOAT_EQ(1024.67, reinterpret_cast<DoubleFPMovesCode>(entry)(), 0.001);
+  EXPECT_FLOAT_EQ(1024.67,
+                  reinterpret_cast<DoubleFPMovesCode>(test->entry())(), 0.001);
 }
 
 
@@ -1799,9 +1803,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleFPOperations, entry) {
+ASSEMBLER_TEST_RUN(DoubleFPOperations, test) {
   typedef double (*SingleFPOperationsCode)();
-  double res = reinterpret_cast<SingleFPOperationsCode>(entry)();
+  double res = reinterpret_cast<SingleFPOperationsCode>(test->entry())();
   EXPECT_FLOAT_EQ(7.668, res, 0.001);
 }
 
@@ -1816,9 +1820,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Int32ToDoubleConversion, entry) {
+ASSEMBLER_TEST_RUN(Int32ToDoubleConversion, test) {
   typedef double (*IntToDoubleConversionCode)();
-  double res = reinterpret_cast<IntToDoubleConversionCode>(entry)();
+  double res = reinterpret_cast<IntToDoubleConversionCode>(test->entry())();
   EXPECT_FLOAT_EQ(-2.0, res, 0.001);
 }
 
@@ -1833,9 +1837,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Int64ToDoubleConversion, entry) {
+ASSEMBLER_TEST_RUN(Int64ToDoubleConversion, test) {
   typedef double (*Int64ToDoubleConversionCode)();
-  double res = reinterpret_cast<Int64ToDoubleConversionCode>(entry)();
+  double res = reinterpret_cast<Int64ToDoubleConversionCode>(test->entry())();
   EXPECT_FLOAT_EQ(static_cast<double>(12LL << 32), res, 0.001);
 }
 
@@ -1856,9 +1860,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleToInt64Conversion, entry) {
+ASSEMBLER_TEST_RUN(DoubleToInt64Conversion, test) {
   typedef int64_t (*DoubleToInt64ConversionCode)();
-  int64_t res = reinterpret_cast<DoubleToInt64ConversionCode>(entry)();
+  int64_t res = reinterpret_cast<DoubleToInt64ConversionCode>(test->entry())();
   EXPECT_EQ(0, res);
 }
 
@@ -1895,9 +1899,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestObjectCompare, entry) {
+ASSEMBLER_TEST_RUN(TestObjectCompare, test) {
   typedef bool (*TestObjectCompare)();
-  bool res = reinterpret_cast<TestObjectCompare>(entry)();
+  bool res = reinterpret_cast<TestObjectCompare>(test->entry())();
   EXPECT_EQ(true, res);
 }
 
@@ -1916,9 +1920,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestNop, entry) {
+ASSEMBLER_TEST_RUN(TestNop, test) {
   typedef int (*TestNop)();
-  int res = reinterpret_cast<TestNop>(entry)();
+  int res = reinterpret_cast<TestNop>(test->entry())();
   EXPECT_EQ(36, res);  // 36 nop bytes emitted.
 }
 
@@ -1930,9 +1934,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestAlign0, entry) {
+ASSEMBLER_TEST_RUN(TestAlign0, test) {
   typedef int (*TestAlign0)();
-  int res = reinterpret_cast<TestAlign0>(entry)();
+  int res = reinterpret_cast<TestAlign0>(test->entry())();
   EXPECT_EQ(0, res);  // 0 bytes emitted.
 }
 
@@ -1945,9 +1949,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestAlign1, entry) {
+ASSEMBLER_TEST_RUN(TestAlign1, test) {
   typedef int (*TestAlign1)();
-  int res = reinterpret_cast<TestAlign1>(entry)();
+  int res = reinterpret_cast<TestAlign1>(test->entry())();
   EXPECT_EQ(4, res);  // 4 bytes emitted.
 }
 
@@ -1960,9 +1964,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestAlign1Offset1, entry) {
+ASSEMBLER_TEST_RUN(TestAlign1Offset1, test) {
   typedef int (*TestAlign1Offset1)();
-  int res = reinterpret_cast<TestAlign1Offset1>(entry)();
+  int res = reinterpret_cast<TestAlign1Offset1>(test->entry())();
   EXPECT_EQ(3, res);  // 3 bytes emitted.
 }
 
@@ -1975,9 +1979,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestAlignLarge, entry) {
+ASSEMBLER_TEST_RUN(TestAlignLarge, test) {
   typedef int (*TestAlignLarge)();
-  int res = reinterpret_cast<TestAlignLarge>(entry)();
+  int res = reinterpret_cast<TestAlignLarge>(test->entry())();
   EXPECT_EQ(16, res);  // 16 bytes emitted.
 }
 
@@ -2000,9 +2004,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestAdds, entry) {
+ASSEMBLER_TEST_RUN(TestAdds, test) {
   typedef int (*TestAdds)();
-  int res = reinterpret_cast<TestAdds>(entry)();
+  int res = reinterpret_cast<TestAdds>(test->entry())();
   EXPECT_EQ(20, res);
 }
 
@@ -2014,9 +2018,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(TestNot, entry) {
+ASSEMBLER_TEST_RUN(TestNot, test) {
   typedef int (*TestNot)();
-  unsigned int res = reinterpret_cast<TestNot>(entry)();
+  unsigned int res = reinterpret_cast<TestNot>(test->entry())();
   EXPECT_EQ(0xFFFFFFFF, res);
 }
 
@@ -2030,9 +2034,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(XorpdZeroing, entry) {
+ASSEMBLER_TEST_RUN(XorpdZeroing, test) {
   typedef double (*XorpdZeroingCode)(double d);
-  double res = reinterpret_cast<XorpdZeroingCode>(entry)(12.56e3);
+  double res = reinterpret_cast<XorpdZeroingCode>(test->entry())(12.56e3);
   EXPECT_FLOAT_EQ(0.0, res, 0.0001);
 }
 
@@ -2050,9 +2054,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(XorpdZeroing2, entry) {
+ASSEMBLER_TEST_RUN(XorpdZeroing2, test) {
   typedef double (*XorpdZeroing2Code)(double d);
-  double res = reinterpret_cast<XorpdZeroing2Code>(entry)(12.56e3);
+  double res = reinterpret_cast<XorpdZeroing2Code>(test->entry())(12.56e3);
   EXPECT_FLOAT_EQ(0.0, res, 0.0001);
 }
 
@@ -2063,9 +2067,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Pxor, entry) {
+ASSEMBLER_TEST_RUN(Pxor, test) {
   typedef double (*PxorCode)(double d);
-  double res = reinterpret_cast<PxorCode>(entry)(12.3456e3);
+  double res = reinterpret_cast<PxorCode>(test->entry())(12.3456e3);
   EXPECT_FLOAT_EQ(0.0, res, 0.0);
 }
 
@@ -2076,10 +2080,11 @@
 }
 
 
-ASSEMBLER_TEST_RUN(SquareRootDouble, entry) {
+ASSEMBLER_TEST_RUN(SquareRootDouble, test) {
   typedef double (*SquareRootDoubleCode)(double d);
   const double kDoubleConst = .7;
-  double res = reinterpret_cast<SquareRootDoubleCode>(entry)(kDoubleConst);
+  double res =
+      reinterpret_cast<SquareRootDoubleCode>(test->entry())(kDoubleConst);
   EXPECT_FLOAT_EQ(sqrt(kDoubleConst), res, 0.0001);
 }
 
@@ -2108,9 +2113,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleFPUStackMoves, entry) {
+ASSEMBLER_TEST_RUN(DoubleFPUStackMoves, test) {
   typedef int64_t (*DoubleFPUStackMovesCode)();
-  int64_t res = reinterpret_cast<DoubleFPUStackMovesCode>(entry)();
+  int64_t res = reinterpret_cast<DoubleFPUStackMovesCode>(test->entry())();
   EXPECT_FLOAT_EQ(1024.67, (bit_cast<double, int64_t>(res)), 0.001);
 }
 
@@ -2127,10 +2132,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Sine, entry) {
+ASSEMBLER_TEST_RUN(Sine, test) {
   typedef double (*SineCode)(double d);
   const double kDoubleConst = 0.7;
-  double res = reinterpret_cast<SineCode>(entry)(kDoubleConst);
+  double res = reinterpret_cast<SineCode>(test->entry())(kDoubleConst);
   EXPECT_FLOAT_EQ(sin(kDoubleConst), res, 0.0001);
 }
 
@@ -2147,10 +2152,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Cosine, entry) {
+ASSEMBLER_TEST_RUN(Cosine, test) {
   typedef double (*CosineCode)(double f);
   const double kDoubleConst = 0.7;
-  double res = reinterpret_cast<CosineCode>(entry)(kDoubleConst);
+  double res = reinterpret_cast<CosineCode>(test->entry())(kDoubleConst);
   EXPECT_FLOAT_EQ(cos(kDoubleConst), res, 0.0001);
 }
 
@@ -2162,9 +2167,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IntToDoubleConversion, entry) {
+ASSEMBLER_TEST_RUN(IntToDoubleConversion, test) {
   typedef double (*IntToDoubleConversionCode)();
-  double res = reinterpret_cast<IntToDoubleConversionCode>(entry)();
+  double res = reinterpret_cast<IntToDoubleConversionCode>(test->entry())();
   EXPECT_FLOAT_EQ(6.0, res, 0.001);
 }
 
@@ -2179,9 +2184,9 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IntToDoubleConversion2, entry) {
+ASSEMBLER_TEST_RUN(IntToDoubleConversion2, test) {
   typedef double (*IntToDoubleConversion2Code)(int i);
-  double res = reinterpret_cast<IntToDoubleConversion2Code>(entry)(3);
+  double res = reinterpret_cast<IntToDoubleConversion2Code>(test->entry())(3);
   EXPECT_FLOAT_EQ(3.0, res, 0.001);
 }
 
@@ -2191,15 +2196,15 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleToDoubleTrunc, entry) {
+ASSEMBLER_TEST_RUN(DoubleToDoubleTrunc, test) {
   typedef double (*DoubleToDoubleTruncCode)(double d);
-  double res = reinterpret_cast<DoubleToDoubleTruncCode>(entry)(12.3);
+  double res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(12.3);
   EXPECT_EQ(12.0, res);
-  res = reinterpret_cast<DoubleToDoubleTruncCode>(entry)(12.8);
+  res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(12.8);
   EXPECT_EQ(12.0, res);
-  res = reinterpret_cast<DoubleToDoubleTruncCode>(entry)(-12.3);
+  res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(-12.3);
   EXPECT_EQ(-12.0, res);
-  res = reinterpret_cast<DoubleToDoubleTruncCode>(entry)(-12.8);
+  res = reinterpret_cast<DoubleToDoubleTruncCode>(test->entry())(-12.8);
   EXPECT_EQ(-12.0, res);
 }
 
@@ -2210,13 +2215,13 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleAbs, entry) {
+ASSEMBLER_TEST_RUN(DoubleAbs, test) {
   typedef double (*DoubleAbsCode)(double d);
   double val = -12.45;
-  double res =  reinterpret_cast<DoubleAbsCode>(entry)(val);
+  double res =  reinterpret_cast<DoubleAbsCode>(test->entry())(val);
   EXPECT_FLOAT_EQ(-val, res, 0.001);
   val = 12.45;
-  res =  reinterpret_cast<DoubleAbsCode>(entry)(val);
+  res =  reinterpret_cast<DoubleAbsCode>(test->entry())(val);
   EXPECT_FLOAT_EQ(val, res, 0.001);
 }
 
@@ -2227,27 +2232,31 @@
 }
 
 
-ASSEMBLER_TEST_RUN(DoubleToDoubleRound, entry) {
+ASSEMBLER_TEST_RUN(DoubleToDoubleRound, test) {
   typedef double (*DoubleToDoubleRoundCode)(double d);
-  double res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(12.3);
+  double res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(12.3);
   EXPECT_EQ(12.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(12.8);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(12.8);
   EXPECT_EQ(13.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(0.5);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(0.5);
   EXPECT_EQ(1.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(-12.3);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(-12.3);
   EXPECT_EQ(-12.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(-12.8);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(-12.8);
   EXPECT_EQ(-13.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(-0.5);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(test->entry())(-0.5);
   EXPECT_EQ(-1.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(0.49999999999999994);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(
+      test->entry())(0.49999999999999994);
   EXPECT_EQ(0.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(-0.49999999999999994);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(
+      test->entry())(-0.49999999999999994);
   EXPECT_EQ(-0.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(9007199254740991.0);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(
+      test->entry())(9007199254740991.0);
   EXPECT_EQ(9007199254740991.0, res);
-  res = reinterpret_cast<DoubleToDoubleRoundCode>(entry)(-9007199254740991.0);
+  res = reinterpret_cast<DoubleToDoubleRoundCode>(
+      test->entry())(-9007199254740991.0);
   EXPECT_EQ(-9007199254740991.0, res);
 }
 
@@ -2259,13 +2268,13 @@
 }
 
 
-ASSEMBLER_TEST_RUN(ExtractSignBits, entry) {
+ASSEMBLER_TEST_RUN(ExtractSignBits, test) {
   typedef int (*ExtractSignBits)(double d);
-  int res = reinterpret_cast<ExtractSignBits>(entry)(1.0);
+  int res = reinterpret_cast<ExtractSignBits>(test->entry())(1.0);
   EXPECT_EQ(0, res);
-  res = reinterpret_cast<ExtractSignBits>(entry)(-1.0);
+  res = reinterpret_cast<ExtractSignBits>(test->entry())(-1.0);
   EXPECT_EQ(1, res);
-  res = reinterpret_cast<ExtractSignBits>(entry)(-0.0);
+  res = reinterpret_cast<ExtractSignBits>(test->entry())(-0.0);
   EXPECT_EQ(1, res);
 }
 
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 27f949b..1b1d8d0 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -56,9 +56,9 @@
 }
 
 
-RawScript* Bootstrap::LoadMathScript(bool patch) {
-  const char* url = patch ? "dart:math-patch" : "dart:math";
-  const char* source = patch ? math_patch_ : math_source_;
+RawScript* Bootstrap::LoadCryptoScript(bool patch) {
+  const char* url = patch ? "dart:crypto-patch" : "dart:crypto";
+  const char* source = patch ? crypto_source_ : crypto_source_;
   return LoadScript(url, source, patch);
 }
 
@@ -70,6 +70,20 @@
 }
 
 
+RawScript* Bootstrap::LoadJsonScript(bool patch) {
+  const char* url = patch ? "dart:json-patch" : "dart:json";
+  const char* source = patch ? json_source_ : json_source_;
+  return LoadScript(url, source, patch);
+}
+
+
+RawScript* Bootstrap::LoadMathScript(bool patch) {
+  const char* url = patch ? "dart:math-patch" : "dart:math";
+  const char* source = patch ? math_patch_ : math_source_;
+  return LoadScript(url, source, patch);
+}
+
+
 RawScript* Bootstrap::LoadMirrorsScript(bool patch)  {
   const char* url = patch ? "dart:mirrors-patch" : "dart:mirrors";
   const char* source = patch ? mirrors_patch_ : mirrors_source_;
@@ -84,6 +98,20 @@
 }
 
 
+RawScript* Bootstrap::LoadUriScript(bool patch) {
+  const char* url = patch ? "dart:uri-patch" : "dart:uri";
+  const char* source = patch ? uri_source_ : uri_source_;
+  return LoadScript(url, source, patch);
+}
+
+
+RawScript* Bootstrap::LoadUtfScript(bool patch) {
+  const char* url = patch ? "dart:utf-patch" : "dart:utf";
+  const char* source = patch ? utf_source_ : utf_source_;
+  return LoadScript(url, source, patch);
+}
+
+
 RawError* Bootstrap::Compile(const Library& library, const Script& script) {
   if (FLAG_print_bootstrap) {
     OS::Print("Bootstrap source '%s':\n%s\n",
diff --git a/runtime/vm/bootstrap.h b/runtime/vm/bootstrap.h
index 4c01cca..275c27d 100644
--- a/runtime/vm/bootstrap.h
+++ b/runtime/vm/bootstrap.h
@@ -21,10 +21,14 @@
   static RawScript* LoadCoreScript(bool patch);
   static RawScript* LoadCollectionScript(bool patch);
   static RawScript* LoadCollectionDevScript(bool patch);
-  static RawScript* LoadMathScript(bool patch);
+  static RawScript* LoadCryptoScript(bool patch);
   static RawScript* LoadIsolateScript(bool patch);
+  static RawScript* LoadJsonScript(bool patch);
+  static RawScript* LoadMathScript(bool patch);
   static RawScript* LoadMirrorsScript(bool patch);
   static RawScript* LoadScalarlistScript(bool patch);
+  static RawScript* LoadUriScript(bool patch);
+  static RawScript* LoadUtfScript(bool patch);
   static RawError* Compile(const Library& library, const Script& script);
   static void SetupNativeResolver();
 
@@ -37,14 +41,18 @@
   static const char corelib_patch_[];
   static const char collection_source_[];
   static const char collection_dev_source_[];
-  static const char math_source_[];
-  static const char math_patch_[];
+  static const char crypto_source_[];
   static const char isolate_source_[];
   static const char isolate_patch_[];
+  static const char json_source_[];
+  static const char math_source_[];
+  static const char math_patch_[];
   static const char mirrors_source_[];
   static const char mirrors_patch_[];
   static const char scalarlist_source_[];
   static const char scalarlist_patch_[];
+  static const char uri_source_[];
+  static const char utf_source_[];
 };
 
 }  // namespace dart
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index bcff2ab..dd21318 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -14,7 +14,7 @@
 // List of bootstrap native entry points used in the core dart library.
 #define BOOTSTRAP_NATIVE_LIST(V)                                               \
   V(Object_toString, 1)                                                        \
-  V(Object_noSuchMethod, 5)                                                    \
+  V(Object_noSuchMethod, 6)                                                    \
   V(Object_runtimeType, 1)                                                     \
   V(Object_instanceOf, 5)                                                      \
   V(Function_apply, 2)                                                         \
diff --git a/runtime/vm/bootstrap_nocorelib.cc b/runtime/vm/bootstrap_nocorelib.cc
index 7093777..d838fc2 100644
--- a/runtime/vm/bootstrap_nocorelib.cc
+++ b/runtime/vm/bootstrap_nocorelib.cc
@@ -39,7 +39,7 @@
 }
 
 
-RawScript* Bootstrap::LoadMathScript(bool is_patch) {
+RawScript* Bootstrap::LoadCryptoScript(bool is_patch) {
   UNREACHABLE();
   return Script::null();
 }
@@ -51,6 +51,18 @@
 }
 
 
+RawScript* Bootstrap::LoadJsonScript(bool is_patch) {
+  UNREACHABLE();
+  return Script::null();
+}
+
+
+RawScript* Bootstrap::LoadMathScript(bool is_patch) {
+  UNREACHABLE();
+  return Script::null();
+}
+
+
 RawScript* Bootstrap::LoadMirrorsScript(bool is_patch) {
   UNREACHABLE();
   return Script::null();
@@ -63,6 +75,18 @@
 }
 
 
+RawScript* Bootstrap::LoadUriScript(bool is_patch) {
+  UNREACHABLE();
+  return Script::null();
+}
+
+
+RawScript* Bootstrap::LoadUtfScript(bool is_patch) {
+  UNREACHABLE();
+  return Script::null();
+}
+
+
 RawError* Bootstrap::Compile(const Library& library, const Script& script) {
   UNREACHABLE();
   return Error::null();
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 08ff160..75e1a03 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -762,8 +762,9 @@
   // Before patching verify that we are not repeatedly patching to the same
   // target.
   ASSERT(target_code.EntryPoint() !=
-         CodePatcher::GetStaticCallTargetAt(caller_frame->pc()));
-  CodePatcher::PatchStaticCallAt(caller_frame->pc(), target_code.EntryPoint());
+         CodePatcher::GetStaticCallTargetAt(caller_frame->pc(), caller_code));
+  CodePatcher::PatchStaticCallAt(caller_frame->pc(), caller_code,
+                                 target_code.EntryPoint());
   caller_code.SetStaticCallTargetCodeAt(caller_frame->pc(), target_code);
   if (FLAG_trace_patching) {
     OS::PrintErr("PatchStaticCall: patching from %#"Px" to '%s' %#"Px"\n",
@@ -1356,7 +1357,8 @@
   const Function& target_function = Function::Handle(
       caller_code.GetStaticCallTargetFunctionAt(frame->pc()));
   const Code& target_code = Code::Handle(target_function.CurrentCode());
-  CodePatcher::PatchStaticCallAt(frame->pc(), target_code.EntryPoint());
+  CodePatcher::PatchStaticCallAt(frame->pc(), caller_code,
+                                 target_code.EntryPoint());
   caller_code.SetStaticCallTargetCodeAt(frame->pc(), target_code);
   if (FLAG_trace_patching) {
     OS::PrintErr("FixCallersTarget: patching from %#"Px" to '%s' %#"Px"\n",
diff --git a/runtime/vm/code_patcher.h b/runtime/vm/code_patcher.h
index ce9945f..ddf5c73 100644
--- a/runtime/vm/code_patcher.h
+++ b/runtime/vm/code_patcher.h
@@ -24,11 +24,15 @@
  public:
   // Dart static calls have a distinct, machine-dependent code pattern.
 
-  // Patch static call to the new target.
-  static void PatchStaticCallAt(uword addr, uword new_target_address);
+  // Patch static call before return_address in given code to the new target.
+  static void PatchStaticCallAt(uword return_address,
+                                const Code& code,
+                                uword new_target_address);
 
-  // Patch instance call to the new target.
-  static void PatchInstanceCallAt(uword addr, uword new_target_address);
+  // Patch instance call before return_address in given code to the new target.
+  static void PatchInstanceCallAt(uword return_address,
+                                  const Code& code,
+                                  uword new_target_address);
 
   // Patch entry point with a jump as specified in the code's patch region.
   static void PatchEntry(const Code& code);
@@ -40,16 +44,15 @@
   // that there are no conflicts with object pointers). Used in ASSERTs.
   static bool CodeIsPatchable(const Code& code);
 
-  // Returns true if the code before return_address is a static
-  // or dynamic Dart call.
-  static bool IsDartCall(uword return_address);
-
-  static uword GetStaticCallTargetAt(uword return_address);
+  // Return the target address of the static call before return_address
+  // in given code.
+  static uword GetStaticCallTargetAt(uword return_address, const Code& code);
 
   // Get instance call information.  Returns the call target and sets each
   // of the output parameters ic_data and arguments_descriptor if they are
   // non-NULL.
   static uword GetInstanceCallAt(uword return_address,
+                                 const Code& code,
                                  ICData* ic_data,
                                  Array* arguments_descriptor);
 
diff --git a/runtime/vm/code_patcher_arm.cc b/runtime/vm/code_patcher_arm.cc
index 1297273..90582f8 100644
--- a/runtime/vm/code_patcher_arm.cc
+++ b/runtime/vm/code_patcher_arm.cc
@@ -7,20 +7,30 @@
 
 #include "vm/code_patcher.h"
 
+#include "vm/object.h"
+
 namespace dart {
 
-uword CodePatcher::GetStaticCallTargetAt(uword return_address) {
+uword CodePatcher::GetStaticCallTargetAt(uword return_address,
+                                         const Code& code) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   UNIMPLEMENTED();
   return 0;
 }
 
 
-void CodePatcher::PatchStaticCallAt(uword return_address, uword new_target) {
+void CodePatcher::PatchStaticCallAt(uword return_address,
+                                    const Code& code,
+                                    uword new_target) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   UNIMPLEMENTED();
 }
 
 
-void CodePatcher::PatchInstanceCallAt(uword return_address, uword new_target) {
+void CodePatcher::PatchInstanceCallAt(uword return_address,
+                                      const Code& code,
+                                      uword new_target) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   UNIMPLEMENTED();
 }
 
@@ -30,15 +40,11 @@
 }
 
 
-bool CodePatcher::IsDartCall(uword return_address) {
-  UNIMPLEMENTED();
-  return false;
-}
-
-
 uword CodePatcher::GetInstanceCallAt(uword return_address,
+                                     const Code& code,
                                      ICData* ic_data,
                                      Array* arguments_descriptor) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   UNIMPLEMENTED();
   return 0;
 }
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index fc73e85..5b9d1fb 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -49,10 +49,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IcDataAccess, entry) {
-  uword return_address = entry + CodePatcher::InstanceCallSizeInBytes();
+ASSEMBLER_TEST_RUN(IcDataAccess, test) {
+  uword return_address = test->entry() + CodePatcher::InstanceCallSizeInBytes();
   ICData& ic_data = ICData::Handle();
-  CodePatcher::GetInstanceCallAt(return_address, &ic_data, NULL);
+  CodePatcher::GetInstanceCallAt(return_address, test->code(), &ic_data, NULL);
   EXPECT_STREQ("targetFunction",
       String::Handle(ic_data.target_name()).ToCString());
   EXPECT_EQ(1, ic_data.num_args_tested());
diff --git a/runtime/vm/code_patcher_ia32.cc b/runtime/vm/code_patcher_ia32.cc
index 1209cbe..cd21ef2 100644
--- a/runtime/vm/code_patcher_ia32.cc
+++ b/runtime/vm/code_patcher_ia32.cc
@@ -142,19 +142,27 @@
 };
 
 
-uword CodePatcher::GetStaticCallTargetAt(uword return_address) {
+uword CodePatcher::GetStaticCallTargetAt(uword return_address,
+                                         const Code& code) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   StaticCall call(return_address);
   return call.target();
 }
 
 
-void CodePatcher::PatchStaticCallAt(uword return_address, uword new_target) {
+void CodePatcher::PatchStaticCallAt(uword return_address,
+                                    const Code& code,
+                                    uword new_target) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   StaticCall call(return_address);
   call.set_target(new_target);
 }
 
 
-void CodePatcher::PatchInstanceCallAt(uword return_address, uword new_target) {
+void CodePatcher::PatchInstanceCallAt(uword return_address,
+                                      const Code& code,
+                                      uword new_target) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   InstanceCall call(return_address);
   call.set_target(new_target);
 }
@@ -169,14 +177,11 @@
 }
 
 
-bool CodePatcher::IsDartCall(uword return_address) {
-  return DartCallPattern::IsValid(return_address);
-}
-
-
 uword CodePatcher::GetInstanceCallAt(uword return_address,
+                                     const Code& code,
                                      ICData* ic_data,
                                      Array* arguments_descriptor) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   InstanceCall call(return_address);
   if (ic_data != NULL) {
     *ic_data ^= call.ic_data();
diff --git a/runtime/vm/code_patcher_ia32_test.cc b/runtime/vm/code_patcher_ia32_test.cc
index 9845ab0..2bb6601 100644
--- a/runtime/vm/code_patcher_ia32_test.cc
+++ b/runtime/vm/code_patcher_ia32_test.cc
@@ -70,10 +70,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IcDataAccess, entry) {
-  uword return_address = entry + CodePatcher::InstanceCallSizeInBytes();
+ASSEMBLER_TEST_RUN(IcDataAccess, test) {
+  uword return_address = test->entry() + CodePatcher::InstanceCallSizeInBytes();
   ICData& ic_data = ICData::Handle();
-  CodePatcher::GetInstanceCallAt(return_address, &ic_data, NULL);
+  CodePatcher::GetInstanceCallAt(return_address, test->code(), &ic_data, NULL);
   EXPECT_STREQ("targetFunction",
       String::Handle(ic_data.target_name()).ToCString());
   EXPECT_EQ(1, ic_data.num_args_tested());
diff --git a/runtime/vm/code_patcher_mips.cc b/runtime/vm/code_patcher_mips.cc
index 987589d..a7ed7e0 100644
--- a/runtime/vm/code_patcher_mips.cc
+++ b/runtime/vm/code_patcher_mips.cc
@@ -7,20 +7,30 @@
 
 #include "vm/code_patcher.h"
 
+#include "vm/object.h"
+
 namespace dart {
 
-uword CodePatcher::GetStaticCallTargetAt(uword return_address) {
+uword CodePatcher::GetStaticCallTargetAt(uword return_address,
+                                         const Code& code) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   UNIMPLEMENTED();
   return 0;
 }
 
 
-void CodePatcher::PatchStaticCallAt(uword return_address, uword new_target) {
+void CodePatcher::PatchStaticCallAt(uword return_address,
+                                    const Code& code,
+                                    uword new_target) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   UNIMPLEMENTED();
 }
 
 
-void CodePatcher::PatchInstanceCallAt(uword return_address, uword new_target) {
+void CodePatcher::PatchInstanceCallAt(uword return_address,
+                                      const Code& code,
+                                      uword new_target) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   UNIMPLEMENTED();
 }
 
@@ -30,15 +40,11 @@
 }
 
 
-bool CodePatcher::IsDartCall(uword return_address) {
-  UNIMPLEMENTED();
-  return false;
-}
-
-
 uword CodePatcher::GetInstanceCallAt(uword return_address,
+                                     const Code& code,
                                      ICData* ic_data,
                                      Array* arguments_descriptor) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   UNIMPLEMENTED();
   return 0;
 }
diff --git a/runtime/vm/code_patcher_mips_test.cc b/runtime/vm/code_patcher_mips_test.cc
index 91cf209..79c9b63 100644
--- a/runtime/vm/code_patcher_mips_test.cc
+++ b/runtime/vm/code_patcher_mips_test.cc
@@ -49,10 +49,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IcDataAccess, entry) {
-  uword return_address = entry + CodePatcher::InstanceCallSizeInBytes();
+ASSEMBLER_TEST_RUN(IcDataAccess, test) {
+  uword return_address = test->entry() + CodePatcher::InstanceCallSizeInBytes();
   ICData& ic_data = ICData::Handle();
-  CodePatcher::GetInstanceCallAt(return_address, &ic_data, NULL);
+  CodePatcher::GetInstanceCallAt(return_address, test->code(), &ic_data, NULL);
   EXPECT_STREQ("targetFunction",
       String::Handle(ic_data.target_name()).ToCString());
   EXPECT_EQ(1, ic_data.num_args_tested());
diff --git a/runtime/vm/code_patcher_x64.cc b/runtime/vm/code_patcher_x64.cc
index ab3312e..5be92be 100644
--- a/runtime/vm/code_patcher_x64.cc
+++ b/runtime/vm/code_patcher_x64.cc
@@ -126,32 +126,37 @@
 };
 
 
-uword CodePatcher::GetStaticCallTargetAt(uword return_address) {
+uword CodePatcher::GetStaticCallTargetAt(uword return_address,
+                                         const Code& code) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   StaticCall call(return_address);
   return call.target();
 }
 
 
-void CodePatcher::PatchStaticCallAt(uword return_address, uword new_target) {
+void CodePatcher::PatchStaticCallAt(uword return_address,
+                                    const Code& code,
+                                    uword new_target) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   StaticCall call(return_address);
   call.set_target(new_target);
 }
 
 
-void CodePatcher::PatchInstanceCallAt(uword return_address, uword new_target) {
+void CodePatcher::PatchInstanceCallAt(uword return_address,
+                                      const Code& code,
+                                      uword new_target) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   InstanceCall call(return_address);
   call.set_target(new_target);
 }
 
 
-bool CodePatcher::IsDartCall(uword return_address) {
-  return DartCallPattern::IsValid(return_address);
-}
-
-
 uword CodePatcher::GetInstanceCallAt(uword return_address,
+                                     const Code& code,
                                      ICData* ic_data,
                                      Array* arguments_descriptor) {
+  ASSERT(code.ContainsInstructionAt(return_address));
   InstanceCall call(return_address);
   if (ic_data != NULL) {
     *ic_data ^= call.ic_data();
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index eef51c7..61807b3 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -70,10 +70,10 @@
 }
 
 
-ASSEMBLER_TEST_RUN(IcDataAccess, entry) {
-  uword return_address = entry + CodePatcher::InstanceCallSizeInBytes();
+ASSEMBLER_TEST_RUN(IcDataAccess, test) {
+  uword return_address = test->entry() + CodePatcher::InstanceCallSizeInBytes();
   ICData& ic_data = ICData::Handle();
-  CodePatcher::GetInstanceCallAt(return_address, &ic_data, NULL);
+  CodePatcher::GetInstanceCallAt(return_address, test->code(), &ic_data, NULL);
   EXPECT_STREQ("targetFunction",
       String::Handle(ic_data.target_name()).ToCString());
   EXPECT_EQ(1, ic_data.num_args_tested());
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 2efb71d..149691b 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -54,7 +54,6 @@
 DECLARE_FLAG(bool, print_flow_graph);
 DECLARE_FLAG(bool, print_flow_graph_optimized);
 DECLARE_FLAG(bool, trace_failed_optimization_attempts);
-DECLARE_FLAG(bool, trace_type_propagation);
 
 // Compile a function. Should call only if the function has not been compiled.
 //   Arg0: function object.
@@ -160,6 +159,7 @@
                        isolate);
       // Transform to SSA (virtual register 0 and no inlining arguments).
       flow_graph->ComputeSSA(0, NULL);
+      DEBUG_ASSERT(flow_graph->VerifyUseLists());
     }
 
     if (FLAG_print_flow_graph ||
@@ -174,13 +174,15 @@
                        &CompilerStats::graphoptimizer_timer,
                        isolate);
 
-      flow_graph->ComputeUseLists();
-
       FlowGraphOptimizer optimizer(flow_graph);
       optimizer.ApplyICData();
+      DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
-      // Compute the use lists.
-      flow_graph->ComputeUseLists();
+      // Optimize (a << b) & c patterns. Must occur before
+      // 'SelectRepresentations' which inserts conversion nodes.
+      // TODO(srdjan): Moved before inlining until environment use list can
+      // be used to detect when shift-left is outside the scope of bit-and.
+      optimizer.TryOptimizeLeftShiftWithBitAndPattern();
 
       // Inlining (mutates the flow graph)
       if (FLAG_use_inlining) {
@@ -189,64 +191,53 @@
         FlowGraphInliner inliner(flow_graph);
         inliner.Inline();
         // Use lists are maintained and validated by the inliner.
-      }
-
-      if (FLAG_trace_type_propagation) {
-        OS::Print("Before type propagation:\n");
-        FlowGraphPrinter printer(*flow_graph);
-        printer.PrintBlocks();
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
       }
 
       // Propagate types and eliminate more type tests.
       if (FLAG_propagate_types) {
         FlowGraphTypePropagator propagator(flow_graph);
         propagator.Propagate();
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
       }
 
-      if (FLAG_trace_type_propagation) {
-        OS::Print("After type propagation:\n");
-        FlowGraphPrinter printer(*flow_graph);
-        printer.PrintBlocks();
-      }
-
-      flow_graph->ComputeUseLists();
-
       // Use propagated class-ids to optimize further.
       optimizer.ApplyClassIds();
-
-      // Recompute use lists after applying class ids.
-      flow_graph->ComputeUseLists();
+      DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
       // Do optimizations that depend on the propagated type information.
       optimizer.Canonicalize();
-
-      flow_graph->ComputeUseLists();
+      DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
       if (FLAG_constant_propagation) {
         ConstantPropagator::Optimize(flow_graph);
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
         // A canonicalization pass to remove e.g. smi checks on smi constants.
         optimizer.Canonicalize();
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
       }
 
       // Unbox doubles. Performed after constant propagation to minimize
       // interference from phis merging double values and tagged
       // values comming from dead paths.
-      flow_graph->ComputeUseLists();
       optimizer.SelectRepresentations();
-      flow_graph->ComputeUseLists();
+      DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
       if (FLAG_common_subexpression_elimination) {
         if (DominatorBasedCSE::Optimize(flow_graph)) {
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
           // Do another round of CSE to take secondary effects into account:
           // e.g. when eliminating dependent loads (a.x[0] + a.x[0])
           // TODO(fschneider): Change to a one-pass optimization pass.
           DominatorBasedCSE::Optimize(flow_graph);
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
         }
       }
       if (FLAG_loop_invariant_code_motion &&
           (parsed_function.function().deoptimization_counter() <
            (FLAG_deoptimization_counter_threshold - 1))) {
         LICM::Optimize(flow_graph);
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
       }
 
       if (FLAG_range_analysis) {
@@ -254,10 +245,12 @@
         // optimistically moves CheckSmi through phis into loop preheaders
         // making some phis smi.
         optimizer.InferSmiRanges();
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
       }
 
       // The final canonicalization pass before the code generation.
       optimizer.Canonicalize();
+      DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
       // Perform register allocation on the SSA graph.
       FlowGraphAllocator allocator(*flow_graph);
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 747b9a8..1ba6550 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -134,7 +134,7 @@
 // Register aliases.
 const Register TMP = kNoRegister;  // No scratch register used by assembler.
 const Register CTX = R9;  // Caches current context in generated code.
-const Register CP = R10;  // Caches constant pool base in generated code.
+const Register PP = R10;  // Caches object pool pointer in generated code.
 const Register SPREG = SP;
 const Register FPREG = FP;
 
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 1c90a7c..f4a9fa8 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -2060,7 +2060,85 @@
 }
 
 
-// TODO(hpayer): value should always be smaller then 0xff. Add error handling.
+static RawObject* ResolveConstructor(const char* current_func,
+                                     const Class& cls,
+                                     const String& class_name,
+                                     const String& dotted_name,
+                                     int num_args);
+
+
+static RawObject* ThrowArgumentError(const char* exception_message) {
+  Isolate* isolate = Isolate::Current();
+  // Lookup the class ArgumentError in dart:core.
+  const String& lib_url = String::Handle(String::New("dart:core"));
+  const String& class_name =
+      String::Handle(String::New("ArgumentError"));
+  const Library& lib =
+      Library::Handle(isolate, Library::LookupLibrary(lib_url));
+  if (lib.IsNull()) {
+    const String& message = String::Handle(
+        String::NewFormatted("%s: library '%s' not found.",
+                             CURRENT_FUNC, lib_url.ToCString()));
+    return ApiError::New(message);
+  }
+  const Class& cls = Class::Handle(isolate,
+                                   lib.LookupClassAllowPrivate(class_name));
+  if (cls.IsNull()) {
+    const String& message = String::Handle(
+        String::NewFormatted("%s: class '%s' not found in library '%s'.",
+                             CURRENT_FUNC, class_name.ToCString(),
+                             lib_url.ToCString()));
+    return ApiError::New(message);
+  }
+  String& dot_name = String::Handle(String::New("."));
+  Object& result = Object::Handle(isolate);
+  result = ResolveConstructor(CURRENT_FUNC, cls, class_name, dot_name, 1);
+  if (result.IsError()) return result.raw();
+  ASSERT(result.IsFunction());
+  Function& constructor = Function::Handle(isolate);
+  constructor ^= result.raw();
+  if (!constructor.IsConstructor()) {
+    const String& message = String::Handle(
+        String::NewFormatted("%s: class '%s' is not a constructor.",
+                             CURRENT_FUNC, class_name.ToCString()));
+    return ApiError::New(message);
+  }
+  Instance& exception = Instance::Handle(isolate);
+  exception = Instance::New(cls);
+  const Array& args = Array::Handle(isolate, Array::New(3));
+  args.SetAt(0, exception);
+  args.SetAt(1,
+             Smi::Handle(isolate, Smi::New(Function::kCtorPhaseAll)));
+  args.SetAt(2, String::Handle(String::New(exception_message)));
+  result = DartEntry::InvokeStatic(constructor, args);
+  if (result.IsError()) return result.raw();
+  ASSERT(result.IsNull());
+
+  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.
+    const String& message = String::Handle(
+            String::New("No Dart frames on stack, cannot throw exception"));
+    return ApiError::New(message);
+  }
+  // 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 = exception.raw();
+    state->UnwindScopes(isolate->top_exit_frame_info());
+    saved_exception = &Instance::Handle(raw_exception);
+  }
+  Exceptions::Throw(*saved_exception);
+  const String& message = String::Handle(
+          String::New("Exception was not thrown, internal error"));
+  return ApiError::New(message);
+}
+
+// TODO(sgjesse): value should always be smaller then 0xff. Add error handling.
 #define GET_LIST_ELEMENT_AS_BYTES(isolate, type, obj, native_array, offset,    \
                                   length)                                      \
   const type& array = type::Cast(obj);                                         \
@@ -2069,8 +2147,9 @@
     for (int i = 0; i < length; i++) {                                         \
       element = array.At(offset + i);                                          \
       if (!element.IsInteger()) {                                              \
-        return Api::NewError("%s expects the argument 'list' to be "           \
-                             "a List of int", CURRENT_FUNC);                   \
+        return Api::NewHandle(                                                 \
+            isolate, ThrowArgumentError("List contains non-int elements"));    \
+                                                                               \
       }                                                                        \
       const Integer& integer = Integer::Cast(element);                         \
       native_array[i] = static_cast<uint8_t>(integer.AsInt64Value() & 0xff);   \
@@ -2240,30 +2319,147 @@
 }
 
 
-// --- Byte Arrays ---
+// --- Typed Data ---
 
 
-DART_EXPORT bool Dart_IsByteArray(Dart_Handle object) {
-  return RawObject::IsByteArrayClassId(Api::ClassId(object));
+// Helper method to get the type of a TypedData object.
+static Dart_TypedData_Type GetType(intptr_t class_id) {
+  Dart_TypedData_Type type;
+  switch (class_id) {
+    case kByteArrayCid :
+      type = kByteData;
+      break;
+    case kInt8ArrayCid :
+    case kExternalInt8ArrayCid :
+      type = kInt8;
+      break;
+    case kUint8ArrayCid :
+    case kExternalUint8ArrayCid :
+      type = kUint8;
+      break;
+    case kUint8ClampedArrayCid :
+    case kExternalUint8ClampedArrayCid :
+      type = kUint8Clamped;
+      break;
+    case kInt16ArrayCid :
+    case kExternalInt16ArrayCid :
+      type = kInt16;
+      break;
+    case kUint16ArrayCid :
+    case kExternalUint16ArrayCid :
+      type = kUint16;
+      break;
+    case kInt32ArrayCid :
+    case kExternalInt32ArrayCid :
+      type = kInt32;
+      break;
+    case kUint32ArrayCid :
+    case kExternalUint32ArrayCid :
+      type = kUint32;
+      break;
+    case kInt64ArrayCid :
+    case kExternalInt64ArrayCid :
+      type = kInt64;
+      break;
+    case kUint64ArrayCid :
+    case kExternalUint64ArrayCid :
+      type = kUint64;
+      break;
+    case kFloat32ArrayCid :
+    case kExternalFloat32ArrayCid :
+      type = kFloat32;
+      break;
+    case kFloat64ArrayCid :
+    case kExternalFloat64ArrayCid :
+      type = kFloat64;
+      break;
+    default:
+      type = kInvalid;
+      break;
+  }
+  return type;
 }
 
 
-DART_EXPORT bool Dart_IsByteArrayExternal(Dart_Handle object) {
-  return RawObject::IsExternalByteArrayClassId(Api::ClassId(object));
+DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object) {
+  intptr_t class_id = Api::ClassId(object);
+  return GetType(class_id);
 }
 
 
-DART_EXPORT Dart_Handle Dart_NewByteArray(intptr_t length) {
+DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfExternalTypedData(
+    Dart_Handle object) {
+  intptr_t class_id = Api::ClassId(object);
+  if (!RawObject::IsExternalByteArrayClassId(class_id)) {
+    return kInvalid;
+  }
+  return GetType(class_id);
+}
+
+
+template<typename type>
+static Dart_Handle NewTypedData(Isolate* isolate, intptr_t length) {
+  CHECK_LENGTH(length, type::kMaxElements);
+  return Api::NewHandle(isolate, type::New(length));
+}
+
+
+template<typename type, typename datatype>
+static Dart_Handle NewExternalTypedData(
+    void* data,
+    intptr_t length,
+    void* peer,
+    Dart_WeakPersistentHandleFinalizer callback) {
+  CHECK_LENGTH(length, type::kMaxElements);
+  const type& obj =
+      type::Handle(type::New(reinterpret_cast<datatype*>(data), length));
+  return reinterpret_cast<Dart_Handle>(obj.AddFinalizer(peer, callback));
+}
+
+
+DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type,
+                                          intptr_t length) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
-  CHECK_LENGTH(length, Uint8Array::kMaxElements);
   CHECK_CALLBACK_STATE(isolate);
-  return Api::NewHandle(isolate, Uint8Array::New(length));
+  switch (type) {
+    case kByteData :
+      // TODO(asiva): Add a new ByteArray::New() method.
+      break;
+    case kInt8 :
+      return NewTypedData<Int8Array>(isolate, length);
+    case kUint8 :
+      return NewTypedData<Uint8Array>(isolate, length);
+    case kUint8Clamped :
+      return NewTypedData<Uint8ClampedArray>(isolate, length);
+    case kInt16 :
+      return NewTypedData<Int16Array>(isolate, length);
+    case kUint16 :
+      return NewTypedData<Uint16Array>(isolate, length);
+    case kInt32 :
+      return NewTypedData<Int32Array>(isolate, length);
+    case kUint32 :
+      return NewTypedData<Uint32Array>(isolate, length);
+    case kInt64 :
+      return NewTypedData<Int64Array>(isolate, length);
+    case kUint64 :
+      return NewTypedData<Uint64Array>(isolate, length);
+    case kFloat32 :
+      return NewTypedData<Float32Array>(isolate, length);
+    case kFloat64 :
+      return NewTypedData<Float64Array>(isolate, length);
+    default:
+      return Api::NewError("%s expects argument 'type' to be of 'TypedData'",
+                           CURRENT_FUNC);
+  }
+  UNREACHABLE();
+  return Api::Null(isolate);
 }
 
 
-DART_EXPORT Dart_Handle Dart_NewExternalByteArray(
-    uint8_t* data,
+DART_EXPORT Dart_Handle Dart_NewExternalTypedData(
+    Dart_TypedData_Type type,
+    void* data,
     intptr_t length,
     void* peer,
     Dart_WeakPersistentHandleFinalizer callback) {
@@ -2272,57 +2468,83 @@
   if (data == NULL && length != 0) {
     RETURN_NULL_ERROR(data);
   }
-  CHECK_LENGTH(length, ExternalUint8Array::kMaxElements);
   CHECK_CALLBACK_STATE(isolate);
-  const ExternalUint8Array& obj = ExternalUint8Array::Handle(
-      ExternalUint8Array::New(data, length));
-  return reinterpret_cast<Dart_Handle>(obj.AddFinalizer(peer, callback));
+  switch (type) {
+    case kByteData :
+      // TODO(asiva): Allocate external ByteData object.
+      break;
+    case kInt8 :
+      return NewExternalTypedData<ExternalInt8Array, int8_t>(data,
+                                                             length,
+                                                             peer,
+                                                             callback);
+    case kUint8 :
+      return NewExternalTypedData<ExternalUint8Array, uint8_t>(data,
+                                                               length,
+                                                               peer,
+                                                               callback);
+    case kUint8Clamped :
+      return NewExternalTypedData<ExternalUint8ClampedArray, uint8_t>(data,
+                                                                      length,
+                                                                      peer,
+                                                                      callback);
+    case kInt16 :
+      return NewExternalTypedData<ExternalInt16Array, int16_t>(data,
+                                                               length,
+                                                               peer,
+                                                               callback);
+    case kUint16 :
+      return NewExternalTypedData<ExternalUint16Array, uint16_t>(data,
+                                                                 length,
+                                                                 peer,
+                                                                 callback);
+    case kInt32 :
+      return NewExternalTypedData<ExternalInt32Array, int32_t>(data,
+                                                               length,
+                                                               peer,
+                                                               callback);
+    case kUint32 :
+      return NewExternalTypedData<ExternalUint32Array, uint32_t>(data,
+                                                                 length,
+                                                                 peer,
+                                                                 callback);
+    case kInt64 :
+      return NewExternalTypedData<ExternalInt64Array, int64_t>(data,
+                                                               length,
+                                                               peer,
+                                                               callback);
+    case kUint64 :
+      return NewExternalTypedData<ExternalUint64Array, uint64_t>(data,
+                                                                 length,
+                                                                 peer,
+                                                                 callback);
+    case kFloat32 :
+      return NewExternalTypedData<ExternalFloat32Array, float>(data,
+                                                               length,
+                                                               peer,
+                                                               callback);
+    case kFloat64 :
+      return NewExternalTypedData<ExternalFloat64Array, double>(data,
+                                                                length,
+                                                                peer,
+                                                                callback);
+    default:
+      return Api::NewError("%s expects argument 'type' to be of"
+                           " 'external TypedData'", CURRENT_FUNC);
+  }
+  UNREACHABLE();
+  return Api::Null(isolate);
 }
 
 
-DART_EXPORT Dart_Handle Dart_NewExternalClampedByteArray(
-    uint8_t* data,
-    intptr_t length,
-    void* peer,
-    Dart_WeakPersistentHandleFinalizer callback) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (data == NULL && length != 0) {
-    RETURN_NULL_ERROR(data);
-  }
-  CHECK_LENGTH(length, ExternalUint8ClampedArray::kMaxElements);
-  CHECK_CALLBACK_STATE(isolate);
-  const ExternalUint8ClampedArray& obj = ExternalUint8ClampedArray::Handle(
-      ExternalUint8ClampedArray::New(data, length));
-  return reinterpret_cast<Dart_Handle>(obj.AddFinalizer(peer, callback));
-}
-
-
-DART_EXPORT Dart_Handle Dart_ExternalByteArrayGetData(Dart_Handle object,
-                                                      void** data) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const ExternalUint8Array& array =
-      Api::UnwrapExternalUint8ArrayHandle(isolate, object);
-  if (array.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, object, ExternalUint8Array);
-  }
-  if (data == NULL) {
-    RETURN_NULL_ERROR(data);
-  }
-  *data = array.GetData();
-  return Api::Success(isolate);
-}
-
-
-DART_EXPORT Dart_Handle Dart_ExternalByteArrayGetPeer(Dart_Handle object,
+DART_EXPORT Dart_Handle Dart_ExternalTypedDataGetPeer(Dart_Handle object,
                                                       void** peer) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
-  const ExternalUint8Array& array =
-      Api::UnwrapExternalUint8ArrayHandle(isolate, object);
+  const ByteArray& array =
+      Api::UnwrapByteArrayHandle(isolate, object);
   if (array.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, object, ExternalUint8Array);
+    RETURN_TYPE_ERROR(isolate, object, ByteArray);
   }
   if (peer == NULL) {
     RETURN_NULL_ERROR(peer);
@@ -2332,15 +2554,15 @@
 }
 
 
-DART_EXPORT Dart_Handle Dart_ScalarListAcquireData(Dart_Handle array,
-                                                   Dart_Scalar_Type* type,
-                                                   void** data,
-                                                   intptr_t* len) {
+DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object,
+                                                  Dart_TypedData_Type* type,
+                                                  void** data,
+                                                  intptr_t* len) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
-  intptr_t class_id = Api::ClassId(array);
+  intptr_t class_id = Api::ClassId(object);
   if (!RawObject::IsByteArrayClassId(class_id)) {
-    RETURN_TYPE_ERROR(isolate, array, 'scalar list');
+    RETURN_TYPE_ERROR(isolate, object, 'TypedData');
   }
   if (type == NULL) {
     RETURN_NULL_ERROR(type);
@@ -2351,64 +2573,16 @@
   if (len == NULL) {
     RETURN_NULL_ERROR(len);
   }
-  // Get the type of typed array.
-  switch (class_id) {
-    case kByteArrayCid :
-      *type = kByteArray;
-      break;
-    case kInt8ArrayCid :
-    case kExternalInt8ArrayCid :
-      *type = kInt8;
-      break;
-    case kUint8ArrayCid :
-    case kExternalUint8ArrayCid :
-      *type = kUint8;
-      break;
-    case kUint8ClampedArrayCid :
-    case kExternalUint8ClampedArrayCid :
-      *type = kUint8Clamped;
-      break;
-    case kInt16ArrayCid :
-    case kExternalInt16ArrayCid :
-      *type = kInt16;
-      break;
-    case kUint16ArrayCid :
-    case kExternalUint16ArrayCid :
-      *type = kUint16;
-      break;
-    case kInt32ArrayCid :
-    case kExternalInt32ArrayCid :
-      *type = kInt32;
-      break;
-    case kUint32ArrayCid :
-    case kExternalUint32ArrayCid :
-      *type = kUint32;
-      break;
-    case kInt64ArrayCid :
-    case kExternalInt64ArrayCid :
-      *type = kInt64;
-      break;
-    case kUint64ArrayCid :
-    case kExternalUint64ArrayCid :
-      *type = kUint64;
-      break;
-    case kFloat32ArrayCid :
-    case kExternalFloat32ArrayCid :
-      *type = kFloat32;
-      break;
-    case kFloat64ArrayCid :
-    case kExternalFloat64ArrayCid :
-      *type = kFloat64;
-      break;
-  }
-  const ByteArray& obj = Api::UnwrapByteArrayHandle(isolate, array);
+  // Get the type of typed data object.
+  *type = GetType(class_id);
+  const ByteArray& obj = Api::UnwrapByteArrayHandle(isolate, object);
   ASSERT(!obj.IsNull());
   *len = obj.Length();
-  // If it is an external typed array object just return the data field.
+  // If it is an external typed data object just return the data field.
   if (RawObject::IsExternalByteArrayClassId(class_id)) {
     *data = reinterpret_cast<void*>(obj.ByteAddr(0));
   } else {
-    // Regular typed array object, set up some GC and API callback guards.
+    // Regular typed data object, set up some GC and API callback guards.
     isolate->IncrementNoGCScopeDepth();
     START_NO_CALLBACK_SCOPE(isolate);
     *data = reinterpret_cast<void*>(obj.ByteAddr(0));
@@ -2417,12 +2591,12 @@
 }
 
 
-DART_EXPORT Dart_Handle Dart_ScalarListReleaseData(Dart_Handle array) {
+DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
-  intptr_t class_id = Api::ClassId(array);
+  intptr_t class_id = Api::ClassId(object);
   if (!RawObject::IsByteArrayClassId(class_id)) {
-    RETURN_TYPE_ERROR(isolate, array, 'scalar list');
+    RETURN_TYPE_ERROR(isolate, object, 'TypedData');
   }
   if (!RawObject::IsExternalByteArrayClassId(class_id)) {
     isolate->DecrementNoGCScopeDepth();
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 0dbbccd..ea91a9e 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -816,11 +816,13 @@
 }
 
 
-TEST_CASE(ByteArrayAccess) {
-  Dart_Handle byte_array1 = Dart_NewByteArray(10);
+TEST_CASE(TypedDataAccess) {
+  EXPECT_EQ(kInvalid, Dart_GetTypeOfTypedData(Dart_True()));
+  EXPECT_EQ(kInvalid, Dart_GetTypeOfExternalTypedData(Dart_False()));
+  Dart_Handle byte_array1 = Dart_NewTypedData(kUint8, 10);
   EXPECT_VALID(byte_array1);
-  EXPECT(Dart_IsByteArray(byte_array1));
-  EXPECT(!Dart_IsByteArrayExternal(byte_array1));
+  EXPECT_EQ(kUint8, Dart_GetTypeOfTypedData(byte_array1));
+  EXPECT_EQ(kInvalid, Dart_GetTypeOfExternalTypedData(byte_array1));
   EXPECT(Dart_IsList(byte_array1));
 
   intptr_t length = 0;
@@ -847,7 +849,7 @@
     EXPECT_EQ(i + 1, int64_t_value);
   }
 
-  Dart_Handle byte_array2 = Dart_NewByteArray(10);
+  Dart_Handle byte_array2 = Dart_NewTypedData(kUint8, 10);
   bool is_equal = false;
   Dart_ObjectEquals(byte_array1, byte_array2, &is_equal);
   EXPECT(!is_equal);
@@ -883,54 +885,54 @@
 }
 
 
-TEST_CASE(ScalarListDirectAccess) {
+TEST_CASE(TypedDataDirectAccess) {
   Dart_Handle str = Dart_NewStringFromCString("junk");
-  Dart_Handle byte_array = Dart_NewByteArray(10);
+  Dart_Handle byte_array = Dart_NewTypedData(kUint8, 10);
   EXPECT_VALID(byte_array);
   Dart_Handle result;
-  result = Dart_ScalarListAcquireData(byte_array, NULL, NULL, NULL);
-  EXPECT_ERROR(result, "Dart_ScalarListAcquireData expects argument 'type'"
+  result = Dart_TypedDataAcquireData(byte_array, NULL, NULL, NULL);
+  EXPECT_ERROR(result, "Dart_TypedDataAcquireData expects argument 'type'"
                        " to be non-null.");
-  Dart_Scalar_Type type;
-  result = Dart_ScalarListAcquireData(byte_array, &type, NULL, NULL);
-  EXPECT_ERROR(result, "Dart_ScalarListAcquireData expects argument 'data'"
+  Dart_TypedData_Type type;
+  result = Dart_TypedDataAcquireData(byte_array, &type, NULL, NULL);
+  EXPECT_ERROR(result, "Dart_TypedDataAcquireData expects argument 'data'"
                        " to be non-null.");
   void* data;
-  result = Dart_ScalarListAcquireData(byte_array, &type, &data, NULL);
-  EXPECT_ERROR(result, "Dart_ScalarListAcquireData expects argument 'len'"
+  result = Dart_TypedDataAcquireData(byte_array, &type, &data, NULL);
+  EXPECT_ERROR(result, "Dart_TypedDataAcquireData expects argument 'len'"
                        " to be non-null.");
   intptr_t len;
-  result = Dart_ScalarListAcquireData(Dart_Null(), &type, &data, &len);
-  EXPECT_ERROR(result, "Dart_ScalarListAcquireData expects argument 'array'"
+  result = Dart_TypedDataAcquireData(Dart_Null(), &type, &data, &len);
+  EXPECT_ERROR(result, "Dart_TypedDataAcquireData expects argument 'object'"
                        " to be non-null.");
-  result = Dart_ScalarListAcquireData(str, &type, &data, &len);
-  EXPECT_ERROR(result, "Dart_ScalarListAcquireData expects argument 'array'"
-                       " to be of type 'scalar list'.");
+  result = Dart_TypedDataAcquireData(str, &type, &data, &len);
+  EXPECT_ERROR(result, "Dart_TypedDataAcquireData expects argument 'object'"
+                       " to be of type 'TypedData'.");
 
-  result = Dart_ScalarListReleaseData(Dart_Null());
-  EXPECT_ERROR(result, "Dart_ScalarListReleaseData expects argument 'array'"
+  result = Dart_TypedDataReleaseData(Dart_Null());
+  EXPECT_ERROR(result, "Dart_TypedDataReleaseData expects argument 'object'"
                        " to be non-null.");
-  result = Dart_ScalarListReleaseData(str);
-  EXPECT_ERROR(result, "Dart_ScalarListReleaseData expects argument 'array'"
-                       " to be of type 'scalar list'.");
+  result = Dart_TypedDataReleaseData(str);
+  EXPECT_ERROR(result, "Dart_TypedDataReleaseData expects argument 'object'"
+                       " to be of type 'TypedData'.");
 }
 
 
 static void TestDirectAccess(Dart_Handle lib,
                              Dart_Handle array,
-                             Dart_Scalar_Type expected_type) {
+                             Dart_TypedData_Type expected_type) {
   // Invoke the dart function that sets initial values.
   Dart_Handle dart_args[1];
   dart_args[0] = array;
   Dart_Invoke(lib, NewString("setMain"), 1, dart_args);
 
-  // Now Get a direct access to this typed array and check it's contents.
+  // Now Get a direct access to this typed data object and check it's contents.
   const int kLength = 10;
   Dart_Handle result;
-  Dart_Scalar_Type type;
+  Dart_TypedData_Type type;
   void* data;
   intptr_t len;
-  result = Dart_ScalarListAcquireData(array, &type, &data, &len);
+  result = Dart_TypedDataAcquireData(array, &type, &data, &len);
   EXPECT_VALID(result);
   EXPECT_EQ(expected_type, type);
   EXPECT_EQ(kLength, len);
@@ -945,8 +947,8 @@
     dataP[i] += 10;
   }
 
-  // Release direct accesss to the typed array.
-  result = Dart_ScalarListReleaseData(array);
+  // Release direct accesss to the typed data object.
+  result = Dart_TypedDataReleaseData(array);
   EXPECT_VALID(result);
 
   // Invoke the dart function in order to check the modified values.
@@ -954,7 +956,7 @@
 }
 
 
-TEST_CASE(ScalarListDirectAccess1) {
+TEST_CASE(TypedDataDirectAccess1) {
   const char* kScriptChars =
       "import 'dart:scalarlist';\n"
       "void setMain(var a) {"
@@ -974,17 +976,18 @@
   // Create a test library and Load up a test script in it.
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
 
-  // Test with an regular typed array object.
+  // Test with an regular typed data object.
   Dart_Handle list_access_test_obj;
   list_access_test_obj = Dart_Invoke(lib, NewString("main"), 0, NULL);
   EXPECT_VALID(list_access_test_obj);
   TestDirectAccess(lib, list_access_test_obj, kInt8);
 
-  // Test with an external typed array object.
+  // Test with an external typed data object.
   uint8_t data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
   intptr_t data_length = ARRAY_SIZE(data);
   Dart_Handle ext_list_access_test_obj;
-  ext_list_access_test_obj = Dart_NewExternalByteArray(data,
+  ext_list_access_test_obj = Dart_NewExternalTypedData(kUint8,
+                                                       data,
                                                        data_length,
                                                        NULL, NULL);
   EXPECT_VALID(ext_list_access_test_obj);
@@ -992,20 +995,26 @@
 }
 
 
-static void ExternalByteArrayAccessTests(Dart_Handle obj,
+static void ExternalTypedDataAccessTests(Dart_Handle obj,
+                                         Dart_TypedData_Type expected_type,
                                          uint8_t data[],
                                          intptr_t data_length) {
   EXPECT_VALID(obj);
-  EXPECT(Dart_IsByteArray(obj));
-  EXPECT(Dart_IsByteArrayExternal(obj));
+  EXPECT_EQ(expected_type, Dart_GetTypeOfTypedData(obj));
+  EXPECT_EQ(expected_type, Dart_GetTypeOfExternalTypedData(obj));
   EXPECT(Dart_IsList(obj));
 
   void* raw_data = NULL;
-  EXPECT_VALID(Dart_ExternalByteArrayGetData(obj, &raw_data));
+  intptr_t len;
+  Dart_TypedData_Type type;
+  EXPECT_VALID(Dart_TypedDataAcquireData(obj, &type, &raw_data, &len));
   EXPECT(raw_data == data);
+  EXPECT_EQ(data_length, len);
+  EXPECT_EQ(expected_type, type);
+  EXPECT_VALID(Dart_TypedDataReleaseData(obj));
 
   void* peer = &data;  // just a non-NULL value
-  EXPECT_VALID(Dart_ExternalByteArrayGetPeer(obj, &peer));
+  EXPECT_VALID(Dart_ExternalTypedDataGetPeer(obj, &peer));
   EXPECT(peer == NULL);
 
   intptr_t list_length = 0;
@@ -1048,22 +1057,25 @@
 }
 
 
-TEST_CASE(ExternalByteArrayAccess) {
+TEST_CASE(ExternalTypedDataAccess) {
   uint8_t data[] = { 0, 11, 22, 33, 44, 55, 66, 77 };
   intptr_t data_length = ARRAY_SIZE(data);
 
-  Dart_Handle obj = Dart_NewExternalByteArray(data, data_length, NULL, NULL);
-  ExternalByteArrayAccessTests(obj, data, data_length);
+  Dart_Handle obj = Dart_NewExternalTypedData(kUint8,
+                                              data, data_length,
+                                              NULL, NULL);
+  ExternalTypedDataAccessTests(obj, kUint8, data, data_length);
 }
 
 
-TEST_CASE(ExternalClampedByteArrayAccess) {
+TEST_CASE(ExternalClampedTypedDataAccess) {
   uint8_t data[] = { 0, 11, 22, 33, 44, 55, 66, 77 };
   intptr_t data_length = ARRAY_SIZE(data);
 
-  Dart_Handle obj = Dart_NewExternalClampedByteArray(
-      data, data_length, NULL, NULL);
-  ExternalByteArrayAccessTests(obj, data, data_length);
+  Dart_Handle obj = Dart_NewExternalTypedData(kUint8Clamped,
+                                              data, data_length,
+                                              NULL, NULL);
+  ExternalTypedDataAccessTests(obj, kUint8Clamped, data, data_length);
 }
 
 
@@ -1082,8 +1094,9 @@
 
   uint8_t data[] = { 0, 11, 22, 33, 44, 55, 66, 77 };
   intptr_t data_length = ARRAY_SIZE(data);
-  Dart_Handle obj = Dart_NewExternalClampedByteArray(
-      data, data_length, NULL, NULL);
+  Dart_Handle obj = Dart_NewExternalTypedData(kUint8Clamped,
+                                              data, data_length,
+                                              NULL, NULL);
   EXPECT_VALID(obj);
   Dart_Handle result;
   // Create a test library and Load up a test script in it.
@@ -1102,25 +1115,27 @@
 }
 
 
-static void ExternalByteArrayCallbackFinalizer(Dart_Handle handle, void* peer) {
+static void ExternalTypedDataCallbackFinalizer(Dart_Handle handle,
+                                               void* peer) {
   Dart_DeletePersistentHandle(handle);
   *static_cast<int*>(peer) = 42;
 }
 
 
-TEST_CASE(ExternalByteArrayCallback) {
+TEST_CASE(ExternalTypedDataCallback) {
   int peer = 0;
   {
     Dart_EnterScope();
     uint8_t data[] = { 1, 2, 3, 4 };
-    Dart_Handle obj = Dart_NewExternalByteArray(
+    Dart_Handle obj = Dart_NewExternalTypedData(
+        kUint8,
         data,
         ARRAY_SIZE(data),
         &peer,
-        ExternalByteArrayCallbackFinalizer);
+        ExternalTypedDataCallbackFinalizer);
     EXPECT_VALID(obj);
     void* api_peer = NULL;
-    EXPECT_VALID(Dart_ExternalByteArrayGetPeer(obj, &api_peer));
+    EXPECT_VALID(Dart_ExternalTypedDataGetPeer(obj, &api_peer));
     EXPECT_EQ(api_peer, &peer);
     Dart_ExitScope();
   }
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index e4924c8..66ae155 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -326,6 +326,7 @@
 
 RawObject* DartLibraryCalls::ExceptionCreate(const Library& lib,
                                              const String& class_name,
+                                             const String& constructor_name,
                                              const Array& arguments) {
   const Class& cls = Class::Handle(lib.LookupClassAllowPrivate(class_name));
   ASSERT(!cls.IsNull());
@@ -343,10 +344,10 @@
     constructor_arguments.SetAt((i + kNumExtraArgs), obj);
   }
 
-  String& constructor_name = String::Handle(
-      String::Concat(class_name, Symbols::Dot()));
-  Function& constructor =
-      Function::Handle(cls.LookupConstructor(constructor_name));
+  const String& function_name = String::Handle(
+      String::Concat(class_name, constructor_name));
+  const Function& constructor =
+      Function::Handle(cls.LookupConstructorAllowPrivate(function_name));
   ASSERT(!constructor.IsNull());
   const Object& retval =
     Object::Handle(DartEntry::InvokeStatic(constructor, constructor_arguments));
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index 130475c..e4c6d5c 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -157,6 +157,7 @@
   // On success, returns a RawInstance.  On failure, a RawError.
   static RawObject* ExceptionCreate(const Library& library,
                                     const String& exception_name,
+                                    const String& constructor_name,
                                     const Array& arguments);
 
   // On success, returns a RawInstance.  On failure, a RawError.
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 7a68fc2..61a9f69 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -620,16 +620,21 @@
   ASSERT(!is_enabled_);
   switch (breakpoint_kind_) {
     case PcDescriptors::kIcCall: {
+      const Code& code =
+          Code::Handle(Function::Handle(function_).unoptimized_code());
       saved_bytes_.target_address_ =
-          CodePatcher::GetInstanceCallAt(pc_, NULL, NULL);
-      CodePatcher::PatchInstanceCallAt(pc_,
+          CodePatcher::GetInstanceCallAt(pc_, code, NULL, NULL);
+      CodePatcher::PatchInstanceCallAt(pc_, code,
                                        StubCode::BreakpointDynamicEntryPoint());
       break;
     }
     case PcDescriptors::kFuncCall: {
-      saved_bytes_.target_address_ = CodePatcher::GetStaticCallTargetAt(pc_);
-      CodePatcher::PatchStaticCallAt(pc_,
-          StubCode::BreakpointStaticEntryPoint());
+      const Code& code =
+          Code::Handle(Function::Handle(function_).unoptimized_code());
+      saved_bytes_.target_address_ =
+          CodePatcher::GetStaticCallTargetAt(pc_, code);
+      CodePatcher::PatchStaticCallAt(pc_, code,
+                                     StubCode::BreakpointStaticEntryPoint());
       break;
     }
     case PcDescriptors::kReturn:
@@ -645,12 +650,20 @@
 void CodeBreakpoint::RestoreCode() {
   ASSERT(is_enabled_);
   switch (breakpoint_kind_) {
-    case PcDescriptors::kIcCall:
-      CodePatcher::PatchInstanceCallAt(pc_, saved_bytes_.target_address_);
+    case PcDescriptors::kIcCall: {
+      const Code& code =
+          Code::Handle(Function::Handle(function_).unoptimized_code());
+      CodePatcher::PatchInstanceCallAt(pc_, code,
+                                       saved_bytes_.target_address_);
       break;
-    case PcDescriptors::kFuncCall:
-      CodePatcher::PatchStaticCallAt(pc_, saved_bytes_.target_address_);
+    }
+    case PcDescriptors::kFuncCall: {
+      const Code& code =
+          Code::Handle(Function::Handle(function_).unoptimized_code());
+      CodePatcher::PatchStaticCallAt(pc_, code,
+                                     saved_bytes_.target_address_);
       break;
+    }
     case PcDescriptors::kReturn:
       RestoreFunctionReturn();
       break;
@@ -1483,18 +1496,20 @@
       func_to_instrument = bpt->function();
       ICData& ic_data = ICData::Handle();
       Array& descriptor = Array::Handle();
-      CodePatcher::GetInstanceCallAt(bpt->pc_, &ic_data, &descriptor);
+      const Code& code =
+          Code::Handle(Function::Handle(bpt->function_).unoptimized_code());
+      CodePatcher::GetInstanceCallAt(bpt->pc_, code, &ic_data, &descriptor);
       ArgumentsDescriptor arg_descriptor(descriptor);
       ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0);
       intptr_t num_args = arg_descriptor.Count();
       Instance& receiver =
           Instance::Handle(top_frame->GetInstanceCallReceiver(num_args));
-      Code& code =
+      Code& target_code =
           Code::Handle(ResolveCompileInstanceCallTarget(receiver,
                                                         ic_data,
                                                         descriptor));
-      if (!code.IsNull()) {
-        Function& callee = Function::Handle(code.function());
+      if (!target_code.IsNull()) {
+        Function& callee = Function::Handle(target_code.function());
         if (IsDebuggable(callee)) {
           func_to_instrument = callee.raw();
         }
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index bcde541..f33e5f7 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -1408,17 +1408,19 @@
   EXPECT_EQ(kStackTraceLen, trace_len);
 
   // Frame 0 corresponding to "Object._noSuchMethod".
-  Dart_Handle frame0_locals = Dart_NewList(10);
+  Dart_Handle frame0_locals = Dart_NewList(12);
   Dart_ListSetAt(frame0_locals, 0, NewString("this"));
   Dart_ListSetAt(frame0_locals, 1, Dart_Null());
   Dart_ListSetAt(frame0_locals, 2, NewString("isMethod"));
   Dart_ListSetAt(frame0_locals, 3, Dart_Null());
   Dart_ListSetAt(frame0_locals, 4, NewString("memberName"));
   Dart_ListSetAt(frame0_locals, 5, Dart_Null());
-  Dart_ListSetAt(frame0_locals, 6, NewString("arguments"));
+  Dart_ListSetAt(frame0_locals, 6, NewString("type"));
   Dart_ListSetAt(frame0_locals, 7, Dart_Null());
-  Dart_ListSetAt(frame0_locals, 8, NewString("namedArguments"));
+  Dart_ListSetAt(frame0_locals, 8, NewString("arguments"));
   Dart_ListSetAt(frame0_locals, 9, Dart_Null());
+  Dart_ListSetAt(frame0_locals, 10, NewString("namedArguments"));
+  Dart_ListSetAt(frame0_locals, 11, Dart_Null());
 
   // Frame 1 corresponding to "Object.noSuchMethod".
   Dart_Handle frame1_locals = Dart_NewList(4);
diff --git a/runtime/vm/debuginfo_android.cc b/runtime/vm/debuginfo_android.cc
index 1a11e1b..ee4015c 100644
--- a/runtime/vm/debuginfo_android.cc
+++ b/runtime/vm/debuginfo_android.cc
@@ -2,6 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "vm/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "vm/debuginfo.h"
 
 #include "vm/elfgen.h"
@@ -70,3 +73,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/debuginfo_linux.cc b/runtime/vm/debuginfo_linux.cc
index ef4b31a..9e73553 100644
--- a/runtime/vm/debuginfo_linux.cc
+++ b/runtime/vm/debuginfo_linux.cc
@@ -2,6 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "vm/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "vm/debuginfo.h"
 
 #include "vm/elfgen.h"
@@ -70,3 +73,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 035cc65..1e4a614 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -269,7 +269,7 @@
       // If the deoptimization happened at an IC call, update the IC data
       // to avoid repeated deoptimization at the same site next time around.
       ICData& ic_data = ICData::Handle();
-      CodePatcher::GetInstanceCallAt(pc, &ic_data, NULL);
+      CodePatcher::GetInstanceCallAt(pc, code, &ic_data, NULL);
       if (!ic_data.IsNull()) {
         ic_data.set_deopt_reason(deopt_context->deopt_reason());
       }
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index e88f6ca..b4e862e 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -10,11 +10,1208 @@
 
 namespace dart {
 
+class ARMDecoder : public ValueObject {
+ public:
+  ARMDecoder(char* buffer, size_t buffer_size)
+      : buffer_(buffer),
+        buffer_size_(buffer_size),
+        buffer_pos_(0) {
+    buffer_[buffer_pos_] = '\0';
+  }
+
+  ~ARMDecoder() {}
+
+  // Writes one disassembled instruction into 'buffer' (0-terminated).
+  void InstructionDecode(uword pc);
+
+ private:
+  // Bottleneck functions to print into the out_buffer.
+  void Print(const char* str);
+
+  // Printing of common values.
+  void PrintRegister(int reg);
+  void PrintSRegister(int reg);
+  void PrintDRegister(int reg);
+  void PrintCondition(Instr* instr);
+  void PrintShiftRm(Instr* instr);
+  void PrintShiftImm(Instr* instr);
+  void PrintPU(Instr* instr);
+
+  // Handle formatting of instructions and their options.
+  int FormatRegister(Instr* instr, const char* option);
+  int FormatSRegister(Instr* instr, const char* option);
+  int FormatDRegister(Instr* instr, const char* option);
+  int FormatOption(Instr* instr, const char* option);
+  void Format(Instr* instr, const char* format);
+  void Unknown(Instr* instr);
+
+  // Each of these functions decodes one particular instruction type, a 3-bit
+  // field in the instruction encoding.
+  // Types 0 and 1 are combined as they are largely the same except for the way
+  // they interpret the shifter operand.
+  void DecodeType01(Instr* instr);
+  void DecodeType2(Instr* instr);
+  void DecodeType3(Instr* instr);
+  void DecodeType4(Instr* instr);
+  void DecodeType5(Instr* instr);
+  void DecodeType6(Instr* instr);
+  void DecodeType7(Instr* instr);
+
+  // Convenience functions.
+  char* get_buffer() const { return buffer_; }
+  char* current_position_in_buffer() { return buffer_ + buffer_pos_; }
+  size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; }
+
+  char* buffer_;  // Decode instructions into this buffer.
+  size_t buffer_size_;  // The size of the character buffer.
+  size_t buffer_pos_;  // Current character position in buffer.
+
+  DISALLOW_COPY_AND_ASSIGN(ARMDecoder);
+};
+
+
+// Support for assertions in the ARMDecoder formatting functions.
+#define STRING_STARTS_WITH(string, compare_string) \
+  (strncmp(string, compare_string, strlen(compare_string)) == 0)
+
+
+// Append the str to the output buffer.
+void ARMDecoder::Print(const char* str) {
+  char cur = *str++;
+  while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) {
+    buffer_[buffer_pos_++] = cur;
+    cur = *str++;
+  }
+  buffer_[buffer_pos_] = '\0';
+}
+
+
+// These condition names are defined in a way to match the native disassembler
+// formatting. See for example the command "objdump -d <binary file>".
+static const char* cond_names[kMaxCondition] = {
+  "eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" ,
+  "hi", "ls", "ge", "lt", "gt", "le", "", "invalid",
+};
+
+
+// Print the condition guarding the instruction.
+void ARMDecoder::PrintCondition(Instr* instr) {
+  Print(cond_names[instr->ConditionField()]);
+}
+
+
+// These register names are defined in a way to match the native disassembler
+// formatting. See for example the command "objdump -d <binary file>".
+static const char* reg_names[kNumberOfCpuRegisters] = {
+  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+  "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc",
+};
+
+
+// Print the register name according to the active name converter.
+void ARMDecoder::PrintRegister(int reg) {
+  ASSERT(0 <= reg);
+  ASSERT(reg < kNumberOfCpuRegisters);
+  Print(reg_names[reg]);
+}
+
+
+void ARMDecoder::PrintSRegister(int reg) {
+  ASSERT(0 <= reg);
+  ASSERT(reg < kNumberOfSRegisters);
+  buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                             remaining_size_in_buffer(),
+                             "s%d", reg);
+}
+
+
+void ARMDecoder::PrintDRegister(int reg) {
+  ASSERT(0 <= reg);
+  ASSERT(reg < kNumberOfDRegisters);
+  buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                             remaining_size_in_buffer(),
+                             "d%d", reg);
+}
+
+
+// These shift names are defined in a way to match the native disassembler
+// formatting. See for example the command "objdump -d <binary file>".
+static const char* shift_names[kMaxShift] = {
+  "lsl", "lsr", "asr", "ror"
+};
+
+
+// Print the register shift operands for the instruction. Generally used for
+// data processing instructions.
+void ARMDecoder::PrintShiftRm(Instr* instr) {
+  Shift shift = instr->ShiftField();
+  int shift_amount = instr->ShiftAmountField();
+  int rm = instr->RmField();
+
+  PrintRegister(rm);
+
+  if ((instr->RegShiftField() == 0) && (shift == LSL) && (shift_amount == 0)) {
+    // Special case for using rm only.
+    return;
+  }
+  if (instr->RegShiftField() == 0) {
+    // by immediate
+    if ((shift == ROR) && (shift_amount == 0)) {
+      Print(", RRX");
+      return;
+    } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
+      shift_amount = 32;
+    }
+    buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                               remaining_size_in_buffer(),
+                               ", %s #%d",
+                               shift_names[shift],
+                               shift_amount);
+  } else {
+    // by register
+    int rs = instr->RsField();
+    buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                               remaining_size_in_buffer(),
+                              ", %s ",
+                              shift_names[shift]);
+    PrintRegister(rs);
+  }
+}
+
+
+// Print the immediate operand for the instruction. Generally used for data
+// processing instructions.
+void ARMDecoder::PrintShiftImm(Instr* instr) {
+  int rotate = instr->RotateField() * 2;
+  int immed8 = instr->Immed8Field();
+  int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
+  buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                             remaining_size_in_buffer(),
+                             "#%d",
+                             imm);
+}
+
+
+// Print PU formatting to reduce complexity of FormatOption.
+void ARMDecoder::PrintPU(Instr* instr) {
+  switch (instr->PUField()) {
+    case 0: {
+      Print("da");
+      break;
+    }
+    case 1: {
+      Print("ia");
+      break;
+    }
+    case 2: {
+      Print("db");
+      break;
+    }
+    case 3: {
+      Print("ib");
+      break;
+    }
+    default: {
+      UNREACHABLE();
+      break;
+    }
+  }
+}
+
+
+// Handle all register based formatting in these functions to reduce the
+// complexity of FormatOption.
+int ARMDecoder::FormatRegister(Instr* instr, const char* format) {
+  ASSERT(format[0] == 'r');
+  if (format[1] == 'n') {  // 'rn: Rn register
+    int reg = instr->RnField();
+    PrintRegister(reg);
+    return 2;
+  } else if (format[1] == 'd') {  // 'rd: Rd register
+    int reg = instr->RdField();
+    PrintRegister(reg);
+    if (format[2] == '2') {  // 'rd2: possibly Rd, Rd+1 register pair
+      if (instr->HasSign() && !instr->HasL()) {
+        if ((reg % 2) != 0) {
+          Print(" *** unknown (odd register pair) ***");
+        } else {
+          Print(", ");
+          PrintRegister(reg + 1);
+        }
+      }
+      return 3;
+    }
+    return 2;
+  } else if (format[1] == 's') {  // 'rs: Rs register
+    int reg = instr->RsField();
+    PrintRegister(reg);
+    return 2;
+  } else if (format[1] == 'm') {  // 'rm: Rm register
+    int reg = instr->RmField();
+    PrintRegister(reg);
+    return 2;
+  } else if (format[1] == 'l') {
+    // 'rlist: register list for load and store multiple instructions
+    ASSERT(STRING_STARTS_WITH(format, "rlist"));
+    int rlist = instr->RlistField();
+    int reg = 0;
+    Print("{");
+    // Print register list in ascending order, by scanning the bit mask.
+    while (rlist != 0) {
+      if ((rlist & 1) != 0) {
+        PrintRegister(reg);
+        if ((rlist >> 1) != 0) {
+          Print(", ");
+        }
+      }
+      reg++;
+      rlist >>= 1;
+    }
+    Print("}");
+    return 5;
+  }
+  UNREACHABLE();
+  return -1;
+}
+
+
+int ARMDecoder::FormatSRegister(Instr* instr, const char* format) {
+  ASSERT(format[0] == 's');
+  if (format[1] == 'n') {  // 'sn: Sn register
+    int reg = instr->SnField();
+    PrintSRegister(reg);
+    return 2;
+  } else if (format[1] == 'd') {  // 'sd: Sd register
+    int reg = instr->SdField();
+    PrintSRegister(reg);
+    return 2;
+  } else if (format[1] == 'm') {
+    int reg = instr->SmField();
+    if (format[2] == '1') {  // 'sm1: S[m+1] register
+      reg++;
+      ASSERT(reg < kNumberOfSRegisters);
+      PrintSRegister(reg);
+      return 3;
+    } else {  // 'sm: Sm register
+      PrintSRegister(reg);
+      return 2;
+    }
+  }
+  UNREACHABLE();
+  return -1;
+}
+
+
+int ARMDecoder::FormatDRegister(Instr* instr, const char* format) {
+  ASSERT(format[0] == 'd');
+  if (format[1] == 'n') {  // 'dn: Dn register
+    int reg = instr->DnField();
+    PrintDRegister(reg);
+    return 2;
+  } else if (format[1] == 'd') {  // 'dd: Dd register
+    int reg = instr->DdField();
+    PrintDRegister(reg);
+    return 2;
+  } else if (format[1] == 'm') {  // 'dm: Dm register
+    int reg = instr->DmField();
+    PrintDRegister(reg);
+    return 2;
+  }
+  UNREACHABLE();
+  return -1;
+}
+
+
+// FormatOption takes a formatting string and interprets it based on
+// the current instructions. The format string points to the first
+// character of the option string (the option escape has already been
+// consumed by the caller.)  FormatOption returns the number of
+// characters that were consumed from the formatting string.
+int ARMDecoder::FormatOption(Instr* instr, const char* format) {
+  switch (format[0]) {
+    case 'a': {  // 'a: accumulate multiplies
+      if (instr->Bit(21) == 0) {
+        Print("ul");
+      } else {
+        Print("la");
+      }
+      return 1;
+    }
+    case 'b': {  // 'b: byte loads or stores
+      if (instr->HasB()) {
+        Print("b");
+      }
+      return 1;
+    }
+    case 'c': {  // 'cond: conditional execution
+      ASSERT(STRING_STARTS_WITH(format, "cond"));
+      PrintCondition(instr);
+      return 4;
+    }
+    case 'd': {
+      if (format[1] == 'e') {  // 'dest: branch destination
+        ASSERT(STRING_STARTS_WITH(format, "dest"));
+        int off = (instr->SImmed24Field() << 2) + 8;
+        uword destination = reinterpret_cast<uword>(instr) + off;
+        buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                                   remaining_size_in_buffer(),
+                                   "%#"Px"",
+                                   destination);
+        return 4;
+      } else {
+        return FormatDRegister(instr, format);
+      }
+    }
+    case 'i': {  // 'imm12_4, imm4_12, immf, or immd
+      uint16_t immed16;
+      if (format[3] == 'f') {
+        ASSERT(STRING_STARTS_WITH(format, "immf"));
+        buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                                   remaining_size_in_buffer(),
+                                   "%f",
+                                   instr->ImmFloatField());
+        return 4;
+      } else if (format[3] == 'd') {
+        ASSERT(STRING_STARTS_WITH(format, "immd"));
+        buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                                   remaining_size_in_buffer(),
+                                   "%g",
+                                   instr->ImmDoubleField());
+        return 4;
+      } else if (format[3] == '1') {
+        ASSERT(STRING_STARTS_WITH(format, "imm12_4"));
+        immed16 = instr->BkptField();
+      } else {
+        ASSERT(STRING_STARTS_WITH(format, "imm4_12"));
+        immed16 = instr->MovwField();
+      }
+      buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                                 remaining_size_in_buffer(),
+                                 "0x%x",
+                                 immed16);
+      return 7;
+    }
+    case 'l': {  // 'l: branch and link
+      if (instr->HasLink()) {
+        Print("l");
+      }
+      return 1;
+    }
+    case 'm': {  // 'memop: load/store instructions
+      ASSERT(STRING_STARTS_WITH(format, "memop"));
+      if (instr->HasL() ||
+          // Extra load/store instructions.
+          ((instr->TypeField() == 0) && instr->HasSign() && !instr->HasH())) {
+        Print("ldr");
+      } else {
+        Print("str");
+      }
+      return 5;
+    }
+    case 'o': {
+      if (format[3] == '1') {
+        if (format[4] == '0') {
+          // 'off10: 10-bit offset for VFP load and store instructions
+          buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                                     remaining_size_in_buffer(),
+                                     "%d",
+                                     instr->Bits(0, 8) << 2);
+        } else {
+          // 'off12: 12-bit offset for load and store instructions
+          ASSERT(STRING_STARTS_WITH(format, "off12"));
+          buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                                     remaining_size_in_buffer(),
+                                     "%d",
+                                     instr->Offset12Field());
+        }
+        return 5;
+      }
+      // 'off8: 8-bit offset for extra load and store instructions
+      ASSERT(STRING_STARTS_WITH(format, "off8"));
+      int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField();
+      buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                                 remaining_size_in_buffer(),
+                                 "%d",
+                                 offs8);
+      return 4;
+    }
+    case 'p': {  // 'pu: P and U bits for load and store instructions
+      ASSERT(STRING_STARTS_WITH(format, "pu"));
+      PrintPU(instr);
+      return 2;
+    }
+    case 'r': {
+      return FormatRegister(instr, format);
+    }
+    case 's': {
+      if (format[1] == 'h') {  // 'shift_op or 'shift_rm
+        if (format[6] == 'o') {  // 'shift_op
+          ASSERT(STRING_STARTS_WITH(format, "shift_op"));
+          if (instr->TypeField() == 0) {
+            PrintShiftRm(instr);
+          } else {
+            ASSERT(instr->TypeField() == 1);
+            PrintShiftImm(instr);
+          }
+          return 8;
+        } else {  // 'shift_rm
+          ASSERT(STRING_STARTS_WITH(format, "shift_rm"));
+          PrintShiftRm(instr);
+          return 8;
+        }
+      } else if (format[1] == 'v') {  // 'svc
+        ASSERT(STRING_STARTS_WITH(format, "svc"));
+        buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                                   remaining_size_in_buffer(),
+                                   "0x%x",
+                                   instr->SvcField());
+        return 3;
+      } else if (format[1] == ' ') {
+        // 's: S field of data processing instructions
+        if (instr->HasS()) {
+          Print("s");
+        }
+        return 1;
+      } else {
+        return FormatSRegister(instr, format);
+      }
+    }
+    case 't': {  // 'target: target of branch instructions
+      ASSERT(STRING_STARTS_WITH(format, "target"));
+      int off = (instr->SImmed24Field() << 2) + 8;
+      buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                                 remaining_size_in_buffer(),
+                                 "%+d",
+                                 off);
+      return 6;
+    }
+    case 'u': {  // 'u: signed or unsigned multiplies
+      if (instr->Bit(22) == 0) {
+        Print("u");
+      } else {
+        Print("s");
+      }
+      return 1;
+    }
+    case 'w': {  // 'w: W field of load and store instructions
+      if (instr->HasW()) {
+        Print("!");
+      }
+      return 1;
+    }
+    case 'x': {  // 'x: type of extra load/store instructions
+      if (!instr->HasSign()) {
+        Print("h");
+      } else if (instr->HasL()) {
+        if (instr->HasH()) {
+          Print("sh");
+        } else {
+          Print("sb");
+        }
+      } else {
+        Print("d");
+      }
+      return 1;
+    }
+    default: {
+      UNREACHABLE();
+      break;
+    }
+  }
+  UNREACHABLE();
+  return -1;
+}
+
+
+// Format takes a formatting string for a whole instruction and prints it into
+// the output buffer. All escaped options are handed to FormatOption to be
+// parsed further.
+void ARMDecoder::Format(Instr* instr, const char* format) {
+  char cur = *format++;
+  while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) {
+    if (cur == '\'') {  // Single quote is used as the formatting escape.
+      format += FormatOption(instr, format);
+    } else {
+      buffer_[buffer_pos_++] = cur;
+    }
+    cur = *format++;
+  }
+  buffer_[buffer_pos_]  = '\0';
+}
+
+
+// For currently unimplemented decodings the disassembler calls Unknown(instr)
+// which will just print "unknown" of the instruction bits.
+void ARMDecoder::Unknown(Instr* instr) {
+  Format(instr, "unknown");
+}
+
+
+void ARMDecoder::DecodeType01(Instr* instr) {
+  if (!instr->IsDataProcessing()) {
+    // miscellaneous, multiply, sync primitives, extra loads and stores.
+    if (instr->IsMiscellaneous()) {
+      switch (instr->Bits(4, 3)) {
+        case 1: {
+          if (instr->Bits(21, 2) == 0x3) {
+            Format(instr, "clz'cond 'rd, 'rm");
+          } else {
+            Unknown(instr);
+          }
+          break;
+        }
+        case 3: {
+          if (instr->Bits(21, 2) == 0x1) {
+            Format(instr, "blx'cond 'rm");
+          } else {
+            // Could be inlined constant.
+            Unknown(instr);
+          }
+          break;
+        }
+        case 7: {
+          if (instr->Bits(21, 2) == 0x1) {
+            Format(instr, "bkpt #'imm12_4");
+          } else {
+             // Format(instr, "smc'cond");
+            Unknown(instr);  // Not used.
+          }
+          break;
+        }
+        default: {
+          Unknown(instr);  // Not used.
+          break;
+        }
+      }
+    } else if (instr->IsMultiplyOrSyncPrimitive()) {
+      if (instr->Bit(24) == 0) {
+        // multiply instructions
+        switch (instr->Bits(21, 3)) {
+          case 0: {
+            // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
+            Format(instr, "mul'cond's 'rn, 'rm, 'rs");
+            break;
+          }
+          case 1: {
+            // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
+            Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
+            break;
+          }
+          case 3: {
+            // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
+            Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
+            break;
+          }
+          case 4: {
+            // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+            Format(instr, "umull'cond's 'rd, 'rn, 'rm, 'rs");
+            break;
+          }
+          default: {
+            Unknown(instr);  // Not used.
+            break;
+          }
+        }
+      } else {
+        // synchronization primitives
+        switch (instr->Bits(20, 4)) {
+          case 8: {
+            Format(instr, "strex'cond 'rd, 'rm, ['rn]");
+            break;
+          }
+          case 9: {
+            Format(instr, "ldrex'cond 'rd, ['rn]");
+            break;
+          }
+          default: {
+            Unknown(instr);  // Not used.
+            break;
+          }
+        }
+      }
+    } else if (instr->Bit(25) == 1) {
+      // 16-bit immediate loads, msr (immediate), and hints
+      switch (instr->Bits(20, 5)) {
+        case 16: {
+          Format(instr, "movw'cond 'rd, #'imm4_12");
+          break;
+        }
+        case 18: {
+          if ((instr->Bits(16, 4) == 0) && (instr->Bits(0, 8) == 0)) {
+            Format(instr, "nop'cond");
+          } else {
+            Unknown(instr);  // Not used.
+          }
+          break;
+        }
+        case 20: {
+          Format(instr, "movt'cond 'rd, #'imm4_12");
+          break;
+        }
+        default: {
+          Unknown(instr);  // Not used.
+          break;
+        }
+      }
+    } else {
+      // extra load/store instructions
+      switch (instr->PUField()) {
+        case 0: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond'x 'rd2, ['rn], -'rm");
+          } else {
+            Format(instr, "'memop'cond'x 'rd2, ['rn], #-'off8");
+          }
+          break;
+        }
+        case 1: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond'x 'rd2, ['rn], +'rm");
+          } else {
+            Format(instr, "'memop'cond'x 'rd2, ['rn], #+'off8");
+          }
+          break;
+        }
+        case 2: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond'x 'rd2, ['rn, -'rm]'w");
+          } else {
+            Format(instr, "'memop'cond'x 'rd2, ['rn, #-'off8]'w");
+          }
+          break;
+        }
+        case 3: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond'x 'rd2, ['rn, +'rm]'w");
+          } else {
+            Format(instr, "'memop'cond'x 'rd2, ['rn, #+'off8]'w");
+          }
+          break;
+        }
+        default: {
+          // The PU field is a 2-bit field.
+          UNREACHABLE();
+          break;
+        }
+      }
+    }
+  } else {
+    switch (instr->OpcodeField()) {
+      case AND: {
+        Format(instr, "and'cond's 'rd, 'rn, 'shift_op");
+        break;
+      }
+      case EOR: {
+        Format(instr, "eor'cond's 'rd, 'rn, 'shift_op");
+        break;
+      }
+      case SUB: {
+        Format(instr, "sub'cond's 'rd, 'rn, 'shift_op");
+        break;
+      }
+      case RSB: {
+        Format(instr, "rsb'cond's 'rd, 'rn, 'shift_op");
+        break;
+      }
+      case ADD: {
+        Format(instr, "add'cond's 'rd, 'rn, 'shift_op");
+        break;
+      }
+      case ADC: {
+        Format(instr, "adc'cond's 'rd, 'rn, 'shift_op");
+        break;
+      }
+      case SBC: {
+        Format(instr, "sbc'cond's 'rd, 'rn, 'shift_op");
+        break;
+      }
+      case RSC: {
+        Format(instr, "rsc'cond's 'rd, 'rn, 'shift_op");
+        break;
+      }
+      case TST: {
+        if (instr->HasS()) {
+          Format(instr, "tst'cond 'rn, 'shift_op");
+        } else {
+          Unknown(instr);  // Not used.
+        }
+        break;
+      }
+      case TEQ: {
+        if (instr->HasS()) {
+          Format(instr, "teq'cond 'rn, 'shift_op");
+        } else {
+          Unknown(instr);  // Not used.
+        }
+        break;
+      }
+      case CMP: {
+        if (instr->HasS()) {
+          Format(instr, "cmp'cond 'rn, 'shift_op");
+        } else {
+          Unknown(instr);  // Not used.
+        }
+        break;
+      }
+      case CMN: {
+        if (instr->HasS()) {
+          Format(instr, "cmn'cond 'rn, 'shift_op");
+        } else {
+          Unknown(instr);  // Not used.
+        }
+        break;
+      }
+      case ORR: {
+        Format(instr, "orr'cond's 'rd, 'rn, 'shift_op");
+        break;
+      }
+      case MOV: {
+        Format(instr, "mov'cond's 'rd, 'shift_op");
+        break;
+      }
+      case BIC: {
+        Format(instr, "bic'cond's 'rd, 'rn, 'shift_op");
+        break;
+      }
+      case MVN: {
+        Format(instr, "mvn'cond's 'rd, 'shift_op");
+        break;
+      }
+      default: {
+        // The Opcode field is a 4-bit field.
+        UNREACHABLE();
+        break;
+      }
+    }
+  }
+}
+
+
+void ARMDecoder::DecodeType2(Instr* instr) {
+  switch (instr->PUField()) {
+    case 0: {
+      if (instr->HasW()) {
+        Unknown(instr);  // Not used.
+      } else {
+        Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
+      }
+      break;
+    }
+    case 1: {
+      if (instr->HasW()) {
+        Unknown(instr);  // Not used.
+      } else {
+        Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
+      }
+      break;
+    }
+    case 2: {
+      Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
+      break;
+    }
+    case 3: {
+      Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
+      break;
+    }
+    default: {
+      // The PU field is a 2-bit field.
+      UNREACHABLE();
+      break;
+    }
+  }
+}
+
+
+void ARMDecoder::DecodeType3(Instr* instr) {
+  switch (instr->PUField()) {
+    case 0: {
+      if (instr->HasW()) {
+        Unknown(instr);
+      } else {
+        Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
+      }
+      break;
+    }
+    case 1: {
+      if (instr->HasW()) {
+        Unknown(instr);
+      } else {
+        Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
+      }
+      break;
+    }
+    case 2: {
+      Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
+      break;
+    }
+    case 3: {
+      Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
+      break;
+    }
+    default: {
+      // The PU field is a 2-bit field.
+      UNREACHABLE();
+      break;
+    }
+  }
+}
+
+
+void ARMDecoder::DecodeType4(Instr* instr) {
+  if (instr->Bit(22) == 1) {
+    Unknown(instr);  // Privileged mode currently not supported.
+  } else if (instr->HasL()) {
+    Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
+  } else {
+    Format(instr, "stm'cond'pu 'rn'w, 'rlist");
+  }
+}
+
+
+void ARMDecoder::DecodeType5(Instr* instr) {
+  Format(instr, "b'l'cond 'target ; 'dest");
+}
+
+
+void ARMDecoder::DecodeType6(Instr* instr) {
+  if (instr->IsVFPDoubleTransfer()) {
+    if (instr->Bit(8) == 0) {
+      if (instr->Bit(20) == 1) {
+        Format(instr, "vmovrrs'cond 'rd, 'rn, {'sm, 'sm1}");
+      } else {
+        Format(instr, "vmovsrr'cond {'sm, 'sm1}, 'rd, 'rn");
+      }
+    } else {
+      if (instr->Bit(20) == 1) {
+        Format(instr, "vmovrrd'cond 'rd, 'rn, 'dm");
+      } else {
+        Format(instr, "vmovdrr'cond 'dm, 'rd, 'rn");
+      }
+    }
+  } else if (instr-> IsVFPLoadStore()) {
+    if (instr->Bit(8) == 0) {
+      if (instr->Bit(20) == 1) {  // vldrs
+        if (instr->Bit(23) == 1) {
+          Format(instr, "vldrs'cond 'sd, ['rn, #+'off10]");
+        } else {
+          Format(instr, "vldrs'cond 'sd, ['rn, #-'off10]");
+        }
+      } else {  // vstrs
+        if (instr->Bit(23) == 1) {
+          Format(instr, "vstrs'cond 'sd, ['rn, #+'off10]");
+        } else {
+          Format(instr, "vstrs'cond 'sd, ['rn, #-'off10]");
+        }
+      }
+    } else {
+      if (instr->Bit(20) == 1) {  // vldrd
+        if (instr->Bit(23) == 1) {
+          Format(instr, "vldrd'cond 'dd, ['rn, #+'off10]");
+        } else {
+          Format(instr, "vldrd'cond 'dd, ['rn, #-'off10]");
+        }
+      } else {  // vstrd
+        if (instr->Bit(23) == 1) {
+          Format(instr, "vstrd'cond 'dd, ['rn, #+'off10]");
+        } else {
+          Format(instr, "vstrd'cond 'dd, ['rn, #-'off10]");
+        }
+      }
+    }
+  } else {
+    Unknown(instr);
+  }
+}
+
+
+void ARMDecoder::DecodeType7(Instr* instr) {
+  if (instr->Bit(24) == 1) {
+    Format(instr, "svc'cond #'svc");
+    if (instr->SvcField() == kStopMessageSvcCode) {
+      const char* message = *reinterpret_cast<const char**>(
+          reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize);
+      buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
+                                 remaining_size_in_buffer(),
+                                 " ; \"%s\"",
+                                 message);
+    }
+  } else if (instr->IsVFPDataProcessingOrSingleTransfer()) {
+    if (instr->Bit(4) == 0) {
+      // VFP Data Processing
+      switch (instr->Bits(20, 4) & 0xb) {
+        case 0: {  // vmla, vmls floating-point
+          if (instr->Bit(8) == 0) {
+            if (instr->Bit(6) == 0) {
+              Format(instr, "vmlas'cond 'sd, 'sn, 'sm");
+            } else {
+              Format(instr, "vmlss'cond 'sd, 'sn, 'sm");
+            }
+          } else {
+            if (instr->Bit(6) == 0) {
+              Format(instr, "vmlad'cond 'dd, 'dn, 'dm");
+            } else {
+              Format(instr, "vmlsd'cond 'dd, 'dn, 'dm");
+            }
+          }
+          break;
+        }
+        case 1:  // vnmla, vnmls, vnmul
+        default: {
+          Unknown(instr);
+          break;
+        }
+        case 2: {  // vmul
+          if (instr->Bit(8) == 0) {
+            Format(instr, "vmuls'cond 'sd, 'sn, 'sm");
+          } else {
+            Format(instr, "vmuld'cond 'dd, 'dn, 'dm");
+          }
+          break;
+        }
+        case 8: {  // vdiv
+          if (instr->Bit(8) == 0) {
+            Format(instr, "vdivs'cond 'sd, 'sn, 'sm");
+          } else {
+            Format(instr, "vdivd'cond 'dd, 'dn, 'dm");
+          }
+          break;
+        }
+        case 3: {  // vadd, vsub floating-point
+          if (instr->Bit(8) == 0) {
+            if (instr->Bit(6) == 0) {
+              Format(instr, "vadds'cond 'sd, 'sn, 'sm");
+            } else {
+              Format(instr, "vsubs'cond 'sd, 'sn, 'sm");
+            }
+          } else {
+            if (instr->Bit(6) == 0) {
+              Format(instr, "vaddd'cond 'dd, 'dn, 'dm");
+            } else {
+              Format(instr, "vsubd'cond 'dd, 'dn, 'dm");
+            }
+          }
+          break;
+        }
+        case 0xb: {  // Other VFP data-processing instructions
+          if (instr->Bit(6) == 0) {  // vmov immediate
+            if (instr->Bit(8) == 0) {
+              Format(instr, "vmovs'cond 'sd, #'immf");
+            } else {
+              Format(instr, "vmovd'cond 'dd, #'immd");
+            }
+            break;
+          }
+          switch (instr->Bits(16, 4)) {
+            case 0: {  // vmov register, vabs
+              switch (instr->Bits(6, 2)) {
+                case 1: {  // vmov register
+                  if (instr->Bit(8) == 0) {
+                    Format(instr, "vmovs'cond 'sd, 'sm");
+                  } else {
+                    Format(instr, "vmovd'cond 'dd, 'dm");
+                  }
+                  break;
+                }
+                case 3: {  // vabs
+                  if (instr->Bit(8) == 0) {
+                    Format(instr, "vabss'cond 'sd, 'sm");
+                  } else {
+                    Format(instr, "vabsd'cond 'dd, 'dm");
+                  }
+                  break;
+                }
+                default: {
+                  Unknown(instr);
+                  break;
+                }
+              }
+              break;
+            }
+            case 1: {  // vneg, vsqrt
+              switch (instr->Bits(6, 2)) {
+                case 1: {  // vneg
+                  if (instr->Bit(8) == 0) {
+                    Format(instr, "vnegs'cond 'sd, 'sm");
+                  } else {
+                    Format(instr, "vnegd'cond 'dd, 'dm");
+                  }
+                  break;
+                }
+                case 3: {  // vsqrt
+                  if (instr->Bit(8) == 0) {
+                    Format(instr, "vsqrts'cond 'sd, 'sm");
+                  } else {
+                    Format(instr, "vsqrtd'cond 'dd, 'dm");
+                  }
+                  break;
+                }
+                default: {
+                  Unknown(instr);
+                  break;
+                }
+              }
+              break;
+            }
+            case 4:  // vcmp, vcmpe
+            case 5: {  // vcmp #0.0, vcmpe #0.0
+              if (instr->Bit(7) == 1) {  // vcmpe
+                Unknown(instr);
+              } else {
+                if (instr->Bit(8) == 0) {  // vcmps
+                  if (instr->Bit(16) == 0) {
+                    Format(instr, "vcmps'cond 'sd, 'sm");
+                  } else {
+                    Format(instr, "vcmps'cond 'sd, #0.0");
+                  }
+                } else {  // vcmpd
+                  if (instr->Bit(16) == 0) {
+                    Format(instr, "vcmpd'cond 'dd, 'dm");
+                  } else {
+                    Format(instr, "vcmpd'cond 'dd, #0.0");
+                  }
+                }
+              }
+              break;
+            }
+            case 7: {  // vcvt between double-precision and single-precision
+              if (instr->Bit(8) == 0) {
+                Format(instr, "vcvtds'cond 'dd, 'sm");
+              } else {
+                Format(instr, "vcvtsd'cond 'sd, 'dm");
+              }
+              break;
+            }
+            case 8: {  // vcvt, vcvtr between floating-point and integer
+              if (instr->Bit(8) == 0) {
+                if (instr->Bit(7) == 0) {
+                  Format(instr, "vcvtsu'cond 'sd, 'sm");
+                } else {
+                  Format(instr, "vcvtsi'cond 'sd, 'sm");
+                }
+              } else {
+                if (instr->Bit(7) == 0) {
+                  Format(instr, "vcvtdu'cond 'dd, 'sm");
+                } else {
+                  Format(instr, "vcvtdi'cond 'dd, 'sm");
+                }
+              }
+              break;
+            }
+            case 12:
+            case 13: {  // vcvt, vcvtr between floating-point and integer
+              if (instr->Bit(7) == 0) {
+                // We only support round-to-zero mode
+                Unknown(instr);
+                break;
+              }
+              if (instr->Bit(8) == 0) {
+                if (instr->Bit(16) == 0) {
+                  Format(instr, "vcvtus'cond 'sd, 'sm");
+                } else {
+                  Format(instr, "vcvtis'cond 'sd, 'sm");
+                }
+              } else {
+                if (instr->Bit(16) == 0) {
+                  Format(instr, "vcvtud'cond 'sd, 'dm");
+                } else {
+                  Format(instr, "vcvtid'cond 'sd, 'dm");
+                }
+              }
+              break;
+            }
+            case 2:  // vcvtb, vcvtt
+            case 3:  // vcvtb, vcvtt
+            case 9:  // undefined
+            case 10:  // vcvt between floating-point and fixed-point
+            case 11:  // vcvt between floating-point and fixed-point
+            case 14:  // vcvt between floating-point and fixed-point
+            case 15:  // vcvt between floating-point and fixed-point
+            default: {
+              Unknown(instr);
+              break;
+            }
+          }
+        }
+        break;
+      }
+    } else {
+      // 8, 16, or 32-bit Transfer between ARM Core and VFP
+      if ((instr->Bits(21, 3) == 0) && (instr->Bit(8) == 0)) {
+        if (instr->Bit(20) == 0) {
+          Format(instr, "vmovs'cond 'sn, 'rd");
+        } else {
+          Format(instr, "vmovr'cond 'rd, 'sn");
+        }
+      } else if ((instr->Bits(20, 4) == 0xf) && (instr->Bit(8) == 0) &&
+                 (instr->Bits(12, 4) == 0xf)) {
+        Format(instr, "vmstat'cond");
+      } else {
+        Unknown(instr);
+      }
+    }
+  } else {
+    Unknown(instr);
+  }
+}
+
+
+void ARMDecoder::InstructionDecode(uword pc) {
+Instr* instr = Instr::At(pc);
+  if (instr->ConditionField() == kSpecialCondition) {
+    if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) {
+      Format(instr, "clrex");
+    } else {
+      Unknown(instr);
+    }
+  } else {
+    switch (instr->TypeField()) {
+      case 0:
+      case 1: {
+        DecodeType01(instr);
+        break;
+      }
+      case 2: {
+        DecodeType2(instr);
+        break;
+      }
+      case 3: {
+        DecodeType3(instr);
+        break;
+      }
+      case 4: {
+        DecodeType4(instr);
+        break;
+      }
+      case 5: {
+        DecodeType5(instr);
+        break;
+      }
+      case 6: {
+        DecodeType6(instr);
+        break;
+      }
+      case 7: {
+        DecodeType7(instr);
+        break;
+      }
+      default: {
+        // The type field is 3-bits in the ARM encoding.
+        UNREACHABLE();
+        break;
+      }
+    }
+  }
+}
+
+
 int Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
                                     char* human_buffer, intptr_t human_size,
                                     uword pc) {
-  UNIMPLEMENTED();
-  return 0;
+  ARMDecoder decoder(human_buffer, human_size);
+  decoder.InstructionDecode(pc);
+  int32_t instruction_bits = Instr::At(pc)->InstructionBits();
+  OS::SNPrint(hex_buffer, hex_size, "%08x", instruction_bits);
+  return Instr::kInstrSize;
 }
 
 
@@ -22,7 +1219,32 @@
                                uword end,
                                DisassemblyFormatter* formatter,
                                const Code::Comments& comments) {
-  UNIMPLEMENTED();
+  ASSERT(formatter != NULL);
+  char hex_buffer[kHexadecimalBufferSize];  // Instruction in hexadecimal form.
+  char human_buffer[kUserReadableBufferSize];  // Human-readable instruction.
+  uword pc = start;
+  intptr_t comment_finger = 0;
+  while (pc < end) {
+    const intptr_t offset = pc - start;
+    while (comment_finger < comments.Length() &&
+           comments.PCOffsetAt(comment_finger) <= offset) {
+      formatter->Print(
+          "        ;; %s\n",
+          String::Handle(comments.CommentAt(comment_finger)).ToCString());
+      comment_finger++;
+    }
+    int instruction_length = DecodeInstruction(hex_buffer,
+                                               sizeof(hex_buffer),
+                                               human_buffer,
+                                               sizeof(human_buffer),
+                                               pc);
+    formatter->ConsumeInstruction(hex_buffer,
+                                  sizeof(hex_buffer),
+                                  human_buffer,
+                                  sizeof(human_buffer),
+                                  pc);
+    pc += instruction_length;
+  }
 }
 
 }  // namespace dart
diff --git a/runtime/vm/disassembler_test.cc b/runtime/vm/disassembler_test.cc
index 2a33e0e..56ac9bd 100644
--- a/runtime/vm/disassembler_test.cc
+++ b/runtime/vm/disassembler_test.cc
@@ -9,19 +9,21 @@
 
 namespace dart {
 
-// Disassembler only supported on IA32 and X64 now.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+// Disassembler only supported on IA32, X64, and ARM.
+#if defined(TARGET_ARCH_IA32) ||                                               \
+    defined(TARGET_ARCH_X64) ||                                                \
+    defined(TARGET_ARCH_ARM)
 TEST_CASE(Disassembler) {
   Assembler assembler;
   // The used instructions work on all platforms.
   Register reg = static_cast<Register>(0);
-  assembler.AddImmediate(reg, Immediate(1));
-  assembler.AddImmediate(reg, Immediate(3));
+  assembler.PopRegister(reg);
+  assembler.Stop("testing disassembler");
 
   // Only verify that the disassembler does not crash.
   AssemblerTest test("Disassembler", &assembler);
-  uword entry = test.Assemble();
-  Disassembler::Disassemble(entry, entry + assembler.CodeSize());
+  test.Assemble();
+  Disassembler::Disassemble(test.entry(), test.entry() + assembler.CodeSize());
 }
 #endif
 
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 98f2d04..f6413ba 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -424,6 +424,7 @@
 RawObject* Exceptions::Create(ExceptionType type, const Array& arguments) {
   Library& library = Library::Handle();
   const String* class_name = NULL;
+  const String* constructor_name = &Symbols::Dot();
   switch (type) {
     case kNone:
       UNREACHABLE();
@@ -439,6 +440,7 @@
     case kNoSuchMethod:
       library = Library::CoreLibrary();
       class_name = &Symbols::NoSuchMethodError();
+      constructor_name = &String::Handle(Symbols::New("._withType"));
       break;
     case kFormat:
       library = Library::CoreLibrary();
@@ -478,7 +480,10 @@
       break;
   }
 
-  return DartLibraryCalls::ExceptionCreate(library, *class_name, arguments);
+  return DartLibraryCalls::ExceptionCreate(library,
+                                           *class_name,
+                                           *constructor_name,
+                                           arguments);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index ea66a5a..e7598ac 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -60,6 +60,34 @@
 }
 
 
+void FlowGraph::InsertBefore(Instruction* next,
+                             Instruction* instr,
+                             Environment* env,
+                             Definition::UseKind use_kind) {
+  InsertAfter(next->previous(), instr, env, use_kind);
+}
+
+
+void FlowGraph::InsertAfter(Instruction* prev,
+                            Instruction* instr,
+                            Environment* env,
+                            Definition::UseKind use_kind) {
+  for (intptr_t i = instr->InputCount() - 1; i >= 0; --i) {
+    Value* input = instr->InputAt(i);
+    input->definition()->AddInputUse(input);
+    input->set_instruction(instr);
+    input->set_use_index(i);
+  }
+  ASSERT(instr->env() == NULL);
+  if (env != NULL) env->DeepCopyTo(instr);
+  if (use_kind == Definition::kValue) {
+    ASSERT(instr->IsDefinition());
+    instr->AsDefinition()->set_ssa_temp_index(alloc_ssa_temp_index());
+  }
+  instr->InsertAfter(prev);
+}
+
+
 void FlowGraph::DiscoverBlocks() {
   // Initialize state.
   preorder_.Clear();
@@ -97,58 +125,14 @@
 }
 
 
-static void ResetUseListsInInstruction(Instruction* instr) {
-  Definition* defn = instr->AsDefinition();
-  if (defn != NULL) {
-    defn->set_input_use_list(NULL);
-    defn->set_env_use_list(NULL);
-  }
-  for (intptr_t i = 0; i < instr->InputCount(); ++i) {
-    Value* use = instr->InputAt(i);
-    use->set_instruction(NULL);
-    use->set_use_index(-1);
-    use->set_previous_use(NULL);
-    use->set_next_use(NULL);
-  }
-  for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) {
-    Value* use = it.CurrentValue();
-    use->set_instruction(NULL);
-    use->set_use_index(-1);
-    use->set_previous_use(NULL);
-    use->set_next_use(NULL);
-  }
-}
-
-
-bool FlowGraph::ResetUseLists() {
-  // Reset initial definitions.
-  for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); ++i) {
-    ResetUseListsInInstruction((*graph_entry_->initial_definitions())[i]);
-  }
-
-  // Reset phis in join entries and the instructions in each block.
-  for (intptr_t i = 0; i < preorder_.length(); ++i) {
-    BlockEntryInstr* entry = preorder_[i];
-    JoinEntryInstr* join = entry->AsJoinEntry();
-    if (join != NULL && join->phis() != NULL) {
-      for (intptr_t i = 0; i < join->phis()->length(); ++i) {
-        PhiInstr* phi = (*join->phis())[i];
-        if (phi != NULL) ResetUseListsInInstruction(phi);
-      }
-    }
-    for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
-      ResetUseListsInInstruction(it.Current());
-    }
-  }
-  return true;  // Return true so we can ASSERT the reset code.
-}
-
-
-static void ValidateUseListsInInstruction(Instruction* instr) {
+static void VerifyUseListsInInstruction(Instruction* instr) {
   ASSERT(instr != NULL);
   ASSERT(!instr->IsJoinEntry());
   for (intptr_t i = 0; i < instr->InputCount(); ++i) {
     Value* use = instr->InputAt(i);
+    ASSERT(use->definition() != NULL);
+    ASSERT((use->definition() != instr) || use->definition()->IsPhi());
+    ASSERT(use->instruction() == instr);
     ASSERT(use->use_index() == i);
     ASSERT(!FLAG_verify_compiler ||
            (1 == MembershipCount(use, use->definition()->input_use_list())));
@@ -157,6 +141,9 @@
     intptr_t use_index = 0;
     for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) {
       Value* use = it.CurrentValue();
+      ASSERT(use->definition() != NULL);
+      ASSERT((use->definition() != instr) || use->definition()->IsPhi());
+      ASSERT(use->instruction() == instr);
       ASSERT(use->use_index() == use_index++);
       ASSERT(!FLAG_verify_compiler ||
              (1 == MembershipCount(use, use->definition()->env_use_list())));
@@ -170,9 +157,13 @@
       ASSERT(prev == curr->previous_use());
       ASSERT(defn == curr->definition());
       Instruction* instr = curr->instruction();
-      // The instruction should not be removed from the graph (phis are not
-      // removed until register allocation.)
-      ASSERT(instr->IsPhi() || (instr->previous() != NULL));
+      // The instruction should not be removed from the graph.  Removed
+      // instructions have a NULL previous link.  Phis are not removed until
+      // register allocation.  Comparisons used only in a branch will have a
+      // NULL previous link though they are still in the graph.
+      ASSERT(instr->IsPhi() ||
+             (instr->IsDefinition() && instr->AsDefinition()->IsComparison()) ||
+             (instr->previous() != NULL));
       ASSERT(curr == instr->InputAt(curr->use_index()));
       prev = curr;
       curr = curr->next_use();
@@ -185,9 +176,9 @@
       ASSERT(defn == curr->definition());
       Instruction* instr = curr->instruction();
       ASSERT(curr == instr->env()->ValueAtUseIndex(curr->use_index()));
-      // The instruction should not be removed from the graph (phis are not
-      // removed until register allocation.)
-      ASSERT(instr->IsPhi() || (instr->previous() != NULL));
+      ASSERT(instr->IsPhi() ||
+             (instr->IsDefinition() && instr->AsDefinition()->IsComparison()) ||
+             (instr->previous() != NULL));
       prev = curr;
       curr = curr->next_use();
     }
@@ -195,24 +186,24 @@
 }
 
 
-bool FlowGraph::ValidateUseLists() {
-  // Validate initial definitions.
+bool FlowGraph::VerifyUseLists() {
+  // Verify the initial definitions.
   for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); ++i) {
-    ValidateUseListsInInstruction((*graph_entry_->initial_definitions())[i]);
+    VerifyUseListsInInstruction((*graph_entry_->initial_definitions())[i]);
   }
 
-  // Validate phis in join entries and the instructions in each block.
+  // Verify phis in join entries and the instructions in each block.
   for (intptr_t i = 0; i < preorder_.length(); ++i) {
     BlockEntryInstr* entry = preorder_[i];
     JoinEntryInstr* join = entry->AsJoinEntry();
     if (join != NULL && join->phis() != NULL) {
       for (intptr_t i = 0; i < join->phis()->length(); ++i) {
         PhiInstr* phi = (*join->phis())[i];
-        if (phi != NULL) ValidateUseListsInInstruction(phi);
+        if (phi != NULL) VerifyUseListsInInstruction(phi);
       }
     }
     for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
-      ValidateUseListsInInstruction(it.Current());
+      VerifyUseListsInInstruction(it.Current());
     }
   }
   return true;  // Return true so we can ASSERT validation.
@@ -220,108 +211,6 @@
 #endif  // DEBUG
 
 
-static void ClearUseLists(Definition* defn) {
-  ASSERT(defn != NULL);
-  ASSERT(!defn->HasUses());
-  defn->set_input_use_list(NULL);
-  defn->set_env_use_list(NULL);
-}
-
-
-static void RecordInputUses(Instruction* instr) {
-  ASSERT(instr != NULL);
-  for (intptr_t i = 0; i < instr->InputCount(); ++i) {
-    Value* use = instr->InputAt(i);
-    ASSERT(use->instruction() == NULL);
-    ASSERT(use->use_index() == -1);
-    ASSERT(use->previous_use() == NULL);
-    ASSERT(use->next_use() == NULL);
-    DEBUG_ASSERT(!FLAG_verify_compiler ||
-        (0 == MembershipCount(use, use->definition()->input_use_list())));
-    use->set_instruction(instr);
-    use->set_use_index(i);
-    use->definition()->AddInputUse(use);
-  }
-}
-
-
-static void RecordEnvUses(Instruction* instr) {
-  ASSERT(instr != NULL);
-  if (instr->env() == NULL) return;
-  intptr_t use_index = 0;
-  for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) {
-    Value* use = it.CurrentValue();
-    ASSERT(use->instruction() == NULL);
-    ASSERT(use->use_index() == -1);
-    ASSERT(use->previous_use() == NULL);
-    ASSERT(use->next_use() == NULL);
-    DEBUG_ASSERT(!FLAG_verify_compiler ||
-        (0 == MembershipCount(use, use->definition()->env_use_list())));
-    use->set_instruction(instr);
-    use->set_use_index(use_index++);
-    use->definition()->AddEnvUse(use);
-  }
-}
-
-
-static void ComputeUseListsRecursive(BlockEntryInstr* block) {
-  // Clear phi definitions.
-  JoinEntryInstr* join = block->AsJoinEntry();
-  if (join != NULL && join->phis() != NULL) {
-    for (intptr_t i = 0; i < join->phis()->length(); ++i) {
-      PhiInstr* phi = (*join->phis())[i];
-      if (phi != NULL) ClearUseLists(phi);
-    }
-  }
-  // Compute uses on normal instructions.
-  for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
-    Instruction* instr = it.Current();
-    if (instr->IsDefinition()) ClearUseLists(instr->AsDefinition());
-    RecordInputUses(instr);
-    RecordEnvUses(instr);
-  }
-  // Compute recursively on dominated blocks.
-  for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
-    ComputeUseListsRecursive(block->dominated_blocks()[i]);
-  }
-  // Add phi uses on successor edges.
-  if (block->last_instruction()->SuccessorCount() == 1 &&
-      block->last_instruction()->SuccessorAt(0)->IsJoinEntry()) {
-    JoinEntryInstr* join =
-        block->last_instruction()->SuccessorAt(0)->AsJoinEntry();
-    intptr_t pred_index = join->IndexOfPredecessor(block);
-    ASSERT(pred_index >= 0);
-    if (join->phis() != NULL) {
-      for (intptr_t i = 0; i < join->phis()->length(); ++i) {
-        PhiInstr* phi = (*join->phis())[i];
-        if (phi == NULL) continue;
-        Value* use = phi->InputAt(pred_index);
-        ASSERT(use->instruction() == NULL);
-        ASSERT(use->use_index() == -1);
-        ASSERT(use->previous_use() == NULL);
-        ASSERT(use->next_use() == NULL);
-        DEBUG_ASSERT(!FLAG_verify_compiler ||
-            (0 == MembershipCount(use, use->definition()->input_use_list())));
-        use->set_instruction(phi);
-        use->set_use_index(pred_index);
-        use->definition()->AddInputUse(use);
-      }
-    }
-  }
-}
-
-
-void FlowGraph::ComputeUseLists() {
-  DEBUG_ASSERT(ResetUseLists());
-  // Clear initial definitions.
-  for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); ++i) {
-    ClearUseLists((*graph_entry_->initial_definitions())[i]);
-  }
-  ComputeUseListsRecursive(graph_entry_);
-  DEBUG_ASSERT(!FLAG_verify_compiler || ValidateUseLists());
-}
-
-
 void FlowGraph::ComputeSSA(intptr_t next_virtual_register_number,
                            GrowableArray<Definition*>* inlining_parameters) {
   ASSERT((next_virtual_register_number == 0) || (inlining_parameters != NULL));
@@ -581,9 +470,18 @@
     // at goto instructions. Optimizations like LICM expect an environment at
     // gotos.
     if (current->CanDeoptimize() || current->IsGoto()) {
-      current->set_env(Environment::From(*env,
-                                         num_non_copied_params_,
-                                         parsed_function_.function()));
+      Environment* deopt_env =
+          Environment::From(*env,
+                            num_non_copied_params_,
+                            parsed_function_.function());
+      current->set_env(deopt_env);
+      intptr_t use_index = 0;
+      for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) {
+        Value* use = it.CurrentValue();
+        use->set_instruction(current);
+        use->set_use_index(use_index++);
+        use->definition()->AddEnvUse(use);
+      }
     }
     if (current->CanDeoptimize()) {
       current->env()->set_deopt_id(current->deopt_id());
@@ -603,11 +501,16 @@
       Definition* input_defn = v->definition();
       if (input_defn->IsLoadLocal() || input_defn->IsStoreLocal()) {
         // Remove the load/store from the graph.
+        input_defn->UnuseAllInputs();
         input_defn->RemoveFromGraph();
         // Assert we are not referencing nulls in the initial environment.
         ASSERT(reaching_defn->ssa_temp_index() != -1);
-        current->SetInputAt(i, new Value(reaching_defn));
+        v->set_definition(reaching_defn);
+        input_defn = reaching_defn;
       }
+      v->set_instruction(current);
+      v->set_use_index(i);
+      input_defn->AddInputUse(v);
     }
 
     // Drop pushed arguments for calls.
@@ -645,6 +548,7 @@
           env->Add((*env)[index]);
           // We remove load/store instructions when we find their use in 2a.
         } else {
+          definition->UnuseAllInputs();
           it.RemoveCurrentFromGraph();
         }
       } else {
@@ -685,7 +589,11 @@
         PhiInstr* phi = (*successor->phis())[i];
         if (phi != NULL) {
           // Rename input operand.
-          phi->SetInputAt(pred_index, new Value((*env)[i]));
+          Value* use = new Value((*env)[i]);
+          phi->SetInputAt(pred_index, use);
+          use->set_instruction(phi);
+          use->set_use_index(pred_index);
+          use->definition()->AddInputUse(use);
         }
       }
     }
diff --git a/runtime/vm/flow_graph.h b/runtime/vm/flow_graph.h
index 81edee2..59c0c0d 100644
--- a/runtime/vm/flow_graph.h
+++ b/runtime/vm/flow_graph.h
@@ -6,17 +6,12 @@
 #define VM_FLOW_GRAPH_H_
 
 #include "vm/growable_array.h"
+#include "vm/intermediate_language.h"
 #include "vm/parser.h"
 
 namespace dart {
 
-class BlockEntryInstr;
-class ConstantInstr;
-class Definition;
 class FlowGraphBuilder;
-class GraphEntryInstr;
-class PhiInstr;
-class ReturnInstr;
 class ValueInliningContext;
 
 class BlockIterator : public ValueObject {
@@ -117,10 +112,18 @@
   ConstantInstr* AddConstantToInitialDefinitions(const Object& object);
   void AddToInitialDefinitions(Definition* defn);
 
+  void InsertBefore(Instruction* next,
+                    Instruction* instr,
+                    Environment* env,
+                    Definition::UseKind use_kind);
+  void InsertAfter(Instruction* prev,
+                   Instruction* instr,
+                   Environment* env,
+                   Definition::UseKind use_kind);
+
   // Operations on the flow graph.
   void ComputeSSA(intptr_t next_virtual_register_number,
                   GrowableArray<Definition*>* inlining_parameters);
-  void ComputeUseLists();
 
   // Finds natural loops in the flow graph and attaches a list of loop
   // body blocks for each loop header.
@@ -134,9 +137,8 @@
   void InvalidateDominatorTree() { invalid_dominator_tree_ = true; }
 
 #ifdef DEBUG
-  // Validation methods for debugging.
-  bool ResetUseLists();
-  bool ValidateUseLists();
+  // Verification methods for debugging.
+  bool VerifyUseLists();
 #endif  // DEBUG
 
  private:
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index 4adf681..a2b0c36 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -2432,9 +2432,11 @@
     for (ForwardInstructionIterator instr_it(block);
          !instr_it.Done();
          instr_it.Advance()) {
-      Instruction* instr = instr_it.Current();
-      if (instr->IsDefinition() && instr->representation() == kUnboxedMint) {
-        mint_values_->Add(instr->AsDefinition()->ssa_temp_index());
+      Definition* defn = instr_it.Current()->AsDefinition();
+      if ((defn != NULL) &&
+          (defn->ssa_temp_index() >= 0) &&
+          (defn->representation() == kUnboxedMint)) {
+        mint_values_->Add(defn->ssa_temp_index());
       }
     }
   }
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 909d937..8bcba37 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -4,6 +4,7 @@
 
 #include "vm/flow_graph_builder.h"
 
+#include "lib/invocation_mirror.h"
 #include "vm/ast_printer.h"
 #include "vm/code_descriptors.h"
 #include "vm/dart_entry.h"
@@ -136,6 +137,7 @@
   } else if (num_exits == 1) {
     // For just one exit, replace the uses and remove the call from the graph.
     call->ReplaceUsesWith(ValueAt(0)->definition());
+    ValueAt(0)->RemoveFromUseList();
     call->previous()->LinkTo(callee_entry->next());
     LastInstructionAt(0)->LinkTo(call->next());
     // In case of control flow, locally update the predecessors, phis and
@@ -210,6 +212,12 @@
       }
       // Replace uses of the call with the phi.
       call->ReplaceUsesWith(phi);
+    } else {
+      // In the case that the result is unused, remove the return value uses
+      // from their definition's use list.
+      for (intptr_t i = 0; i < num_exits; ++i) {
+        ValueAt(i)->RemoveFromUseList();
+      }
     }
     // Remove the call from the graph.
     call->previous()->LinkTo(callee_entry->next());
@@ -2367,9 +2375,15 @@
       // NoSuchMethodError.
 
       // Throw a NoSuchMethodError.
-      StaticCallInstr* call = BuildThrowNoSuchMethodError(node->token_pos(),
-                                                          node->cls(),
-                                                          getter_name);
+      StaticCallInstr* call = BuildThrowNoSuchMethodError(
+          node->token_pos(),
+          node->cls(),
+          getter_name,
+          InvocationMirror::EncodeType(
+              node->cls().IsTopLevel() ?
+                  InvocationMirror::kTopLevel :
+                  InvocationMirror::kStatic,
+              InvocationMirror::kGetter));
       ReturnDefinition(call);
       return;
     }
@@ -2411,9 +2425,15 @@
                                          arguments);
     } else {
       // Throw a NoSuchMethodError.
-      call = BuildThrowNoSuchMethodError(node->token_pos(),
-                                         node->cls(),
-                                         setter_name);
+      call = BuildThrowNoSuchMethodError(
+          node->token_pos(),
+          node->cls(),
+          setter_name,
+          InvocationMirror::EncodeType(
+            node->cls().IsTopLevel() ?
+                InvocationMirror::kTopLevel :
+                InvocationMirror::kStatic,
+            InvocationMirror::kGetter));
     }
   } else {
     if (is_super_setter) {
@@ -3090,7 +3110,8 @@
 StaticCallInstr* EffectGraphVisitor::BuildThrowNoSuchMethodError(
     intptr_t token_pos,
     const Class& function_class,
-    const String& function_name) {
+    const String& function_name,
+    int invocation_type) {
   ZoneGrowableArray<PushArgumentInstr*>* arguments =
       new ZoneGrowableArray<PushArgumentInstr*>();
   // Object receiver.
@@ -3109,6 +3130,10 @@
   const String& member_name = String::ZoneHandle(Symbols::New(function_name));
   Value* member_name_value = Bind(new ConstantInstr(member_name));
   arguments->Add(PushArgument(member_name_value));
+  // Smi invocation_type.
+  Value* invocation_type_value = Bind(new ConstantInstr(
+      Smi::ZoneHandle(Smi::New(invocation_type))));
+  arguments->Add(PushArgument(invocation_type_value));
   // List arguments.
   Value* arguments_value = Bind(new ConstantInstr(Array::ZoneHandle()));
   arguments->Add(PushArgument(arguments_value));
@@ -3219,7 +3244,7 @@
   TargetEntryInstr* normal_entry =
       new TargetEntryInstr(AllocateBlockId(),
                            CatchClauseNode::kInvalidTryIndex);
-  graph_entry_ = new GraphEntryInstr(normal_entry);
+  graph_entry_ = new GraphEntryInstr(parsed_function(), normal_entry);
   EffectGraphVisitor for_effect(this, 0);
   // TODO(kmillikin): We can eliminate stack checks in some cases (e.g., the
   // stack check on entry for leaf routines).
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index b30ad92..92f5174 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -317,7 +317,8 @@
 
   StaticCallInstr* BuildThrowNoSuchMethodError(intptr_t token_pos,
                                                const Class& function_class,
-                                               const String& function_name);
+                                               const String& function_name,
+                                               int invocation_type);
 
   void BuildStaticSetter(StaticSetterNode* node, bool result_is_needed);
   Definition* BuildStoreStaticField(StoreStaticFieldNode* node,
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 72e7d35..138ecf3 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -24,6 +24,7 @@
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, print_ast);
 DECLARE_FLAG(bool, print_scopes);
+DECLARE_FLAG(bool, enable_type_checks);
 DECLARE_FLAG(bool, eliminate_type_checks);
 
 
@@ -624,6 +625,12 @@
 
 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
   if (!is_optimizing()) {
+    if (FLAG_enable_type_checks && instr->IsAssertAssignable()) {
+      AssertAssignableInstr* assert = instr->AsAssertAssignable();
+      AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
+                           assert->deopt_id(),
+                           assert->token_pos());
+    }
     AllocateRegistersLocally(instr);
   }
 }
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index f92c613..6d62e562 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -23,6 +23,7 @@
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, print_ast);
 DECLARE_FLAG(bool, print_scopes);
+DECLARE_FLAG(bool, enable_type_checks);
 DECLARE_FLAG(bool, eliminate_type_checks);
 
 
@@ -620,6 +621,12 @@
 
 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
   if (!is_optimizing()) {
+    if (FLAG_enable_type_checks && instr->IsAssertAssignable()) {
+      AssertAssignableInstr* assert = instr->AsAssertAssignable();
+      AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
+                           assert->deopt_id(),
+                           assert->token_pos());
+    }
     AllocateRegistersLocally(instr);
   }
 }
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index bd74d4c..3fc75b3 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -491,7 +491,7 @@
         // Compute SSA on the callee graph, catching bailouts.
         callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(),
                                  &param_stubs);
-        callee_graph->ComputeUseLists();
+        DEBUG_ASSERT(callee_graph->VerifyUseLists());
       }
 
       {
@@ -501,7 +501,7 @@
         // TODO(zerny): Do more optimization passes on the callee graph.
         FlowGraphOptimizer optimizer(callee_graph);
         optimizer.ApplyICData();
-        callee_graph->ComputeUseLists();
+        DEBUG_ASSERT(callee_graph->VerifyUseLists());
       }
 
       if (FLAG_trace_inlining &&
@@ -561,13 +561,6 @@
         // Plug result in the caller graph.
         inlining_context->ReplaceCall(caller_graph_, call, callee_graph);
 
-        // Remove push arguments of the call.
-        for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-          PushArgumentInstr* push = call->ArgumentAt(i);
-          push->ReplaceUsesWith(push->value()->definition());
-          push->RemoveFromGraph();
-        }
-
         // Replace each stub with the actual argument or the caller's constant.
         // Nulls denote optional parameters for which no actual was given.
         for (intptr_t i = 0; i < arguments->length(); ++i) {
@@ -576,6 +569,14 @@
           if (actual != NULL) stub->ReplaceUsesWith(actual->definition());
         }
 
+        // Remove push arguments of the call.
+        for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+          PushArgumentInstr* push = call->PushArgumentAt(i);
+          push->ReplaceUsesWith(push->value()->definition());
+          push->UnuseAllInputs();
+          push->RemoveFromGraph();
+        }
+
         // Replace remaining constants with uses by constants in the caller's
         // initial definitions.
         GrowableArray<Definition*>* defns =
@@ -596,7 +597,7 @@
       if (!in_cache) function_cache_.Add(parsed_function);
 
       // Check that inlining maintains use lists.
-      DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->ValidateUseLists());
+      DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->VerifyUseLists());
 
       // Build succeeded so we restore the bailout jump.
       inlined_ = true;
@@ -652,7 +653,7 @@
       StaticCallInstr* call = calls[i];
       GrowableArray<Value*> arguments(call->ArgumentCount());
       for (int i = 0; i < call->ArgumentCount(); ++i) {
-        arguments.Add(call->ArgumentAt(i)->value());
+        arguments.Add(call->PushArgumentAt(i)->value());
       }
       TryInlining(call->function(), call->argument_names(), &arguments, call);
     }
@@ -667,14 +668,14 @@
       // Find the closure of the callee.
       ASSERT(call->ArgumentCount() > 0);
       const CreateClosureInstr* closure =
-          call->ArgumentAt(0)->value()->definition()->AsCreateClosure();
+          call->ArgumentAt(0)->AsCreateClosure();
       if (closure == NULL) {
         TRACE_INLINING(OS::Print("     Bailout: non-closure operator\n"));
         continue;
       }
       GrowableArray<Value*> arguments(call->ArgumentCount());
       for (int i = 0; i < call->ArgumentCount(); ++i) {
-        arguments.Add(call->ArgumentAt(i)->value());
+        arguments.Add(call->PushArgumentAt(i)->value());
       }
       TryInlining(closure->function(),
                   call->argument_names(),
@@ -710,7 +711,7 @@
       }
       GrowableArray<Value*> arguments(instr->ArgumentCount());
       for (int arg_i = 0; arg_i < instr->ArgumentCount(); ++arg_i) {
-        arguments.Add(instr->ArgumentAt(arg_i)->value());
+        arguments.Add(instr->PushArgumentAt(arg_i)->value());
       }
       TryInlining(target,
                   instr->instance_call()->argument_names(),
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index c72acf8..58cf837 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -33,6 +33,8 @@
 DEFINE_FLAG(int, max_polymorphic_checks, 4,
     "Maximum number of polymorphic check, otherwise it is megamorphic.");
 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis.");
+DEFINE_FLAG(bool, truncating_left_shift, true,
+    "Optimize left shift to truncate if possible");
 
 
 void FlowGraphOptimizer::ApplyICData() {
@@ -49,20 +51,20 @@
     ForwardInstructionIterator it(entry);
     current_iterator_ = &it;
     for (; !it.Done(); it.Advance()) {
-      if (it.Current()->IsInstanceCall()) {
-        InstanceCallInstr* call = it.Current()->AsInstanceCall();
+      Instruction* instr = it.Current();
+      if (instr->IsInstanceCall()) {
+        InstanceCallInstr* call = instr->AsInstanceCall();
         if (call->HasICData()) {
           if (TryCreateICData(call)) {
             VisitInstanceCall(call);
           }
         }
-      } else if (it.Current()->IsPolymorphicInstanceCall()) {
-        SpecializePolymorphicInstanceCall(
-            it.Current()->AsPolymorphicInstanceCall());
-      } else if (it.Current()->IsStrictCompare()) {
-        VisitStrictCompare(it.Current()->AsStrictCompare());
-      } else if (it.Current()->IsBranch()) {
-        ComparisonInstr* compare = it.Current()->AsBranch()->comparison();
+      } else if (instr->IsPolymorphicInstanceCall()) {
+        SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall());
+      } else if (instr->IsStrictCompare()) {
+        VisitStrictCompare(instr->AsStrictCompare());
+      } else if (instr->IsBranch()) {
+        ComparisonInstr* compare = instr->AsBranch()->comparison();
         if (compare->IsStrictCompare()) {
           VisitStrictCompare(compare->AsStrictCompare());
         }
@@ -84,7 +86,7 @@
   GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested());
   ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount());
   for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) {
-    intptr_t cid = call->ArgumentAt(i)->value()->Type()->ToCid();
+    intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid();
     class_ids.Add(cid);
   }
   // TODO(srdjan): Test for other class_ids > 1.
@@ -150,7 +152,8 @@
     return;  // Already specialized.
   }
 
-  const intptr_t receiver_cid  = call->ArgumentAt(0)->value()->Type()->ToCid();
+  const intptr_t receiver_cid =
+      call->PushArgumentAt(0)->value()->Type()->ToCid();
   if (receiver_cid == kDynamicCid) {
     return;  // No information about receiver was infered.
   }
@@ -166,6 +169,93 @@
 }
 
 
+static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
+  BinarySmiOpInstr* instr = d->AsBinarySmiOp();
+  if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
+    return instr;
+  }
+  return NULL;
+}
+
+
+static bool IsPositiveOrZeroSmiConst(Definition* d) {
+  ConstantInstr* const_instr = d->AsConstant();
+  if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
+    return Smi::Cast(const_instr->value()).Value() >= 0;
+  }
+  return false;
+}
+
+
+void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp(
+    Definition* bit_and_instr,
+    Definition* left_instr,
+    Definition* right_instr) {
+  ASSERT(bit_and_instr != NULL);
+  ASSERT((left_instr != NULL) && (right_instr != NULL));
+
+  // Check for pattern, smi_shift_left must be single-use.
+  bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
+  if (!is_positive_or_zero) {
+    is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
+  }
+  if (!is_positive_or_zero) return;
+
+  BinarySmiOpInstr* smi_shift_left = NULL;
+  if (bit_and_instr->InputAt(0)->IsSingleUse()) {
+    smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
+  }
+  if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
+    smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
+  }
+  if (smi_shift_left == NULL) return;
+
+  // Pattern recognized.
+  smi_shift_left->set_is_truncating(true);
+  ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
+  if (bit_and_instr->IsBinaryMintOp()) {
+    // Replace Mint op with Smi op.
+    BinarySmiOpInstr* smi_op = new BinarySmiOpInstr(
+        Token::kBIT_AND,
+        bit_and_instr->AsBinaryMintOp()->instance_call(),
+        new Value(left_instr),
+        new Value(right_instr));
+    bit_and_instr->ReplaceWith(smi_op, current_iterator());
+  }
+}
+
+
+// Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
+// shift can be a truncating Smi shift-left and result is always Smi.
+void FlowGraphOptimizer::TryOptimizeLeftShiftWithBitAndPattern() {
+  if (!FLAG_truncating_left_shift) return;
+  ASSERT(current_iterator_ == NULL);
+  for (intptr_t i = 0; i < block_order_.length(); ++i) {
+    BlockEntryInstr* entry = block_order_[i];
+    ForwardInstructionIterator it(entry);
+    current_iterator_ = &it;
+    for (; !it.Done(); it.Advance()) {
+      if (it.Current()->IsBinarySmiOp()) {
+        BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
+        if (binop->op_kind() == Token::kBIT_AND) {
+          OptimizeLeftShiftBitAndSmiOp(binop,
+                                       binop->left()->definition(),
+                                       binop->right()->definition());
+        }
+      } else if (it.Current()->IsBinaryMintOp()) {
+        BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
+        if (mintop->op_kind() == Token::kBIT_AND) {
+          OptimizeLeftShiftBitAndSmiOp(mintop,
+                                       mintop->left()->definition(),
+                                       mintop->right()->definition());
+        }
+      }
+    }
+    current_iterator_ = NULL;
+  }
+}
+
+
 static void EnsureSSATempIndex(FlowGraph* graph,
                                Definition* defn,
                                Definition* replacement) {
@@ -234,24 +324,32 @@
            (use->Type()->ToCid() == kDoubleCid));
     const intptr_t deopt_id = (deopt_target != NULL) ?
         deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
-    converted = new UnboxIntegerInstr(new Value(use->definition()), deopt_id);
+    converted = new UnboxIntegerInstr(use->CopyWithType(), deopt_id);
+
   } else if ((from == kUnboxedMint) && (to == kTagged)) {
-    converted = new BoxIntegerInstr(new Value(use->definition()));
+    converted = new BoxIntegerInstr(use->CopyWithType());
+
   } else if (from == kUnboxedMint && to == kUnboxedDouble) {
     // Convert by boxing/unboxing.
     // TODO(fschneider): Implement direct unboxed mint-to-double conversion.
-    BoxIntegerInstr* boxed = new BoxIntegerInstr(new Value(use->definition()));
+    BoxIntegerInstr* boxed = new BoxIntegerInstr(use->CopyWithType());
+    use->RemoveFromUseList();
+    use->set_definition(boxed);
+    boxed->AddInputUse(use);
     InsertBefore(insert_before, boxed, NULL, Definition::kValue);
+
     const intptr_t deopt_id = (deopt_target != NULL) ?
         deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
     converted = new UnboxDoubleInstr(new Value(boxed), deopt_id);
+
   } else if ((from == kUnboxedDouble) && (to == kTagged)) {
-    converted = new BoxDoubleInstr(new Value(use->definition()), NULL);
+    converted = new BoxDoubleInstr(use->CopyWithType(), NULL);
+
   } else if ((from == kTagged) && (to == kUnboxedDouble)) {
-    const intptr_t deopt_id = (deopt_target != NULL) ?
-        deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
     ASSERT((deopt_target != NULL) ||
            (use->Type()->ToCid() == kDoubleCid));
+    const intptr_t deopt_id = (deopt_target != NULL) ?
+        deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
     ConstantInstr* constant = use->definition()->AsConstant();
     if ((constant != NULL) && constant->value().IsSmi()) {
       const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue();
@@ -261,13 +359,15 @@
       InsertBefore(insert_before, double_const, NULL, Definition::kValue);
       converted = new UnboxDoubleInstr(new Value(double_const), deopt_id);
     } else {
-      converted = new UnboxDoubleInstr(new Value(use->definition()), deopt_id);
+      converted = new UnboxDoubleInstr(use->CopyWithType(), deopt_id);
     }
   }
   ASSERT(converted != NULL);
+  use->RemoveFromUseList();
+  use->set_definition(converted);
+  converted->AddInputUse(use);
   InsertBefore(insert_before, converted, use->instruction()->env(),
                Definition::kValue);
-  use->set_definition(converted);
 }
 
 
@@ -459,23 +559,16 @@
 }
 
 
-static void RemovePushArguments(InstanceCallInstr* call) {
-  // Remove original push arguments.
+void FlowGraphOptimizer::ReplaceCall(Definition* call,
+                                     Definition* replacement) {
+  // Remove the original push arguments.
   for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-    PushArgumentInstr* push = call->ArgumentAt(i);
+    PushArgumentInstr* push = call->PushArgumentAt(i);
     push->ReplaceUsesWith(push->value()->definition());
+    push->UnuseAllInputs();
     push->RemoveFromGraph();
   }
-}
-
-
-static void RemovePushArguments(StaticCallInstr* call) {
-  // Remove original push arguments.
-  for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-    PushArgumentInstr* push = call->ArgumentAt(i);
-    push->ReplaceUsesWith(push->value()->definition());
-    push->RemoveFromGraph();
-  }
+  call->ReplaceWith(replacement, current_iterator());
 }
 
 
@@ -496,19 +589,42 @@
 }
 
 
-void FlowGraphOptimizer::AddCheckClass(InstanceCallInstr* call,
-                                       Value* value) {
+void FlowGraphOptimizer::AddCheckSmi(Definition* to_check,
+                                     intptr_t deopt_id,
+                                     Environment* deopt_environment,
+                                     Instruction* insert_before) {
+  if (to_check->Type()->ToCid() != kSmiCid) {
+    InsertBefore(insert_before,
+                 new CheckSmiInstr(new Value(to_check), deopt_id),
+                 deopt_environment,
+                 Definition::kEffect);
+  }
+}
+
+
+void FlowGraphOptimizer::AddCheckClass(Definition* to_check,
+                                       const ICData& unary_checks,
+                                       intptr_t deopt_id,
+                                       Environment* deopt_environment,
+                                       Instruction* insert_before) {
   // Type propagation has not run yet, we cannot eliminate the check.
-  const ICData& unary_checks =
-      ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
   Instruction* check = NULL;
   if ((unary_checks.NumberOfChecks() == 1) &&
       (unary_checks.GetReceiverClassIdAt(0) == kSmiCid)) {
-    check = new CheckSmiInstr(value, call->deopt_id());
+    check = new CheckSmiInstr(new Value(to_check), deopt_id);
   } else {
-    check = new CheckClassInstr(value, call->deopt_id(), unary_checks);
+    check = new CheckClassInstr(new Value(to_check), deopt_id, unary_checks);
   }
-  InsertBefore(call, check, call->env(), Definition::kEffect);
+  InsertBefore(insert_before, check, deopt_environment, Definition::kEffect);
+}
+
+
+void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
+  AddCheckClass(call->ArgumentAt(0),
+                ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()),
+                call->deopt_id(),
+                call->env(),
+                call);
 }
 
 
@@ -530,46 +646,43 @@
 
 intptr_t FlowGraphOptimizer::PrepareIndexedOp(InstanceCallInstr* call,
                                               intptr_t class_id,
-                                              Value** array,
-                                              Value** index) {
-  *array = call->ArgumentAt(0)->value();
-  *index = call->ArgumentAt(1)->value();
+                                              Definition** array,
+                                              Definition** index) {
   // Insert class check and index smi checks and attach a copy of the
   // original environment because the operation can still deoptimize.
-  AddCheckClass(call, (*array)->Copy());
+  AddReceiverCheck(call);
   InsertBefore(call,
-               new CheckSmiInstr((*index)->Copy(), call->deopt_id()),
+               new CheckSmiInstr(new Value(*index), call->deopt_id()),
                call->env(),
                Definition::kEffect);
+
   // If both index and array are constants, then do a compile-time check.
   // TODO(srdjan): Remove once constant propagation handles bounds checks.
   bool skip_check = false;
-  if ((*array)->BindsToConstant() && (*index)->BindsToConstant()) {
-    ConstantInstr* array_def = (*array)->definition()->AsConstant();
+  if ((*array)->IsConstant() && (*index)->IsConstant()) {
     const ImmutableArray& constant_array =
-        ImmutableArray::Cast(array_def->value());
-    ConstantInstr* index_def = (*index)->definition()->AsConstant();
-    if (index_def->value().IsSmi()) {
-      intptr_t constant_index = Smi::Cast(index_def->value()).Value();
-      skip_check = (constant_index < constant_array.Length());
-    }
+        ImmutableArray::Cast((*array)->AsConstant()->value());
+    const Object& constant_index = (*index)->AsConstant()->value();
+      skip_check = constant_index.IsSmi() &&
+          (Smi::Cast(constant_index).Value() < constant_array.Length());
   }
   if (!skip_check) {
     // Insert array length load and bounds check.
     const bool is_immutable =
         CheckArrayBoundInstr::IsFixedLengthArrayType(class_id);
-    LoadFieldInstr* length = new LoadFieldInstr(
-        (*array)->Copy(),
-        CheckArrayBoundInstr::LengthOffsetFor(class_id),
-        Type::ZoneHandle(Type::SmiType()),
-        is_immutable);
+    LoadFieldInstr* length =
+        new LoadFieldInstr(new Value(*array),
+                           CheckArrayBoundInstr::LengthOffsetFor(class_id),
+                           Type::ZoneHandle(Type::SmiType()),
+                           is_immutable);
     length->set_result_cid(kSmiCid);
     length->set_recognized_kind(
         LoadFieldInstr::RecognizedKindFromArrayCid(class_id));
     InsertBefore(call, length, NULL, Definition::kValue);
+
     InsertBefore(call,
                  new CheckArrayBoundInstr(new Value(length),
-                                          (*index)->Copy(),
+                                          new Value(*index),
                                           class_id,
                                           call),
                  call->env(),
@@ -578,12 +691,12 @@
   if (class_id == kGrowableObjectArrayCid) {
     // Insert data elements load.
     LoadFieldInstr* elements =
-        new LoadFieldInstr((*array)->Copy(),
+        new LoadFieldInstr(new Value(*array),
                            GrowableObjectArray::data_offset(),
                            Type::ZoneHandle(Type::DynamicType()));
     elements->set_result_cid(kArrayCid);
     InsertBefore(call, elements, NULL, Definition::kValue);
-    *array = new Value(elements);
+    *array = elements;
     return kArrayCid;
   }
   return class_id;
@@ -651,9 +764,73 @@
       return false;
   }
 
+  BuildStoreIndexed(call, value_check, class_id);
+  return true;
+}
+
+
+bool FlowGraphOptimizer::TryInlineByteArraySetIndexed(InstanceCallInstr* call) {
+  const intptr_t class_id = ReceiverClassId(call);
+  ICData& value_check = ICData::ZoneHandle();
+  switch (class_id) {
+    case kInt8ArrayCid:
+    case kUint8ArrayCid:
+    case kUint8ClampedArrayCid:
+    case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
+    case kInt16ArrayCid:
+    case kUint16ArrayCid: {
+      // Check that value is always smi.
+      value_check = ICData::New(Function::Handle(),
+                                String::Handle(),
+                                Isolate::kNoDeoptId,
+                                1);
+      value_check.AddReceiverCheck(kSmiCid, Function::Handle());
+      break;
+    }
+    case kInt32ArrayCid:
+    case kUint32ArrayCid:
+      // Check if elements fit into a smi or the platform supports unboxed
+      // mints.
+      if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) {
+        return false;
+      }
+      // We don't have ICData for the value stored, so we optimistically assume
+      // smis first. If we ever deoptimized here, we require to unbox the value
+      // before storing to handle the mint case, too.
+      if (call->ic_data()->deopt_reason() == kDeoptUnknown) {
+        value_check = ICData::New(Function::Handle(),
+                                  String::Handle(),
+                                  Isolate::kNoDeoptId,
+                                  1);
+        value_check.AddReceiverCheck(kSmiCid, Function::Handle());
+      }
+      break;
+    case kFloat32ArrayCid:
+    case kFloat64ArrayCid: {
+      // Check that value is always double.
+      value_check = ICData::New(Function::Handle(),
+                                String::Handle(),
+                                Isolate::kNoDeoptId,
+                                1);
+      value_check.AddReceiverCheck(kDoubleCid, Function::Handle());
+      break;
+    }
+    default:
+      return false;
+  }
+  BuildStoreIndexed(call, value_check, class_id);
+  return true;
+}
+
+
+void FlowGraphOptimizer::BuildStoreIndexed(InstanceCallInstr* call,
+                                           const ICData& value_check,
+                                           intptr_t class_id) {
+  Definition* array = call->ArgumentAt(0);
+  Definition* index = call->ArgumentAt(1);
+  Definition* stored_value = call->ArgumentAt(2);
   if (FLAG_enable_type_checks) {
-    Value* array = call->ArgumentAt(0)->value();
-    Value* value = call->ArgumentAt(2)->value();
     // Only type check for the value. A type check for the index is not
     // needed here because we insert a deoptimizing smi-check for the case
     // the index is not a smi.
@@ -661,8 +838,8 @@
         Function::ZoneHandle(call->ic_data()->GetTargetAt(0));
     const AbstractType& value_type =
         AbstractType::ZoneHandle(target.ParameterTypeAt(2));
-    Value* instantiator = NULL;
-    Value* type_args = NULL;
+    Definition* instantiator = NULL;
+    Definition* type_args = NULL;
     switch (class_id) {
       case kArrayCid:
       case kGrowableObjectArrayCid: {
@@ -670,12 +847,12 @@
         intptr_t type_arguments_field_offset =
             instantiator_class.type_arguments_field_offset();
         LoadFieldInstr* load_type_args =
-            new LoadFieldInstr(array->Copy(),
+            new LoadFieldInstr(new Value(array),
                                type_arguments_field_offset,
                                Type::ZoneHandle());  // No type.
         InsertBefore(call, load_type_args, NULL, Definition::kValue);
-        instantiator = array->Copy();
-        type_args = new Value(load_type_args);
+        instantiator = array;
+        type_args = load_type_args;
         break;
       }
       case kInt8ArrayCid:
@@ -691,8 +868,7 @@
         // Fall through.
       case kFloat32ArrayCid:
       case kFloat64ArrayCid: {
-        instantiator = new Value(flow_graph_->constant_null());
-        type_args = new Value(flow_graph_->constant_null());
+        type_args = instantiator = flow_graph_->constant_null();
         ASSERT((class_id != kFloat32ArrayCid && class_id != kFloat64ArrayCid) ||
                value_type.IsDoubleType());
         ASSERT(value_type.IsInstantiated());
@@ -704,9 +880,9 @@
     }
     AssertAssignableInstr* assert_value =
         new AssertAssignableInstr(call->token_pos(),
-                                  value->Copy(),
-                                  instantiator,
-                                  type_args,
+                                  new Value(stored_value),
+                                  new Value(instantiator),
+                                  new Value(type_args),
                                   value_type,
                                   Symbols::Value());
     // Newly inserted instructions that can deoptimize or throw an exception
@@ -716,36 +892,22 @@
     InsertBefore(call, assert_value, call->env(), Definition::kValue);
   }
 
-  Value* array = NULL;
-  Value* index = NULL;
   intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index);
-  Value* value = call->ArgumentAt(2)->value();
   // Check if store barrier is needed.
-  bool needs_store_barrier = true;
+  bool needs_store_barrier = !RawObject::IsByteArrayClassId(array_cid);
   if (!value_check.IsNull()) {
     needs_store_barrier = false;
-    if (value_check.NumberOfChecks() == 1 &&
-        value_check.GetReceiverClassIdAt(0) == kSmiCid) {
-      InsertBefore(call,
-                   new CheckSmiInstr(value->Copy(), call->deopt_id()),
-                   call->env(),
-                   Definition::kEffect);
-    } else {
-      InsertBefore(call,
-                   new CheckClassInstr(value->Copy(),
-                                       call->deopt_id(),
-                                       value_check),
-                   call->env(),
-                   Definition::kEffect);
-    }
+    AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(),
+                  call);
   }
 
-  Definition* array_op =
-      new StoreIndexedInstr(array, index, value,
-                            needs_store_barrier, array_cid, call->deopt_id());
-  call->ReplaceWith(array_op, current_iterator());
-  RemovePushArguments(call);
-  return true;
+  Definition* array_op = new StoreIndexedInstr(new Value(array),
+                                               new Value(index),
+                                               new Value(stored_value),
+                                               needs_store_barrier,
+                                               array_cid,
+                                               call->deopt_id());
+  ReplaceCall(call, array_op);
 }
 
 
@@ -787,49 +949,20 @@
     default:
       return false;
   }
-  Value* array = NULL;
-  Value* index = NULL;
+  Definition* array = call->ArgumentAt(0);
+  Definition* index = call->ArgumentAt(1);
   intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index);
   Definition* array_op =
-      new LoadIndexedInstr(array,
-                           index,
+      new LoadIndexedInstr(new Value(array),
+                           new Value(index),
                            FlowGraphCompiler::ElementSizeFor(array_cid),
                            array_cid,
                            deopt_id);
-  call->ReplaceWith(array_op, current_iterator());
-  RemovePushArguments(call);
+  ReplaceCall(call, array_op);
   return true;
 }
 
 
-void FlowGraphOptimizer::InsertBefore(Instruction* next,
-                                      Instruction* instr,
-                                      Environment* env,
-                                      Definition::UseKind use_kind) {
-  if (env != NULL) env->DeepCopyTo(instr);
-  if (use_kind == Definition::kValue) {
-    ASSERT(instr->IsDefinition());
-    instr->AsDefinition()->set_ssa_temp_index(
-        flow_graph_->alloc_ssa_temp_index());
-  }
-  instr->InsertBefore(next);
-}
-
-
-void FlowGraphOptimizer::InsertAfter(Instruction* prev,
-                                     Instruction* instr,
-                                     Environment* env,
-                                     Definition::UseKind use_kind) {
-  if (env != NULL) env->DeepCopyTo(instr);
-  if (use_kind == Definition::kValue) {
-    ASSERT(instr->IsDefinition());
-    instr->AsDefinition()->set_ssa_temp_index(
-        flow_graph_->alloc_ssa_temp_index());
-  }
-  instr->InsertAfter(prev);
-}
-
-
 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
                                                 Token::Kind op_kind) {
   intptr_t operands_type = kIllegalCid;
@@ -926,89 +1059,77 @@
       break;
     default:
       UNREACHABLE();
-  };
+  }
 
   ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
   if (operands_type == kDoubleCid) {
-    Value* left = call->ArgumentAt(0)->value();
-    Value* right = call->ArgumentAt(1)->value();
-
-    // Check that either left or right are not a smi.  Result or a
+    // Check that either left or right are not a smi.  Result of a
     // binary operation with two smis is a smi not a double.
     InsertBefore(call,
-                 new CheckEitherNonSmiInstr(left->Copy(),
-                                            right->Copy(),
+                 new CheckEitherNonSmiInstr(new Value(left),
+                                            new Value(right),
                                             call),
                  call->env(),
                  Definition::kEffect);
 
     BinaryDoubleOpInstr* double_bin_op =
-        new BinaryDoubleOpInstr(op_kind, left->Copy(), right->Copy(), call);
-    call->ReplaceWith(double_bin_op, current_iterator());
-    RemovePushArguments(call);
+        new BinaryDoubleOpInstr(op_kind, new Value(left), new Value(right),
+                                call);
+    ReplaceCall(call, double_bin_op);
   } else if (operands_type == kMintCid) {
     if (!FlowGraphCompiler::SupportsUnboxedMints()) return false;
-    Value* left = call->ArgumentAt(0)->value();
-    Value* right = call->ArgumentAt(1)->value();
     if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
       ShiftMintOpInstr* shift_op =
-          new ShiftMintOpInstr(op_kind, left, right, call);
-      call->ReplaceWith(shift_op, current_iterator());
+          new ShiftMintOpInstr(op_kind, new Value(left), new Value(right),
+                               call);
+      ReplaceCall(call, shift_op);
     } else {
       BinaryMintOpInstr* bin_op =
-          new BinaryMintOpInstr(op_kind, left, right, call);
-      call->ReplaceWith(bin_op, current_iterator());
+          new BinaryMintOpInstr(op_kind, new Value(left), new Value(right),
+                                call);
+      ReplaceCall(call, bin_op);
     }
-    RemovePushArguments(call);
   } else if (op_kind == Token::kMOD) {
     // TODO(vegorov): implement fast path code for modulo.
     ASSERT(operands_type == kSmiCid);
-    if (!call->ArgumentAt(1)->value()->BindsToConstant()) return false;
-    const Object& obj = call->ArgumentAt(1)->value()->BoundConstant();
+    if (!right->IsConstant()) return false;
+    const Object& obj = right->AsConstant()->value();
     if (!obj.IsSmi()) return false;
     const intptr_t value = Smi::Cast(obj).Value();
-    if ((value > 0) && Utils::IsPowerOfTwo(value)) {
-      Value* left = call->ArgumentAt(0)->value();
-      // Insert smi check and attach a copy of the original
-      // environment because the smi operation can still deoptimize.
-      InsertBefore(call,
-                   new CheckSmiInstr(left->Copy(), call->deopt_id()),
-                   call->env(),
-                   Definition::kEffect);
-      ConstantInstr* c = new ConstantInstr(Smi::Handle(Smi::New(value - 1)));
-      InsertBefore(call, c, NULL, Definition::kValue);
-      BinarySmiOpInstr* bin_op =
-          new BinarySmiOpInstr(Token::kBIT_AND, call, left, new Value(c));
-      call->ReplaceWith(bin_op, current_iterator());
-      RemovePushArguments(call);
-    } else {
-      // Did not replace.
-      return false;
-    }
+    if ((value <= 0) || !Utils::IsPowerOfTwo(value)) return false;
+
+    // Insert smi check and attach a copy of the original environment
+    // because the smi operation can still deoptimize.
+    InsertBefore(call,
+                 new CheckSmiInstr(new Value(left), call->deopt_id()),
+                 call->env(),
+                 Definition::kEffect);
+    ConstantInstr* constant =
+        new ConstantInstr(Smi::Handle(Smi::New(value - 1)));
+    InsertBefore(call, constant, NULL, Definition::kValue);
+    BinarySmiOpInstr* bin_op =
+        new BinarySmiOpInstr(Token::kBIT_AND, call,
+                             new Value(left),
+                             new Value(constant));
+    ReplaceCall(call, bin_op);
   } else {
     ASSERT(operands_type == kSmiCid);
-    Value* left = call->ArgumentAt(0)->value();
-    Value* right = call->ArgumentAt(1)->value();
     // Insert two smi checks and attach a copy of the original
     // environment because the smi operation can still deoptimize.
-    InsertBefore(call,
-                 new CheckSmiInstr(left->Copy(), call->deopt_id()),
-                 call->env(),
-                 Definition::kEffect);
-    InsertBefore(call,
-                 new CheckSmiInstr(right->Copy(), call->deopt_id()),
-                 call->env(),
-                 Definition::kEffect);
-    if (left->BindsToConstant() &&
+    AddCheckSmi(left, call->deopt_id(), call->env(), call);
+    AddCheckSmi(right, call->deopt_id(), call->env(), call);
+    if (left->IsConstant() &&
         ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) {
       // Constant should be on the right side.
-      Value* temp = left;
+      Definition* temp = left;
       left = right;
       right = temp;
     }
-    BinarySmiOpInstr* bin_op = new BinarySmiOpInstr(op_kind, call, left, right);
-    call->ReplaceWith(bin_op, current_iterator());
-    RemovePushArguments(call);
+    BinarySmiOpInstr* bin_op =
+        new BinarySmiOpInstr(op_kind, call, new Value(left), new Value(right));
+    ReplaceCall(call, bin_op);
   }
   return true;
 }
@@ -1017,35 +1138,32 @@
 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
                                                Token::Kind op_kind) {
   ASSERT(call->ArgumentCount() == 1);
+  Definition* input = call->ArgumentAt(0);
   Definition* unary_op = NULL;
   if (HasOnlyOneSmi(*call->ic_data())) {
-    Value* value = call->ArgumentAt(0)->value();
     InsertBefore(call,
-                 new CheckSmiInstr(value->Copy(), call->deopt_id()),
+                 new CheckSmiInstr(new Value(input), call->deopt_id()),
                  call->env(),
                  Definition::kEffect);
-    unary_op = new UnarySmiOpInstr(op_kind, call, value);
+    unary_op = new UnarySmiOpInstr(op_kind, call, new Value(input));
   } else if ((op_kind == Token::kBIT_NOT) &&
              HasOnlySmiOrMint(*call->ic_data()) &&
              FlowGraphCompiler::SupportsUnboxedMints()) {
-    Value* value = call->ArgumentAt(0)->value();
-    unary_op = new UnaryMintOpInstr(op_kind, value, call);
+    unary_op = new UnaryMintOpInstr(op_kind, new Value(input), call);
   } else if (HasOnlyOneDouble(*call->ic_data()) &&
              (op_kind == Token::kNEGATE)) {
-    Value* value = call->ArgumentAt(0)->value();
-    AddCheckClass(call, value->Copy());
+    AddReceiverCheck(call);
     ConstantInstr* minus_one =
         new ConstantInstr(Double::ZoneHandle(Double::NewCanonical(-1)));
     InsertBefore(call, minus_one, NULL, Definition::kValue);
     unary_op = new BinaryDoubleOpInstr(Token::kMUL,
-                                       value,
+                                       new Value(input),
                                        new Value(minus_one),
                                        call);
   }
   if (unary_op == NULL) return false;
 
-  call->ReplaceWith(unary_op, current_iterator());
-  RemovePushArguments(call);
+  ReplaceCall(call, unary_op);
   return true;
 }
 
@@ -1071,7 +1189,7 @@
 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck(
     InstanceCallInstr* call) const {
   if (!FLAG_use_cha) return true;
-  Definition* callee_receiver = call->ArgumentAt(0)->value()->definition();
+  Definition* callee_receiver = call->ArgumentAt(0);
   ASSERT(callee_receiver != NULL);
   const Function& function = flow_graph_->parsed_function().function();
   if (function.IsDynamicFunction() &&
@@ -1087,7 +1205,7 @@
 bool FlowGraphOptimizer::MethodExtractorNeedsClassCheck(
     InstanceCallInstr* call) const {
   if (!FLAG_use_cha) return true;
-  Definition* callee_receiver = call->ArgumentAt(0)->value()->definition();
+  Definition* callee_receiver = call->ArgumentAt(0);
   ASSERT(callee_receiver != NULL);
   const Function& function = flow_graph_->parsed_function().function();
   if (function.IsDynamicFunction() &&
@@ -1115,18 +1233,20 @@
   ASSERT(!field.IsNull());
 
   if (InstanceCallNeedsClassCheck(call)) {
-    AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
+    AddReceiverCheck(call);
   }
-  // Detach environment from the original instruction because it can't
-  // deoptimize.
-  call->set_env(NULL);
   LoadFieldInstr* load = new LoadFieldInstr(
-      call->ArgumentAt(0)->value(),
+      new Value(call->ArgumentAt(0)),
       field.Offset(),
       AbstractType::ZoneHandle(field.type()),
       field.is_final());
-  call->ReplaceWith(load, current_iterator());
-  RemovePushArguments(call);
+  // Detach environment from the original instruction because it can't
+  // deoptimize.
+  for (Environment::DeepIterator it(call->env()); !it.Done(); it.Advance()) {
+    it.CurrentValue()->RemoveFromUseList();
+  }
+  call->set_env(NULL);
+  ReplaceCall(call, load);
 }
 
 
@@ -1134,29 +1254,26 @@
                                                  intptr_t length_offset,
                                                  bool is_immutable,
                                                  MethodRecognizer::Kind kind) {
-  // Check receiver class.
-  AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
+  AddReceiverCheck(call);
 
   LoadFieldInstr* load = new LoadFieldInstr(
-      call->ArgumentAt(0)->value(),
+      new Value(call->ArgumentAt(0)),
       length_offset,
       Type::ZoneHandle(Type::SmiType()),
       is_immutable);
   load->set_result_cid(kSmiCid);
   load->set_recognized_kind(kind);
-  call->ReplaceWith(load, current_iterator());
-  RemovePushArguments(call);
+  ReplaceCall(call, load);
 }
 
 
 void FlowGraphOptimizer::InlineGrowableArrayCapacityGetter(
     InstanceCallInstr* call) {
-  // Check receiver class.
-  AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
+  AddReceiverCheck(call);
 
   // TODO(srdjan): type of load should be GrowableObjectArrayType.
   LoadFieldInstr* data_load = new LoadFieldInstr(
-      call->ArgumentAt(0)->value(),
+      new Value(call->ArgumentAt(0)),
       Array::data_offset(),
       Type::ZoneHandle(Type::DynamicType()));
   data_load->set_result_cid(kArrayCid);
@@ -1169,18 +1286,17 @@
   length_load->set_result_cid(kSmiCid);
   length_load->set_recognized_kind(MethodRecognizer::kObjectArrayLength);
 
-  call->ReplaceWith(length_load, current_iterator());
-  RemovePushArguments(call);
+  ReplaceCall(call, length_load);
 }
 
 
-static LoadFieldInstr* BuildLoadStringLength(Value* str) {
+static LoadFieldInstr* BuildLoadStringLength(Definition* str) {
   // Treat length loads as mutable (i.e. affected by side effects) to avoid
   // hoisting them since we can't hoist the preceding class-check. This
   // is because of externalization of strings that affects their class-id.
   const bool is_immutable = false;
   LoadFieldInstr* load = new LoadFieldInstr(
-      str,
+      new Value(str),
       String::length_offset(),
       Type::ZoneHandle(Type::SmiType()),
       is_immutable);
@@ -1191,20 +1307,16 @@
 
 
 void FlowGraphOptimizer::InlineStringLengthGetter(InstanceCallInstr* call) {
-  // Check receiver class.
-  AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
-
-  LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)->value());
-  call->ReplaceWith(load, current_iterator());
-  RemovePushArguments(call);
+  AddReceiverCheck(call);
+  LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0));
+  ReplaceCall(call, load);
 }
 
 
 void FlowGraphOptimizer::InlineStringIsEmptyGetter(InstanceCallInstr* call) {
-  // Check receiver class.
-  AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
+  AddReceiverCheck(call);
 
-  LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)->value());
+  LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0));
   InsertBefore(call, load, NULL, Definition::kValue);
 
   ConstantInstr* zero = new ConstantInstr(Smi::Handle(Smi::New(0)));
@@ -1214,8 +1326,7 @@
       new StrictCompareInstr(Token::kEQ_STRICT,
                              new Value(load),
                              new Value(zero));
-  call->ReplaceWith(compare, current_iterator());
-  RemovePushArguments(call);
+  ReplaceCall(call, compare);
 }
 
 
@@ -1306,40 +1417,37 @@
 LoadIndexedInstr* FlowGraphOptimizer::BuildStringCharCodeAt(
     InstanceCallInstr* call,
     intptr_t cid) {
-  Value* str = call->ArgumentAt(0)->value();
-  Value* index = call->ArgumentAt(1)->value();
-  AddCheckClass(call, str->Copy());
+  Definition* str = call->ArgumentAt(0);
+  Definition* index = call->ArgumentAt(1);
+  AddReceiverCheck(call);
   InsertBefore(call,
-               new CheckSmiInstr(index->Copy(), call->deopt_id()),
+               new CheckSmiInstr(new Value(index), call->deopt_id()),
                call->env(),
                Definition::kEffect);
   // If both index and string are constants, then do a compile-time check.
   // TODO(srdjan): Remove once constant propagation handles bounds checks.
   bool skip_check = false;
-  if (str->BindsToConstant() && index->BindsToConstant()) {
-    ConstantInstr* string_def = str->definition()->AsConstant();
+  if (str->IsConstant() && index->IsConstant()) {
     const String& constant_string =
-        String::Cast(string_def->value());
-    ConstantInstr* index_def = index->definition()->AsConstant();
-    if (index_def->value().IsSmi()) {
-      intptr_t constant_index = Smi::Cast(index_def->value()).Value();
-      skip_check = (constant_index < constant_string.Length());
-    }
+        String::Cast(str->AsConstant()->value());
+    const Object& constant_index = index->AsConstant()->value();
+    skip_check = constant_index.IsSmi() &&
+        (Smi::Cast(constant_index).Value() < constant_string.Length());
   }
   if (!skip_check) {
     // Insert bounds check.
-    LoadFieldInstr* length = BuildLoadStringLength(str->Copy());
+    LoadFieldInstr* length = BuildLoadStringLength(str);
     InsertBefore(call, length, NULL, Definition::kValue);
     InsertBefore(call,
                  new CheckArrayBoundInstr(new Value(length),
-                                          index->Copy(),
+                                          new Value(index),
                                           cid,
                                           call),
                  call->env(),
                  Definition::kEffect);
   }
-  return new LoadIndexedInstr(str,
-                              index,
+  return new LoadIndexedInstr(new Value(str),
+                              new Value(index),
                               FlowGraphCompiler::ElementSizeFor(cid),
                               cid,
                               Isolate::kNoDeoptId);  // Can't deoptimize.
@@ -1349,16 +1457,15 @@
 void FlowGraphOptimizer::ReplaceWithMathCFunction(
   InstanceCallInstr* call,
   MethodRecognizer::Kind recognized_kind) {
-  AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
+  AddReceiverCheck(call);
   ZoneGrowableArray<Value*>* args =
       new ZoneGrowableArray<Value*>(call->ArgumentCount());
   for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
-    args->Add(call->ArgumentAt(i)->value());
+    args->Add(new Value(call->ArgumentAt(i)));
   }
   InvokeMathCFunctionInstr* invoke =
       new InvokeMathCFunctionInstr(args, call, recognized_kind);
-  call->ReplaceWith(invoke, current_iterator());
-  RemovePushArguments(call);
+  ReplaceCall(call, invoke);
 }
 
 
@@ -1390,18 +1497,51 @@
     // No type feedback collected or multiple targets found.
     return false;
   }
+
   Function& target = Function::Handle();
   GrowableArray<intptr_t> class_ids;
   ic_data.GetCheckAt(0, &class_ids, &target);
   MethodRecognizer::Kind recognized_kind =
       MethodRecognizer::RecognizeKind(target);
+
+  // Byte array access.
+  switch (recognized_kind) {
+    case MethodRecognizer::kFloat32ArrayGetIndexed:
+    case MethodRecognizer::kFloat64ArrayGetIndexed:
+    case MethodRecognizer::kInt8ArrayGetIndexed:
+    case MethodRecognizer::kUint8ArrayGetIndexed:
+    case MethodRecognizer::kUint8ClampedArrayGetIndexed:
+    case MethodRecognizer::kExternalUint8ArrayGetIndexed:
+    case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
+    case MethodRecognizer::kInt16ArrayGetIndexed:
+    case MethodRecognizer::kUint16ArrayGetIndexed:
+    case MethodRecognizer::kInt32ArrayGetIndexed:
+    case MethodRecognizer::kUint32ArrayGetIndexed:
+      return TryReplaceWithLoadIndexed(call);
+
+    case MethodRecognizer::kFloat32ArraySetIndexed:
+    case MethodRecognizer::kFloat64ArraySetIndexed:
+    case MethodRecognizer::kInt8ArraySetIndexed:
+    case MethodRecognizer::kUint8ArraySetIndexed:
+    case MethodRecognizer::kUint8ClampedArraySetIndexed:
+    case MethodRecognizer::kExternalUint8ArraySetIndexed:
+    case MethodRecognizer::kExternalUint8ClampedArraySetIndexed:
+    case MethodRecognizer::kInt16ArraySetIndexed:
+    case MethodRecognizer::kUint16ArraySetIndexed:
+    case MethodRecognizer::kInt32ArraySetIndexed:
+    case MethodRecognizer::kUint32ArraySetIndexed:
+      return TryInlineByteArraySetIndexed(call);
+
+    default:
+      break;
+  }
+
   if ((recognized_kind == MethodRecognizer::kStringBaseCharCodeAt) &&
       (ic_data.NumberOfChecks() == 1) &&
       ((class_ids[0] == kOneByteStringCid) ||
        (class_ids[0] == kTwoByteStringCid))) {
     LoadIndexedInstr* instr = BuildStringCharCodeAt(call, class_ids[0]);
-    call->ReplaceWith(instr, current_iterator());
-    RemovePushArguments(call);
+    ReplaceCall(call, instr);
     return true;
   }
   if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) &&
@@ -1414,8 +1554,7 @@
     StringFromCharCodeInstr* char_at =
         new StringFromCharCodeInstr(new Value(load_char_code),
                                     kOneByteStringCid);
-    call->ReplaceWith(char_at, current_iterator());
-    RemovePushArguments(call);
+    ReplaceCall(call, char_at);
     return true;
   }
 
@@ -1431,20 +1570,19 @@
   if (class_ids[0] == kDoubleCid) {
     switch (recognized_kind) {
       case MethodRecognizer::kDoubleToInteger: {
-        AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
+        AddReceiverCheck(call);
         ASSERT(call->HasICData());
         const ICData& ic_data = *call->ic_data();
+        Definition* input = call->ArgumentAt(0);
         Definition* d2i_instr = NULL;
         if (ic_data.deopt_reason() == kDeoptDoubleToSmi) {
           // Do not repeatedly deoptimize because result didn't fit into Smi.
-          d2i_instr = new DoubleToIntegerInstr(call->ArgumentAt(0)->value(),
-                                               call);
+          d2i_instr = new DoubleToIntegerInstr(new Value(input), call);
         } else {
           // Optimistically assume result fits into Smi.
-          d2i_instr = new DoubleToSmiInstr(call->ArgumentAt(0)->value(), call);
+          d2i_instr = new DoubleToSmiInstr(new Value(input), call);
         }
-        call->ReplaceWith(d2i_instr, current_iterator());
-        RemovePushArguments(call);
+        ReplaceCall(call, d2i_instr);
         return true;
       }
       case MethodRecognizer::kDoubleMod:
@@ -1458,13 +1596,12 @@
         if (!CPUFeatures::double_truncate_round_supported()) {
           ReplaceWithMathCFunction(call, recognized_kind);
         } else {
-          AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
+          AddReceiverCheck(call);
           DoubleToDoubleInstr* d2d_instr =
-              new DoubleToDoubleInstr(call->ArgumentAt(0)->value(),
+              new DoubleToDoubleInstr(new Value(call->ArgumentAt(0)),
                                       call,
                                       recognized_kind);
-          call->ReplaceWith(d2d_instr, current_iterator());
-          RemovePushArguments(call);
+          ReplaceCall(call, d2d_instr);
         }
         return true;
       default:
@@ -1490,9 +1627,19 @@
         array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint16ArrayCid);
         break;
       case MethodRecognizer::kByteArrayBaseGetInt32:
+        // Check if elements fit into a smi or the platform supports unboxed
+        // mints.
+        if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) {
+          return false;
+        }
         array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt32ArrayCid);
         break;
       case MethodRecognizer::kByteArrayBaseGetUint32:
+        // Check if elements fit into a smi or the platform supports unboxed
+        // mints.
+        if ((kSmiBits < 32) && !FlowGraphCompiler::SupportsUnboxedMints()) {
+          return false;
+        }
         array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint32ArrayCid);
         break;
       case MethodRecognizer::kByteArrayBaseGetFloat32:
@@ -1506,8 +1653,7 @@
         return false;
     }
     ASSERT(array_op != NULL);
-    call->ReplaceWith(array_op, current_iterator());
-    RemovePushArguments(call);
+    ReplaceCall(call, array_op);
     return true;
   }
   return false;
@@ -1518,50 +1664,50 @@
     InstanceCallInstr* call,
     intptr_t receiver_cid,
     intptr_t view_cid) {
-    Value* array = call->ArgumentAt(0)->value();
-    Value* byte_index = call->ArgumentAt(1)->value();
+  Definition* array = call->ArgumentAt(0);
+  Definition* byte_index = call->ArgumentAt(1);
 
-    AddCheckClass(call, array->Copy());
-    const bool is_immutable = true;
-    LoadFieldInstr* length = new LoadFieldInstr(
-        array->Copy(),
-        CheckArrayBoundInstr::LengthOffsetFor(receiver_cid),
-        Type::ZoneHandle(Type::SmiType()),
-        is_immutable);
-    length->set_result_cid(kSmiCid);
-    length->set_recognized_kind(
-        LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid));
-    InsertBefore(call, length, NULL, Definition::kValue);
+  AddReceiverCheck(call);
+  const bool is_immutable = true;
+  LoadFieldInstr* length = new LoadFieldInstr(
+      new Value(array),
+      CheckArrayBoundInstr::LengthOffsetFor(receiver_cid),
+      Type::ZoneHandle(Type::SmiType()),
+      is_immutable);
+  length->set_result_cid(kSmiCid);
+  length->set_recognized_kind(
+      LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid));
+  InsertBefore(call, length, NULL, Definition::kValue);
 
-    // len_in_bytes = length * kBytesPerElement(receiver)
-    intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid);
-    ConstantInstr* bytes_per_element =
-        new ConstantInstr(Smi::Handle(Smi::New(element_size)));
-    InsertBefore(call, bytes_per_element, NULL, Definition::kValue);
-    BinarySmiOpInstr* len_in_bytes =
-        new BinarySmiOpInstr(Token::kMUL,
-                             call,
-                             new Value(length),
-                             new Value(bytes_per_element));
-    InsertBefore(call, len_in_bytes, call->env(), Definition::kValue);
+  // len_in_bytes = length * kBytesPerElement(receiver)
+  intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid);
+  ConstantInstr* bytes_per_element =
+      new ConstantInstr(Smi::Handle(Smi::New(element_size)));
+  InsertBefore(call, bytes_per_element, NULL, Definition::kValue);
+  BinarySmiOpInstr* len_in_bytes =
+      new BinarySmiOpInstr(Token::kMUL,
+                           call,
+                           new Value(length),
+                           new Value(bytes_per_element));
+  InsertBefore(call, len_in_bytes, call->env(), Definition::kValue);
 
     // Check byte_index < len_in_bytes.
-    InsertBefore(call,
-                 new CheckArrayBoundInstr(new Value(len_in_bytes),
-                                          byte_index->Copy(),
-                                          receiver_cid,
-                                          call),
-                 call->env(),
-                 Definition::kEffect);
+  InsertBefore(call,
+               new CheckArrayBoundInstr(new Value(len_in_bytes),
+                                        new Value(byte_index),
+                                        receiver_cid,
+                                        call),
+               call->env(),
+               Definition::kEffect);
 
-    // TODO(fschneider): Optimistically build smi load for Int32 and Uint32
-    // loads on ia32 like we do for normal array loads, and only revert to
-    // mint case after deoptimizing here.
-    return new LoadIndexedInstr(array,
-                                byte_index,
-                                1,  // Index scale.
-                                view_cid,
-                                Isolate::kNoDeoptId);  // Can't deoptimize.
+  // TODO(fschneider): Optimistically build smi load for Int32 and Uint32
+  // loads on ia32 like we do for normal array loads, and only revert to
+  // mint case after deoptimizing here.
+  return new LoadIndexedInstr(new Value(array),
+                              new Value(byte_index),
+                              1,  // Index scale.
+                              view_cid,
+                              Isolate::kNoDeoptId);  // Can't deoptimize.
 }
 
 
@@ -1597,37 +1743,35 @@
 // TODO(srdjan): Use ICData to check if always true or false.
 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
   ASSERT(Token::IsTypeTestOperator(call->token_kind()));
-  Value* left_val = call->ArgumentAt(0)->value();
-  Value* instantiator_val = call->ArgumentAt(1)->value();
-  Value* type_args_val = call->ArgumentAt(2)->value();
+  Definition* left = call->ArgumentAt(0);
+  Definition* instantiator = call->ArgumentAt(1);
+  Definition* type_args = call->ArgumentAt(2);
   const AbstractType& type =
-      AbstractType::Cast(call->ArgumentAt(3)->value()->BoundConstant());
+      AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value());
   const bool negate =
-      Bool::Cast(call->ArgumentAt(4)->value()->BoundConstant()).value();
+      Bool::Cast(call->ArgumentAt(4)->AsConstant()->value()).value();
   const ICData& unary_checks =
       ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks());
   if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
     Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type));
     if (!as_bool.IsNull()) {
-      AddCheckClass(call, left_val->Copy());
+      AddReceiverCheck(call);
       if (negate) {
-        as_bool = as_bool.value() ? Bool::False().raw() : Bool::True().raw();
+        as_bool = Bool::Get(!as_bool.value());
       }
       ConstantInstr* bool_const = new ConstantInstr(as_bool);
-      call->ReplaceWith(bool_const, current_iterator());
-      RemovePushArguments(call);
+      ReplaceCall(call, bool_const);
       return;
     }
   }
   InstanceOfInstr* instance_of =
       new InstanceOfInstr(call->token_pos(),
-                          left_val,
-                          instantiator_val,
-                          type_args_val,
+                          new Value(left),
+                          new Value(instantiator),
+                          new Value(type_args),
                           type,
                           negate);
-  call->ReplaceWith(instance_of, current_iterator());
-  RemovePushArguments(call);
+  ReplaceCall(call, instance_of);
 }
 
 
@@ -1635,7 +1779,6 @@
 // (e.g, binary op, field load, ..).
 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
   if (!instr->HasICData() || (instr->ic_data()->NumberOfChecks() == 0)) {
-    // An instance call without ICData will trigger deoptimization.
     return;
   }
 
@@ -1703,7 +1846,7 @@
     bool call_with_checks;
     if (has_one_target) {
       // Type propagation has not run yet, we cannot eliminate the check.
-      AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy());
+      AddReceiverCheck(instr);
       // Call can still deoptimize, do not detach environment from instr.
       call_with_checks = false;
     } else {
@@ -1721,9 +1864,9 @@
   MethodRecognizer::Kind recognized_kind =
       MethodRecognizer::RecognizeKind(call->function());
   if (recognized_kind == MethodRecognizer::kMathSqrt) {
-    MathSqrtInstr* sqrt = new MathSqrtInstr(call->ArgumentAt(0)->value(), call);
-    call->ReplaceWith(sqrt, current_iterator());
-    RemovePushArguments(call);
+    MathSqrtInstr* sqrt =
+        new MathSqrtInstr(new Value(call->ArgumentAt(0)), call);
+    ReplaceCall(call, sqrt);
   }
 }
 
@@ -1761,51 +1904,50 @@
   ASSERT(!field.IsNull());
 
   if (InstanceCallNeedsClassCheck(instr)) {
-    AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy());
+    AddReceiverCheck(instr);
   }
   bool needs_store_barrier = true;
   if (ArgIsAlwaysSmi(*instr->ic_data(), 1)) {
     InsertBefore(instr,
-                 new CheckSmiInstr(instr->ArgumentAt(1)->value()->Copy(),
+                 new CheckSmiInstr(new Value(instr->ArgumentAt(1)),
                                    instr->deopt_id()),
                  instr->env(),
                  Definition::kEffect);
     needs_store_barrier = false;
   }
-  // Detach environment from the original instruction because it can't
-  // deoptimize.
-  instr->set_env(NULL);
   StoreInstanceFieldInstr* store = new StoreInstanceFieldInstr(
       field,
-      instr->ArgumentAt(0)->value(),
-      instr->ArgumentAt(1)->value(),
+      new Value(instr->ArgumentAt(0)),
+      new Value(instr->ArgumentAt(1)),
       needs_store_barrier);
-  instr->ReplaceWith(store, current_iterator());
-  RemovePushArguments(instr);
+  // Detach environment from the original instruction because it can't
+  // deoptimize.
+  for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) {
+    it.CurrentValue()->RemoveFromUseList();
+  }
+  instr->set_env(NULL);
+  ReplaceCall(instr, store);
   return true;
 }
 
 
-static void HandleRelationalOp(FlowGraphOptimizer* optimizer,
-                               RelationalOpInstr* comp,
-                               Instruction* instr) {
+void FlowGraphOptimizer::HandleRelationalOp(RelationalOpInstr* comp) {
   if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) {
     return;
   }
   const ICData& ic_data = *comp->ic_data();
+  Instruction* instr = current_iterator()->Current();
   if (ic_data.NumberOfChecks() == 1) {
     ASSERT(ic_data.HasOneTarget());
     if (HasOnlyTwoSmis(ic_data)) {
-      optimizer->InsertBefore(
-          instr,
-          new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
-          instr->env(),
-          Definition::kEffect);
-      optimizer->InsertBefore(
-          instr,
-          new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
-          instr->env(),
-          Definition::kEffect);
+      InsertBefore(instr,
+                   new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
+                   instr->env(),
+                   Definition::kEffect);
+      InsertBefore(instr,
+                   new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
+                   instr->env(),
+                   Definition::kEffect);
       comp->set_operands_class_id(kSmiCid);
     } else if (ShouldSpecializeForDouble(ic_data)) {
       comp->set_operands_class_id(kDoubleCid);
@@ -1823,23 +1965,23 @@
 
 
 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpInstr* instr) {
-  HandleRelationalOp(this, instr, instr);
+  HandleRelationalOp(instr);
 }
 
 
 template <typename T>
-static void HandleEqualityCompare(FlowGraphOptimizer* optimizer,
-                                  EqualityCompareInstr* comp,
-                                  T instr,
-                                  ForwardInstructionIterator* iterator) {
+void FlowGraphOptimizer::HandleEqualityCompare(EqualityCompareInstr* comp,
+                                               T current_instruction) {
   // If one of the inputs is null, no ICdata will be collected.
   if (comp->left()->BindsToConstantNull() ||
       comp->right()->BindsToConstantNull()) {
     Token::Kind strict_kind = (comp->kind() == Token::kEQ) ?
         Token::kEQ_STRICT : Token::kNE_STRICT;
     StrictCompareInstr* strict_comp =
-        new StrictCompareInstr(strict_kind, comp->left(), comp->right());
-    instr->ReplaceWith(strict_comp, iterator);
+        new StrictCompareInstr(strict_kind,
+                               comp->left()->Copy(),
+                               comp->right()->Copy());
+    current_instruction->ReplaceWith(strict_comp, current_iterator());
     return;
   }
   if (!comp->HasICData() || (comp->ic_data()->NumberOfChecks() == 0)) {
@@ -1853,16 +1995,14 @@
     // TODO(srdjan): allow for mixed mode int/double comparison.
 
     if ((class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
-      optimizer->InsertBefore(
-          instr,
-          new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
-          instr->env(),
-          Definition::kEffect);
-      optimizer->InsertBefore(
-          instr,
-          new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
-          instr->env(),
-          Definition::kEffect);
+      InsertBefore(current_instruction,
+                   new CheckSmiInstr(comp->left()->Copy(), comp->deopt_id()),
+                   current_instruction->env(),
+                   Definition::kEffect);
+      InsertBefore(current_instruction,
+                   new CheckSmiInstr(comp->right()->Copy(), comp->deopt_id()),
+                   current_instruction->env(),
+                   Definition::kEffect);
       comp->set_receiver_class_id(kSmiCid);
     } else if ((class_ids[0] == kDoubleCid) && (class_ids[1] == kDoubleCid)) {
       comp->set_receiver_class_id(kDoubleCid);
@@ -1889,63 +2029,40 @@
   GrowableArray<intptr_t> smi_or_null(2);
   smi_or_null.Add(kSmiCid);
   smi_or_null.Add(kNullCid);
-  if (ICDataHasOnlyReceiverArgumentClassIds(
-        *comp->ic_data(), smi_or_null, smi_or_null)) {
+  if (ICDataHasOnlyReceiverArgumentClassIds(*comp->ic_data(),
+                                            smi_or_null,
+                                            smi_or_null)) {
     const ICData& unary_checks_0 =
         ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecks());
-    const intptr_t deopt_id = comp->deopt_id();
-    if ((unary_checks_0.NumberOfChecks() == 1) &&
-        (unary_checks_0.GetReceiverClassIdAt(0) == kSmiCid)) {
-      // Smi only.
-      optimizer->InsertBefore(
-        instr,
-        new CheckSmiInstr(comp->left()->Copy(), deopt_id),
-        instr->env(),
-        Definition::kEffect);
-    } else {
-      // Smi or NULL.
-      optimizer->InsertBefore(
-        instr,
-        new CheckClassInstr(comp->left()->Copy(), deopt_id, unary_checks_0),
-        instr->env(),
-        Definition::kEffect);
-    }
+    AddCheckClass(comp->left()->definition(),
+                  unary_checks_0,
+                  comp->deopt_id(),
+                  current_instruction->env(),
+                  current_instruction);
 
     const ICData& unary_checks_1 =
         ICData::ZoneHandle(comp->ic_data()->AsUnaryClassChecksForArgNr(1));
-    if ((unary_checks_1.NumberOfChecks() == 1) &&
-        (unary_checks_1.GetReceiverClassIdAt(0) == kSmiCid)) {
-      // Smi only.
-      optimizer->InsertBefore(
-        instr,
-        new CheckSmiInstr(comp->right()->Copy(), deopt_id),
-        instr->env(),
-        Definition::kEffect);
-    } else {
-      // Smi or NULL.
-      optimizer->InsertBefore(
-        instr,
-        new CheckClassInstr(comp->right()->Copy(), deopt_id, unary_checks_1),
-        instr->env(),
-        Definition::kEffect);
-    }
+    AddCheckClass(comp->right()->definition(),
+                  unary_checks_1,
+                  comp->deopt_id(),
+                  current_instruction->env(),
+                  current_instruction);
     comp->set_receiver_class_id(kSmiCid);
   }
 }
 
 
 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareInstr* instr) {
-  HandleEqualityCompare(this, instr, instr, current_iterator());
+  HandleEqualityCompare(instr, instr);
 }
 
 
 void FlowGraphOptimizer::VisitBranch(BranchInstr* instr) {
   ComparisonInstr* comparison = instr->comparison();
   if (comparison->IsRelationalOp()) {
-    HandleRelationalOp(this, comparison->AsRelationalOp(), instr);
+    HandleRelationalOp(comparison->AsRelationalOp());
   } else if (comparison->IsEqualityCompare()) {
-    HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr,
-                          current_iterator());
+    HandleEqualityCompare(comparison->AsEqualityCompare(), instr);
   } else {
     ASSERT(comparison->IsStrictCompare());
     // Nothing to do.
@@ -2232,15 +2349,11 @@
   // No need to constrain constants.
   if (defn->IsConstant()) return NULL;
 
-  Value* value = new Value(defn);
-  ConstraintInstr* constraint = new ConstraintInstr(value, constraint_range);
-  constraint->InsertAfter(after);
-  constraint->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
-  RenameDominatedUses(defn, after, constraint);
+  ConstraintInstr* constraint =
+      new ConstraintInstr(new Value(defn), constraint_range);
+  flow_graph_->InsertAfter(after, constraint, NULL, Definition::kValue);
+  RenameDominatedUses(defn, constraint, constraint);
   constraints_.Add(constraint);
-  value->set_instruction(constraint);
-  value->set_use_index(0);
-  defn->AddInputUse(value);
   return constraint;
 }
 
@@ -2641,7 +2754,7 @@
   current->value()->set_definition(non_smi_input_defn);
   non_smi_input_defn->AddInputUse(current->value());
 
-  phi->Type()->ReplaceWith(CompileType::FromCid(kSmiCid));
+  phi->UpdateType(CompileType::FromCid(kSmiCid));
 }
 
 
@@ -4140,14 +4253,23 @@
        !b.Done();
        b.Advance()) {
     BlockEntryInstr* block = b.Current();
+    JoinEntryInstr* join = block->AsJoinEntry();
     if (!reachable_->Contains(block->preorder_number())) {
       if (FLAG_trace_constant_propagation) {
         OS::Print("Unreachable B%"Pd"\n", block->block_id());
       }
+      // Remove all uses in unreachable blocks.
+      if (join != NULL) {
+        for (PhiIterator it(join); !it.Done(); it.Advance()) {
+          it.Current()->UnuseAllInputs();
+        }
+      }
+      for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+        it.Current()->UnuseAllInputs();
+      }
       continue;
     }
 
-    JoinEntryInstr* join = block->AsJoinEntry();
     if (join != NULL) {
       // Remove phi inputs corresponding to unreachable predecessor blocks.
       // Predecessors will be recomputed (in block id order) after removing
@@ -4163,18 +4285,32 @@
               for (intptr_t phi_idx = 0; phi_idx < phis->length(); ++phi_idx) {
                 PhiInstr* phi = (*phis)[phi_idx];
                 if (phi == NULL) continue;
-                phi->inputs_[live_count] = phi->inputs_[pred_idx];
+                Value* input = phi->inputs_[pred_idx];
+                input->set_use_index(live_count);
+                phi->inputs_[live_count] = input;
               }
             }
             ++live_count;
+          } else {
+            for (intptr_t phi_idx = 0; phi_idx < phis->length(); ++phi_idx) {
+              PhiInstr* phi = (*phis)[phi_idx];
+              if (phi == NULL) continue;
+              phi->inputs_[pred_idx]->RemoveFromUseList();
+            }
           }
         }
         if (live_count < pred_count) {
           for (intptr_t phi_idx = 0; phi_idx < phis->length(); ++phi_idx) {
             PhiInstr* phi = (*phis)[phi_idx];
             if (phi == NULL) continue;
-            phi->inputs_.TruncateTo(live_count);
-            if (live_count == 1) redundant_phis.Add(phi);
+            if (FLAG_remove_redundant_phis && (live_count == 1)) {
+              Value* input = phi->InputAt(0);
+              phi->ReplaceUsesWith(input->definition());
+              input->RemoveFromUseList();
+              (*phis)[phi_idx] = NULL;
+            } else {
+              phi->inputs_.TruncateTo(live_count);
+            }
           }
         }
       }
@@ -4199,7 +4335,7 @@
                     defn->ssa_temp_index(),
                     defn->constant_value().ToCString());
         }
-        i.ReplaceCurrentWith(new ConstantInstr(defn->constant_value()));
+        defn->ReplaceWith(new ConstantInstr(defn->constant_value()), &i);
       }
     }
 
@@ -4236,6 +4372,7 @@
         // Replace the false target entry with the new join entry. We will
         // recompute the dominators after this pass.
         join->LinkTo(next);
+        branch->UnuseAllInputs();
       }
     }
   }
@@ -4243,15 +4380,6 @@
   graph_->DiscoverBlocks();
   GrowableArray<BitVector*> dominance_frontier;
   graph_->ComputeDominators(&dominance_frontier);
-  graph_->ComputeUseLists();
-
-  if (FLAG_remove_redundant_phis) {
-    for (intptr_t i = 0; i < redundant_phis.length(); i++) {
-      PhiInstr* phi = redundant_phis[i];
-      phi->ReplaceUsesWith(phi->InputAt(0)->definition());
-      phi->mark_dead();
-    }
-  }
 
   if (FLAG_trace_constant_propagation) {
     OS::Print("\n==== After constant propagation ====\n");
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index a0922ef..6ec0e35 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -21,12 +21,18 @@
         flow_graph_(flow_graph) { }
   virtual ~FlowGraphOptimizer() {}
 
+  FlowGraph* flow_graph() const { return flow_graph_; }
+
   // Use ICData to optimize, replace or eliminate instructions.
   void ApplyICData();
 
   // Use propagated class ids to optimize, replace or eliminate instructions.
   void ApplyClassIds();
 
+  // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
+  // shift can be a truncating Smi shift-left and result is always Smi.
+  void TryOptimizeLeftShiftWithBitAndPattern();
+
   void Canonicalize();
 
   void EliminateDeadPhis();
@@ -47,7 +53,9 @@
   void InsertBefore(Instruction* next,
                     Instruction* instr,
                     Environment* env,
-                    Definition::UseKind use_kind);
+                    Definition::UseKind use_kind) {
+    flow_graph_->InsertBefore(next, instr, env, use_kind);
+  }
 
  private:
   // Attempt to build ICData for call using propagated class-ids.
@@ -57,9 +65,13 @@
 
   intptr_t PrepareIndexedOp(InstanceCallInstr* call,
                             intptr_t class_id,
-                            Value** array,
-                            Value** index);
+                            Definition** array,
+                            Definition** index);
   bool TryReplaceWithStoreIndexed(InstanceCallInstr* call);
+  bool TryInlineByteArraySetIndexed(InstanceCallInstr* call);
+  void BuildStoreIndexed(InstanceCallInstr* call,
+                         const ICData& value_check,
+                         intptr_t class_id);
   bool TryReplaceWithLoadIndexed(InstanceCallInstr* call);
 
   bool TryReplaceWithBinaryOp(InstanceCallInstr* call, Token::Kind op_kind);
@@ -79,12 +91,28 @@
                                            intptr_t receiver_cid,
                                            intptr_t view_cid);
 
-  void AddCheckClass(InstanceCallInstr* call, Value* value);
+  // Insert a check of 'to_check' determined by 'unary_checks'.  If the
+  // check fails it will deoptimize to 'deopt_id' using the deoptimization
+  // environment 'deopt_environment'.  The check is inserted immediately
+  // before 'insert_before'.
+  void AddCheckClass(Definition* to_check,
+                     const ICData& unary_checks,
+                     intptr_t deopt_id,
+                     Environment* deopt_environment,
+                     Instruction* insert_before);
 
-  void InsertAfter(Instruction* prev,
-                   Instruction* instr,
-                   Environment* env,
-                   Definition::UseKind use_kind);
+  // Insert a Smi check if needed.
+  void AddCheckSmi(Definition* to_check,
+                   intptr_t deopt_id,
+                   Environment* deopt_environment,
+                   Instruction* insert_before);
+
+  // Add a class check for a call's first argument immediately before the
+  // call, using the call's IC data to determine the check, and the call's
+  // deopt ID and deoptimization environment if the check fails.
+  void AddReceiverCheck(InstanceCallInstr* call);
+
+  void ReplaceCall(Definition* call, Definition* replacement);
 
   void InsertConversionsFor(Definition* def);
 
@@ -112,6 +140,18 @@
   void ReplaceWithMathCFunction(InstanceCallInstr* call,
                                 MethodRecognizer::Kind recognized_kind);
 
+  void HandleRelationalOp(RelationalOpInstr* comp);
+
+  // Visit an equality compare.  The current instruction can be the
+  // comparison itself or a branch on the comparison.
+  template <typename T>
+  void HandleEqualityCompare(EqualityCompareInstr* comp,
+                             T current_instruction);
+
+  void OptimizeLeftShiftBitAndSmiOp(Definition* bit_and_instr,
+                                    Definition* left_instr,
+                                    Definition* right_instr);
+
   FlowGraph* flow_graph_;
 
   DISALLOW_COPY_AND_ASSIGN(FlowGraphOptimizer);
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 020172c..8810fbc 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -6,6 +6,7 @@
 
 #include "vm/cha.h"
 #include "vm/bit_vector.h"
+#include "vm/il_printer.h"
 
 namespace dart {
 
@@ -20,27 +21,46 @@
     : FlowGraphVisitor(flow_graph->reverse_postorder()),
       flow_graph_(flow_graph),
       types_(flow_graph->current_ssa_temp_index()),
-      in_worklist_(new BitVector(flow_graph->current_ssa_temp_index())) {
+      in_worklist_(new BitVector(flow_graph->current_ssa_temp_index())),
+      asserts_(NULL),
+      collected_asserts_(NULL) {
   for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
     types_.Add(NULL);
   }
+
+  if (FLAG_enable_type_checks) {
+    asserts_ = new ZoneGrowableArray<AssertAssignableInstr*>(
+        flow_graph->current_ssa_temp_index());
+    for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
+      asserts_->Add(NULL);
+    }
+
+    collected_asserts_ = new ZoneGrowableArray<intptr_t>(10);
+  }
 }
 
 
 void FlowGraphTypePropagator::Propagate() {
-  // Walk dominator tree and propagate reaching types to all Values.
-  // Collect all phis for a fix point iteration.
+  if (FLAG_trace_type_propagation) {
+    OS::Print("Before type propagation:\n");
+    FlowGraphPrinter printer(*flow_graph_);
+    printer.PrintBlocks();
+  }
+
+  // Walk the dominator tree and propagate reaching types to all Values.
+  // Collect all phis for a fixed point iteration.
   PropagateRecursive(flow_graph_->graph_entry());
 
 #ifdef DEBUG
-  // Initially work-list contains only phis.
+  // Initially the worklist contains only phis.
   for (intptr_t i = 0; i < worklist_.length(); i++) {
     ASSERT(worklist_[i]->IsPhi());
     ASSERT(worklist_[i]->Type()->IsNone());
   }
 #endif
 
-  // Iterate until fix point is reached updating types of definitions.
+  // Iterate until a fixed point is reached, updating the types of
+  // definitions.
   while (!worklist_.is_empty()) {
     Definition* def = RemoveLastFromWorklist();
     if (FLAG_trace_type_propagation) {
@@ -62,12 +82,22 @@
       }
     }
   }
+
+  if (FLAG_trace_type_propagation) {
+    OS::Print("After type propagation:\n");
+    FlowGraphPrinter printer(*flow_graph_);
+    printer.PrintBlocks();
+  }
 }
 
 
 void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
   const intptr_t rollback_point = rollback_.length();
 
+  if (FLAG_enable_type_checks) {
+    StrengthenAsserts(block);
+  }
+
   block->Accept(this);
 
   for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
@@ -76,6 +106,9 @@
     for (intptr_t i = 0; i < instr->InputCount(); i++) {
       VisitValue(instr->InputAt(i));
     }
+    if (instr->IsDefinition()) {
+      instr->AsDefinition()->RecomputeType();
+    }
     instr->Accept(this);
   }
 
@@ -123,7 +156,7 @@
   CompileType* current = TypeOf(def);
   if (current->ToCid() == cid) return;
 
-  SetTypeOf(def, CompileType::FromCid(cid));
+  SetTypeOf(def, ZoneCompileType::Wrap(CompileType::FromCid(cid)));
 }
 
 
@@ -189,13 +222,93 @@
 }
 
 
+// Unwrap all assert assignable and get a real definition of the value.
+static Definition* UnwrapAsserts(Definition* defn) {
+  while (defn->IsAssertAssignable()) {
+    defn = defn->AsAssertAssignable()->value()->definition();
+  }
+  return defn;
+}
+
+
+// In the given block strengthen type assertions by hoisting first class or smi
+// check over the same value up to the point before the assertion. This allows
+// to eliminate type assertions that are postdominated by class or smi checks as
+// these checks are strongly stricter than type assertions.
+void FlowGraphTypePropagator::StrengthenAsserts(BlockEntryInstr* block) {
+  for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+    Instruction* instr = it.Current();
+
+    if (instr->IsCheckSmi() || instr->IsCheckClass()) {
+      StrengthenAssertWith(instr);
+    }
+
+    // If this is the first type assertion checking given value record it.
+    AssertAssignableInstr* assert = instr->AsAssertAssignable();
+    if (assert != NULL) {
+      Definition* defn = UnwrapAsserts(assert->value()->definition());
+      if ((*asserts_)[defn->ssa_temp_index()] == NULL) {
+        (*asserts_)[defn->ssa_temp_index()] = assert;
+        collected_asserts_->Add(defn->ssa_temp_index());
+      }
+    }
+  }
+
+  for (intptr_t i = 0; i < collected_asserts_->length(); i++) {
+    (*asserts_)[(*collected_asserts_)[i]] = NULL;
+  }
+
+  collected_asserts_->TruncateTo(0);
+}
+
+
+void FlowGraphTypePropagator::StrengthenAssertWith(Instruction* check) {
+  // Marker that is used to mark values that already had type assertion
+  // strengthened.
+  AssertAssignableInstr* kStrengthenedAssertMarker =
+      reinterpret_cast<AssertAssignableInstr*>(-1);
+
+  Definition* defn = UnwrapAsserts(check->InputAt(0)->definition());
+
+  AssertAssignableInstr* assert = (*asserts_)[defn->ssa_temp_index()];
+  if ((assert == NULL) || (assert == kStrengthenedAssertMarker)) {
+    return;
+  }
+
+  Instruction* check_clone = NULL;
+  if (check->IsCheckSmi()) {
+    check_clone =
+        new CheckSmiInstr(assert->value()->Copy(),
+                          assert->env()->deopt_id());
+  } else {
+    ASSERT(check->IsCheckClass());
+    check_clone =
+        new CheckClassInstr(assert->value()->Copy(),
+                            assert->env()->deopt_id(),
+                            check->AsCheckClass()->unary_checks());
+  }
+  ASSERT(check_clone != NULL);
+  ASSERT(assert->deopt_id() == assert->env()->deopt_id());
+
+  Value* use = check_clone->InputAt(0);
+  use->set_instruction(check_clone);
+  use->set_use_index(0);
+  use->definition()->AddInputUse(use);
+
+  assert->env()->DeepCopyTo(check_clone);
+  check_clone->InsertBefore(assert);
+
+  (*asserts_)[defn->ssa_temp_index()] = kStrengthenedAssertMarker;
+}
+
+
 void CompileType::Union(CompileType* other) {
   if (other->IsNone()) {
     return;
   }
 
   if (IsNone()) {
-    ReplaceWith(other);
+    *this = *other;
     return;
   }
 
@@ -233,38 +346,38 @@
 }
 
 
-CompileType* CompileType::New(intptr_t cid, const AbstractType& type) {
-  return new CompileType(IsNullableCid(cid), cid, &type);
+CompileType CompileType::Create(intptr_t cid, const AbstractType& type) {
+  return CompileType(IsNullableCid(cid), cid, &type);
 }
 
 
-CompileType* CompileType::FromAbstractType(const AbstractType& type,
+CompileType CompileType::FromAbstractType(const AbstractType& type,
                                            bool is_nullable) {
-  return new CompileType(is_nullable, kIllegalCid, &type);
+  return CompileType(is_nullable, kIllegalCid, &type);
 }
 
 
-CompileType* CompileType::FromCid(intptr_t cid) {
-  return new CompileType(IsNullableCid(cid), cid, NULL);
+CompileType CompileType::FromCid(intptr_t cid) {
+  return CompileType(IsNullableCid(cid), cid, NULL);
 }
 
 
-CompileType* CompileType::Dynamic() {
-  return New(kDynamicCid, Type::ZoneHandle(Type::DynamicType()));
+CompileType CompileType::Dynamic() {
+  return Create(kDynamicCid, Type::ZoneHandle(Type::DynamicType()));
 }
 
 
-CompileType* CompileType::Null() {
-  return New(kNullCid, Type::ZoneHandle(Type::NullType()));
+CompileType CompileType::Null() {
+  return Create(kNullCid, Type::ZoneHandle(Type::NullType()));
 }
 
 
-CompileType* CompileType::Bool() {
-  return New(kBoolCid, Type::ZoneHandle(Type::BoolType()));
+CompileType CompileType::Bool() {
+  return Create(kBoolCid, Type::ZoneHandle(Type::BoolType()));
 }
 
 
-CompileType* CompileType::Int() {
+CompileType CompileType::Int() {
   return FromAbstractType(Type::ZoneHandle(Type::IntType()), kNonNullable);
 }
 
@@ -290,6 +403,8 @@
       const intptr_t cid = Class::Handle(type_->type_class()).id();
       if (!CHA::HasSubclasses(cid)) {
         cid_ = cid;
+      } else {
+        cid_ = kDynamicCid;
       }
     } else {
       cid_ = kDynamicCid;
@@ -394,7 +509,16 @@
 
 
 bool CompileType::IsMoreSpecificThan(const AbstractType& other) {
-  return !IsNone() && ToAbstractType()->IsMoreSpecificThan(other, NULL);
+  if (IsNone()) {
+    return false;
+  }
+
+  if (other.IsVoidType()) {
+    // The only value assignable to void is null.
+    return IsNull();
+  }
+
+  return ToAbstractType()->IsMoreSpecificThan(other, NULL);
 }
 
 
@@ -406,7 +530,7 @@
 }
 
 
-CompileType* PhiInstr::ComputeInitialType() const {
+CompileType PhiInstr::ComputeType() const {
   // Initially type of phis is unknown until type propagation is run
   // for the first time.
   return CompileType::None();
@@ -418,7 +542,7 @@
     return false;
   }
 
-  CompileType* result = CompileType::None();
+  CompileType result = CompileType::None();
 
   for (intptr_t i = 0; i < InputCount(); i++) {
     if (FLAG_trace_type_propagation) {
@@ -428,45 +552,59 @@
                 InputAt(i)->definition()->ssa_temp_index(),
                 InputAt(i)->Type()->ToCString());
     }
-    result->Union(InputAt(i)->Type());
+    result.Union(InputAt(i)->Type());
   }
 
-  if (result->IsNone()) {
+  if (result.IsNone()) {
     ASSERT(Type()->IsNone());
     return false;
   }
 
-  if (Type()->IsNone() || !Type()->IsEqualTo(result)) {
-    Type()->ReplaceWith(result);
-    return true;
-  }
-
-  return false;
+  return UpdateType(result);
 }
 
 
+static bool CanTrustParameterType(const Function& function, intptr_t index) {
+  // Parameter is receiver.
+  if (index == 0) {
+    return function.IsDynamicFunction() || function.IsConstructor();
+  }
 
-CompileType* ParameterInstr::ComputeInitialType() const {
+  // Parameter is the constructor phase.
+  return (index == 1) && function.IsConstructor();
+}
+
+
+CompileType ParameterInstr::ComputeType() const {
   // Note that returning the declared type of the formal parameter would be
   // incorrect, because ParameterInstr is used as input to the type check
   // verifying the run time type of the passed-in parameter and this check would
   // always be wrongly eliminated.
+  // However there are parameters that are known to match their declared type:
+  // for example receiver and construction phase.
+  if (!CanTrustParameterType(block_->parsed_function().function(),
+                             index())) {
+    return CompileType::Dynamic();
+  }
+
+  LocalScope* scope = block_->parsed_function().node_sequence()->scope();
+  return CompileType::FromAbstractType(scope->VariableAt(index())->type(),
+                                       CompileType::kNonNullable);
+}
+
+
+CompileType PushArgumentInstr::ComputeType() const {
   return CompileType::Dynamic();
 }
 
 
-CompileType* PushArgumentInstr::ComputeInitialType() const {
-  return CompileType::Dynamic();
-}
-
-
-CompileType* ConstantInstr::ComputeInitialType() const {
+CompileType ConstantInstr::ComputeType() const {
   if (value().IsNull()) {
     return CompileType::Null();
   }
 
   if (value().IsInstance()) {
-    return CompileType::New(
+    return CompileType::Create(
         Class::Handle(value().clazz()).id(),
         AbstractType::ZoneHandle(Instance::Cast(value()).GetType()));
   } else {
@@ -478,10 +616,17 @@
 
 CompileType* AssertAssignableInstr::ComputeInitialType() const {
   CompileType* value_type = value()->Type();
+
   if (value_type->IsMoreSpecificThan(dst_type())) {
     return value_type;
   }
-  return CompileType::FromAbstractType(dst_type());
+
+  if (dst_type().IsVoidType()) {
+    // The only value assignable to void is null.
+    return ZoneCompileType::Wrap(CompileType::Null());
+  }
+
+  return ZoneCompileType::Wrap(CompileType::FromAbstractType(dst_type()));
 }
 
 
@@ -491,69 +636,77 @@
     return false;
   }
 
-  if (value_type->IsMoreSpecificThan(dst_type()) &&
-      !Type()->IsEqualTo(value_type)) {
-    Type()->ReplaceWith(value_type);
-    return true;
+  if (value_type->IsMoreSpecificThan(dst_type())) {
+    return UpdateType(*value_type);
   }
 
   return false;
 }
 
 
-CompileType* AssertBooleanInstr::ComputeInitialType() const {
+CompileType AssertBooleanInstr::ComputeType() const {
   return CompileType::Bool();
 }
 
 
-CompileType* ArgumentDefinitionTestInstr::ComputeInitialType() const {
+CompileType ArgumentDefinitionTestInstr::ComputeType() const {
   return CompileType::Bool();
 }
 
 
-CompileType* BooleanNegateInstr::ComputeInitialType() const {
+CompileType BooleanNegateInstr::ComputeType() const {
   return CompileType::Bool();
 }
 
 
-CompileType* InstanceOfInstr::ComputeInitialType() const {
+CompileType InstanceOfInstr::ComputeType() const {
   return CompileType::Bool();
 }
 
 
-CompileType* StrictCompareInstr::ComputeInitialType() const {
+CompileType StrictCompareInstr::ComputeType() const {
   return CompileType::Bool();
 }
 
 
-CompileType* EqualityCompareInstr::ComputeInitialType() const {
+CompileType EqualityCompareInstr::ComputeType() const {
   return IsInlinedNumericComparison() ? CompileType::Bool()
                                       : CompileType::Dynamic();
 }
 
 
-CompileType* RelationalOpInstr::ComputeInitialType() const {
+bool EqualityCompareInstr::RecomputeType() {
+  return UpdateType(ComputeType());
+}
+
+
+CompileType RelationalOpInstr::ComputeType() const {
   return IsInlinedNumericComparison() ? CompileType::Bool()
                                       : CompileType::Dynamic();
 }
 
 
-CompileType* CurrentContextInstr::ComputeInitialType() const {
+bool RelationalOpInstr::RecomputeType() {
+  return UpdateType(ComputeType());
+}
+
+
+CompileType CurrentContextInstr::ComputeType() const {
   return CompileType::FromCid(kContextCid);
 }
 
 
-CompileType* CloneContextInstr::ComputeInitialType() const {
+CompileType CloneContextInstr::ComputeType() const {
   return CompileType::FromCid(kContextCid);
 }
 
 
-CompileType* AllocateContextInstr::ComputeInitialType() const {
+CompileType AllocateContextInstr::ComputeType() const {
   return CompileType::FromCid(kContextCid);
 }
 
 
-CompileType* StaticCallInstr::ComputeInitialType() const {
+CompileType StaticCallInstr::ComputeType() const {
   if (result_cid_ != kDynamicCid) {
     return CompileType::FromCid(result_cid_);
   }
@@ -567,7 +720,7 @@
 }
 
 
-CompileType* LoadLocalInstr::ComputeInitialType() const {
+CompileType LoadLocalInstr::ComputeType() const {
   if (FLAG_enable_type_checks) {
     return CompileType::FromAbstractType(local().type());
   }
@@ -581,7 +734,7 @@
 }
 
 
-CompileType* StringFromCharCodeInstr::ComputeInitialType() const {
+CompileType StringFromCharCodeInstr::ComputeType() const {
   return CompileType::FromCid(cid_);
 }
 
@@ -591,7 +744,7 @@
 }
 
 
-CompileType* LoadStaticFieldInstr::ComputeInitialType() const {
+CompileType LoadStaticFieldInstr::ComputeType() const {
   if (FLAG_enable_type_checks) {
     return CompileType::FromAbstractType(
         AbstractType::ZoneHandle(field().type()));
@@ -605,12 +758,12 @@
 }
 
 
-CompileType* CreateArrayInstr::ComputeInitialType() const {
+CompileType CreateArrayInstr::ComputeType() const {
   return CompileType::FromAbstractType(type(), CompileType::kNonNullable);
 }
 
 
-CompileType* CreateClosureInstr::ComputeInitialType() const {
+CompileType CreateClosureInstr::ComputeType() const {
   const Function& fun = function();
   const Class& signature_class = Class::Handle(fun.signature_class());
   return CompileType::FromAbstractType(
@@ -619,13 +772,13 @@
 }
 
 
-CompileType* AllocateObjectInstr::ComputeInitialType() const {
+CompileType AllocateObjectInstr::ComputeType() const {
   // TODO(vegorov): Incorporate type arguments into the returned type.
   return CompileType::FromCid(cid_);
 }
 
 
-CompileType* LoadFieldInstr::ComputeInitialType() const {
+CompileType LoadFieldInstr::ComputeType() const {
   // Type may be null if the field is a VM field, e.g. context parent.
   // Keep it as null for debug purposes and do not return dynamic in production
   // mode, since misuse of the type would remain undetected.
@@ -646,87 +799,87 @@
 }
 
 
-CompileType* BinarySmiOpInstr::ComputeInitialType() const {
+CompileType BinarySmiOpInstr::ComputeType() const {
   return CompileType::FromCid(kSmiCid);
 }
 
 
-CompileType* UnarySmiOpInstr::ComputeInitialType() const {
+CompileType UnarySmiOpInstr::ComputeType() const {
   return CompileType::FromCid(kSmiCid);
 }
 
 
-CompileType* DoubleToSmiInstr::ComputeInitialType() const {
+CompileType DoubleToSmiInstr::ComputeType() const {
   return CompileType::FromCid(kSmiCid);
 }
 
 
-CompileType* ConstraintInstr::ComputeInitialType() const {
+CompileType ConstraintInstr::ComputeType() const {
   return CompileType::FromCid(kSmiCid);
 }
 
 
-CompileType* BinaryMintOpInstr::ComputeInitialType() const {
+CompileType BinaryMintOpInstr::ComputeType() const {
   return CompileType::Int();
 }
 
 
-CompileType* ShiftMintOpInstr::ComputeInitialType() const {
+CompileType ShiftMintOpInstr::ComputeType() const {
   return CompileType::Int();
 }
 
 
-CompileType* UnaryMintOpInstr::ComputeInitialType() const {
+CompileType UnaryMintOpInstr::ComputeType() const {
   return CompileType::Int();
 }
 
 
-CompileType* BoxIntegerInstr::ComputeInitialType() const {
+CompileType BoxIntegerInstr::ComputeType() const {
   return CompileType::Int();
 }
 
 
-CompileType* UnboxIntegerInstr::ComputeInitialType() const {
+CompileType UnboxIntegerInstr::ComputeType() const {
   return CompileType::Int();
 }
 
 
-CompileType* DoubleToIntegerInstr::ComputeInitialType() const {
+CompileType DoubleToIntegerInstr::ComputeType() const {
   return CompileType::Int();
 }
 
 
-CompileType* BinaryDoubleOpInstr::ComputeInitialType() const {
+CompileType BinaryDoubleOpInstr::ComputeType() const {
   return CompileType::FromCid(kDoubleCid);
 }
 
 
-CompileType* MathSqrtInstr::ComputeInitialType() const {
+CompileType MathSqrtInstr::ComputeType() const {
   return CompileType::FromCid(kDoubleCid);
 }
 
 
-CompileType* UnboxDoubleInstr::ComputeInitialType() const {
+CompileType UnboxDoubleInstr::ComputeType() const {
   return CompileType::FromCid(kDoubleCid);
 }
 
 
-CompileType* BoxDoubleInstr::ComputeInitialType() const {
+CompileType BoxDoubleInstr::ComputeType() const {
   return CompileType::FromCid(kDoubleCid);
 }
 
 
-CompileType* SmiToDoubleInstr::ComputeInitialType() const {
+CompileType SmiToDoubleInstr::ComputeType() const {
   return CompileType::FromCid(kDoubleCid);
 }
 
 
-CompileType* DoubleToDoubleInstr::ComputeInitialType() const {
+CompileType DoubleToDoubleInstr::ComputeType() const {
   return CompileType::FromCid(kDoubleCid);
 }
 
 
-CompileType* InvokeMathCFunctionInstr::ComputeInitialType() const {
+CompileType InvokeMathCFunctionInstr::ComputeType() const {
   return CompileType::FromCid(kDoubleCid);
 }
 
diff --git a/runtime/vm/flow_graph_type_propagator.h b/runtime/vm/flow_graph_type_propagator.h
index fafd1b6..f01dc5f 100644
--- a/runtime/vm/flow_graph_type_propagator.h
+++ b/runtime/vm/flow_graph_type_propagator.h
@@ -38,6 +38,10 @@
   void AddToWorklist(Definition* defn);
   Definition* RemoveLastFromWorklist();
 
+  // Type assertion strengthening.
+  void StrengthenAsserts(BlockEntryInstr* block);
+  void StrengthenAssertWith(Instruction* check);
+
   FlowGraph* flow_graph_;
 
   // Mapping between SSA values and their current reaching types. Valid
@@ -48,6 +52,9 @@
   GrowableArray<Definition*> worklist_;
   BitVector* in_worklist_;
 
+  ZoneGrowableArray<AssertAssignableInstr*>* asserts_;
+  ZoneGrowableArray<intptr_t>* collected_asserts_;
+
   // RollbackEntry is used to track and rollback changed in the types_ array
   // done during dominator tree traversal.
   class RollbackEntry {
diff --git a/runtime/vm/gdbjit_android.cc b/runtime/vm/gdbjit_android.cc
index 101f378..1141fbf 100644
--- a/runtime/vm/gdbjit_android.cc
+++ b/runtime/vm/gdbjit_android.cc
@@ -2,9 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include "vm/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
+#include <stdint.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
 
 #include "vm/gdbjit_android.h"
 
@@ -77,3 +80,5 @@
     last_dynamic_region = NULL;
   }
 };
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/gdbjit_linux.cc b/runtime/vm/gdbjit_linux.cc
index 35d4f44..9e06b85 100644
--- a/runtime/vm/gdbjit_linux.cc
+++ b/runtime/vm/gdbjit_linux.cc
@@ -2,9 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include "vm/globals.h"
+#if defined(TARGET_OS_LINUX)
+
+#include <stdint.h>  // NOLINT
+#include <stdio.h>  // NOLINT
+#include <stdlib.h>  // NOLINT
 
 #include "vm/gdbjit_linux.h"
 
@@ -77,3 +80,5 @@
     last_dynamic_region = NULL;
   }
 };
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 02db6e23..c4d74e5 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -112,8 +112,7 @@
   } else {
     f->Print("?, ");
   }
-  f->Print("%s}", (type_ != NULL) ? String::Handle(type_->Name()).ToCString()
-                                  : "?");
+  f->Print("%s}", (type_ != NULL) ? type_->ToCString() : "?");
 }
 
 
@@ -319,7 +318,7 @@
 void ClosureCallInstr::PrintOperandsTo(BufferFormatter* f) const {
   for (intptr_t i = 0; i < ArgumentCount(); ++i) {
     if (i > 0) f->Print(", ");
-    ArgumentAt(i)->value()->PrintTo(f);
+    PushArgumentAt(i)->value()->PrintTo(f);
   }
 }
 
@@ -328,7 +327,7 @@
   f->Print("%s", function_name().ToCString());
   for (intptr_t i = 0; i < ArgumentCount(); ++i) {
     f->Print(", ");
-    ArgumentAt(i)->value()->PrintTo(f);
+    PushArgumentAt(i)->value()->PrintTo(f);
   }
   if (HasICData()) {
     PrintICData(f, *ic_data());
@@ -340,7 +339,7 @@
   f->Print("%s", instance_call()->function_name().ToCString());
   for (intptr_t i = 0; i < ArgumentCount(); ++i) {
     f->Print(", ");
-    ArgumentAt(i)->value()->PrintTo(f);
+    PushArgumentAt(i)->value()->PrintTo(f);
   }
   PrintICData(f, ic_data());
 }
@@ -368,7 +367,7 @@
   f->Print("%s ", String::Handle(function().name()).ToCString());
   for (intptr_t i = 0; i < ArgumentCount(); ++i) {
     if (i > 0) f->Print(", ");
-    ArgumentAt(i)->value()->PrintTo(f);
+    PushArgumentAt(i)->value()->PrintTo(f);
   }
 }
 
@@ -440,7 +439,7 @@
   f->Print("%s", Class::Handle(constructor().Owner()).ToCString());
   for (intptr_t i = 0; i < ArgumentCount(); i++) {
     f->Print(", ");
-    ArgumentAt(i)->value()->PrintTo(f);
+    PushArgumentAt(i)->value()->PrintTo(f);
   }
 }
 
@@ -458,7 +457,7 @@
 void CreateArrayInstr::PrintOperandsTo(BufferFormatter* f) const {
   for (int i = 0; i < ArgumentCount(); ++i) {
     if (i != 0) f->Print(", ");
-    ArgumentAt(i)->value()->PrintTo(f);
+    PushArgumentAt(i)->value()->PrintTo(f);
   }
   if (ArgumentCount() > 0) f->Print(", ");
   element_type()->PrintTo(f);
@@ -469,7 +468,7 @@
   f->Print("%s", function().ToCString());
   for (intptr_t i = 0; i < ArgumentCount(); ++i) {
     if (i > 0) f->Print(", ");
-    ArgumentAt(i)->value()->PrintTo(f);
+    PushArgumentAt(i)->value()->PrintTo(f);
   }
 }
 
@@ -517,8 +516,10 @@
 void BinarySmiOpInstr::PrintTo(BufferFormatter* f) const {
   Definition::PrintTo(f);
   f->Print(" %co", overflow_ ? '+' : '-');
+  f->Print(" %ct", is_truncating() ? '+' : '-');
 }
 
+
 void BinarySmiOpInstr::PrintOperandsTo(BufferFormatter* f) const {
   f->Print("%s, ", Token::Str(op_kind()));
   left()->PrintTo(f);
diff --git a/runtime/vm/instructions_arm.cc b/runtime/vm/instructions_arm.cc
index 1ba1dcc..ba7ec59 100644
--- a/runtime/vm/instructions_arm.cc
+++ b/runtime/vm/instructions_arm.cc
@@ -10,34 +10,84 @@
 
 namespace dart {
 
-bool InstructionPattern::TestBytesWith(const int* data, int num_bytes) const {
+uword InstructionPattern::Back(int n) const {
+  ASSERT(n > 0);
+  return *(end_ - n);
+}
+
+
+CallPattern::CallPattern(uword pc, const Code& code)
+    : InstructionPattern(pc),
+      pool_index_(DecodePoolIndex()),
+      object_pool_(Array::Handle(code.ObjectPool())) { }
+
+
+int CallPattern::DecodePoolIndex() {
+  ASSERT(Back(1) == 0xe12fff3e);  // Last instruction: blx lr
+  // Decode the second to last instruction.
+  uword instr = Back(2);
+  int offset = 0;
+  if ((instr & 0xfffff000) == 0xe59ae000) {  // ldr lr, [pp, #+offset]
+    offset = instr & 0xfff;
+  } else {
+    ASSERT((instr & 0xfffff000) == 0xe59ee000);  // ldr lr, [lr, #+offset]
+    offset = instr & 0xfff;
+    instr = Back(3);
+    if ((instr & 0xfffff000) == 0xe28ae000) {  // add lr, pp, shifter_op
+      const int rot = (instr & 0xf00) * 2;
+      const int imm8 = instr & 0xff;
+      offset |= (imm8 >> rot) | (imm8 << (32 - rot));
+    } else {
+      ASSERT(instr == 0xe08ae00e);  // add lr, pp, lr
+      instr = Back(4);
+      if ((instr & 0xfff0f000) == 0xe340e000) {  // movt lr, offset_hi
+        offset |= (instr & 0xf0000) << 12;
+        offset |= (instr & 0xfff) << 16;
+        instr = Back(5);
+      }
+      ASSERT((instr & 0xfff0f000) == 0xe300e000);  // movw lr, offset_lo
+      ASSERT((offset & 0xffff) == 0);
+      offset |= (instr & 0xf0000) >> 4;
+      offset |= instr & 0xfff;
+    }
+  }
+  offset += kHeapObjectTag;
+  ASSERT(Utils::IsAligned(offset, 4));
+  return (offset - Array::data_offset())/4;
+}
+
+
+uword CallPattern::TargetAddress() const {
+  const Object& target_address = Object::Handle(object_pool_.At(pool_index_));
+  ASSERT(target_address.IsSmi());
+  return Smi::Cast(target_address).Value() << kSmiTagShift;
+}
+
+
+void CallPattern::SetTargetAddress(uword target_address) const {
+  ASSERT(Utils::IsAligned(target_address, 4));
+  // The address is stored in the object array as a RawSmi.
+  const Smi& smi = Smi::Handle(Smi::New(target_address >> kSmiTagShift));
+  object_pool_.SetAt(pool_index_, smi);
+}
+
+
+bool JumpPattern::IsValid() const {
   UNIMPLEMENTED();
   return false;
 }
 
 
-uword CallOrJumpPattern::TargetAddress() const {
+uword JumpPattern::TargetAddress() const {
   UNIMPLEMENTED();
   return 0;
 }
 
 
-void CallOrJumpPattern::SetTargetAddress(uword target) const {
+void JumpPattern::SetTargetAddress(uword target) const {
   UNIMPLEMENTED();
 }
 
-
-const int* CallPattern::pattern() const {
-  UNIMPLEMENTED();
-  return NULL;
-}
-
-
-const int* JumpPattern::pattern() const {
-  UNIMPLEMENTED();
-  return NULL;
-}
-
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/instructions_arm.h b/runtime/vm/instructions_arm.h
index c3ea8ea..0ebac6f 100644
--- a/runtime/vm/instructions_arm.h
+++ b/runtime/vm/instructions_arm.h
@@ -10,86 +10,58 @@
 #error Do not include instructions_arm.h directly; use instructions.h instead.
 #endif
 
-#include "vm/allocation.h"
+#include "vm/object.h"
 
 namespace dart {
 
-// Forward declarations.
-class RawClass;
-class Immediate;
-class RawObject;
-
 // Abstract class for all instruction pattern classes.
 class InstructionPattern : public ValueObject {
  public:
-  explicit InstructionPattern(uword pc) : start_(pc) {
+  explicit InstructionPattern(uword pc) : end_(reinterpret_cast<uword*>(pc)) {
     ASSERT(pc != 0);
   }
-  virtual ~InstructionPattern() {}
-
-  // Call to check if the instruction pattern at 'pc' match the instruction.
-  virtual bool IsValid() const {
-    return TestBytesWith(pattern(), pattern_length_in_bytes());
-  }
-
-  // 'pattern' returns the expected byte pattern in form of an integer array
-  // with length of 'pattern_length_in_bytes'. A '-1' element means 'any byte'.
-  virtual const int* pattern() const = 0;
-  virtual int pattern_length_in_bytes() const = 0;
+  virtual ~InstructionPattern() { }
 
  protected:
-  uword start() const { return start_; }
+  uword Back(int n) const;
 
  private:
-  // Returns true if the 'num_bytes' bytes at 'start_' correspond to
-  // array of integers 'data'. 'data' elements are either a byte or -1, which
-  // represents any byte.
-  bool TestBytesWith(const int* data, int num_bytes) const;
-
-  const uword start_;
+  const uword* end_;
 
   DISALLOW_COPY_AND_ASSIGN(InstructionPattern);
 };
 
 
-class CallOrJumpPattern : public InstructionPattern {
+class CallPattern : public InstructionPattern {
  public:
-  virtual int pattern_length_in_bytes() const {
-    return kLengthInBytes;
-  }
+  CallPattern(uword pc, const Code& code);
+
   uword TargetAddress() const;
-  void SetTargetAddress(uword new_target) const;
-
- protected:
-  explicit CallOrJumpPattern(uword pc) : InstructionPattern(pc) {}
-  static const int kLengthInBytes = 0;
+  void SetTargetAddress(uword target_address) const;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(CallOrJumpPattern);
-};
-
-
-class CallPattern : public CallOrJumpPattern {
- public:
-  explicit CallPattern(uword pc) : CallOrJumpPattern(pc) {}
-  static int InstructionLength() {
-    return kLengthInBytes;
-  }
-
- private:
-  virtual const int* pattern() const;
+  int DecodePoolIndex();
+  const int pool_index_;
+  const Array& object_pool_;
 
   DISALLOW_COPY_AND_ASSIGN(CallPattern);
 };
 
 
-class JumpPattern : public CallOrJumpPattern {
+class JumpPattern : public InstructionPattern {
  public:
-  explicit JumpPattern(uword pc) : CallOrJumpPattern(pc) {}
+  explicit JumpPattern(uword pc) : InstructionPattern(pc) { }
+
+  static const int kLengthInBytes = 3*kWordSize;
+
+  int pattern_length_in_bytes() const {
+    return kLengthInBytes;
+  }
+  bool IsValid() const;
+  uword TargetAddress() const;
+  void SetTargetAddress(uword target_address) const;
 
  private:
-  virtual const int* pattern() const;
-
   DISALLOW_COPY_AND_ASSIGN(JumpPattern);
 };
 
diff --git a/runtime/vm/instructions_arm_test.cc b/runtime/vm/instructions_arm_test.cc
index 86e4dc1..cf2e98c 100644
--- a/runtime/vm/instructions_arm_test.cc
+++ b/runtime/vm/instructions_arm_test.cc
@@ -15,12 +15,14 @@
 #define __ assembler->
 
 ASSEMBLER_TEST_GENERATE(Call, assembler) {
-  UNIMPLEMENTED();
+  __ BranchLinkPatchable(&StubCode::InstanceFunctionLookupLabel());
+  // Do not emit any code after the call above, since we decode backwards
+  // starting from the return address, i.e. from the end of this code buffer.
 }
 
 
-ASSEMBLER_TEST_RUN(Call, entry) {
-  CallPattern call(entry);
+ASSEMBLER_TEST_RUN(Call, test) {
+  CallPattern call(test->entry() + test->code().Size(), test->code());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             call.TargetAddress());
 }
@@ -31,11 +33,11 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Jump, entry) {
-  JumpPattern jump1(entry);
+ASSEMBLER_TEST_RUN(Jump, test) {
+  JumpPattern jump1(test->entry());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             jump1.TargetAddress());
-  JumpPattern jump2(entry + jump1.pattern_length_in_bytes());
+  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
   EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
             jump2.TargetAddress());
   uword target1 = jump1.TargetAddress();
diff --git a/runtime/vm/instructions_ia32_test.cc b/runtime/vm/instructions_ia32_test.cc
index 12d7e3b..3ceade7 100644
--- a/runtime/vm/instructions_ia32_test.cc
+++ b/runtime/vm/instructions_ia32_test.cc
@@ -20,8 +20,8 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Call, entry) {
-  CallPattern call(entry);
+ASSEMBLER_TEST_RUN(Call, test) {
+  CallPattern call(test->entry());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             call.TargetAddress());
 }
@@ -34,11 +34,11 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Jump, entry) {
-  JumpPattern jump1(entry);
+ASSEMBLER_TEST_RUN(Jump, test) {
+  JumpPattern jump1(test->entry());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             jump1.TargetAddress());
-  JumpPattern jump2(entry + jump1.pattern_length_in_bytes());
+  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
   EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
             jump2.TargetAddress());
   uword target1 = jump1.TargetAddress();
diff --git a/runtime/vm/instructions_mips.cc b/runtime/vm/instructions_mips.cc
index 5e115a0..5dd5a0b 100644
--- a/runtime/vm/instructions_mips.cc
+++ b/runtime/vm/instructions_mips.cc
@@ -16,17 +16,30 @@
 }
 
 
-uword CallOrJumpPattern::TargetAddress() const {
+uword CallPattern::TargetAddress() const {
   UNIMPLEMENTED();
   return 0;
 }
 
 
-void CallOrJumpPattern::SetTargetAddress(uword target) const {
+uword JumpPattern::TargetAddress() const {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+
+void CallPattern::SetTargetAddress(uword target) const {
   UNIMPLEMENTED();
 }
 
 
+void JumpPattern::SetTargetAddress(uword target) const {
+  UNIMPLEMENTED();
+}
+
+
+
 const int* CallPattern::pattern() const {
   UNIMPLEMENTED();
   return NULL;
diff --git a/runtime/vm/instructions_mips.h b/runtime/vm/instructions_mips.h
index 6da4eb0..47400f7 100644
--- a/runtime/vm/instructions_mips.h
+++ b/runtime/vm/instructions_mips.h
@@ -11,6 +11,7 @@
 #endif
 
 #include "vm/allocation.h"
+#include "vm/object.h"
 
 namespace dart {
 
@@ -22,12 +23,12 @@
 // Abstract class for all instruction pattern classes.
 class InstructionPattern : public ValueObject {
  public:
-  explicit InstructionPattern(uword pc) : start_(pc) {
+  explicit InstructionPattern(uword pc) : end_(pc) {
     ASSERT(pc != 0);
   }
-  virtual ~InstructionPattern() {}
+  virtual ~InstructionPattern() { }
 
-  // Call to check if the instruction pattern at 'pc' match the instruction.
+  // Check if the instruction ending at 'end_' matches the expected pattern.
   virtual bool IsValid() const {
     return TestBytesWith(pattern(), pattern_length_in_bytes());
   }
@@ -38,54 +39,53 @@
   virtual int pattern_length_in_bytes() const = 0;
 
  protected:
-  uword start() const { return start_; }
+  uword end() const { return end_; }
 
  private:
-  // Returns true if the 'num_bytes' bytes at 'start_' correspond to
-  // array of integers 'data'. 'data' elements are either a byte or -1, which
-  // represents any byte.
+  // Returns true if the 'num_bytes' bytes at 'num_bytes' before 'end_'
+  // correspond to array of integers 'data'. 'data' elements are either a byte
+  // or -1, which represents any byte.
   bool TestBytesWith(const int* data, int num_bytes) const;
 
-  const uword start_;
+  const uword end_;
 
   DISALLOW_COPY_AND_ASSIGN(InstructionPattern);
 };
 
 
-class CallOrJumpPattern : public InstructionPattern {
+class CallPattern : public InstructionPattern {
  public:
+  CallPattern(uword pc, const Code& code)
+      : InstructionPattern(pc), code_(code) { }
+
+  static const int kLengthInBytes = 1*kWordSize;
+
   virtual int pattern_length_in_bytes() const {
     return kLengthInBytes;
   }
   uword TargetAddress() const;
   void SetTargetAddress(uword new_target) const;
 
- protected:
-  explicit CallOrJumpPattern(uword pc) : InstructionPattern(pc) {}
-  static const int kLengthInBytes = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CallOrJumpPattern);
-};
-
-
-class CallPattern : public CallOrJumpPattern {
- public:
-  explicit CallPattern(uword pc) : CallOrJumpPattern(pc) {}
-  static int InstructionLength() {
-    return kLengthInBytes;
-  }
-
  private:
   virtual const int* pattern() const;
 
+  const Code& code_;
+
   DISALLOW_COPY_AND_ASSIGN(CallPattern);
 };
 
 
-class JumpPattern : public CallOrJumpPattern {
+class JumpPattern : public InstructionPattern {
  public:
-  explicit JumpPattern(uword pc) : CallOrJumpPattern(pc) {}
+  explicit JumpPattern(uword pc) : InstructionPattern(pc) { }
+
+  static const int kLengthInBytes = 3*kWordSize;
+
+  virtual int pattern_length_in_bytes() const {
+    return kLengthInBytes;
+  }
+  uword TargetAddress() const;
+  void SetTargetAddress(uword new_target) const;
 
  private:
   virtual const int* pattern() const;
diff --git a/runtime/vm/instructions_mips_test.cc b/runtime/vm/instructions_mips_test.cc
index 3fec989..3db5dae 100644
--- a/runtime/vm/instructions_mips_test.cc
+++ b/runtime/vm/instructions_mips_test.cc
@@ -19,8 +19,8 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Call, entry) {
-  CallPattern call(entry);
+ASSEMBLER_TEST_RUN(Call, test) {
+  CallPattern call(test->entry(), test->code());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             call.TargetAddress());
 }
@@ -31,11 +31,11 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Jump, entry) {
-  JumpPattern jump1(entry);
+ASSEMBLER_TEST_RUN(Jump, test) {
+  JumpPattern jump1(test->entry());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             jump1.TargetAddress());
-  JumpPattern jump2(entry + jump1.pattern_length_in_bytes());
+  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
   EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
             jump2.TargetAddress());
   uword target1 = jump1.TargetAddress();
diff --git a/runtime/vm/instructions_x64_test.cc b/runtime/vm/instructions_x64_test.cc
index 4108cdf..fb46518 100644
--- a/runtime/vm/instructions_x64_test.cc
+++ b/runtime/vm/instructions_x64_test.cc
@@ -20,8 +20,8 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Call, entry) {
-  CallPattern call(entry);
+ASSEMBLER_TEST_RUN(Call, test) {
+  CallPattern call(test->entry());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             call.TargetAddress());
 }
@@ -34,12 +34,12 @@
 }
 
 
-ASSEMBLER_TEST_RUN(Jump, entry) {
-  JumpPattern jump1(entry);
+ASSEMBLER_TEST_RUN(Jump, test) {
+  JumpPattern jump1(test->entry());
   jump1.IsValid();
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             jump1.TargetAddress());
-  JumpPattern jump2(entry + jump1.pattern_length_in_bytes());
+  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
   EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
             jump2.TargetAddress());
   uword target1 = jump1.TargetAddress();
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 9e92536..2b10211 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -66,7 +66,6 @@
 }
 
 
-
 CheckClassInstr::CheckClassInstr(Value* value,
                                  intptr_t deopt_id,
                                  const ICData& unary_checks)
@@ -138,7 +137,8 @@
   BinarySmiOpInstr* other_op = other->AsBinarySmiOp();
   ASSERT(other_op != NULL);
   return (op_kind() == other_op->op_kind()) &&
-      (overflow_ == other_op->overflow_);
+      (overflow_ == other_op->overflow_) &&
+      (is_truncating_ == other_op->is_truncating_);
 }
 
 
@@ -196,8 +196,10 @@
 }
 
 
-GraphEntryInstr::GraphEntryInstr(TargetEntryInstr* normal_entry)
+GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
+                                 TargetEntryInstr* normal_entry)
     : BlockEntryInstr(0, CatchClauseNode::kInvalidTryIndex),
+      parsed_function_(parsed_function),
       normal_entry_(normal_entry),
       catch_entries_(),
       initial_definitions_(),
@@ -373,21 +375,6 @@
 }
 
 
-void ForwardInstructionIterator::ReplaceCurrentWith(Definition* other) {
-  Definition* defn = current_->AsDefinition();
-  ASSERT(defn != NULL);
-  defn->ReplaceUsesWith(other);
-  ASSERT(other->env() == NULL);
-  other->set_env(defn->env());
-  defn->set_env(NULL);
-  ASSERT(!other->HasSSATemp());
-  if (defn->HasSSATemp()) other->set_ssa_temp_index(defn->ssa_temp_index());
-
-  other->InsertBefore(current_);  // So other will be current.
-  RemoveCurrentFromGraph();
-}
-
-
 // Default implementation of visiting basic blocks.  Can be overridden.
 void FlowGraphVisitor::VisitBlocks() {
   ASSERT(current_iterator_ == NULL);
@@ -544,22 +531,74 @@
 
 void Definition::ReplaceWith(Definition* other,
                              ForwardInstructionIterator* iterator) {
-  if ((iterator != NULL) && (this == iterator->Current())) {
-    iterator->ReplaceCurrentWith(other);
-  } else {
-    ReplaceUsesWith(other);
-    ASSERT(other->env() == NULL);
-    other->set_env(env());
-    set_env(NULL);
-    ASSERT(!other->HasSSATemp());
-    if (HasSSATemp()) other->set_ssa_temp_index(ssa_temp_index());
-
-    previous()->LinkTo(other);
-    other->LinkTo(next());
-
-    set_previous(NULL);
-    set_next(NULL);
+  // Record other's input uses.
+  for (intptr_t i = other->InputCount() - 1; i >= 0; --i) {
+    Value* input = other->InputAt(i);
+    input->definition()->AddInputUse(input);
+    input->set_instruction(other);
+    input->set_use_index(i);
   }
+  // Take other's environment from this definition.
+  ASSERT(other->env() == NULL);
+  intptr_t use_index = 0;
+  for (Environment::DeepIterator it(env()); !it.Done(); it.Advance()) {
+    Value* use = it.CurrentValue();
+    use->set_instruction(other);
+    use->set_use_index(use_index++);
+  }
+  other->set_env(env());
+  set_env(NULL);
+  // Replace all uses of this definition with other.
+  ReplaceUsesWith(other);
+  // Reuse this instruction's SSA name for other.
+  ASSERT(!other->HasSSATemp());
+  if (HasSSATemp()) other->set_ssa_temp_index(ssa_temp_index());
+  // Remove this definition's input uses.
+  UnuseAllInputs();
+
+  // Finally remove this definition from the graph.
+  previous()->LinkTo(other);
+  if ((iterator != NULL) && (this == iterator->Current())) {
+    // Remove through the iterator.
+    other->LinkTo(this);
+    iterator->RemoveCurrentFromGraph();
+  } else {
+    other->LinkTo(next());
+  }
+  set_previous(NULL);
+  set_next(NULL);
+}
+
+
+// A misleadingly named function for use in template functions that replace
+// both definitions with definitions and branch comparisons with
+// comparisons.  In the branch case, leave the branch intact and replace its
+// comparison with another comparison.
+void BranchInstr::ReplaceWith(ComparisonInstr* other,
+                              ForwardInstructionIterator* ignored) {
+  // Record the new comparison's input uses.
+  for (intptr_t i = other->InputCount() - 1; i >= 0; --i) {
+    Value* input = other->InputAt(i);
+    input->definition()->AddInputUse(input);
+  }
+  SetComparison(other);
+}
+
+
+void BranchInstr::SetComparison(ComparisonInstr* comp) {
+  // The new comparison's input uses are already recorded in their
+  // definition's use lists.
+  for (intptr_t i = comp->InputCount() - 1; i >= 0; --i) {
+    Value* input = comp->InputAt(i);
+    input->set_instruction(this);
+    input->set_use_index(i);
+  }
+  // There should be no need to copy or unuse an environment.
+  ASSERT(comparison()->env() == NULL);
+  // Remove the current comparison's input uses.
+  comparison()->UnuseAllInputs();
+  ASSERT(!comp->HasUses());
+  comparison_ = comp;
 }
 
 
@@ -843,6 +882,14 @@
       return (right_range == NULL)
           || !right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
     }
+    case Token::kSHL: {
+      Range* right_range = this->right()->definition()->range();
+      if ((right_range != NULL) && is_truncating()) {
+        // Can deoptimize if right can be negative.
+        return !right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
+      }
+      return true;
+    }
     default:
       return overflow_;
   }
@@ -1083,7 +1130,7 @@
   if (call != NULL &&
       call->is_known_constructor() &&
       (call->Type()->ToCid() == kArrayCid)) {
-    return call->ArgumentAt(1)->value()->definition();
+    return call->ArgumentAt(1);
   }
   return this;
 }
@@ -1104,7 +1151,7 @@
     return value()->definition();
   }
 
-  // (3) For uninstantiated target types: If the instantiator type arguments
+  // For uninstantiated target types: If the instantiator type arguments
   // are constant, instantiate the target type here.
   if (dst_type().IsInstantiated()) return this;
 
@@ -1156,17 +1203,13 @@
       // It is safe to pass a NULL iterator because we're replacing the
       // comparison wrapped in a BranchInstr which does not modify the
       // linked list of instructions.
-      ReplaceWith(comp, NULL /* ignored */);
-      for (intptr_t i = 0; i < comp->InputCount(); ++i) {
-        Value* operand = comp->InputAt(i);
-        operand->set_instruction(this);
-      }
+      SetComparison(comp);
       if (FLAG_trace_optimization) {
         OS::Print("Merging comparison v%"Pd"\n", comp->ssa_temp_index());
       }
-      // Clear the comparison's use list, temp index and ssa temp index since
-      // the value of the comparison is not used outside the branch anymore.
-      comp->set_input_use_list(NULL);
+      // Clear the comparison's temp index and ssa temp index since the
+      // value of the comparison is not used outside the branch anymore.
+      ASSERT(comp->input_use_list() == NULL);
       comp->ClearSSATempIndex();
       comp->ClearTempIndex();
     }
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 7e875e1..4d25a91 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -22,11 +22,12 @@
 class Definition;
 class Environment;
 class FlowGraphCompiler;
+class FlowGraphOptimizer;
 class FlowGraphVisitor;
 class Instruction;
 class LocalVariable;
+class ParsedFunction;
 class Range;
-class FlowGraphOptimizer;
 
 
 // TODO(srdjan): Unify with INTRINSIC_LIST.
@@ -44,6 +45,30 @@
   V(_ByteArrayBase, _getUint32, ByteArrayBaseGetUint32, 261365835)             \
   V(_ByteArrayBase, _getFloat32, ByteArrayBaseGetFloat32, 434247298)           \
   V(_ByteArrayBase, _getFloat64, ByteArrayBaseGetFloat64, 434247298)           \
+  V(_Float32Array, _getIndexed, Float32ArrayGetIndexed, 734006846)             \
+  V(_Float64Array, _getIndexed, Float64ArrayGetIndexed, 498074772)             \
+  V(_Int8Array, _getIndexed, Int8ArrayGetIndexed, 712069760)                   \
+  V(_Uint8Array, _getIndexed, Uint8ArrayGetIndexed, 535849990)                 \
+  V(_Uint8ClampedArray, _getIndexed, Uint8ClampedArrayGetIndexed, 873344956)   \
+  V(_ExternalUint8Array, _getIndexed, ExternalUint8ArrayGetIndexed, 402720239) \
+  V(_ExternalUint8ClampedArray, _getIndexed,                                   \
+    ExternalUint8ClampedArrayGetIndexed, 682839007)                            \
+  V(_Int16Array, _getIndexed, Int16ArrayGetIndexed, 313999108)                 \
+  V(_Uint16Array, _getIndexed, Uint16ArrayGetIndexed, 539701175)               \
+  V(_Int32Array, _getIndexed, Int32ArrayGetIndexed, 655321526)                 \
+  V(_Uint32Array, _getIndexed, Uint32ArrayGetIndexed, 1060443550)              \
+  V(_Float32Array, _setIndexed, Float32ArraySetIndexed, 1040992157)            \
+  V(_Float64Array, _setIndexed, Float64ArraySetIndexed, 330158324)             \
+  V(_Int8Array, _setIndexed, Int8ArraySetIndexed, 680713569)                   \
+  V(_Uint8Array, _setIndexed, Uint8ArraySetIndexed, 785627791)                 \
+  V(_Uint8ClampedArray, _setIndexed, Uint8ClampedArraySetIndexed, 464766374)   \
+  V(_ExternalUint8Array, _setIndexed, ExternalUint8ArraySetIndexed, 159706697) \
+  V(_ExternalUint8ClampedArray, _setIndexed,                                   \
+    ExternalUint8ClampedArraySetIndexed, 335716123)                            \
+  V(_Int16Array, _setIndexed, Int16ArraySetIndexed, 12169534)                  \
+  V(_Uint16Array, _setIndexed, Uint16ArraySetIndexed, 36054302)                \
+  V(_Int32Array, _setIndexed, Int32ArraySetIndexed, 306194131)                 \
+  V(_Uint32Array, _setIndexed, Uint32ArraySetIndexed, 410753485)               \
   V(_GrowableObjectArray, get:length, GrowableArrayLength, 725548050)          \
   V(_GrowableObjectArray, get:_capacity, GrowableArrayCapacity, 725548050)     \
   V(_StringBase, get:length, StringBaseLength, 320803993)                      \
@@ -88,7 +113,7 @@
 // Values of CompileType form a lattice with a None type as a bottom and a
 // nullable Dynamic type as a top element. Method Union provides a join
 // operation for the lattice.
-class CompileType : public ZoneAllocated {
+class CompileType {
  public:
   static const bool kNullable = true;
   static const bool kNonNullable = false;
@@ -125,34 +150,34 @@
 
   // Create a new CompileType representing given combination of class id and
   // abstract type. The pair is assumed to be coherent.
-  static CompileType* New(intptr_t cid, const AbstractType& type);
+  static CompileType Create(intptr_t cid, const AbstractType& type);
 
   // Create a new CompileType representing given abstract type. By default
   // values as assumed to be nullable.
-  static CompileType* FromAbstractType(const AbstractType& type,
+  static CompileType FromAbstractType(const AbstractType& type,
                                        bool is_nullable = kNullable);
 
   // Create a new CompileType representing an value with the given class id.
   // Resulting CompileType is nullable only if cid is kDynamicCid or kNullCid.
-  static CompileType* FromCid(intptr_t cid);
+  static CompileType FromCid(intptr_t cid);
 
   // Create None CompileType. It is the bottom of the lattice and is used to
   // represent type of the phi that was not yet inferred.
-  static CompileType* None() {
-    return new CompileType(true, kIllegalCid, NULL);
+  static CompileType None() {
+    return CompileType(true, kIllegalCid, NULL);
   }
 
   // Create Dynamic CompileType. It is the top of the lattice and is used to
   // represent unknown type.
-  static CompileType* Dynamic();
+  static CompileType Dynamic();
 
-  static CompileType* Null();
+  static CompileType Null();
 
   // Create non-nullable Bool type.
-  static CompileType* Bool();
+  static CompileType Bool();
 
   // Create non-nullable Int type.
-  static CompileType* Int();
+  static CompileType Int();
 
   // Perform a join operation over the type lattice.
   void Union(CompileType* other);
@@ -164,13 +189,6 @@
         (ToAbstractType()->Equals(*other->ToAbstractType()));
   }
 
-  // Replaces this type with other.
-  void ReplaceWith(CompileType* other) {
-    is_nullable_ = other->is_nullable_;
-    cid_ = other->cid_;
-    type_ = other->type_;
-  }
-
   bool IsNone() const {
     return (cid_ == kIllegalCid) && (type_ == NULL);
   }
@@ -192,6 +210,21 @@
 };
 
 
+// Zone allocated wrapper for the CompileType value.
+class ZoneCompileType : public ZoneAllocated {
+ public:
+  static CompileType* Wrap(const CompileType& type) {
+    ZoneCompileType* zone_type = new ZoneCompileType(type);
+    return &zone_type->type_;
+  }
+
+ private:
+  explicit ZoneCompileType(const CompileType& type) : type_(type) { }
+
+  CompileType type_;
+};
+
+
 class Value : public ZoneAllocated {
  public:
   // A forward iterator that allows removing the current value from the
@@ -228,6 +261,10 @@
   Value* next_use() const { return next_use_; }
   void set_next_use(Value* next) { next_use_ = next; }
 
+  bool IsSingleUse() const {
+    return (next_use_ == NULL) && (previous_use_ == NULL);
+  }
+
   Instruction* instruction() const { return instruction_; }
   void set_instruction(Instruction* instruction) { instruction_ = instruction; }
 
@@ -239,6 +276,14 @@
 
   Value* Copy() { return new Value(definition_); }
 
+  // This function must only be used when the new Value is dominated by
+  // the original Value.
+  Value* CopyWithType() {
+    Value* copy = new Value(definition_);
+    copy->reaching_type_ = reaching_type_;
+    return copy;
+  }
+
   CompileType* Type();
 
   void SetReachingType(CompileType* type) {
@@ -249,6 +294,8 @@
 
   const char* DebugName() const { return "Value"; }
 
+  bool IsSmiValue() { return Type()->ToCid() == kSmiCid; }
+
   // Return true if the value represents a constant.
   bool BindsToConstant() const;
 
@@ -472,10 +519,11 @@
   // Call instructions override this function and return the number of
   // pushed arguments.
   virtual intptr_t ArgumentCount() const = 0;
-  virtual PushArgumentInstr* ArgumentAt(intptr_t index) const {
+  virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const {
     UNREACHABLE();
     return NULL;
-  };
+  }
+  inline Definition* ArgumentAt(intptr_t index) const;
 
   // Returns true, if this instruction can deoptimize.
   virtual bool CanDeoptimize() const = 0;
@@ -957,10 +1005,6 @@
   // Removes 'current_' from graph and sets 'current_' to previous instruction.
   void RemoveCurrentFromGraph();
 
-  // Inserts replaces 'current_', which must be a definition, with another
-  // definition.  The new definition becomes 'current_'.
-  void ReplaceCurrentWith(Definition* other);
-
   Instruction* Current() const { return current_; }
 
  private:
@@ -993,7 +1037,8 @@
 
 class GraphEntryInstr : public BlockEntryInstr {
  public:
-  explicit GraphEntryInstr(TargetEntryInstr* normal_entry);
+  GraphEntryInstr(const ParsedFunction& parsed_function,
+                  TargetEntryInstr* normal_entry);
 
   DECLARE_INSTRUCTION(GraphEntry)
 
@@ -1022,12 +1067,17 @@
 
   TargetEntryInstr* normal_entry() const { return normal_entry_; }
 
+  const ParsedFunction& parsed_function() const {
+    return parsed_function_;
+  }
+
   virtual void PrintTo(BufferFormatter* f) const;
 
  private:
   virtual void ClearPredecessors() {}
   virtual void AddPredecessor(BlockEntryInstr* predecessor) { UNREACHABLE(); }
 
+  const ParsedFunction& parsed_function_;
   TargetEntryInstr* normal_entry_;
   GrowableArray<TargetEntryInstr*> catch_entries_;
   GrowableArray<Definition*> initial_definitions_;
@@ -1088,7 +1138,7 @@
  public:
   explicit PhiIterator(JoinEntryInstr* join)
       : phis_(join->phis()), index_(-1) {
-    if (!Done()) Advance();  // Advance to the first smi.
+    if (!Done()) Advance();  // Advance to the first phi.
   }
 
   void Advance() {
@@ -1207,10 +1257,14 @@
     return type_;
   }
 
-  // Compute initial compile type for this definition. It is safe to use this
+  virtual CompileType* ComputeInitialType() const {
+    return ZoneCompileType::Wrap(ComputeType());
+  }
+
+  // Compute compile type for this definition. It is safe to use this
   // approximation even before type propagator was run (e.g. during graph
   // building).
-  virtual CompileType* ComputeInitialType() const {
+  virtual CompileType ComputeType() const {
     return CompileType::Dynamic();
   }
 
@@ -1219,6 +1273,20 @@
     return false;
   }
 
+  bool UpdateType(CompileType new_type) {
+    if (type_ == NULL) {
+      type_ = ZoneCompileType::Wrap(new_type);
+      return true;
+    }
+
+    if (type_->IsNone() || !type_->IsEqualTo(&new_type)) {
+      *type_ = new_type;
+      return true;
+    }
+
+    return false;
+  }
+
   bool HasUses() const {
     return (input_use_list_ != NULL) || (env_use_list_ != NULL);
   }
@@ -1318,7 +1386,7 @@
   virtual BlockEntryInstr* GetBlock() const { return block(); }
   JoinEntryInstr* block() const { return block_; }
 
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
   virtual bool RecomputeType();
 
   virtual intptr_t ArgumentCount() const { return 0; }
@@ -1336,7 +1404,6 @@
   // Phi is alive if it reaches a non-environment use.
   bool is_alive() const { return is_alive_; }
   void mark_alive() { is_alive_ = true; }
-  void mark_dead() { is_alive_ = false; }
 
   virtual Representation RequiredInputRepresentation(intptr_t i) const {
     return representation_;
@@ -1415,7 +1482,7 @@
 
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
  private:
   const intptr_t index_;
@@ -1446,7 +1513,7 @@
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   Value* value() const { return value_; }
 
@@ -1476,6 +1543,11 @@
 };
 
 
+inline Definition* Instruction::ArgumentAt(intptr_t index) const {
+  return PushArgumentAt(index)->value()->definition();
+}
+
+
 class ReturnInstr : public TemplateInstruction<1> {
  public:
   ReturnInstr(intptr_t token_pos, Value* value)
@@ -1633,7 +1705,7 @@
   virtual bool HasSideEffect() const;
 
   ComparisonInstr* comparison() const { return comparison_; }
-  void set_comparison(ComparisonInstr* value) { comparison_ = value; }
+  void SetComparison(ComparisonInstr* comp);
 
   bool is_checked() const { return is_checked_; }
 
@@ -1641,11 +1713,13 @@
   virtual intptr_t DeoptimizationTarget() const;
   virtual Representation RequiredInputRepresentation(intptr_t i) const;
 
-  // Replace the comparison with another, leaving the branch intact.
+  // A misleadingly named function for use in template functions that also
+  // replace definitions.  In this case, leave the branch intact and replace
+  // its comparison with another comparison that has been removed from the
+  // graph but still has uses properly linked into their definition's use
+  // list.
   void ReplaceWith(ComparisonInstr* other,
-                   ForwardInstructionIterator* ignored) {
-    comparison_ = other;
-  }
+                   ForwardInstructionIterator* ignored);
 
   virtual Instruction* Canonicalize(FlowGraphOptimizer* optimizer);
 
@@ -1885,7 +1959,7 @@
     return (inputs_[1] == NULL) ? 1 : 2;
   }
 
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual bool CanDeoptimize() const { return false; }
 
@@ -1932,7 +2006,7 @@
       : value_(value) { }
 
   DECLARE_INSTRUCTION(Constant)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   const Object& value() const { return value_; }
 
@@ -2019,7 +2093,7 @@
   }
 
   DECLARE_INSTRUCTION(AssertBoolean)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   intptr_t token_pos() const { return token_pos_; }
   Value* value() const { return inputs_[0]; }
@@ -2052,7 +2126,7 @@
   }
 
   DECLARE_INSTRUCTION(ArgumentDefinitionTest)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   intptr_t token_pos() const { return ast_node_.token_pos(); }
   intptr_t formal_parameter_index() const {
@@ -2084,7 +2158,7 @@
   CurrentContextInstr() { }
 
   DECLARE_INSTRUCTION(CurrentContext)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual bool CanDeoptimize() const { return false; }
 
@@ -2108,7 +2182,7 @@
   intptr_t token_pos() const { return ast_node_.token_pos(); }
 
   virtual intptr_t ArgumentCount() const { return arguments_->length(); }
-  PushArgumentInstr* ArgumentAt(intptr_t index) const {
+  virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const {
     return (*arguments_)[index];
   }
 
@@ -2167,7 +2241,7 @@
   const String& function_name() const { return function_name_; }
   Token::Kind token_kind() const { return token_kind_; }
   virtual intptr_t ArgumentCount() const { return arguments_->length(); }
-  PushArgumentInstr* ArgumentAt(intptr_t index) const {
+  virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const {
     return (*arguments_)[index];
   }
   const Array& argument_names() const { return argument_names_; }
@@ -2213,8 +2287,8 @@
   virtual intptr_t ArgumentCount() const {
     return instance_call()->ArgumentCount();
   }
-  PushArgumentInstr* ArgumentAt(intptr_t index) const {
-    return instance_call()->ArgumentAt(index);
+  virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const {
+    return instance_call()->PushArgumentAt(index);
   }
 
   DECLARE_INSTRUCTION(PolymorphicInstanceCall)
@@ -2321,7 +2395,7 @@
   StrictCompareInstr(Token::Kind kind, Value* left, Value* right);
 
   DECLARE_INSTRUCTION(StrictCompare)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
@@ -2364,7 +2438,8 @@
   }
 
   DECLARE_INSTRUCTION(EqualityCompare)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
+  virtual bool RecomputeType();
 
   const ICData* ic_data() const { return ic_data_; }
   bool HasICData() const {
@@ -2433,7 +2508,8 @@
   }
 
   DECLARE_INSTRUCTION(RelationalOp)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
+  virtual bool RecomputeType();
 
   const ICData* ic_data() const { return ic_data_; }
   bool HasICData() const {
@@ -2506,7 +2582,7 @@
   }
 
   DECLARE_INSTRUCTION(StaticCall)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   // Accessors forwarded to the AST node.
   const Function& function() const { return function_; }
@@ -2514,7 +2590,7 @@
   intptr_t token_pos() const { return token_pos_; }
 
   virtual intptr_t ArgumentCount() const { return arguments_->length(); }
-  PushArgumentInstr* ArgumentAt(intptr_t index) const {
+  virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const {
     return (*arguments_)[index];
   }
 
@@ -2552,7 +2628,7 @@
         context_level_(context_level) { }
 
   DECLARE_INSTRUCTION(LoadLocal)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   const LocalVariable& local() const { return local_; }
   intptr_t context_level() const { return context_level_; }
@@ -2687,7 +2763,7 @@
   explicit LoadStaticFieldInstr(const Field& field) : field_(field) {}
 
   DECLARE_INSTRUCTION(LoadStaticField);
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   const Field& field() const { return field_; }
 
@@ -2751,7 +2827,7 @@
   }
 
   DECLARE_INSTRUCTION(LoadIndexed)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   Value* array() const { return inputs_[0]; }
   Value* index() const { return inputs_[1]; }
@@ -2792,7 +2868,7 @@
   }
 
   DECLARE_INSTRUCTION(StringFromCharCode)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   Value* char_code() const { return inputs_[0]; }
 
@@ -2871,7 +2947,7 @@
   }
 
   DECLARE_INSTRUCTION(BooleanNegate)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   Value* value() const { return inputs_[0]; }
 
@@ -2905,7 +2981,7 @@
   }
 
   DECLARE_INSTRUCTION(InstanceOf)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   Value* value() const { return inputs_[0]; }
   Value* instantiator() const { return inputs_[1]; }
@@ -2945,10 +3021,10 @@
   }
 
   DECLARE_INSTRUCTION(AllocateObject)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual intptr_t ArgumentCount() const { return arguments_->length(); }
-  PushArgumentInstr* ArgumentAt(intptr_t index) const {
+  virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const {
     return (*arguments_)[index];
   }
 
@@ -3019,7 +3095,7 @@
   }
 
   DECLARE_INSTRUCTION(CreateArray)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   intptr_t num_elements() const { return num_elements_; }
 
@@ -3052,13 +3128,13 @@
         token_pos_(token_pos) { }
 
   DECLARE_INSTRUCTION(CreateClosure)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   intptr_t token_pos() const { return token_pos_; }
   const Function& function() const { return function_; }
 
   virtual intptr_t ArgumentCount() const { return arguments_->length(); }
-  PushArgumentInstr* ArgumentAt(intptr_t index) const {
+  virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const {
     return (*arguments_)[index];
   }
 
@@ -3094,7 +3170,7 @@
   }
 
   DECLARE_INSTRUCTION(LoadField)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   Value* value() const { return inputs_[0]; }
   intptr_t offset_in_bytes() const { return offset_in_bytes_; }
@@ -3280,7 +3356,7 @@
         num_context_variables_(num_context_variables) {}
 
   DECLARE_INSTRUCTION(AllocateContext);
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   intptr_t token_pos() const { return token_pos_; }
   intptr_t num_context_variables() const { return num_context_variables_; }
@@ -3333,7 +3409,7 @@
   Value* context_value() const { return inputs_[0]; }
 
   DECLARE_INSTRUCTION(CloneContext)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual bool CanDeoptimize() const { return true; }
 
@@ -3433,7 +3509,7 @@
   }
 
   DECLARE_INSTRUCTION(BoxDouble)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
  private:
   const intptr_t token_pos_;
@@ -3464,7 +3540,7 @@
   }
 
   DECLARE_INSTRUCTION(BoxInteger)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(BoxIntegerInstr);
@@ -3496,7 +3572,7 @@
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
   DECLARE_INSTRUCTION(UnboxDouble)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(UnboxDoubleInstr);
@@ -3520,7 +3596,7 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual Representation representation() const {
     return kUnboxedMint;
@@ -3571,7 +3647,7 @@
   }
 
   DECLARE_INSTRUCTION(MathSqrt)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MathSqrtInstr);
@@ -3625,7 +3701,7 @@
   }
 
   DECLARE_INSTRUCTION(BinaryDoubleOp)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
 
@@ -3642,7 +3718,8 @@
                            Value* left,
                            Value* right,
                            InstanceCallInstr* instance_call)
-      : op_kind_(op_kind) {
+      : op_kind_(op_kind),
+        instance_call_(instance_call) {
     ASSERT(left != NULL);
     ASSERT(right != NULL);
     inputs_[0] = left;
@@ -3655,6 +3732,8 @@
 
   Token::Kind op_kind() const { return op_kind_; }
 
+  InstanceCallInstr* instance_call() const { return instance_call_; }
+
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const {
@@ -3666,10 +3745,11 @@
   virtual bool AffectedBySideEffect() const { return false; }
 
   virtual bool AttributesEqual(Instruction* other) const {
+    ASSERT(other->IsBinaryMintOp());
     return op_kind() == other->AsBinaryMintOp()->op_kind();
   }
 
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual Representation representation() const {
     return kUnboxedMint;
@@ -3692,6 +3772,7 @@
 
  private:
   const Token::Kind op_kind_;
+  InstanceCallInstr* instance_call_;
 
   DISALLOW_COPY_AND_ASSIGN(BinaryMintOpInstr);
 };
@@ -3729,7 +3810,7 @@
     return op_kind() == other->AsShiftMintOp()->op_kind();
   }
 
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual Representation representation() const {
     return kUnboxedMint;
@@ -3783,7 +3864,7 @@
     return op_kind() == other->AsUnaryMintOp()->op_kind();
   }
 
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual Representation representation() const {
     return kUnboxedMint;
@@ -3817,7 +3898,8 @@
                    Value* right)
       : op_kind_(op_kind),
         instance_call_(instance_call),
-        overflow_(true) {
+        overflow_(true),
+        is_truncating_(false) {
     ASSERT(left != NULL);
     ASSERT(right != NULL);
     inputs_[0] = left;
@@ -3838,7 +3920,7 @@
 
   DECLARE_INSTRUCTION(BinarySmiOp)
 
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual bool CanDeoptimize() const;
 
@@ -3851,6 +3933,11 @@
     overflow_ = overflow;
   }
 
+  void set_is_truncating(bool value) {
+    is_truncating_ = value;
+  }
+  bool is_truncating() const { return is_truncating_; }
+
   void PrintTo(BufferFormatter* f) const;
 
   virtual void InferRange();
@@ -3865,6 +3952,7 @@
   const Token::Kind op_kind_;
   InstanceCallInstr* instance_call_;
   bool overflow_;
+  bool is_truncating_;
 
   DISALLOW_COPY_AND_ASSIGN(BinarySmiOpInstr);
 };
@@ -3889,7 +3977,7 @@
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   DECLARE_INSTRUCTION(UnarySmiOp)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual bool CanDeoptimize() const { return op_kind() == Token::kNEGATE; }
 
@@ -3932,7 +4020,7 @@
   InstanceCallInstr* instance_call() const { return instance_call_; }
 
   DECLARE_INSTRUCTION(SmiToDouble)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual intptr_t ArgumentCount() const { return 1; }
 
@@ -3959,7 +4047,7 @@
   InstanceCallInstr* instance_call() const { return instance_call_; }
 
   DECLARE_INSTRUCTION(DoubleToInteger)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual intptr_t ArgumentCount() const { return 1; }
 
@@ -3987,7 +4075,7 @@
   Value* value() const { return inputs_[0]; }
 
   DECLARE_INSTRUCTION(DoubleToSmi)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual bool CanDeoptimize() const { return true; }
 
@@ -4021,7 +4109,7 @@
   MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
 
   DECLARE_INSTRUCTION(DoubleToDouble)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
 
   virtual bool CanDeoptimize() const { return false; }
 
@@ -4062,7 +4150,7 @@
   MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
 
   DECLARE_INSTRUCTION(InvokeMathCFunction)
-  virtual CompileType* ComputeInitialType() const;
+  virtual CompileType ComputeType() const;
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const { return false; }
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 2e3f226..f35ed33 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -172,9 +172,9 @@
 }
 
 
-CompileType* LoadIndexedInstr::ComputeInitialType() const {
+CompileType LoadIndexedInstr::ComputeType() const {
   UNIMPLEMENTED();
-  return NULL;
+  return CompileType::Dynamic();
 }
 
 
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index a475fd6..50a4972 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -796,7 +796,6 @@
   ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
   BranchInstr* kNoBranch = NULL;
   if (receiver_class_id() == kSmiCid) {
-    // Deoptimizes if both arguments not Smi.
     EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch);
     return;
   }
@@ -1095,7 +1094,7 @@
 }
 
 
-CompileType* LoadIndexedInstr::ComputeInitialType() const {
+CompileType LoadIndexedInstr::ComputeType() const {
   switch (class_id_) {
     case kArrayCid:
     case kImmutableArrayCid:
@@ -1314,7 +1313,7 @@
       return kTagged;
     case kInt32ArrayCid:
     case kUint32ArrayCid:
-      return kUnboxedMint;
+      return value()->IsSmiValue() ? kTagged : kUnboxedMint;
     case kFloat32ArrayCid :
     case kFloat64ArrayCid :
       return kUnboxedDouble;
@@ -1368,12 +1367,18 @@
       // Writable register because the value must be untagged before storing.
       locs->set_in(2, Location::WritableRegister());
       break;
+    case kInt32ArrayCid:
+    case kUint32ArrayCid:
+      // Mints are stored in XMM registers. For smis, use a writable register
+      // because the value must be untagged before storing.
+      locs->set_in(2, value()->IsSmiValue()
+                      ? Location::WritableRegister()
+                      : Location::RequiresFpuRegister());
+      break;
     case kFloat32ArrayCid:
       // Need temp register for float-to-double conversion.
       locs->AddTemp(Location::RequiresFpuRegister());
       // Fall through.
-    case kInt32ArrayCid:
-    case kUint32ArrayCid:
     case kFloat64ArrayCid:
       // TODO(srdjan): Support Float64 constants.
       locs->set_in(2, Location::RequiresFpuRegister());
@@ -1483,7 +1488,15 @@
     }
     case kInt32ArrayCid:
     case kUint32ArrayCid:
+      if (value()->IsSmiValue()) {
+        ASSERT(RequiredInputRepresentation(2) == kTagged);
+        Register value = locs()->in(2).reg();
+        __ SmiUntag(value);
+        __ movl(element_address, value);
+      } else {
+        ASSERT(RequiredInputRepresentation(2) == kUnboxedMint);
       __ movss(element_address, locs()->in(2).fpu_reg());
+      }
       break;
     case kFloat32ArrayCid:
       // Convert to single precision.
@@ -1986,6 +1999,131 @@
 }
 
 
+static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
+                             BinarySmiOpInstr* shift_left) {
+  const bool is_truncating = shift_left->is_truncating();
+  const LocationSummary& locs = *shift_left->locs();
+  Register left = locs.in(0).reg();
+  Register result = locs.out().reg();
+  ASSERT(left == result);
+  Label* deopt = shift_left->CanDeoptimize() ?
+      compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL;
+  if (locs.in(1).IsConstant()) {
+    const Object& constant = locs.in(1).constant();
+    ASSERT(constant.IsSmi());
+    // shll operation masks the count to 5 bits.
+    const intptr_t kCountLimit = 0x1F;
+    const intptr_t value = Smi::Cast(constant).Value();
+    if (value == 0) {
+      // No code needed.
+    } else if ((value < 0) || (value >= kCountLimit)) {
+      // This condition may not be known earlier in some cases because
+      // of constant propagation, inlining, etc.
+      if ((value >=kCountLimit) && is_truncating) {
+        __ xorl(result, result);
+      } else {
+        // Result is Mint or exception.
+        __ jmp(deopt);
+      }
+    } else {
+      if (!is_truncating) {
+        // Check for overflow.
+        Register temp = locs.temp(0).reg();
+        __ movl(temp, left);
+        __ shll(left, Immediate(value));
+        __ sarl(left, Immediate(value));
+        __ cmpl(left, temp);
+        __ j(NOT_EQUAL, deopt);  // Overflow.
+      }
+      // Shift for result now we know there is no overflow.
+      __ shll(left, Immediate(value));
+    }
+    return;
+  }
+
+  // Right (locs.in(1)) is not constant.
+  Register right = locs.in(1).reg();
+  Range* right_range = shift_left->right()->definition()->range();
+  if (shift_left->left()->BindsToConstant() && !is_truncating) {
+    // TODO(srdjan): Implement code below for is_truncating().
+    // If left is constant, we know the maximal allowed size for right.
+    const Object& obj = shift_left->left()->BoundConstant();
+    if (obj.IsSmi()) {
+      const intptr_t left_int = Smi::Cast(obj).Value();
+      if (left_int == 0) {
+        __ cmpl(right, Immediate(0));
+        __ j(NEGATIVE, deopt);
+        return;
+      }
+      intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
+      intptr_t max_right = kSmiBits;
+      while ((tmp >>= 1) != 0) {
+        max_right--;
+      }
+      const bool right_needs_check =
+          (right_range == NULL) ||
+          !right_range->IsWithin(0, max_right - 1);
+      if (right_needs_check) {
+        __ cmpl(right,
+            Immediate(reinterpret_cast<int32_t>(Smi::New(max_right))));
+        __ j(ABOVE_EQUAL, deopt);
+      }
+      __ SmiUntag(right);
+      __ shll(left, right);
+    }
+    return;
+  }
+
+  const bool right_needs_check =
+      (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
+  ASSERT(right == ECX);  // Count must be in ECX
+  if (is_truncating) {
+    if (right_needs_check) {
+      const bool right_may_be_negative =
+          (right_range == NULL) ||
+          !right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
+      if (right_may_be_negative) {
+        ASSERT(shift_left->CanDeoptimize());
+        __ cmpl(right, Immediate(0));
+        __ j(NEGATIVE, deopt);
+      }
+      Label done, is_not_zero;
+      __ cmpl(right,
+          Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
+      __ j(BELOW, &is_not_zero, Assembler::kNearJump);
+      __ xorl(left, left);
+      __ jmp(&done, Assembler::kNearJump);
+      __ Bind(&is_not_zero);
+      __ SmiUntag(right);
+      __ shll(left, right);
+      __ Bind(&done);
+    } else {
+      __ SmiUntag(right);
+      __ shll(left, right);
+    }
+  } else {
+    if (right_needs_check) {
+      ASSERT(shift_left->CanDeoptimize());
+      __ cmpl(right,
+        Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
+      __ j(ABOVE_EQUAL, deopt);
+    }
+    // Left is not a constant.
+    Register temp = locs.temp(0).reg();
+    // Check if count too large for handling it inlined.
+    __ movl(temp, left);
+    __ SmiUntag(right);
+    // Overflow test (preserve temp and right);
+    __ shll(left, right);
+    __ sarl(left, right);
+    __ cmpl(left, temp);
+    __ j(NOT_EQUAL, deopt);  // Overflow.
+    // Shift for result now we know there is no overflow.
+    __ shll(left, right);
+  }
+}
+
+
 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 2;
   if (op_kind() == Token::kTRUNCDIV) {
@@ -2016,12 +2154,14 @@
     summary->set_out(Location::SameAsFirstInput());
     return summary;
   } else if (op_kind() == Token::kSHL) {
-    const intptr_t kNumTemps = 1;
+    const intptr_t kNumTemps = 0;
     LocationSummary* summary =
         new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
     summary->set_in(0, Location::RequiresRegister());
     summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), ECX));
-    summary->set_temp(0, Location::RequiresRegister());
+    if (!is_truncating()) {
+      summary->AddTemp(Location::RequiresRegister());
+    }
     summary->set_out(Location::SameAsFirstInput());
     return summary;
   } else {
@@ -2037,6 +2177,12 @@
 
 
 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  if (op_kind() == Token::kSHL) {
+    EmitSmiShiftLeft(compiler, this);
+    return;
+  }
+
+  ASSERT(!is_truncating());
   Register left = locs()->in(0).reg();
   Register result = locs()->out().reg();
   ASSERT(left == result);
@@ -2134,27 +2280,6 @@
         __ SmiTag(left);
         break;
       }
-      case Token::kSHL: {
-        // shll operation masks the count to 5 bits.
-        const intptr_t kCountLimit = 0x1F;
-        intptr_t value = Smi::Cast(constant).Value();
-        if (value == 0) break;
-        if ((value < 0) || (value >= kCountLimit)) {
-          // This condition may not be known earlier in some cases because
-          // of constant propagation, inlining, etc.
-          __ jmp(deopt);
-          break;
-        }
-        Register temp = locs()->temp(0).reg();
-        __ movl(temp, left);
-        __ shll(left, Immediate(value));
-        __ sarl(left, Immediate(value));
-        __ cmpl(left, temp);
-        __ j(NOT_EQUAL, deopt);  // Overflow.
-        // Shift for result now we know there is no overflow.
-        __ shll(left, Immediate(value));
-        break;
-      }
 
       default:
         UNREACHABLE();
@@ -2238,57 +2363,6 @@
       __ SmiTag(left);
       break;
     }
-    case Token::kSHL: {
-      Range* right_range = this->right()->definition()->range();
-      if (this->left()->BindsToConstant()) {
-        // If left is constant, we know the maximal allowed size for right.
-        const Object& obj = this->left()->BoundConstant();
-        if (obj.IsSmi()) {
-          const intptr_t left_int = Smi::Cast(obj).Value();
-          if (left_int == 0) {
-            __ cmpl(right, Immediate(0));
-            __ j(NEGATIVE, deopt);
-            break;
-          }
-          intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
-          intptr_t max_right = kSmiBits;
-          while ((tmp >>= 1) != 0) {
-            max_right--;
-          }
-          const bool right_needs_check =
-              (right_range == NULL) ||
-              !right_range->IsWithin(0, max_right - 1);
-          if (right_needs_check) {
-            __ cmpl(right,
-              Immediate(reinterpret_cast<int32_t>(Smi::New(max_right))));
-            __ j(ABOVE_EQUAL, deopt);
-          }
-          __ SmiUntag(right);
-          __ shll(left, right);
-          break;
-        }
-      }
-      Register temp = locs()->temp(0).reg();
-      // Check if count too large for handling it inlined.
-      __ movl(temp, left);
-      const bool right_needs_check =
-          (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
-      if (right_needs_check) {
-        __ cmpl(right,
-          Immediate(reinterpret_cast<int32_t>(Smi::New(Smi::kBits))));
-        __ j(ABOVE_EQUAL, deopt);
-      }
-      ASSERT(right == ECX);  // Count must be in ECX
-      __ SmiUntag(right);
-      // Overflow test (preserve temp and right);
-      __ shll(left, right);
-      __ sarl(left, right);
-      __ cmpl(left, temp);
-      __ j(NOT_EQUAL, deopt);  // Overflow.
-      // Shift for result now we know there is no overflow.
-      __ shll(left, right);
-      break;
-    }
     case Token::kDIV: {
       // Dispatches to 'Double./'.
       // TODO(srdjan): Implement as conversion to double and double division.
@@ -2315,25 +2389,37 @@
 
 
 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
-  ASSERT((left()->Type()->ToCid() != kDoubleCid) &&
-         (right()->Type()->ToCid() != kDoubleCid));
+  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 = 1;
+  const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid);
+  const intptr_t kNumTemps = need_temp ? 1 : 0;
   LocationSummary* summary =
     new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
   summary->set_in(0, Location::RequiresRegister());
   summary->set_in(1, Location::RequiresRegister());
-  summary->set_temp(0, Location::RequiresRegister());
+  if (need_temp) summary->set_temp(0, Location::RequiresRegister());
   return summary;
 }
 
 
 void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryDoubleOp);
-  Register temp = locs()->temp(0).reg();
-  __ movl(temp, locs()->in(0).reg());
-  __ orl(temp, locs()->in(1).reg());
-  __ testl(temp, Immediate(kSmiTagMask));
+  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) {
+    __ testl(right, Immediate(kSmiTagMask));
+  } else if (right_cid == kSmiCid) {
+    __ testl(left, Immediate(kSmiTagMask));
+  } else {
+    Register temp = locs()->temp(0).reg();
+    __ movl(temp, left);
+    __ orl(temp, right);
+    __ testl(temp, Immediate(kSmiTagMask));
+  }
   __ j(ZERO, deopt);
 }
 
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 2ec2dc6..5b392ce 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -172,9 +172,9 @@
 }
 
 
-CompileType* LoadIndexedInstr::ComputeInitialType() const {
+CompileType LoadIndexedInstr::ComputeType() const {
   UNIMPLEMENTED();
-  return NULL;
+  return CompileType::Dynamic();
 }
 
 
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 41b82f9..7b8f669 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -959,7 +959,7 @@
 }
 
 
-CompileType* LoadIndexedInstr::ComputeInitialType() const {
+CompileType LoadIndexedInstr::ComputeType() const {
   switch (class_id_) {
     case kArrayCid:
     case kImmutableArrayCid:
@@ -984,7 +984,7 @@
 
     default:
       UNIMPLEMENTED();
-      return NULL;
+      return CompileType::Dynamic();
   }
 }
 
@@ -1817,6 +1817,131 @@
 }
 
 
+static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
+                             BinarySmiOpInstr* shift_left) {
+  const bool is_truncating = shift_left->is_truncating();
+  const LocationSummary& locs = *shift_left->locs();
+  Register left = locs.in(0).reg();
+  Register result = locs.out().reg();
+  ASSERT(left == result);
+  Label* deopt = shift_left->CanDeoptimize() ?
+      compiler->AddDeoptStub(shift_left->deopt_id(), kDeoptBinarySmiOp) : NULL;
+  if (locs.in(1).IsConstant()) {
+    const Object& constant = locs.in(1).constant();
+    ASSERT(constant.IsSmi());
+    // shll operation masks the count to 6 bits.
+    const intptr_t kCountLimit = 0x3F;
+    const intptr_t value = Smi::Cast(constant).Value();
+    if (value == 0) {
+      // No code needed.
+    } else if ((value < 0) || (value >= kCountLimit)) {
+      // This condition may not be known earlier in some cases because
+      // of constant propagation, inlining, etc.
+      if ((value >=kCountLimit) && is_truncating) {
+        __ xorq(result, result);
+      } else {
+        // Result is Mint or exception.
+        __ jmp(deopt);
+      }
+    } else {
+      if (!is_truncating) {
+        // Check for overflow.
+        Register temp = locs.temp(0).reg();
+        __ movq(temp, left);
+        __ shlq(left, Immediate(value));
+        __ sarq(left, Immediate(value));
+        __ cmpq(left, temp);
+        __ j(NOT_EQUAL, deopt);  // Overflow.
+      }
+      // Shift for result now we know there is no overflow.
+      __ shlq(left, Immediate(value));
+    }
+    return;
+  }
+
+  // Right (locs.in(1)) is not constant.
+  Register right = locs.in(1).reg();
+  Range* right_range = shift_left->right()->definition()->range();
+  if (shift_left->left()->BindsToConstant() && !is_truncating) {
+    // TODO(srdjan): Implement code below for is_truncating().
+    // If left is constant, we know the maximal allowed size for right.
+    const Object& obj = shift_left->left()->BoundConstant();
+    if (obj.IsSmi()) {
+      const intptr_t left_int = Smi::Cast(obj).Value();
+      if (left_int == 0) {
+        __ cmpq(right, Immediate(0));
+        __ j(NEGATIVE, deopt);
+        return;
+      }
+      intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
+      intptr_t max_right = kSmiBits;
+      while ((tmp >>= 1) != 0) {
+        max_right--;
+      }
+      const bool right_needs_check =
+          (right_range == NULL) ||
+          !right_range->IsWithin(0, max_right - 1);
+      if (right_needs_check) {
+        __ cmpq(right,
+          Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
+        __ j(ABOVE_EQUAL, deopt);
+      }
+      __ SmiUntag(right);
+      __ shlq(left, right);
+    }
+    return;
+  }
+
+  const bool right_needs_check =
+      (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
+  ASSERT(right == RCX);  // Count must be in RCX
+  if (is_truncating) {
+    if (right_needs_check) {
+      const bool right_may_be_negative =
+          (right_range == NULL) ||
+          !right_range->IsWithin(0, RangeBoundary::kPlusInfinity);
+      if (right_may_be_negative) {
+        ASSERT(shift_left->CanDeoptimize());
+        __ cmpq(right, Immediate(0));
+        __ j(NEGATIVE, deopt);
+      }
+      Label done, is_not_zero;
+      __ cmpq(right,
+          Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
+      __ j(BELOW, &is_not_zero, Assembler::kNearJump);
+      __ xorq(left, left);
+      __ jmp(&done, Assembler::kNearJump);
+      __ Bind(&is_not_zero);
+      __ SmiUntag(right);
+      __ shlq(left, right);
+      __ Bind(&done);
+    } else {
+      __ SmiUntag(right);
+      __ shlq(left, right);
+    }
+  } else {
+    if (right_needs_check) {
+      ASSERT(shift_left->CanDeoptimize());
+      __ cmpq(right,
+          Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
+      __ j(ABOVE_EQUAL, deopt);
+    }
+    // Left is not a constant.
+    Register temp = locs.temp(0).reg();
+    // Check if count too large for handling it inlined.
+    __ movq(temp, left);
+    __ SmiUntag(right);
+    // Overflow test (preserve temp and right);
+    __ shlq(left, right);
+    __ sarq(left, right);
+    __ cmpq(left, temp);
+    __ j(NOT_EQUAL, deopt);  // Overflow.
+    // Shift for result now we know there is no overflow.
+    __ shlq(left, right);
+  }
+}
+
+
 static bool CanBeImmediate(const Object& constant) {
   return constant.IsSmi() &&
     Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32();
@@ -1869,12 +1994,14 @@
     summary->set_out(Location::SameAsFirstInput());
     return summary;
   } else if (op_kind() == Token::kSHL) {
-    const intptr_t kNumTemps = 1;
+    const intptr_t kNumTemps = 0;
     LocationSummary* summary =
         new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
     summary->set_in(0, Location::RequiresRegister());
     summary->set_in(1, Location::FixedRegisterOrSmiConstant(right(), RCX));
-    summary->set_temp(0, Location::RequiresRegister());
+    if (!is_truncating()) {
+      summary->AddTemp(Location::RequiresRegister());
+    }
     summary->set_out(Location::SameAsFirstInput());
     return summary;
   } else {
@@ -1889,6 +2016,12 @@
 }
 
 void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  if (op_kind() == Token::kSHL) {
+    EmitSmiShiftLeft(compiler, this);
+    return;
+  }
+
+  ASSERT(!is_truncating());
   Register left = locs()->in(0).reg();
   Register result = locs()->out().reg();
   ASSERT(left == result);
@@ -1990,27 +2123,6 @@
         __ SmiTag(left);
         break;
       }
-      case Token::kSHL: {
-        // shlq operation masks the count to 6 bits.
-        const intptr_t kCountLimit = 0x3F;
-        intptr_t value = Smi::Cast(constant).Value();
-        if (value == 0) break;
-        if ((value < 0) || (value >= kCountLimit)) {
-          // This condition may not be known earlier in some cases because
-          // of constant propagation, inlining, etc.
-          __ jmp(deopt);
-          break;
-        }
-        Register temp = locs()->temp(0).reg();
-        __ movq(temp, left);
-        __ shlq(left, Immediate(value));
-        __ sarq(left, Immediate(value));
-        __ cmpq(left, temp);
-        __ j(NOT_EQUAL, deopt);  // Overflow.
-        // Shift for result now we know there is no overflow.
-        __ shlq(left, Immediate(value));
-        break;
-      }
 
       default:
         UNREACHABLE();
@@ -2094,57 +2206,6 @@
       __ SmiTag(left);
       break;
     }
-    case Token::kSHL: {
-      Range* right_range = this->right()->definition()->range();
-      if (this->left()->BindsToConstant()) {
-        // If left is constant, we know the maximal allowed size for right.
-        const Object& obj = this->left()->BoundConstant();
-        if (obj.IsSmi()) {
-          const intptr_t left_int = Smi::Cast(obj).Value();
-          if (left_int == 0) {
-            __ cmpq(right, Immediate(0));
-            __ j(NEGATIVE, deopt);
-            break;
-          }
-          intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
-          intptr_t max_right = kSmiBits;
-          while ((tmp >>= 1) != 0) {
-            max_right--;
-          }
-          const bool right_needs_check =
-              (right_range == NULL) ||
-              !right_range->IsWithin(0, max_right - 1);
-          if (right_needs_check) {
-            __ cmpq(right,
-              Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
-            __ j(ABOVE_EQUAL, deopt);
-          }
-          __ SmiUntag(right);
-          __ shlq(left, right);
-          break;
-        }
-      }
-      Register temp = locs()->temp(0).reg();
-      // Check if count too large for handling it inlined.
-      __ movq(temp, left);
-      const bool right_needs_check =
-          (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
-      if (right_needs_check) {
-        __ cmpq(right,
-            Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits))));
-        __ j(ABOVE_EQUAL, deopt);
-      }
-      ASSERT(right == RCX);  // Count must be in RCX
-      __ SmiUntag(right);
-      // Overflow test (preserve temp and right);
-      __ shlq(left, right);
-      __ sarq(left, right);
-      __ cmpq(left, temp);
-      __ j(NOT_EQUAL, deopt);  // Overflow.
-      // Shift for result now we know there is no overflow.
-      __ shlq(left, right);
-      break;
-    }
     case Token::kDIV: {
       // Dispatches to 'Double./'.
       // TODO(srdjan): Implement as conversion to double and double division.
@@ -2171,25 +2232,37 @@
 
 
 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
-  ASSERT((left()->Type()->ToCid() != kDoubleCid) &&
-         (right()->Type()->ToCid() != kDoubleCid));
+  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 = 1;
+  const bool need_temp = (left_cid != kSmiCid) && (right_cid != kSmiCid);
+  const intptr_t kNumTemps = need_temp ? 1 : 0;
   LocationSummary* summary =
     new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
   summary->set_in(0, Location::RequiresRegister());
   summary->set_in(1, Location::RequiresRegister());
-  summary->set_temp(0, Location::RequiresRegister());
+  if (need_temp) summary->set_temp(0, Location::RequiresRegister());
   return summary;
 }
 
 
 void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryDoubleOp);
-  Register temp = locs()->temp(0).reg();
-  __ movq(temp, locs()->in(0).reg());
-  __ orq(temp, locs()->in(1).reg());
-  __ testl(temp, Immediate(kSmiTagMask));
+  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) {
+    __ testq(right, Immediate(kSmiTagMask));
+  } else if (right_cid == kSmiCid) {
+    __ testq(left, Immediate(kSmiTagMask));
+  } else {
+    Register temp = locs()->temp(0).reg();
+    __ movq(temp, left);
+    __ orq(temp, right);
+    __ testq(temp, Immediate(kSmiTagMask));
+  }
   __ j(ZERO, deopt);
 }
 
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index 5d4bbf4..379c6c1 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -64,7 +64,7 @@
   V(_ObjectArray, get:length, Array_getLength, 405297088)                      \
   V(_ObjectArray, [], Array_getIndexed, 71937385)                              \
   V(_ObjectArray, []=, Array_setIndexed, 255863719)                            \
-  V(_GrowableObjectArray, .withData, GArray_Allocate, 816132033)               \
+  V(_GrowableObjectArray, .withData, GrowableArray_Allocate, 816132033)        \
   V(_GrowableObjectArray, get:length, GrowableArray_getLength, 725548050)      \
   V(_GrowableObjectArray, get:_capacity, GrowableArray_getCapacity, 725548050) \
   V(_GrowableObjectArray, [], GrowableArray_getIndexed, 581838973)             \
@@ -89,39 +89,19 @@
 
 #define SCALARLIST_LIB_INTRINSIC_LIST(V)                                       \
   V(_ByteArrayBase, get:length, ByteArrayBase_getLength, 1098081765)           \
-  V(_Int8Array, [], Int8Array_getIndexed, 1295306322)                          \
-  V(_Int8Array, []=, Int8Array_setIndexed, 1709956322)                         \
   V(_Int8Array, _new, Int8Array_new, 535958453)                                \
-  V(_Uint8Array, [], Uint8Array_getIndexed, 578331916)                         \
-  V(_Uint8Array, []=, Uint8Array_setIndexed, 121509844)                        \
   V(_Uint8Array, _new, Uint8Array_new, 604355565)                              \
-  V(_Uint8ClampedArray, [], UintClamped8Array_getIndexed, 327062422)           \
-  V(_Uint8ClampedArray, []=, Uint8ClampedArray_setIndexed, 2054663547)         \
   V(_Uint8ClampedArray, _new, Uint8ClampedArray_new, 1070949952)               \
-  V(_Int16Array, [], Int16Array_getIndexed, 870098766)                         \
   V(_Int16Array, _new, Int16Array_new, 903723993)                              \
-  V(_Uint16Array, [], Uint16Array_getIndexed, 1019828411)                      \
-  V(_Uint16Array, []=, Uint16Array_setIndexed, 1457955615)                     \
   V(_Uint16Array, _new, Uint16Array_new, 133542762)                            \
-  V(_Int32Array, [], Int32Array_getIndexed, 1999321436)                        \
   V(_Int32Array, _new, Int32Array_new, 8218286)                                \
-  V(_Uint32Array, [], Uint32Array_getIndexed, 1750764660)                      \
   V(_Uint32Array, _new, Uint32Array_new, 469402161)                            \
   V(_Int64Array, [], Int64Array_getIndexed, 504894128)                         \
   V(_Int64Array, _new, Int64Array_new, 60605075)                               \
   V(_Uint64Array, [], Uint64Array_getIndexed, 31272531)                        \
   V(_Uint64Array, _new, Uint64Array_new, 624354107)                            \
-  V(_Float32Array, [], Float32Array_getIndexed, 147582932)                     \
-  V(_Float32Array, []=, Float32Array_setIndexed, 664454270)                    \
   V(_Float32Array, _new, Float32Array_new, 109944959)                          \
-  V(_Float64Array, [], Float64Array_getIndexed, 638830526)                     \
-  V(_Float64Array, []=, Float64Array_setIndexed, 1948811847)                   \
   V(_Float64Array, _new, Float64Array_new, 147668392)                          \
-  V(_ExternalUint8Array, [], ExternalUint8Array_getIndexed, 753790851)         \
-  V(_ExternalUint8ClampedArray, [], ExternalUint8ClampedArray_getIndexed,      \
-      823759763)                                                               \
-  V(_ExternalUint8ClampedArray, []=, ExternalUint8ClampedArray_setIndexed,     \
-      654373808)                                                               \
 
 
 // TODO(srdjan): Implement _FixedSizeArrayIterator, get:current and
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index e606969..c2b7c2b 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -39,7 +39,7 @@
 }
 
 
-bool Intrinsifier::GArray_Allocate(Assembler* assembler) {
+bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) {
   return false;
 }
 
@@ -84,91 +84,36 @@
 }
 
 
-bool Intrinsifier::Int8Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Int8Array_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Int8Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Uint8Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Uint8Array_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Uint8Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::UintClamped8Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Uint8ClampedArray_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Uint8ClampedArray_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Int16Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Int16Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Uint16Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Uint16Array_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Uint16Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Int32Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Int32Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Uint32Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Uint32Array_new(Assembler* assembler) {
   return false;
 }
@@ -194,51 +139,16 @@
 }
 
 
-bool Intrinsifier::Float32Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Float32Array_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Float32Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Float64Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::ExternalUint8Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::ExternalUint8ClampedArray_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::ExternalUint8ClampedArray_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) {
   return false;
 }
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index b939f78..7bd0c89 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -249,7 +249,7 @@
 
 // Allocate a GrowableObjectArray using the backing array specified.
 // On stack: type argument (+2), data (+1), return-address (+0).
-bool Intrinsifier::GArray_Allocate(Assembler* assembler) {
+bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) {
   // This snippet of inlined code uses the following registers:
   // EAX, EBX
   // and the newly allocated object is returned in EAX.
@@ -468,81 +468,6 @@
 }
 
 
-// Tests if index is a valid length (Smi and within valid index range),
-// jumps to fall_through if it is not.
-// Returns index in EBX, array in EAX.
-// This should be used only on getIndexed intrinsics.
-static void TestByteArrayGetIndex(Assembler* assembler, Label* fall_through) {
-  __ movl(EAX, Address(ESP, + 2 * kWordSize));  // Array.
-  __ movl(EBX, Address(ESP, + 1 * kWordSize));  // Index.
-  __ testl(EBX, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, fall_through, Assembler::kNearJump);  // Non-smi index.
-  // Range check.
-  __ cmpl(EBX, FieldAddress(EAX, ByteArray::length_offset()));
-  // Runtime throws exception.
-  __ j(ABOVE_EQUAL, fall_through, Assembler::kNearJump);
-}
-
-
-// Tests if index is a valid length (Smi and within valid index range),
-// jumps to fall_through if it is not.
-// Returns index in EBX, array in EAX.
-// This should be used only for setIndexed intrinsics.
-static void TestByteArraySetIndex(Assembler* assembler, Label* fall_through) {
-  __ movl(EAX, Address(ESP, + 3 * kWordSize));  // Array.
-  __ movl(EBX, Address(ESP, + 2 * kWordSize));  // Index.
-  __ testl(EBX, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, fall_through, Assembler::kNearJump);  // Non-smi index.
-  // Range check.
-  __ cmpl(EBX, FieldAddress(EAX, ByteArray::length_offset()));
-  // Runtime throws exception.
-  __ j(ABOVE_EQUAL, fall_through, Assembler::kNearJump);
-}
-
-
-bool Intrinsifier::Int8Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ SmiUntag(EBX);
-  __ movsxb(EAX, FieldAddress(EAX,
-                              EBX,
-                              TIMES_1,
-                              Int8Array::data_offset()));
-  __ SmiTag(EAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Int8Array_setIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ SmiUntag(EBX);
-  // Free EBX for the value since we want a byte register.
-  __ movl(EDI, EBX);
-  __ movl(EBX, Address(ESP, + 1 * kWordSize));  // Value.
-  __ testl(EBX, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
-  __ SmiUntag(EBX);
-  // Check that the value is a byte. Add 128 to EBX to bring it into
-  // the range 0..FF.
-  __ addl(EBX, Immediate(128));
-  __ cmpl(EBX, Immediate(0xFF));
-  __ j(ABOVE, &fall_through, Assembler::kNearJump);
-  // Undo addition.
-  __ subl(EBX, Immediate(128));
-  __ movb(FieldAddress(EAX, EDI, TIMES_1, Int8Array::data_offset()), BL);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 #define TYPED_ARRAY_ALLOCATION(type_name, scale_factor)                        \
   Label fall_through;                                                          \
   const intptr_t kArrayLengthStackOffset = 1 * kWordSize;                      \
@@ -635,210 +560,36 @@
 }
 
 
-bool Intrinsifier::Uint8Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ SmiUntag(EBX);
-  __ movzxb(EAX, FieldAddress(EAX,
-                              EBX,
-                              TIMES_1,
-                              Uint8Array::data_offset()));
-  __ SmiTag(EAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Uint8Array_setIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ SmiUntag(EBX);
-  // Free EBX for the value since we want a byte register.
-  __ movl(EDI, EBX);
-  __ movl(EBX, Address(ESP, + 1 * kWordSize));  // Value.
-  __ testl(EBX, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
-  __ SmiUntag(EBX);
-  // Check that the value is a byte.
-  __ cmpl(EBX, Immediate(0xFF));
-  __ j(ABOVE, &fall_through, Assembler::kNearJump);
-  __ movb(FieldAddress(EAX, EDI, TIMES_1, Uint8Array::data_offset()), BL);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Uint8Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Uint8Array, TIMES_1);
   return false;
 }
 
 
-bool Intrinsifier::UintClamped8Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ SmiUntag(EBX);
-  __ movzxb(EAX, FieldAddress(EAX,
-                              EBX,
-                              TIMES_1,
-                              Uint8ClampedArray::data_offset()));
-  __ SmiTag(EAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Uint8ClampedArray_setIndexed(Assembler* assembler) {
-  Label fall_through, store_value, load_0xff;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ SmiUntag(EBX);
-  // Free EBX for the value since we need a byte register.
-  __ leal(EAX, FieldAddress(EAX, EBX, TIMES_1,
-      Uint8ClampedArray::data_offset()));
-  __ movl(EBX, Address(ESP, + 1 * kWordSize));  // Value.
-  __ testl(EBX, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
-
-  __ SmiUntag(EBX);
-  __ cmpl(EBX, Immediate(0xFF));
-  __ j(BELOW_EQUAL, &store_value, Assembler::kNearJump);
-  // Clamp to 0x00 or 0xFF respectively.
-  __ j(GREATER, &load_0xff,  Assembler::kNearJump);
-  __ xorl(EBX, EBX);  // Zero.
-  __ jmp(&store_value, Assembler::kNearJump);
-  __ Bind(&load_0xff);
-  __ movl(EBX, Immediate(0xFF));
-
-  __ Bind(&store_value);
-  __ movb(Address(EAX, 0), BL);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Uint8ClampedArray_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Uint8ClampedArray, TIMES_1);
   return false;
 }
 
 
-bool Intrinsifier::Int16Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ movsxw(EAX, FieldAddress(EAX,
-                              EBX,
-                              TIMES_1,
-                              Int16Array::data_offset()));
-  __ SmiTag(EAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Int16Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Int16Array, TIMES_2);
   return false;
 }
 
 
-bool Intrinsifier::Uint16Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ movzxw(EAX, FieldAddress(EAX,
-                              EBX,
-                              TIMES_1,
-                              Uint16Array::data_offset()));
-  __ SmiTag(EAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Uint16Array_setIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ movl(EDI, Address(ESP, + 1 * kWordSize));
-  __ SmiUntag(EDI);
-  // EDI: undtagged value.
-  __ testl(EDI, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
-  __ movw(FieldAddress(EAX, EBX, TIMES_1, Uint16Array::data_offset()), EDI);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Uint16Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Uint16Array, TIMES_2);
   return false;
 }
 
 
-bool Intrinsifier::Int32Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ movl(EAX, FieldAddress(EAX,
-                            EBX,
-                            TIMES_2,
-                            Int32Array::data_offset()));
-  // Verify that the signed value in EAX can fit inside a Smi.
-  __ cmpl(EAX, Immediate(0xC0000000));
-  __ j(NEGATIVE, &fall_through, Assembler::kNearJump);  // Won't fit Smi.
-  __ SmiTag(EAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Int32Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Int32Array, TIMES_4);
   return false;
 }
 
 
-bool Intrinsifier::Uint32Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ movl(EAX, FieldAddress(EAX,
-                            EBX,
-                            TIMES_2,
-                            Uint32Array::data_offset()));
-  // Verify that the unsigned value in EAX can be stored in a Smi.
-  __ testl(EAX,  Immediate(0xC0000000));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);  // Won't fit Smi.
-  __ SmiTag(EAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Uint32Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Uint32Array, TIMES_4);
   return false;
@@ -867,172 +618,18 @@
 }
 
 
-bool Intrinsifier::Float32Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  // Load single precision float into XMM7.
-  __ movss(XMM7, FieldAddress(EAX, EBX, TIMES_2,
-                              Float32Array::data_offset()));
-  // Convert into a double precision float.
-  __ cvtss2sd(XMM7, XMM7);
-  // Allocate a double instance.
-  const Class& double_class = Class::Handle(
-                          Isolate::Current()->object_store()->double_class());
-  AssemblerMacros::TryAllocate(assembler,
-                               double_class,
-                               &fall_through,
-                               Assembler::kNearJump, EAX);
-  // Store XMM7 into double instance.
-  __ movsd(FieldAddress(EAX, Double::value_offset()), XMM7);
-  __ ret();
-  __ Bind(&fall_through);
-
-  return false;
-}
-
-
-bool Intrinsifier::Float32Array_setIndexed(Assembler* assembler) {
-  Label fall_through;
-  __ movl(EAX, Address(ESP, + 1 * kWordSize));  // Value.
-  // If EAX is not an instance of double, jump to fall through.
-  __ testl(EAX, Immediate(kSmiTagMask));
-  __ j(ZERO, &fall_through);
-  __ CompareClassId(EAX, kDoubleCid, EDI);
-  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
-  // Load double value into XMM7.
-  __ movsd(XMM7, FieldAddress(EAX, Double::value_offset()));
-  TestByteArraySetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  // Convert from double precision float to single precision float.
-  __ cvtsd2ss(XMM7, XMM7);
-  // Store into array.
-  __ movss(FieldAddress(EAX, EBX, TIMES_2, Float32Array::data_offset()), XMM7);
-  // End fast path.
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Float32Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Float32Array, TIMES_4);
   return false;
 }
 
 
-bool Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  // Load double precision float into XMM7.
-  __ movsd(XMM7, FieldAddress(EAX, EBX, TIMES_4,
-                              Float64Array::data_offset()));
-  // Allocate a double instance.
-  const Class& double_class = Class::Handle(
-    Isolate::Current()->object_store()->double_class());
-  AssemblerMacros::TryAllocate(assembler,
-                               double_class,
-                               &fall_through,
-                               Assembler::kNearJump, EAX);
-  // Store XMM7 into double instance.
-  __ movsd(FieldAddress(EAX, Double::value_offset()), XMM7);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
-  Label fall_through;
-  __ movl(EAX, Address(ESP, + 1 * kWordSize));  // Value.
-  // If EAX is not an instance of double, jump to fall through.
-  __ testl(EAX, Immediate(kSmiTagMask));
-  __ j(ZERO, &fall_through, Assembler::kNearJump);
-  __ CompareClassId(EAX, kDoubleCid, EDI);
-  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
-  // Load double value into XMM7.
-  __ movsd(XMM7, FieldAddress(EAX, Double::value_offset()));
-  TestByteArraySetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ movsd(FieldAddress(EAX, EBX, TIMES_4, Float64Array::data_offset()), XMM7);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Float64Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Float64Array, TIMES_8);
   return false;
 }
 
 
-bool Intrinsifier::ExternalUint8Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ SmiUntag(EBX);
-  __ movl(EAX, FieldAddress(EAX, ExternalUint8Array::data_offset()));
-  __ movzxb(EAX, Address(EAX, EBX, TIMES_1, 0));
-  __ SmiTag(EAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::ExternalUint8ClampedArray_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ SmiUntag(EBX);
-  __ movl(EAX, FieldAddress(EAX, ExternalUint8ClampedArray::data_offset()));
-  __ movzxb(EAX, Address(EAX, EBX, TIMES_1, 0));
-  __ SmiTag(EAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::ExternalUint8ClampedArray_setIndexed(Assembler* assembler) {
-  Label fall_through, store_value, load_0xff;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // EBX: index as Smi.
-  // EAX: array.
-  __ SmiUntag(EBX);
-  __ movl(EAX, FieldAddress(EAX, ExternalUint8ClampedArray::data_offset()));
-  // Free EBX for the value since we need a byte register.
-  __ leal(EAX, Address(EAX, EBX, TIMES_1, 0));
-  __ movl(EBX, Address(ESP, + 1 * kWordSize));  // Value.
-  __ testl(EBX, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
-
-  __ SmiUntag(EBX);
-  __ cmpl(EBX, Immediate(0xFF));
-  __ j(BELOW_EQUAL, &store_value, Assembler::kNearJump);
-  // Clamp to 0x00 or 0xFF respectively.
-  __ j(GREATER, &load_0xff,  Assembler::kNearJump);
-  __ xorl(EBX, EBX);  // Zero.
-  __ jmp(&store_value, Assembler::kNearJump);
-  __ Bind(&load_0xff);
-  __ movl(EBX, Immediate(0xFF));
-
-  __ Bind(&store_value);
-  __ movb(Address(EAX, 0), BL);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 // Tests if two top most arguments are smis, jumps to label not_smi if not.
 // Topmost argument is in EAX.
 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) {
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 5c07f27..70540a6 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -39,7 +39,7 @@
 }
 
 
-bool Intrinsifier::GArray_Allocate(Assembler* assembler) {
+bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) {
   return false;
 }
 
@@ -84,91 +84,36 @@
 }
 
 
-bool Intrinsifier::Int8Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Int8Array_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Int8Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Uint8Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Uint8Array_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Uint8Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::UintClamped8Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Uint8ClampedArray_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Uint8ClampedArray_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Int16Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Int16Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Uint16Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Uint16Array_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Uint16Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Int32Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Int32Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Uint32Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Uint32Array_new(Assembler* assembler) {
   return false;
 }
@@ -194,51 +139,16 @@
 }
 
 
-bool Intrinsifier::Float32Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Float32Array_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Float32Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Float64Array_new(Assembler* assembler) {
   return false;
 }
 
 
-bool Intrinsifier::ExternalUint8Array_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::ExternalUint8ClampedArray_getIndexed(Assembler* assembler) {
-  return false;
-}
-
-
-bool Intrinsifier::ExternalUint8ClampedArray_setIndexed(Assembler* assembler) {
-  return false;
-}
-
-
 bool Intrinsifier::Integer_addFromInteger(Assembler* assembler) {
   return false;
 }
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 8d75a2e..694c384 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -202,7 +202,7 @@
 
 // Allocate a GrowableObjectArray using the backing array specified.
 // On stack: type argument (+2), data (+1), return-address (+0).
-bool Intrinsifier::GArray_Allocate(Assembler* assembler) {
+bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) {
   // This snippet of inlined code uses the following registers:
   // RAX, RCX, R13
   // and the newly allocated object is returned in RAX.
@@ -440,63 +440,6 @@
 }
 
 
-// Tests if index is a valid length (Smi and within valid index range),
-// jumps to fall_through if it is not.
-// Returns index in R12, array in RAX.
-// This should be used only for setIndexed intrinsics.
-static void TestByteArraySetIndex(Assembler* assembler, Label* fall_through) {
-  __ movq(RAX, Address(RSP, + 3 * kWordSize));  // Array.
-  __ movq(R12, Address(RSP, + 2 * kWordSize));  // Index.
-  __ testq(R12, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, fall_through, Assembler::kNearJump);  // Non-smi index.
-  // Range check.
-  __ cmpq(R12, FieldAddress(RAX, ByteArray::length_offset()));
-  // Runtime throws exception.
-  __ j(ABOVE_EQUAL, fall_through, Assembler::kNearJump);
-}
-
-
-bool Intrinsifier::Int8Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ SmiUntag(R12);
-  __ movsxb(RAX, FieldAddress(RAX,
-                              R12,
-                              TIMES_1,
-                              Int8Array::data_offset()));
-  __ SmiTag(RAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Int8Array_setIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ SmiUntag(R12);
-  __ movq(RDI, Address(RSP, + 1 * kWordSize));  // Value.
-  __ testq(RDI, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
-  __ SmiUntag(RDI);
-  // Check that the value is a byte. Add 128 to the value to bring it into
-  // the range 0..FF.
-  __ addq(RDI, Immediate(128));
-  __ cmpq(RDI, Immediate(0xFF));
-  __ j(ABOVE, &fall_through, Assembler::kNearJump);
-  // Undo addition.
-  __ subq(RDI, Immediate(128));
-  __ movb(FieldAddress(RAX, R12, TIMES_1, Uint8Array::data_offset()), RDI);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 #define TYPED_ARRAY_ALLOCATION(type_name, scale_factor)                        \
   Label fall_through;                                                          \
   const intptr_t kArrayLengthStackOffset = 1 * kWordSize;                      \
@@ -594,199 +537,36 @@
 }
 
 
-bool Intrinsifier::Uint8Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ SmiUntag(R12);
-  __ movzxb(RAX, FieldAddress(RAX,
-                              R12,
-                              TIMES_1,
-                              Uint8Array::data_offset()));
-  __ SmiTag(RAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Uint8Array_setIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ SmiUntag(R12);
-  __ movq(RDI, Address(RSP, + 1 * kWordSize));  // Value.
-  __ testq(RDI, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
-  __ SmiUntag(RDI);
-  // Check that value is a byte.
-  __ cmpq(RDI, Immediate(0xFF));
-  __ j(ABOVE, &fall_through, Assembler::kNearJump);
-  __ movb(FieldAddress(RAX, R12, TIMES_1, Uint8Array::data_offset()), RDI);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Uint8Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Uint8Array, TIMES_1);
   return false;
 }
 
 
-bool Intrinsifier::UintClamped8Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ SmiUntag(R12);
-  __ movzxb(RAX, FieldAddress(RAX,
-                              R12,
-                              TIMES_1,
-                              Uint8ClampedArray::data_offset()));
-  __ SmiTag(RAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Uint8ClampedArray_setIndexed(Assembler* assembler) {
-  Label fall_through, store_value, load_0xff;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ SmiUntag(R12);
-  __ movq(RDI, Address(RSP, + 1 * kWordSize));  // Value.
-  __ testq(RDI, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
-
-  __ SmiUntag(RDI);
-  __ cmpq(RDI, Immediate(0xFF));
-  __ j(BELOW_EQUAL, &store_value, Assembler::kNearJump);
-  __ j(GREATER, &load_0xff,  Assembler::kNearJump);
-  __ xorq(RDI, RDI);  // Zero.
-  __ jmp(&store_value, Assembler::kNearJump);
-  __ Bind(&load_0xff);
-  __ movq(RDI, Immediate(0xFF));
-
-  __ Bind(&store_value);
-  __ movb(
-      FieldAddress(RAX, R12, TIMES_1, Uint8ClampedArray::data_offset()), RDI);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Uint8ClampedArray_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Uint8ClampedArray, TIMES_1);
   return false;
 }
 
 
-bool Intrinsifier::Int16Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ movsxw(RAX, FieldAddress(RAX,
-                              R12,
-                              TIMES_1,
-                              Int16Array::data_offset()));
-  __ SmiTag(RAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Int16Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Int16Array, TIMES_2);
   return false;
 }
 
 
-bool Intrinsifier::Uint16Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ movzxw(RAX, FieldAddress(RAX,
-                              R12,
-                              TIMES_1,
-                              Uint16Array::data_offset()));
-  __ SmiTag(RAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Uint16Array_setIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ movq(RDI, Address(RSP, + 1 * kWordSize));
-  __ SmiUntag(RDI);
-  // RDI: untagged value.
-  __ testl(RDI, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
-  __ movw(FieldAddress(RAX, R12, TIMES_1, Uint16Array::data_offset()), RDI);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Uint16Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Uint16Array, TIMES_2);
   return false;
 }
 
 
-bool Intrinsifier::Int32Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ movsxl(RAX, FieldAddress(RAX,
-                              R12,
-                              TIMES_2,
-                              Int32Array::data_offset()));
-  __ SmiTag(RAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Int32Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Int32Array, TIMES_4);
   return false;
 }
 
 
-bool Intrinsifier::Uint32Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ movl(RAX, FieldAddress(RAX,
-                            R12,
-                            TIMES_2,
-                            Uint32Array::data_offset()));
-  __ SmiTag(RAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Uint32Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Uint32Array, TIMES_4);
   return false;
@@ -850,169 +630,18 @@
 }
 
 
-bool Intrinsifier::Float32Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  // Load single precision float into XMM7.
-  __ movss(XMM7, FieldAddress(RAX, R12, TIMES_2,
-                              Float32Array::data_offset()));
-  // Convert into a double precision float.
-  __ cvtss2sd(XMM7, XMM7);
-  // Allocate a double instance.
-  const Class& double_class = Class::Handle(
-                          Isolate::Current()->object_store()->double_class());
-  AssemblerMacros::TryAllocate(assembler,
-                               double_class,
-                               &fall_through,
-                               Assembler::kNearJump, RAX);
-  // Store XMM7 into double instance.
-  __ movsd(FieldAddress(RAX, Double::value_offset()), XMM7);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Float32Array_setIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ movq(RDX, Address(RSP, + 1 * kWordSize));  // Value.
-  // If RDX is not an instance of double, jump to fall through.
-  __ testq(RDX, Immediate(kSmiTagMask));
-  __ j(ZERO, &fall_through, Assembler::kNearJump);
-  __ CompareClassId(RDX, kDoubleCid);
-  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
-  // Load double value into XMM7.
-  __ movsd(XMM7, FieldAddress(RDX, Double::value_offset()));
-  // Convert from double precision float to single precision float.
-  __ cvtsd2ss(XMM7, XMM7);
-  // Store into array.
-  __ movss(FieldAddress(RAX, R12, TIMES_2, Float32Array::data_offset()), XMM7);
-  // End fast path.
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Float32Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Float32Array, TIMES_4);
   return false;
 }
 
 
-bool Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  // Load double precision float into XMM7.
-  __ movsd(XMM7, FieldAddress(RAX, R12, TIMES_4,
-                              Float64Array::data_offset()));
-  // Allocate a double instance.
-  const Class& double_class = Class::Handle(
-    Isolate::Current()->object_store()->double_class());
-  AssemblerMacros::TryAllocate(assembler,
-                               double_class,
-                               &fall_through,
-                               Assembler::kNearJump, RAX);
-  // Store XMM7 into double instance.
-  __ movsd(FieldAddress(RAX, Double::value_offset()), XMM7);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ movq(RDX, Address(RSP, + 1 * kWordSize));  // Value.
-  // If RDX is not an instance of double, jump to fall through.
-  __ testq(RDX, Immediate(kSmiTagMask));
-  __ j(ZERO, &fall_through, Assembler::kNearJump);
-  __ CompareClassId(RDX, kDoubleCid);
-  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
-  // Load double value into XMM7.
-  __ movsd(XMM7, FieldAddress(RDX, Double::value_offset()));
-  // Store into array.
-  __ movsd(FieldAddress(RAX, R12, TIMES_4, Float64Array::data_offset()), XMM7);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 bool Intrinsifier::Float64Array_new(Assembler* assembler) {
   TYPED_ARRAY_ALLOCATION(Float64Array, TIMES_8);
   return false;
 }
 
 
-bool Intrinsifier::ExternalUint8Array_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ SmiUntag(R12);
-  __ movq(RAX, FieldAddress(RAX, ExternalUint8Array::data_offset()));
-  __ movzxb(RAX, Address(RAX, R12, TIMES_1, 0));
-  __ SmiTag(RAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::ExternalUint8ClampedArray_getIndexed(Assembler* assembler) {
-  Label fall_through;
-  TestByteArrayGetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ SmiUntag(R12);
-  __ movq(RAX, FieldAddress(RAX, ExternalUint8ClampedArray::data_offset()));
-  __ movzxb(RAX, Address(RAX, R12, TIMES_1, 0));
-  __ SmiTag(RAX);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
-bool Intrinsifier::ExternalUint8ClampedArray_setIndexed(Assembler* assembler) {
-  Label fall_through, store_value, load_0xff;
-  TestByteArraySetIndex(assembler, &fall_through);
-  // R12: index as Smi.
-  // RAX: array.
-  __ SmiUntag(R12);
-  __ movq(RDI, Address(RSP, + 1 * kWordSize));  // Value.
-  __ testq(RDI, Immediate(kSmiTagMask));
-  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
-
-  __ SmiUntag(RDI);
-  __ cmpq(RDI, Immediate(0xFF));
-  __ j(BELOW_EQUAL, &store_value, Assembler::kNearJump);
-  __ j(GREATER, &load_0xff,  Assembler::kNearJump);
-  __ xorq(RDI, RDI);  // Zero.
-  __ jmp(&store_value, Assembler::kNearJump);
-  __ Bind(&load_0xff);
-  __ movq(RDI, Immediate(0xFF));
-
-  __ Bind(&store_value);
-  __ movq(RAX, FieldAddress(RAX, ExternalUint8ClampedArray::data_offset()));
-  __ movb(Address(RAX, R12, TIMES_1, 0), RDI);
-  __ ret();
-  __ Bind(&fall_through);
-  return false;
-}
-
-
 // Tests if two top most arguments are smis, jumps to label not_smi if not.
 // Topmost argument is in RAX.
 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) {
diff --git a/runtime/vm/native_entry_test.cc b/runtime/vm/native_entry_test.cc
index 3ed8980..217c080 100644
--- a/runtime/vm/native_entry_test.cc
+++ b/runtime/vm/native_entry_test.cc
@@ -94,9 +94,9 @@
   DartFrameIterator iterator;
   iterator.NextFrame();  // Skip native call.
   StackFrame* static_caller_frame = iterator.NextFrame();
-  uword target_address =
-      CodePatcher::GetStaticCallTargetAt(static_caller_frame->pc());
   const Code& code = Code::Handle(static_caller_frame->LookupDartCode());
+  uword target_address =
+      CodePatcher::GetStaticCallTargetAt(static_caller_frame->pc(), code);
   const Function& target_function =
       Function::Handle(code.GetStaticCallTargetFunctionAt(
           static_caller_frame->pc()));
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 5ed104a..b2dba5a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -631,6 +631,16 @@
   lib.AddClass(cls);
 }
 
+#define INIT_LIBRARY(name, raw_script, raw_lib)                                \
+  script ^= raw_script;                                                        \
+  Library::Init##name##Library(isolate);                                       \
+  lib ^= raw_lib;                                                              \
+  ASSERT(!lib.IsNull());                                                       \
+  error = Bootstrap::Compile(lib, script);                                     \
+  if (!error.IsNull()) {                                                       \
+    return error.raw();                                                        \
+  }                                                                            \
+
 
 RawError* Object::Init(Isolate* isolate) {
   TIMERSCOPE(time_bootstrap);
@@ -761,7 +771,7 @@
   pending_classes.Add(cls, Heap::kOld);
 
   // Initialize the base interfaces used by the core VM classes.
-  const Script& script = Script::Handle(Bootstrap::LoadCoreScript(false));
+  Script& script = Script::Handle(Bootstrap::LoadCoreScript(false));
 
   // Allocate and initialize the pre-allocated classes in the core library.
   cls = Class::New<Instance>(kInstanceCid);
@@ -1084,6 +1094,19 @@
   if (!error.IsNull()) {
     return error.raw();
   }
+  Library& lib = Library::Handle();
+  INIT_LIBRARY(Crypto,
+               Bootstrap::LoadCryptoScript(false),
+               Library::CryptoLibrary());
+  INIT_LIBRARY(Json,
+               Bootstrap::LoadJsonScript(false),
+               Library::JsonLibrary());
+  INIT_LIBRARY(Utf,
+               Bootstrap::LoadUtfScript(false),
+               Library::UtfLibrary());
+  INIT_LIBRARY(Uri,
+               Bootstrap::LoadUriScript(false),
+               Library::UriLibrary());
   Bootstrap::SetupNativeResolver();
 
   // Remove the Object superclass cycle by setting the super type to null (not
@@ -2355,6 +2378,16 @@
 }
 
 
+RawFunction* Class::LookupConstructorAllowPrivate(const String& name) const {
+  Function& function = Function::Handle(LookupFunctionAllowPrivate(name));
+  if (function.IsNull() || !function.IsConstructor()) {
+    return Function::null();
+  }
+  ASSERT(!function.is_static());
+  return function.raw();
+}
+
+
 RawFunction* Class::LookupFactory(const String& name) const {
   Function& function = Function::Handle(LookupFunction(name));
   if (function.IsNull() || !function.IsFactory()) {
@@ -6373,11 +6406,15 @@
 }
 
 
-void Library::InitMathLibrary(Isolate* isolate) {
-  const String& url = Symbols::DartMath();
+void Library::InitCryptoLibrary(Isolate* isolate) {
+  const String& url = Symbols::DartCrypto();
   const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
   lib.Register();
-  isolate->object_store()->set_math_library(lib);
+  const Library& math_lib = Library::Handle(Library::MathLibrary());
+  const Namespace& math_ns = Namespace::Handle(
+      Namespace::New(math_lib, Array::Handle(), Array::Handle()));
+  lib.AddImport(math_ns);
+  isolate->object_store()->set_crypto_library(lib);
 }
 
 
@@ -6393,6 +6430,22 @@
 }
 
 
+void Library::InitJsonLibrary(Isolate* isolate) {
+  const String& url = Symbols::DartJson();
+  const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
+  lib.Register();
+  isolate->object_store()->set_json_library(lib);
+}
+
+
+void Library::InitMathLibrary(Isolate* isolate) {
+  const String& url = Symbols::DartMath();
+  const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
+  lib.Register();
+  isolate->object_store()->set_math_library(lib);
+}
+
+
 void Library::InitMirrorsLibrary(Isolate* isolate) {
   const String& url = Symbols::DartMirrors();
   const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
@@ -6414,19 +6467,6 @@
 }
 
 
-void Library::InitScalarlistLibrary(Isolate* isolate) {
-  const String& url = Symbols::DartScalarlist();
-  const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
-  lib.Register();
-  const Library& collection_lib =
-      Library::Handle(Library::CollectionLibrary());
-  const Namespace& collection_ns = Namespace::Handle(
-      Namespace::New(collection_lib, Array::Handle(), Array::Handle()));
-  lib.AddImport(collection_ns);
-  isolate->object_store()->set_scalarlist_library(lib);
-}
-
-
 void Library::InitNativeWrappersLibrary(Isolate* isolate) {
   static const int kNumNativeWrappersClasses = 4;
   ASSERT(kNumNativeWrappersClasses > 0 && kNumNativeWrappersClasses < 10);
@@ -6452,6 +6492,47 @@
 }
 
 
+void Library::InitScalarlistLibrary(Isolate* isolate) {
+  const String& url = Symbols::DartScalarlist();
+  const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
+  lib.Register();
+  const Library& collection_lib =
+      Library::Handle(Library::CollectionLibrary());
+  const Namespace& collection_ns = Namespace::Handle(
+      Namespace::New(collection_lib, Array::Handle(), Array::Handle()));
+  lib.AddImport(collection_ns);
+  isolate->object_store()->set_scalarlist_library(lib);
+}
+
+
+void Library::InitUriLibrary(Isolate* isolate) {
+  const String& url = Symbols::DartUri();
+  const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
+  lib.Register();
+  const Library& math_lib = Library::Handle(Library::MathLibrary());
+  const Namespace& math_ns = Namespace::Handle(
+      Namespace::New(math_lib, Array::Handle(), Array::Handle()));
+  const Library& utf_lib = Library::Handle(Library::UtfLibrary());
+  const Namespace& utf_ns = Namespace::Handle(
+      Namespace::New(utf_lib, Array::Handle(), Array::Handle()));
+  lib.AddImport(math_ns);
+  lib.AddImport(utf_ns);
+  isolate->object_store()->set_uri_library(lib);
+}
+
+
+void Library::InitUtfLibrary(Isolate* isolate) {
+  const String& url = Symbols::DartUtf();
+  const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
+  lib.Register();
+  const Library& async_lib = Library::Handle(Library::ASyncLibrary());
+  const Namespace& async_ns = Namespace::Handle(
+      Namespace::New(async_lib, Array::Handle(), Array::Handle()));
+  lib.AddImport(async_ns);
+  isolate->object_store()->set_utf_library(lib);
+}
+
+
 RawLibrary* Library::LookupLibrary(const String &url) {
   Isolate* isolate = Isolate::Current();
   Library& lib = Library::Handle(isolate, Library::null());
@@ -6565,8 +6646,8 @@
 }
 
 
-RawLibrary* Library::MathLibrary() {
-  return Isolate::Current()->object_store()->math_library();
+RawLibrary* Library::CryptoLibrary() {
+  return Isolate::Current()->object_store()->crypto_library();
 }
 
 
@@ -6575,18 +6656,38 @@
 }
 
 
+RawLibrary* Library::JsonLibrary() {
+  return Isolate::Current()->object_store()->json_library();
+}
+
+
+RawLibrary* Library::MathLibrary() {
+  return Isolate::Current()->object_store()->math_library();
+}
+
+
 RawLibrary* Library::MirrorsLibrary() {
   return Isolate::Current()->object_store()->mirrors_library();
 }
 
 
+RawLibrary* Library::NativeWrappersLibrary() {
+  return Isolate::Current()->object_store()->native_wrappers_library();
+}
+
+
 RawLibrary* Library::ScalarlistLibrary() {
   return Isolate::Current()->object_store()->scalarlist_library();
 }
 
 
-RawLibrary* Library::NativeWrappersLibrary() {
-  return Isolate::Current()->object_store()->native_wrappers_library();
+RawLibrary* Library::UriLibrary() {
+  return Isolate::Current()->object_store()->uri_library();
+}
+
+
+RawLibrary* Library::UtfLibrary() {
+  return Isolate::Current()->object_store()->utf_library();
 }
 
 
@@ -7648,9 +7749,12 @@
       region.Store<RawObject*>(offset_in_instrs, object->raw());
     }
 
-    // Hook up Code and Instruction objects.
+    // Hook up Code and Instructions objects.
     instrs.set_code(code.raw());
     code.set_instructions(instrs.raw());
+
+    // Set object pool in Instructions object.
+    instrs.set_object_pool(Array::MakeArray(assembler->object_pool()));
   }
   return code.raw();
 }
@@ -7708,7 +7812,7 @@
     if ((descriptors.DeoptId(i) == deopt_id) &&
         (descriptors.DescriptorKind(i) == kind)) {
       uword pc = descriptors.PC(i);
-      ASSERT((EntryPoint() <= pc) && (pc < (EntryPoint() + Size())));
+      ASSERT(ContainsInstructionAt(pc));
       return pc;
     }
   }
@@ -7777,7 +7881,8 @@
         max_id = deopt_id;
       }
       node_ids->Add(deopt_id);
-      CodePatcher::GetInstanceCallAt(descriptors.PC(i), &ic_data_obj, NULL);
+      CodePatcher::GetInstanceCallAt(descriptors.PC(i), *this,
+                                     &ic_data_obj, NULL);
       ic_data_objs.Add(ic_data_obj);
     }
   }
@@ -7813,7 +7918,7 @@
     if (descriptors.DescriptorKind(i) == PcDescriptors::kFuncCall) {
       // Static call.
       const uword target_addr =
-          CodePatcher::GetStaticCallTargetAt(descriptors.PC(i));
+          CodePatcher::GetStaticCallTargetAt(descriptors.PC(i), *this);
       if (target_addr == StubCode::CallStaticFunctionEntryPoint()) {
         deopt_ids->Add(descriptors.DeoptId(i));
       }
@@ -8116,7 +8221,6 @@
 #endif  // DEBUG
   ASSERT(num_args_tested() == 1);  // Otherwise use 'AddCheck'.
   ASSERT(receiver_class_id != kIllegalCid);
-  ASSERT(!target.IsNull());
 
   const intptr_t old_num = NumberOfChecks();
   Array& data = Array::Handle(ic_data());
@@ -11890,6 +11994,9 @@
 
 
 RawArray* Array::MakeArray(const GrowableObjectArray& growable_array) {
+  if (growable_array.IsNull()) {
+    return Array::null();
+  }
   intptr_t used_len = growable_array.Length();
   intptr_t capacity_len = growable_array.Capacity();
   Isolate* isolate = Isolate::Current();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 88e93d2..a0ba8ae 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -753,6 +753,7 @@
   RawFunction* LookupStaticFunction(const String& name) const;
   RawFunction* LookupStaticFunctionAllowPrivate(const String& name) const;
   RawFunction* LookupConstructor(const String& name) const;
+  RawFunction* LookupConstructorAllowPrivate(const String& name) const;
   RawFunction* LookupFactory(const String& name) const;
   RawFunction* LookupFunction(const String& name) const;
   RawFunction* LookupFunctionAllowPrivate(const String& name) const;
@@ -2116,21 +2117,29 @@
   static void InitCoreLibrary(Isolate* isolate);
   static void InitCollectionLibrary(Isolate* isolate);
   static void InitCollectionDevLibrary(Isolate* isolate);
-  static void InitMathLibrary(Isolate* isolate);
+  static void InitCryptoLibrary(Isolate* isolate);
   static void InitIsolateLibrary(Isolate* isolate);
+  static void InitJsonLibrary(Isolate* isolate);
+  static void InitMathLibrary(Isolate* isolate);
   static void InitMirrorsLibrary(Isolate* isolate);
-  static void InitScalarlistLibrary(Isolate* isolate);
   static void InitNativeWrappersLibrary(Isolate* isolate);
+  static void InitScalarlistLibrary(Isolate* isolate);
+  static void InitUriLibrary(Isolate* isolate);
+  static void InitUtfLibrary(Isolate* isolate);
 
   static RawLibrary* ASyncLibrary();
   static RawLibrary* CoreLibrary();
   static RawLibrary* CollectionLibrary();
   static RawLibrary* CollectionDevLibrary();
-  static RawLibrary* MathLibrary();
+  static RawLibrary* CryptoLibrary();
   static RawLibrary* IsolateLibrary();
+  static RawLibrary* JsonLibrary();
+  static RawLibrary* MathLibrary();
   static RawLibrary* MirrorsLibrary();
-  static RawLibrary* ScalarlistLibrary();
   static RawLibrary* NativeWrappersLibrary();
+  static RawLibrary* ScalarlistLibrary();
+  static RawLibrary* UriLibrary();
+  static RawLibrary* UtfLibrary();
 
   // Eagerly compile all classes and functions in the library.
   static RawError* CompileAll();
@@ -2224,8 +2233,9 @@
 
 class Instructions : public Object {
  public:
-  intptr_t size() const { return raw_ptr()->size_; }
+  intptr_t size() const { return raw_ptr()->size_; }  // Excludes HeaderSize().
   RawCode* code() const { return raw_ptr()->code_; }
+  RawArray* object_pool() const { return raw_ptr()->object_pool_; }
 
   uword EntryPoint() const {
     return reinterpret_cast<uword>(raw_ptr()) + HeaderSize();
@@ -2263,9 +2273,12 @@
   void set_size(intptr_t size) const {
     raw_ptr()->size_ = size;
   }
-  void set_code(RawCode* code) {
+  void set_code(RawCode* code) const {
     raw_ptr()->code_ = code;
   }
+  void set_object_pool(RawArray* object_pool) const {
+    raw_ptr()->object_pool_ = object_pool;
+  }
 
   // New is a private method as RawInstruction and RawCode objects should
   // only be created using the Code::FinalizeCode method. This method creates
@@ -2608,6 +2621,15 @@
     const Instructions& instr = Instructions::Handle(instructions());
     return instr.size();
   }
+  RawArray* ObjectPool() const {
+    const Instructions& instr = Instructions::Handle(instructions());
+    return instr.object_pool();
+  }
+  bool ContainsInstructionAt(uword addr) const {
+    const Instructions& instr = Instructions::Handle(instructions());
+    const uword offset = addr - instr.EntryPoint();
+    return offset < static_cast<uword>(instr.size());
+  }
 
   RawPcDescriptors* pc_descriptors() const {
     return raw_ptr()->pc_descriptors_;
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 0d847da..5343c42 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -66,15 +66,20 @@
     weak_property_class_(Class::null()),
     symbol_table_(Array::null()),
     canonical_type_arguments_(Array::null()),
+    async_library_(Library::null()),
+    builtin_library_(Library::null()),
     core_library_(Library::null()),
     core_impl_library_(Library::null()),
-    math_library_(Library::null()),
+    crypto_library_(Library::null()),
     isolate_library_(Library::null()),
+    json_library_(Library::null()),
+    math_library_(Library::null()),
     mirrors_library_(Library::null()),
-    scalarlist_library_(Library::null()),
     native_wrappers_library_(Library::null()),
-    builtin_library_(Library::null()),
     root_library_(Library::null()),
+    scalarlist_library_(Library::null()),
+    uri_library_(Library::null()),
+    utf_library_(Library::null()),
     libraries_(GrowableObjectArray::null()),
     pending_classes_(GrowableObjectArray::null()),
     sticky_error_(Error::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index bf98064..8bc26cf 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -360,6 +360,13 @@
     async_library_ = value.raw();
   }
 
+  RawLibrary* builtin_library() const {
+    return builtin_library_;
+  }
+  void set_builtin_library(const Library& value) {
+    builtin_library_ = value.raw();
+  }
+
   RawLibrary* core_library() const { return core_library_; }
   void set_core_library(const Library& value) {
     core_library_ = value.raw();
@@ -384,11 +391,11 @@
     collection_dev_library_ = value.raw();
   }
 
-  RawLibrary* math_library() const {
-    return math_library_;
+  RawLibrary* crypto_library() const {
+    return crypto_library_;
   }
-  void set_math_library(const Library& value) {
-    math_library_ = value.raw();
+  void set_crypto_library(const Library& value) {
+    crypto_library_ = value.raw();
   }
 
   RawLibrary* isolate_library() const {
@@ -398,6 +405,25 @@
     isolate_library_ = value.raw();
   }
 
+  RawLibrary* json_library() const {
+    return json_library_;
+  }
+  void set_json_library(const Library& value) {
+    json_library_ = value.raw();
+  }
+
+  RawLibrary* math_library() const {
+    return math_library_;
+  }
+  void set_math_library(const Library& value) {
+    math_library_ = value.raw();
+  }
+
+  RawLibrary* mirrors_library() const { return mirrors_library_; }
+  void set_mirrors_library(const Library& value) {
+    mirrors_library_ = value.raw();
+  }
+
   RawLibrary* native_wrappers_library() const {
     return native_wrappers_library_;
   }
@@ -405,9 +431,9 @@
     native_wrappers_library_ = value.raw();
   }
 
-  RawLibrary* mirrors_library() const { return mirrors_library_; }
-  void set_mirrors_library(const Library& value) {
-    mirrors_library_ = value.raw();
+  RawLibrary* root_library() const { return root_library_; }
+  void set_root_library(const Library& value) {
+    root_library_ = value.raw();
   }
 
   RawLibrary* scalarlist_library() const {
@@ -417,16 +443,18 @@
     scalarlist_library_ = value.raw();
   }
 
-  RawLibrary* builtin_library() const {
-    return builtin_library_;
+  RawLibrary* uri_library() const {
+    return uri_library_;
   }
-  void set_builtin_library(const Library& value) {
-    builtin_library_ = value.raw();
+  void set_uri_library(const Library& value) {
+    uri_library_ = value.raw();
   }
 
-  RawLibrary* root_library() const { return root_library_; }
-  void set_root_library(const Library& value) {
-    root_library_ = value.raw();
+  RawLibrary* utf_library() const {
+    return utf_library_;
+  }
+  void set_utf_library(const Library& value) {
+    utf_library_ = value.raw();
   }
 
   RawGrowableObjectArray* libraries() const { return libraries_; }
@@ -568,17 +596,21 @@
   RawArray* symbol_table_;
   RawArray* canonical_type_arguments_;
   RawLibrary* async_library_;
+  RawLibrary* builtin_library_;
   RawLibrary* core_library_;
   RawLibrary* core_impl_library_;
   RawLibrary* collection_library_;
   RawLibrary* collection_dev_library_;
-  RawLibrary* math_library_;
+  RawLibrary* crypto_library_;
   RawLibrary* isolate_library_;
+  RawLibrary* json_library_;
+  RawLibrary* math_library_;
   RawLibrary* mirrors_library_;
-  RawLibrary* scalarlist_library_;
   RawLibrary* native_wrappers_library_;
-  RawLibrary* builtin_library_;
   RawLibrary* root_library_;
+  RawLibrary* scalarlist_library_;
+  RawLibrary* uri_library_;
+  RawLibrary* utf_library_;
   RawGrowableObjectArray* libraries_;
   RawGrowableObjectArray* pending_classes_;
   RawError* sticky_error_;
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index 94d58b3..0bf5d36 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -2,17 +2,20 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "vm/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "vm/os.h"
 
-#include <android/log.h>
-#include <errno.h>
-#include <limits.h>
-#include <malloc.h>
-#include <time.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
+#include <android/log.h>  // NOLINT
+#include <errno.h>  // NOLINT
+#include <limits.h>  // NOLINT
+#include <malloc.h>  // NOLINT
+#include <time.h>  // NOLINT
+#include <sys/resource.h>  // NOLINT
+#include <sys/time.h>  // NOLINT
+#include <sys/types.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "platform/utils.h"
 #include "vm/code_observers.h"
@@ -417,3 +420,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index 66360b7..a9dcfd9 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -2,16 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "vm/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "vm/os.h"
 
-#include <errno.h>
-#include <limits.h>
-#include <malloc.h>
-#include <time.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
+#include <errno.h>  // NOLINT
+#include <limits.h>  // NOLINT
+#include <malloc.h>  // NOLINT
+#include <time.h>  // NOLINT
+#include <sys/resource.h>  // NOLINT
+#include <sys/time.h>  // NOLINT
+#include <sys/types.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "platform/utils.h"
 #include "vm/code_observers.h"
@@ -422,3 +425,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index 35166e1..fd530de 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -2,16 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "vm/globals.h"
+#if defined(TARGET_OS_MACOS)
+
 #include "vm/os.h"
 
-#include <errno.h>
-#include <limits.h>
-#include <mach/mach.h>
-#include <mach/clock.h>
-#include <mach/mach_time.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <unistd.h>
+#include <errno.h>  // NOLINT
+#include <limits.h>  // NOLINT
+#include <mach/mach.h>  // NOLINT
+#include <mach/clock.h>  // NOLINT
+#include <mach/mach_time.h>  // NOLINT
+#include <sys/time.h>  // NOLINT
+#include <sys/resource.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "platform/utils.h"
 #include "vm/isolate.h"
@@ -219,3 +222,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index d4d51d7..7fa1b8c 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -2,10 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "vm/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "vm/os.h"
 
-#include <malloc.h>
-#include <time.h>
+#include <malloc.h>  // NOLINT
+#include <time.h>  // NOLINT
 
 #include "platform/utils.h"
 #include "platform/assert.h"
@@ -290,3 +293,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 0c9427e..4740688 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -4,6 +4,7 @@
 
 #include "vm/parser.h"
 
+#include "lib/invocation_mirror.h"
 #include "vm/bigint_operations.h"
 #include "vm/class_finalizer.h"
 #include "vm/compiler.h"
@@ -2394,7 +2395,13 @@
     // TODO(regis): For an instance function, pass the receiver to
     // NoSuchMethodError.
     current_block_->statements->Add(
-        ThrowNoSuchMethodError(TokenPos(), current_class(), function_name));
+        ThrowNoSuchMethodError(TokenPos(),
+                               current_class(),
+                               function_name,
+                               func.is_static() ?
+                                   InvocationMirror::kStatic :
+                                   InvocationMirror::kDynamic,
+                               InvocationMirror::kMethod));
   } else {
     UnexpectedToken();
   }
@@ -6849,7 +6856,9 @@
 // argument values? Or should the spec specify a different evaluation order?
 AstNode* Parser::ThrowNoSuchMethodError(intptr_t call_pos,
                                         const Class& cls,
-                                        const String& function_name) {
+                                        const String& function_name,
+                                        InvocationMirror::Call im_call,
+                                        InvocationMirror::Type im_type) {
   ArgumentListNode* arguments = new ArgumentListNode(call_pos);
   // Object receiver.
   // TODO(regis): For now, we pass a class literal of the unresolved
@@ -6862,6 +6871,14 @@
   // String memberName.
   arguments->Add(new LiteralNode(
       call_pos, String::ZoneHandle(Symbols::New(function_name))));
+  // Smi invocation_type.
+  if (cls.IsTopLevel()) {
+    ASSERT(im_call == InvocationMirror::kStatic ||
+           im_call == InvocationMirror::kTopLevel);
+    im_call = InvocationMirror::kTopLevel;
+  }
+  arguments->Add(new LiteralNode(call_pos, Smi::ZoneHandle(
+      Smi::New(InvocationMirror::EncodeType(im_call, im_type)))));
   // List arguments.
   arguments->Add(new LiteralNode(call_pos, Array::ZoneHandle()));
   // List argumentNames.
@@ -7173,7 +7190,9 @@
     // TODO(tball): determine whether NoSuchMethod should be called instead.
     result = ThrowNoSuchMethodError(original->token_pos(),
                                     current_class(),
-                                    type_name);
+                                    type_name,
+                                    InvocationMirror::kStatic,
+                                    InvocationMirror::kSetter);
   }
   if ((result != NULL) &&
       (result->IsStoreIndexedNode() ||
@@ -7458,7 +7477,11 @@
       return new ClosureCallNode(call_pos, closure, arguments);
     }
     // Could not resolve static method: throw a NoSuchMethodError.
-    return ThrowNoSuchMethodError(ident_pos, cls, func_name);
+    return ThrowNoSuchMethodError(ident_pos,
+                                  cls,
+                                  func_name,
+                                  InvocationMirror::kStatic,
+                                  InvocationMirror::kMethod);
   }
   return new StaticCallNode(call_pos, func, arguments);
 }
@@ -7529,7 +7552,11 @@
                                      Resolver::kIsQualified);
       if (func.IsNull()) {
         // No field or explicit setter function, throw a NoSuchMethodError.
-        return ThrowNoSuchMethodError(ident_pos, cls, field_name);
+        return ThrowNoSuchMethodError(ident_pos,
+                                      cls,
+                                      field_name,
+                                      InvocationMirror::kStatic,
+                                      InvocationMirror::kField);
       }
 
       // Explicit setter function for the field found, field does not exist.
@@ -7569,7 +7596,11 @@
         func = cls.LookupStaticFunction(field_name);
         if (func.IsNull()) {
           // No field or explicit getter function, throw a NoSuchMethodError.
-          return ThrowNoSuchMethodError(ident_pos, cls, field_name);
+          return ThrowNoSuchMethodError(ident_pos,
+                                        cls,
+                                        field_name,
+                                        InvocationMirror::kStatic,
+                                        InvocationMirror::kGetter);
         }
         access = CreateImplicitClosureNode(func, call_pos, NULL);
       } else {
@@ -7606,7 +7637,9 @@
         current_function().IsInFactoryScope()) {
       return ThrowNoSuchMethodError(primary->token_pos(),
                                     current_class(),
-                                    name);
+                                    name,
+                                    InvocationMirror::kStatic,
+                                    InvocationMirror::kField);
     } else {
       AstNode* receiver = LoadReceiver(primary->token_pos());
       return CallGetter(node->token_pos(), receiver, name);
@@ -7744,7 +7777,9 @@
           if (current_function().is_static()) {
             selector = ThrowNoSuchMethodError(primary->token_pos(),
                                               current_class(),
-                                              name);
+                                              name,
+                                              InvocationMirror::kStatic,
+                                              InvocationMirror::kMethod);
           } else {
             // Treat as call to unresolved (instance) method.
             AstNode* receiver = LoadReceiver(primary->token_pos());
@@ -8255,7 +8290,14 @@
   }
 
   // Try to find the identifier in the class scope of the current class.
-  Class& cls = Class::Handle(isolate, current_class().raw());
+  // If the current class is the result of a mixin application, we must
+  // use the class scope of the class from which the function originates.
+  Class& cls = Class::Handle(isolate);
+  if (current_class().mixin() == Type::null()) {
+    cls = current_class().raw();
+  } else {
+    cls = parsed_function()->function().origin();
+  }
   Function& func = Function::Handle(isolate, Function::null());
   Field& field = Field::Handle(isolate, Field::null());
 
@@ -8656,7 +8698,11 @@
       // the unresolved name to an instance field access, since a
       // subclass might define a field with this name.
       if (current_function().is_static()) {
-        resolved = ThrowNoSuchMethodError(ident_pos, current_class(), ident);
+        resolved = ThrowNoSuchMethodError(ident_pos,
+                                          current_class(),
+                                          ident,
+                                          InvocationMirror::kStatic,
+                                          InvocationMirror::kField);
       } else {
         // Treat as call to unresolved instance field.
         resolved = CallGetter(ident_pos, LoadReceiver(ident_pos), ident);
@@ -9256,7 +9302,9 @@
       }
       return ThrowNoSuchMethodError(call_pos,
                                     type_class,
-                                    external_constructor_name);
+                                    external_constructor_name,
+                                    InvocationMirror::kConstructor,
+                                    InvocationMirror::kMethod);
     } else if (constructor.IsRedirectingFactory()) {
       Type& redirect_type = Type::Handle(constructor.RedirectionType());
       if (!redirect_type.IsMalformed() && !redirect_type.IsInstantiated()) {
@@ -9316,7 +9364,9 @@
     }
     return ThrowNoSuchMethodError(call_pos,
                                   type_class,
-                                  external_constructor_name);
+                                  external_constructor_name,
+                                  InvocationMirror::kConstructor,
+                                  InvocationMirror::kMethod);
   }
 
   // Return a throw in case of a malformed type or report a compile-time error
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index f0ca6d5..ba83c47 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -7,6 +7,7 @@
 
 #include "include/dart_api.h"
 
+#include "lib/invocation_mirror.h"
 #include "vm/ast.h"
 #include "vm/class_finalizer.h"
 #include "vm/compiler_stats.h"
@@ -614,7 +615,9 @@
   AstNode* ThrowTypeError(intptr_t type_pos, const AbstractType& type);
   AstNode* ThrowNoSuchMethodError(intptr_t call_pos,
                                   const Class& cls,
-                                  const String& function_name);
+                                  const String& function_name,
+                                  InvocationMirror::Call call,
+                                  InvocationMirror::Type type);
 
   void CheckOperatorArity(const MemberDesc& member);
 
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index de55c74..ecf2a79 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -472,7 +472,7 @@
 intptr_t RawInstructions::VisitInstructionsPointers(
     RawInstructions* raw_obj, ObjectPointerVisitor* visitor) {
   RawInstructions* obj = raw_obj->ptr();
-  visitor->VisitPointer(reinterpret_cast<RawObject**>(&obj->code_));
+  visitor->VisitPointers(raw_obj->from(), raw_obj->to());
   return Instructions::InstanceSize(obj->size_);
 }
 
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 9dd8faa..2889ff9 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -791,7 +791,14 @@
 class RawInstructions : public RawObject {
   RAW_HEAP_OBJECT_IMPLEMENTATION(Instructions);
 
+  RawObject** from() {
+    return reinterpret_cast<RawObject**>(&ptr()->code_);
+  }
   RawCode* code_;
+  RawArray* object_pool_;
+  RawObject** to() {
+    return reinterpret_cast<RawObject**>(&ptr()->object_pool_);
+  }
   intptr_t size_;
 
   // Variable length data follows here.
diff --git a/runtime/vm/stack_frame_arm.cc b/runtime/vm/stack_frame_arm.cc
index 2d90b32..8d4ee28 100644
--- a/runtime/vm/stack_frame_arm.cc
+++ b/runtime/vm/stack_frame_arm.cc
@@ -50,4 +50,4 @@
 
 }  // namespace dart
 
-#endif  // defined TARGET_ARCH_ARM
+#endif  // defined(TARGET_ARCH_ARM)
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index b942c17..8160cfb 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -50,8 +50,10 @@
 
 
 void StubCode::InitOnce() {
-  // TODO(regis): Re-enable this after we are able to generate arm code.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+  // TODO(regis): Re-enable this after we are able to generate mips code.
+#if defined(TARGET_ARCH_IA32) ||                                               \
+    defined(TARGET_ARCH_X64) ||                                                \
+    defined(TARGET_ARCH_ARM)
   // Generate all the stubs.
   Code& code = Code::Handle();
   VM_STUB_CODE_LIST(STUB_CODE_GENERATE);
@@ -60,8 +62,10 @@
 
 
 void StubCode::GenerateFor(Isolate* init) {
-  // TODO(regis): Re-enable this after we are able to generate arm code.
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+  // TODO(regis): Re-enable this after we are able to generate mips code.
+#if defined(TARGET_ARCH_IA32) ||                                               \
+    defined(TARGET_ARCH_X64) ||                                                \
+    defined(TARGET_ARCH_ARM)
   // Generate all the stubs.
   Code& code = Code::Handle();
   STUB_CODE_LIST(STUB_CODE_GENERATE);
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 0e6e274..ee82911 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -204,6 +204,10 @@
   V(DartScalarlist, "dart:scalarlist")                                         \
   V(DartNativeWrappers, "dart:nativewrappers")                                 \
   V(DartAsync, "dart:async")                                                   \
+  V(DartUri, "dart:uri")                                                       \
+  V(DartUtf, "dart:utf")                                                       \
+  V(DartCrypto, "dart:crypto")                                                 \
+  V(DartJson, "dart:json")                                                     \
 
 
 // Contains a list of frequently used strings in a canonicalized form. This
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index b12fa1f..06f42ce 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -78,14 +78,6 @@
     // Handle imports of other built-in libraries present in the SDK.
     if (DartUtils::IsDartIOLibURL(url_chars)) {
       return Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
-    } else if (DartUtils::IsDartJsonLibURL(url_chars)) {
-      return Builtin::LoadAndCheckLibrary(Builtin::kJsonLibrary);
-    } else if (DartUtils::IsDartUriLibURL(url_chars)) {
-      return Builtin::LoadAndCheckLibrary(Builtin::kUriLibrary);
-    } else if (DartUtils::IsDartUtfLibURL(url_chars)) {
-      return Builtin::LoadAndCheckLibrary(Builtin::kUtfLibrary);
-    } else if (DartUtils::IsDartCryptoLibURL(url_chars)) {
-      return Builtin::LoadAndCheckLibrary(Builtin::kCryptoLibrary);
     } else if (DartUtils::IsDartBuiltinLibURL(url_chars)) {
       return Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
     } else {
@@ -134,24 +126,24 @@
 }
 
 
-uword AssemblerTest::Assemble() {
+void AssemblerTest::Assemble() {
   const String& function_name = String::ZoneHandle(Symbols::New(name_));
   const Class& cls = Class::ZoneHandle(
        Class::New(function_name, Script::Handle(), Scanner::kDummyTokenIndex));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
                     true, false, false, false, cls, 0));
-  const Code& code = Code::Handle(Code::FinalizeCode(function, assembler_));
+  code_ = Code::FinalizeCode(function, assembler_);
   if (FLAG_disassemble) {
     OS::Print("Code for test '%s' {\n", name_);
     const Instructions& instructions =
-        Instructions::Handle(code.instructions());
+        Instructions::Handle(code_.instructions());
     uword start = instructions.EntryPoint();
     Disassembler::Disassemble(start, start + assembler_->CodeSize());
     OS::Print("}\n");
   }
-  const Instructions& instructions = Instructions::Handle(code.instructions());
-  return instructions.EntryPoint();
+  const Instructions& instructions = Instructions::Handle(code_.instructions());
+  entry_ = instructions.EntryPoint();
 }
 
 
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index bd15b1e..26547cc 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -51,15 +51,16 @@
 // The ASSEMBLER_TEST_RUN macro is used to execute the assembler unit
 // test generated using the ASSEMBLER_TEST_GENERATE macro.
 // C++ callee-saved registers are not preserved. Arguments may be passed in.
-#define ASSEMBLER_TEST_RUN(name, entry)                                        \
-  static void AssemblerTestRun##name(uword entry);                             \
+#define ASSEMBLER_TEST_RUN(name, test)                                         \
+  static void AssemblerTestRun##name(AssemblerTest* test);                     \
   TEST_CASE(name) {                                                            \
     Assembler __assembler__;                                                   \
-    AssemblerTest __test__(""#name, &__assembler__);                           \
-    AssemblerTestGenerate##name(__test__.assembler());                         \
-    AssemblerTestRun##name(__test__.Assemble());                               \
+    AssemblerTest test(""#name, &__assembler__);                               \
+    AssemblerTestGenerate##name(test.assembler());                             \
+    test.Assemble();                                                           \
+    AssemblerTestRun##name(&test);                                             \
   }                                                                            \
-  static void AssemblerTestRun##name(uword entry)
+  static void AssemblerTestRun##name(AssemblerTest* test)
 
 // Populate node list with AST nodes.
 #define CODEGEN_TEST_GENERATE(name, test)                                      \
@@ -271,7 +272,8 @@
  public:
   AssemblerTest(const char* name, Assembler* assembler)
       : name_(name),
-        assembler_(assembler) {
+        assembler_(assembler),
+        code_(Code::ZoneHandle()) {
     ASSERT(name != NULL);
     ASSERT(assembler != NULL);
   }
@@ -279,12 +281,18 @@
 
   Assembler* assembler() const { return assembler_; }
 
-  // Assemble test and return entry.
-  uword Assemble();
+  const Code& code() const { return code_; }
+
+  uword entry() const { return entry_; }
+
+  // Assemble test and set code_ and entry_.
+  void Assemble();
 
  private:
   const char* name_;
   Assembler* assembler_;
+  Code& code_;
+  uword entry_;
 
   DISALLOW_COPY_AND_ASSIGN(AssemblerTest);
 };
diff --git a/runtime/vm/virtual_memory_android.cc b/runtime/vm/virtual_memory_android.cc
index e852de5..966644d 100644
--- a/runtime/vm/virtual_memory_android.cc
+++ b/runtime/vm/virtual_memory_android.cc
@@ -2,10 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "vm/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
 #include "vm/virtual_memory.h"
 
-#include <sys/mman.h>
-#include <unistd.h>
+#include <sys/mman.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "platform/assert.h"
 #include "platform/utils.h"
@@ -96,3 +99,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/virtual_memory_linux.cc b/runtime/vm/virtual_memory_linux.cc
index 189c0fc..7a0d02b 100644
--- a/runtime/vm/virtual_memory_linux.cc
+++ b/runtime/vm/virtual_memory_linux.cc
@@ -2,11 +2,14 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "vm/globals.h"
+#if defined(TARGET_OS_LINUX)
+
 #include "vm/virtual_memory.h"
 
-#include <sys/mman.h>
-#include <sys/unistd.h>
-#include <unistd.h>
+#include <sys/mman.h>  // NOLINT
+#include <sys/unistd.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "platform/assert.h"
 #include "platform/utils.h"
@@ -96,3 +99,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/virtual_memory_macos.cc b/runtime/vm/virtual_memory_macos.cc
index ccfa167..c99a349 100644
--- a/runtime/vm/virtual_memory_macos.cc
+++ b/runtime/vm/virtual_memory_macos.cc
@@ -2,10 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "vm/globals.h"
+#if defined(TARGET_OS_MACOS)
+
 #include "vm/virtual_memory.h"
 
-#include <sys/mman.h>
-#include <unistd.h>
+#include <sys/mman.h>  // NOLINT
+#include <unistd.h>  // NOLINT
 
 #include "platform/assert.h"
 #include "platform/utils.h"
@@ -96,3 +99,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/vm/virtual_memory_win.cc b/runtime/vm/virtual_memory_win.cc
index 2ac6784..d1a9277 100644
--- a/runtime/vm/virtual_memory_win.cc
+++ b/runtime/vm/virtual_memory_win.cc
@@ -2,6 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "vm/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
 #include "vm/virtual_memory.h"
 
 #include "platform/assert.h"
@@ -84,3 +87,5 @@
 }
 
 }  // namespace dart
+
+#endif  // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index 9ed725d..ca69ca5 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -11,14 +11,18 @@
     'corelib_patch_cc_file': '<(SHARED_INTERMEDIATE_DIR)/corelib_patch_gen.cc',
     'collection_cc_file': '<(SHARED_INTERMEDIATE_DIR)/collection_gen.cc',
     'collection_dev_cc_file': '<(SHARED_INTERMEDIATE_DIR)/collection_dev_gen.cc',
+    'crypto_cc_file': '<(SHARED_INTERMEDIATE_DIR)/crypto_gen.cc',
     'math_cc_file': '<(SHARED_INTERMEDIATE_DIR)/math_gen.cc',
     'math_patch_cc_file': '<(SHARED_INTERMEDIATE_DIR)/math_patch_gen.cc',
     'mirrors_cc_file': '<(SHARED_INTERMEDIATE_DIR)/mirrors_gen.cc',
     'mirrors_patch_cc_file': '<(SHARED_INTERMEDIATE_DIR)/mirrors_patch_gen.cc',
     'isolate_cc_file': '<(SHARED_INTERMEDIATE_DIR)/isolate_gen.cc',
     'isolate_patch_cc_file': '<(SHARED_INTERMEDIATE_DIR)/isolate_patch_gen.cc',
+    'json_cc_file': '<(SHARED_INTERMEDIATE_DIR)/json_gen.cc',
     'scalarlist_cc_file': '<(SHARED_INTERMEDIATE_DIR)/scalarlist_gen.cc',
     'scalarlist_patch_cc_file': '<(SHARED_INTERMEDIATE_DIR)/scalarlist_patch_gen.cc',
+    'uri_cc_file': '<(SHARED_INTERMEDIATE_DIR)/uri_gen.cc',
+    'utf_cc_file': '<(SHARED_INTERMEDIATE_DIR)/utf_gen.cc',
     'snapshot_test_dat_file': '<(SHARED_INTERMEDIATE_DIR)/snapshot_test.dat',
     'snapshot_test_in_dat_file': 'snapshot_test_in.dat',
     'snapshot_test_dart_file': 'snapshot_test.dart',
@@ -91,14 +95,18 @@
         'generate_corelib_patch_cc_file',
         'generate_collection_cc_file',
         'generate_collection_dev_cc_file',
+        'generate_crypto_cc_file',
         'generate_math_cc_file',
         'generate_math_patch_cc_file',
         'generate_isolate_cc_file',
         'generate_isolate_patch_cc_file',
+        'generate_json_cc_file',
         'generate_mirrors_cc_file',
         'generate_mirrors_patch_cc_file',
         'generate_scalarlist_cc_file',
         'generate_scalarlist_patch_cc_file',
+        'generate_uri_cc_file',
+        'generate_utf_cc_file',
       ],
       'includes': [
         '../lib/async_sources.gypi',
@@ -117,14 +125,18 @@
         '<(corelib_patch_cc_file)',
         '<(collection_cc_file)',
         '<(collection_dev_cc_file)',
+        '<(crypto_cc_file)',
         '<(math_cc_file)',
         '<(math_patch_cc_file)',
         '<(isolate_cc_file)',
         '<(isolate_patch_cc_file)',
+        '<(json_cc_file)',
         '<(mirrors_cc_file)',
         '<(mirrors_patch_cc_file)',
         '<(scalarlist_cc_file)',
         '<(scalarlist_patch_cc_file)',
+        '<(uri_cc_file)',
+        '<(utf_cc_file)',
       ],
       'include_dirs': [
         '..',
@@ -413,6 +425,56 @@
       ]
     },
     {
+      'target_name': 'generate_crypto_cc_file',
+      'type': 'none',
+      'variables': {
+        'crypto_dart': '<(SHARED_INTERMEDIATE_DIR)/crypto_gen.dart',
+      },
+      'includes': [
+        # Load the shared crypto sources.
+        '../../sdk/lib/crypto/crypto_sources.gypi',
+      ],
+      'actions': [
+        {
+          'action_name': 'generate_crypto_dart',
+          'inputs': [
+            '../tools/concat_library.py',
+            '<@(_sources)',
+          ],
+          'outputs': [
+            '<(crypto_dart)',
+          ],
+          'action': [
+            'python',
+            '<@(_inputs)',
+            '--output', '<(crypto_dart)',
+          ],
+          'message': 'Generating ''<(crypto_dart)'' file.',
+        },
+        {
+          'action_name': 'generate_crypto_cc',
+          'inputs': [
+            '../tools/create_string_literal.py',
+            '<(builtin_in_cc_file)',
+            '<(crypto_dart)',
+          ],
+          'outputs': [
+            '<(crypto_cc_file)',
+          ],
+          'action': [
+            'python',
+            'tools/create_string_literal.py',
+            '--output', '<(crypto_cc_file)',
+            '--input_cc', '<(builtin_in_cc_file)',
+            '--include', 'vm/bootstrap.h',
+            '--var_name', 'dart::Bootstrap::crypto_source_',
+            '<(crypto_dart)',
+          ],
+          'message': 'Generating ''<(crypto_cc_file)'' file.'
+        },
+      ]
+    },
+    {
       'target_name': 'generate_math_cc_file',
       'type': 'none',
       'variables': {
@@ -736,6 +798,56 @@
       ]
     },
     {
+      'target_name': 'generate_json_cc_file',
+      'type': 'none',
+      'variables': {
+        'json_dart': '<(SHARED_INTERMEDIATE_DIR)/json_gen.dart',
+      },
+      'includes': [
+        # Load the shared json sources.
+        '../../sdk/lib/json/json_sources.gypi',
+      ],
+      'actions': [
+        {
+          'action_name': 'generate_json_dart',
+          'inputs': [
+            '../tools/concat_library.py',
+            '<@(_sources)',
+          ],
+          'outputs': [
+            '<(json_dart)',
+          ],
+          'action': [
+            'python',
+            '<@(_inputs)',
+            '--output', '<(json_dart)',
+          ],
+          'message': 'Generating ''<(json_dart)'' file.',
+        },
+        {
+          'action_name': 'generate_json_cc',
+          'inputs': [
+            '../tools/create_string_literal.py',
+            '<(builtin_in_cc_file)',
+            '<(json_dart)',
+          ],
+          'outputs': [
+            '<(json_cc_file)',
+          ],
+          'action': [
+            'python',
+            'tools/create_string_literal.py',
+            '--output', '<(json_cc_file)',
+            '--input_cc', '<(builtin_in_cc_file)',
+            '--include', 'vm/bootstrap.h',
+            '--var_name', 'dart::Bootstrap::json_source_',
+            '<(json_dart)',
+          ],
+          'message': 'Generating ''<(json_cc_file)'' file.'
+        },
+      ]
+    },
+    {
       'target_name': 'generate_scalarlist_cc_file',
       'type': 'none',
       'variables': {
@@ -831,6 +943,106 @@
       ]
     },
     {
+      'target_name': 'generate_uri_cc_file',
+      'type': 'none',
+      'variables': {
+        'uri_dart': '<(SHARED_INTERMEDIATE_DIR)/uri_gen.dart',
+      },
+      'includes': [
+        # Load the shared uri sources.
+        '../../sdk/lib/uri/uri_sources.gypi',
+      ],
+      'actions': [
+        {
+          'action_name': 'generate_uri_dart',
+          'inputs': [
+            '../tools/concat_library.py',
+            '<@(_sources)',
+          ],
+          'outputs': [
+            '<(uri_dart)',
+          ],
+          'action': [
+            'python',
+            '<@(_inputs)',
+            '--output', '<(uri_dart)',
+          ],
+          'message': 'Generating ''<(uri_dart)'' file.'
+        },
+        {
+          'action_name': 'generate_uri_cc',
+          'inputs': [
+            '../tools/create_string_literal.py',
+            '<(builtin_in_cc_file)',
+            '<(uri_dart)',
+          ],
+          'outputs': [
+            '<(uri_cc_file)',
+          ],
+          'action': [
+            'python',
+            'tools/create_string_literal.py',
+            '--output', '<(uri_cc_file)',
+            '--input_cc', '<(builtin_in_cc_file)',
+            '--include', 'vm/bootstrap.h',
+            '--var_name', 'dart::Bootstrap::uri_source_',
+            '<(uri_dart)',
+          ],
+          'message': 'Generating ''<(uri_cc_file)'' file.'
+        },
+      ]
+    },
+    {
+      'target_name': 'generate_utf_cc_file',
+      'type': 'none',
+      'variables': {
+        'utf_dart': '<(SHARED_INTERMEDIATE_DIR)/utf_gen.dart',
+      },
+      'includes': [
+        # Load the shared utf sources.
+        '../../sdk/lib/utf/utf_sources.gypi',
+      ],
+      'actions': [
+        {
+          'action_name': 'generate_utf_dart',
+          'inputs': [
+            '../tools/concat_library.py',
+            '<@(_sources)',
+          ],
+          'outputs': [
+            '<(utf_dart)',
+          ],
+          'action': [
+            'python',
+            '<@(_inputs)',
+            '--output', '<(utf_dart)',
+          ],
+          'message': 'Generating ''<(utf_dart)'' file.',
+        },
+        {
+          'action_name': 'generate_utf_cc',
+          'inputs': [
+            '../tools/create_string_literal.py',
+            '<(builtin_in_cc_file)',
+            '<(utf_dart)',
+          ],
+          'outputs': [
+            '<(utf_cc_file)',
+          ],
+          'action': [
+            'python',
+            'tools/create_string_literal.py',
+            '--output', '<(utf_cc_file)',
+            '--input_cc', '<(builtin_in_cc_file)',
+            '--include', 'vm/bootstrap.h',
+            '--var_name', 'dart::Bootstrap::utf_source_',
+            '<(utf_dart)',
+          ],
+          'message': 'Generating ''<(utf_cc_file)'' file.'
+        },
+      ]
+    },
+    {
       'target_name': 'generate_snapshot_test_dat_file',
       'type': 'none',
       'actions': [
diff --git a/sdk/lib/_internal/compiler/implementation/code_buffer.dart b/sdk/lib/_internal/compiler/implementation/code_buffer.dart
index 795742d..fafc409 100644
--- a/sdk/lib/_internal/compiler/implementation/code_buffer.dart
+++ b/sdk/lib/_internal/compiler/implementation/code_buffer.dart
@@ -33,7 +33,7 @@
       return addBuffer(object);
     }
     if (mappedRangeCounter == 0) setSourceLocation(null);
-    buffer.add(object.toString());
+    buffer.write(object);
     return this;
   }
 
@@ -60,7 +60,7 @@
       }
       lastBufferOffset = buffer.length + other.lastBufferOffset;
     }
-    buffer.add(other.getText());
+    buffer.write(other.getText());
     return this;
   }
 
@@ -73,7 +73,7 @@
   }
 
   CodeBuffer clear() {
-    buffer.clear();
+    buffer = new StringBuffer();
     markers.clear();
     lastBufferOffset = 0;
     return this;
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index 691cbac..e4758a2 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -175,7 +175,7 @@
             if (isConst) {
               compiler.reportError(node, new CompileTimeConstantError(
                   MessageKind.NOT_ASSIGNABLE,
-                  {'fromType': elementType, 'toType': constantType}));
+                  {'fromType': constantType, 'toType': elementType}));
             } else {
               // If the field can be lazily initialized, we will throw
               // the exception at runtime.
@@ -337,7 +337,8 @@
       arguments.add(evaluateConstant(link.head));
     }
     // TODO(floitsch): get type parameters.
-    DartType type = new InterfaceType(compiler.listClass);
+    compiler.listClass.computeType(compiler);
+    DartType type = compiler.listClass.rawType;
     Constant constant = new ListConstant(type, arguments);
     handler.registerCompileTimeConstant(constant);
     return constant;
@@ -373,7 +374,8 @@
     }
     bool hasProtoKey = (protoValue != null);
     // TODO(floitsch): this should be a List<String> type.
-    DartType keysType = new InterfaceType(compiler.listClass);
+    compiler.listClass.computeType(compiler);
+    DartType keysType = compiler.listClass.rawType;
     ListConstant keysList = new ListConstant(keysType, keys);
     handler.registerCompileTimeConstant(keysList);
     SourceString className = hasProtoKey
@@ -382,7 +384,7 @@
     ClassElement classElement = compiler.jsHelperLibrary.find(className);
     classElement.ensureResolved(compiler);
     // TODO(floitsch): copy over the generic type.
-    DartType type = new InterfaceType(classElement);
+    DartType type = classElement.rawType;
     handler.registerInstantiatedClass(classElement);
     Constant constant = new MapConstant(type, keysList, values, protoValue);
     handler.registerCompileTimeConstant(constant);
@@ -660,7 +662,8 @@
 
     handler.registerInstantiatedClass(classElement);
     // TODO(floitsch): take generic types into account.
-    DartType type = classElement.computeType(compiler);
+    classElement.computeType(compiler);
+    DartType type = classElement.rawType;
     Constant constant = new ConstructedConstant(type, jsNewArguments);
     handler.registerCompileTimeConstant(constant);
     return constant;
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index adf2a77..ec15da18 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -126,8 +126,24 @@
     return new ItemCompilationContext();
   }
 
-  SourceString getCheckedModeHelper(DartType type) => null;
+  // The following methods are hooks for the backend to register its
+  // helper methods.
   void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) {}
+  void registerStringInterpolation() {}
+  void registerCatchStatement() {}
+  void registerThrow() {}
+  void registerLazyField() {}
+  void registerTypeLiteral() {}
+  void registerStackTraceInCatch() {}
+  void registerIsCheck(DartType type, Enqueuer enqueuer) {}
+  void registerAsCheck(DartType type) {}
+  void registerThrowNoSuchMethod() {}
+  void registerThrowRuntimeError() {}
+  void registerAbstractClassInstantiation() {}
+  void registerFallThroughError() {}
+  void registerSuperNoSuchMethod() {}
+  void registerConstantMap() {}
+  void registerRuntimeType() {}
 }
 
 /**
@@ -291,6 +307,7 @@
   ConstantHandler metadataHandler;
   EnqueueTask enqueuer;
   CompilerTask fileReadingTask;
+  DeferredLoadTask deferredLoadTask;
 
   static const SourceString MAIN = const SourceString('main');
   static const SourceString CALL_OPERATOR_NAME = const SourceString('call');
@@ -369,6 +386,7 @@
       checker = new TypeCheckerTask(this),
       typesTask = new ti.TypesTask(this),
       constantHandler = new ConstantHandler(this, backend.constantSystem),
+      deferredLoadTask = new DeferredLoadTask(this),
       enqueuer = new EnqueueTask(this)];
 
     tasks.addAll(backend.tasks);
@@ -637,6 +655,8 @@
       }
     }
 
+    deferredLoadTask.registerMainApp(mainApp);
+
     log('Resolving...');
     phase = PHASE_RESOLVING;
     if (analyzeAll) {
@@ -845,8 +865,9 @@
       // is more complete.
       if (identical(message.message.kind, MessageKind.NOT_ASSIGNABLE)) return;
       if (identical(message.message.kind, MessageKind.MISSING_RETURN)) return;
-      if (identical(message.message.kind, MessageKind.MAYBE_MISSING_RETURN)) return;
-      if (identical(message.message.kind, MessageKind.METHOD_NOT_FOUND)) return;
+      if (identical(message.message.kind, MessageKind.MAYBE_MISSING_RETURN)) {
+        return;
+      }
     }
     SourceSpan span = spanFromNode(node);
 
@@ -1026,7 +1047,7 @@
   String get name => 'Unknown task';
   int get timing => watch.elapsedMilliseconds;
 
-  measure(Function action) {
+  measure(action()) {
     CompilerTask previous = compiler.measuredTask;
     if (identical(this, previous)) return action();
     compiler.measuredTask = this;
@@ -1040,6 +1061,10 @@
       compiler.measuredTask = previous;
     }
   }
+
+  measureElement(Element element, action()) {
+    compiler.withCurrentElement(element, () => measure(action));
+  }
 }
 
 class CompilerCancelledException implements Exception {
diff --git a/sdk/lib/_internal/compiler/implementation/dart2js.dart b/sdk/lib/_internal/compiler/implementation/dart2js.dart
index 5fdcd2c7..0f0a029 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2js.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2js.dart
@@ -151,6 +151,12 @@
     return passThrough('--categories=${categories.join(",")}');
   }
 
+  // TODO(8522): Remove this method once option is restored.
+  complainAboutDisallowUnsafeEval(String argument) {
+    fail('Error: $argument is currently not supported, '
+         'see http://dartbug.com/8522');
+  }
+
   handleShortOptions(String argument) {
     var shortOptions = argument.substring(1).split("");
     for (var shortOption in shortOptions) {
@@ -196,7 +202,8 @@
                       (_) => passThrough('--enable-concrete-type-inference')),
     new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true),
     new OptionHandler('--package-root=.+|-p.+', setPackageRoot),
-    new OptionHandler('--disallow-unsafe-eval', passThrough),
+    new OptionHandler('--disallow-unsafe-eval',
+                      complainAboutDisallowUnsafeEval),
     new OptionHandler('--analyze-all', passThrough),
     new OptionHandler('--analyze-only', setAnalyzeOnly),
     new OptionHandler('--disable-native-live-type-analysis', passThrough),
@@ -283,7 +290,8 @@
     if (uri.scheme != 'file') {
       fail('Error: Unhandled scheme ${uri.scheme} in $uri.');
     }
-    var outputStream = new File(uriPathToNative(uri.path)).openOutputStream();
+    IOSink output =
+        new File(uriPathToNative(uri.path)).openWrite();
 
     CountingSink sink;
 
@@ -291,16 +299,16 @@
       if (sourceMapFileName != null) {
         String sourceMapTag = '//@ sourceMappingURL=$sourceMapFileName\n';
         sink.count += sourceMapTag.length;
-        outputStream.writeString(sourceMapTag);
+        output.addString(sourceMapTag);
       }
-      outputStream.close();
+      output.close();
       if (isPrimaryOutput) {
         charactersWritten += sink.count;
       }
     }
 
     var controller = new StreamController<String>();
-    controller.stream.listen(outputStream.writeString, onDone: onDone);
+    controller.stream.listen(output.addString, onDone: onDone);
     sink = new CountingSink(controller);
     return sink;
   }
@@ -434,12 +442,18 @@
     Disable the optimization that removes unused native types from dart:html
     and related libraries.
 
+'''
+/* TODO(8522): Restore this comment once option is restored.
+'''
   --disallow-unsafe-eval
     Disable dynamic generation of code in the generated output. This is
     necessary to satisfy CSP restrictions (see http://www.w3.org/TR/CSP/).
     This flag is not continuously tested. Please report breakages and we
     will fix them as soon as possible.
 
+'''
+*/
+'''
   --reject-deprecated-language-features
     Reject deprecated language features.  Without this option, the
     compiler will accept language features that are no longer valid
diff --git a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
index 9b683f2..fd859af 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
@@ -34,6 +34,7 @@
 import 'types/types.dart' as ti;
 import 'resolution/resolution.dart';
 import 'js/js.dart' as js;
+import 'deferred_load.dart' show DeferredLoadTask;
 
 export 'resolution/resolution.dart' show TreeElements, TreeElementMapping;
 export 'scanner/scannerlib.dart' show SourceString,
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 45a6523..d400708 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -440,7 +440,7 @@
       // TODO(antonm): Ideally XML should be a separate backend.
       // TODO(antonm): obey renames and minification, at least as an option.
       StringBuffer sb = new StringBuffer();
-      outputElement(element) { sb.add(parse(element).toDebugString()); }
+      outputElement(element) { sb.write(parse(element).toDebugString()); }
 
       // Emit XML for AST instead of the program.
       for (final topLevel in sortedTopLevels) {
@@ -502,7 +502,7 @@
 
   visit(Node node) {
     if (node != null && renames.containsKey(node)) {
-      sb.add(renames[node]);
+      sb.write(renames[node]);
     } else {
       super.visit(node);
     }
@@ -516,7 +516,7 @@
 
   unparseFunctionName(Node name) {
     if (name != null && renames.containsKey(name)) {
-      sb.add(renames[name]);
+      sb.write(renames[name]);
     } else {
       super.unparseFunctionName(name);
     }
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
index 886d39e..9acc6ec 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
@@ -89,15 +89,15 @@
     StringBuffer result = new StringBuffer(renameElement(type.element));
     if (type is InterfaceType) {
       if (!type.isRaw) {
-        result.add('<');
+        result.write('<');
         Link<DartType> argumentsLink = type.typeArguments;
-        result.add(renameType(argumentsLink.head, renameElement));
+        result.write(renameType(argumentsLink.head, renameElement));
         for (Link<DartType> link = argumentsLink.tail; !link.isEmpty;
              link = link.tail) {
-          result.add(',');
-          result.add(renameType(link.head, renameElement));
+          result.write(',');
+          result.write(renameType(link.head, renameElement));
         }
-        result.add('>');
+        result.write('>');
       }
     }
     return result.toString();
@@ -112,8 +112,8 @@
       // Named constructor or factory. Is there a more reliable way to check
       // this case?
       if (!placeholder.isRedirectingCall) {
-        result.add(renameType(placeholder.type, renameElement));
-        result.add('.');
+        result.write(renameType(placeholder.type, renameElement));
+        result.write('.');
       }
       String prefix = '${element.getEnclosingClass().name.slowToString()}\$';
       if (!name.startsWith(prefix)) {
@@ -125,10 +125,10 @@
       if (!element.getLibrary().isPlatformLibrary) {
         name = renameString(element.getLibrary(), name);
       }
-      result.add(name);
+      result.write(name);
     } else {
       assert(!placeholder.isRedirectingCall);
-      result.add(renameType(placeholder.type, renameElement));
+      result.write(renameType(placeholder.type, renameElement));
     }
     return result.toString();
   }
@@ -346,14 +346,14 @@
     int index = nextIdIndex++;
     StringBuffer resultBuilder = new StringBuffer();
     if (index < firstCharAlphabet.length) return firstCharAlphabet[index];
-    resultBuilder.add(firstCharAlphabet[index % firstCharAlphabet.length]);
+    resultBuilder.write(firstCharAlphabet[index % firstCharAlphabet.length]);
     index ~/= firstCharAlphabet.length;
     int length = otherCharsAlphabet.length;
     while (index >= length) {
-      resultBuilder.add(otherCharsAlphabet[index % length]);
+      resultBuilder.write(otherCharsAlphabet[index % length]);
       index ~/= length;
     }
-    resultBuilder.add(otherCharsAlphabet[index]);
+    resultBuilder.write(otherCharsAlphabet[index]);
     return resultBuilder.toString();
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index 1d9f217..ec79917 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -70,6 +70,14 @@
   DartType unalias(Compiler compiler);
 
   /**
+   * Finds the method, field or property named [name] declared or inherited
+   * on this type.
+   */
+  // TODO(johnniwinther): Implement this for [TypeVariableType], [FunctionType],
+  // and [TypedefType].
+  Member lookupMember(SourceString name) => null;
+
+  /**
    * A type is malformed if it is itself a malformed type or contains a
    * malformed type.
    */
@@ -93,6 +101,8 @@
   bool get isRaw => true;
 
   DartType asRaw() => this;
+
+  accept(DartTypeVisitor visitor, var argument);
 }
 
 /**
@@ -151,6 +161,10 @@
 
   DartType unalias(Compiler compiler) => this;
 
+  accept(DartTypeVisitor visitor, var argument) {
+    return visitor.visitTypeVariableType(this, argument);
+  }
+
   int get hashCode => 17 * element.hashCode;
 
   bool operator ==(other) {
@@ -191,6 +205,10 @@
 
   DartType unalias(Compiler compiler) => this;
 
+  accept(DartTypeVisitor visitor, var argument) {
+    return visitor.visitStatementType(this, argument);
+  }
+
   int get hashCode => 17 * stringName.hashCode;
 
   bool operator ==(other) {
@@ -217,6 +235,10 @@
 
   DartType unalias(Compiler compiler) => this;
 
+  accept(DartTypeVisitor visitor, var argument) {
+    return visitor.visitVoidType(this, argument);
+  }
+
   int get hashCode => 1729;
 
   bool operator ==(other) => other is VoidType;
@@ -264,21 +286,25 @@
 
   DartType unalias(Compiler compiler) => this;
 
+  accept(DartTypeVisitor visitor, var argument) {
+    return visitor.visitMalformedType(this, argument);
+  }
+
   String toString() {
     var sb = new StringBuffer();
     if (typeArguments != null) {
       if (userProvidedBadType != null) {
-        sb.add(userProvidedBadType.name.slowToString());
+        sb.write(userProvidedBadType.name.slowToString());
       } else {
-        sb.add(element.name.slowToString());
+        sb.write(element.name.slowToString());
       }
       if (!typeArguments.isEmpty) {
-        sb.add('<');
+        sb.write('<');
         typeArguments.printOn(sb, ', ');
-        sb.add('>');
+        sb.write('>');
       }
     } else {
-      sb.add(userProvidedBadType.toString());
+      sb.write(userProvidedBadType.toString());
     }
     return sb.toString();
   }
@@ -334,11 +360,11 @@
 
   String toString() {
     StringBuffer sb = new StringBuffer();
-    sb.add(name.slowToString());
+    sb.write(name.slowToString());
     if (!isRaw) {
-      sb.add('<');
+      sb.write('<');
       typeArguments.printOn(sb, ', ');
-      sb.add('>');
+      sb.write('>');
     }
     return sb.toString();
   }
@@ -372,8 +398,17 @@
                 [Link<DartType> typeArguments = const Link<DartType>()])
       : super(typeArguments, hasMalformed(typeArguments)) {
     assert(invariant(element, element.isDeclaration));
+    assert(invariant(element, element.thisType == null ||
+        typeArguments.slowLength() == element.typeVariables.slowLength(),
+        message: 'Invalid type argument count on ${element.thisType}. '
+                 'Provided type arguments: $typeArguments.'));
   }
 
+  InterfaceType.userProvidedBadType(this.element,
+                                    [Link<DartType> typeArguments =
+                                        const Link<DartType>()])
+      : super(typeArguments, true);
+
   TypeKind get kind => TypeKind.INTERFACE;
 
   SourceString get name => element.name;
@@ -402,12 +437,50 @@
 
   DartType unalias(Compiler compiler) => this;
 
+  /**
+   * Finds the method, field or property named [name] declared or inherited
+   * on this interface type.
+   */
+  Member lookupMember(SourceString name) {
+
+    Member createMember(InterfaceType receiver, InterfaceType declarer,
+                        Element member) {
+      if (member.kind == ElementKind.FUNCTION ||
+          member.kind == ElementKind.ABSTRACT_FIELD ||
+          member.kind == ElementKind.FIELD) {
+        return new Member(receiver, declarer, member);
+      }
+      return null;
+    }
+
+    ClassElement classElement = element;
+    InterfaceType receiver = this;
+    InterfaceType declarer = receiver;
+    Element member = classElement.lookupLocalMember(name);
+    if (member != null) {
+      return createMember(receiver, declarer, member);
+    }
+    for (DartType supertype in classElement.allSupertypes) {
+      declarer = supertype;
+      ClassElement lookupTarget = declarer.element;
+      member = lookupTarget.lookupLocalMember(name);
+      if (member != null) {
+        return createMember(receiver, declarer, member);
+      }
+    }
+    return null;
+  }
+
   bool operator ==(other) {
     if (other is !InterfaceType) return false;
     return super == other;
   }
 
   InterfaceType asRaw() => super.asRaw();
+
+  accept(DartTypeVisitor visitor, var argument) {
+    return visitor.visitInterfaceType(this, argument);
+  }
 }
 
 class FunctionType extends DartType {
@@ -535,42 +608,46 @@
 
   DartType unalias(Compiler compiler) => this;
 
+  accept(DartTypeVisitor visitor, var argument) {
+    return visitor.visitFunctionType(this, argument);
+  }
+
   String toString() {
     StringBuffer sb = new StringBuffer();
-    sb.add('(');
+    sb.write('(');
     parameterTypes.printOn(sb, ', ');
     bool first = parameterTypes.isEmpty;
     if (!optionalParameterTypes.isEmpty) {
       if (!first) {
-        sb.add(', ');
+        sb.write(', ');
       }
-      sb.add('[');
+      sb.write('[');
       optionalParameterTypes.printOn(sb, ', ');
-      sb.add(']');
+      sb.write(']');
       first = false;
     }
     if (!namedParameterTypes.isEmpty) {
       if (!first) {
-        sb.add(', ');
+        sb.write(', ');
       }
-      sb.add('{');
+      sb.write('{');
       Link<SourceString> namedParameter = namedParameters;
       Link<DartType> namedParameterType = namedParameterTypes;
       first = true;
       while (!namedParameter.isEmpty && !namedParameterType.isEmpty) {
         if (!first) {
-          sb.add(', ');
+          sb.write(', ');
         }
-        sb.add(namedParameterType.head);
-        sb.add(' ');
-          sb.add(namedParameter.head.slowToString());
+        sb.write(namedParameterType.head);
+        sb.write(' ');
+          sb.write(namedParameter.head.slowToString());
         namedParameter = namedParameter.tail;
         namedParameterType = namedParameterType.tail;
         first = false;
       }
-      sb.add('}');
+      sb.write('}');
     }
-    sb.add(') -> ${returnType}');
+    sb.write(') -> ${returnType}');
     return sb.toString();
   }
 
@@ -612,6 +689,8 @@
 class TypedefType extends GenericType {
   final TypedefElement element;
 
+  // TODO(johnniwinther): Assert that the number of arguments and parameters
+  // match, like for [InterfaceType].
   TypedefType(this.element,
               [Link<DartType> typeArguments = const Link<DartType>()])
       : super(typeArguments, hasMalformed(typeArguments));
@@ -620,6 +699,11 @@
     return new TypedefType(element, newTypeArguments);
   }
 
+  TypedefType.userProvidedBadType(this.element,
+                                  [Link<DartType> typeArguments =
+                                      const Link<DartType>()])
+      : super(typeArguments, true);
+
   TypeKind get kind => TypeKind.TYPEDEF;
 
   SourceString get name => element.name;
@@ -638,6 +722,10 @@
   }
 
   TypedefType asRaw() => super.asRaw();
+
+  accept(DartTypeVisitor visitor, var argument) {
+    return visitor.visitTypedefType(this, argument);
+  }
 }
 
 /**
@@ -648,25 +736,117 @@
   DynamicType(ClassElement element) : super(element);
 
   SourceString get name => const SourceString('dynamic');
+
+  accept(DartTypeVisitor visitor, var argument) {
+    return visitor.visitDynamicType(this, argument);
+  }
 }
 
-class Types {
-  final Compiler compiler;
-  // TODO(karlklose): should we have a class Void?
-  final VoidType voidType;
-  final DynamicType dynamicType;
+/**
+ * Member encapsulates a member (method, field, property) with the types of the
+ * declarer and receiver in order to do substitution on the member type.
+ *
+ * Consider for instance these classes and the variable [: B<String> b :]:
+ *
+ *     class A<E> {
+ *       E field;
+ *     }
+ *     class B<F> extends A<F> {}
+ *
+ * In a [Member] for [: b.field :] the [receiver] is the type [: B<String> :]
+ * and the declarer is the type [: A<F> :], which is the supertype of [: B<F> :]
+ * from which [: field :] has been inherited. To compute the type of
+ * [: b.field :] we must first substitute [: E :] by [: F :] using the relation
+ * between [: A<E> :] and [: A<F> :], and then [: F :] by [: String :] using the
+ * relation between [: B<F> :] and [: B<String> :].
+ */
+class Member {
+  final InterfaceType receiver;
+  final InterfaceType declarer;
+  final Element element;
+  DartType cachedType;
 
-  factory Types(Compiler compiler, ClassElement dynamicElement) {
-    LibraryElement library = new LibraryElementX(new Script(null, null));
-    VoidType voidType = new VoidType(new VoidElementX(library));
-    DynamicType dynamicType = new DynamicType(dynamicElement);
-    dynamicElement.rawType = dynamicElement.thisType = dynamicType;
-    return new Types.internal(compiler, voidType, dynamicType);
+  Member(this.receiver, this.declarer, this.element) {
+    assert(invariant(element, element.isAbstractField() ||
+                              element.isField() ||
+                              element.isFunction(),
+                     message: "Unsupported Member element: $element"));
   }
 
-  Types.internal(this.compiler, this.voidType, this.dynamicType);
+  DartType computeType(Compiler compiler) {
+    if (cachedType == null) {
+      DartType type;
+      if (element.isAbstractField()) {
+        AbstractFieldElement abstractFieldElement = element;
+        if (abstractFieldElement.getter != null) {
+          FunctionType functionType =
+              abstractFieldElement.getter.computeType(compiler);
+          type = functionType.returnType;
+        } else {
+          FunctionType functionType =
+              abstractFieldElement.setter.computeType(
+                  compiler);
+          type = functionType.parameterTypes.head;
+          if (type == null) {
+            type = compiler.types.dynamicType;
+          }
+        }
+      } else {
+        type = element.computeType(compiler);
+      }
+      if (!declarer.element.typeVariables.isEmpty) {
+        type = type.subst(declarer.typeArguments,
+                          declarer.element.typeVariables);
+        type = type.subst(receiver.typeArguments,
+                          receiver.element.typeVariables);
+      }
+      cachedType = type;
+    }
+    return cachedType;
+  }
 
-  /** Returns true if t is a subtype of s */
+  String toString() {
+    return '$receiver.${element.name.slowToString()}';
+  }
+}
+
+abstract class DartTypeVisitor<R, A> {
+  R visitType(DartType type, A argument);
+
+  R visitVoidType(VoidType type, A argument) =>
+      visitType(type, argument);
+
+  R visitTypeVariableType(TypeVariableType type, A argument) =>
+      visitType(type, argument);
+
+  R visitFunctionType(FunctionType type, A argument) =>
+      visitType(type, argument);
+
+  R visitMalformedType(MalformedType type, A argument) =>
+      visitType(type, argument);
+
+  R visitStatementType(StatementType type, A argument) =>
+      visitType(type, argument);
+
+  R visitGenericType(GenericType type, A argument) =>
+      visitType(type, argument);
+
+  R visitInterfaceType(InterfaceType type, A argument) =>
+      visitGenericType(type, argument);
+
+  R visitTypedefType(TypedefType type, A argument) =>
+      visitGenericType(type, argument);
+
+  R visitDynamicType(DynamicType type, A argument) =>
+      visitInterfaceType(type, argument);
+}
+
+class SubtypeVisitor extends DartTypeVisitor<bool, DartType> {
+  final Compiler compiler;
+  final DynamicType dynamicType;
+
+  SubtypeVisitor(Compiler this.compiler, DynamicType this.dynamicType);
+
   bool isSubtype(DartType t, DartType s) {
     if (identical(t, s) ||
         identical(t, dynamicType) ||
@@ -680,84 +860,138 @@
     t = t.unalias(compiler);
     s = s.unalias(compiler);
 
-    if (t is VoidType) {
-      return false;
-    } else if (t is InterfaceType) {
-      if (s is !InterfaceType) return false;
-      ClassElement tc = t.element;
-      if (identical(tc, s.element)) return true;
-      for (Link<DartType> supertypes = tc.allSupertypes;
-           supertypes != null && !supertypes.isEmpty;
-           supertypes = supertypes.tail) {
-        DartType supertype = supertypes.head;
-        if (identical(supertype.element, s.element)) return true;
-      }
-      return false;
-    } else if (t is FunctionType) {
-      if (identical(s.element, compiler.functionClass)) return true;
-      if (s is !FunctionType) return false;
-      FunctionType tf = t;
-      FunctionType sf = s;
-      Link<DartType> tps = tf.parameterTypes;
-      Link<DartType> sps = sf.parameterTypes;
-      while (!tps.isEmpty && !sps.isEmpty) {
-        if (!isAssignable(tps.head, sps.head)) return false;
-        tps = tps.tail;
-        sps = sps.tail;
-      }
-      if (!tps.isEmpty || !sps.isEmpty) return false;
-      if (!isAssignable(sf.returnType, tf.returnType)) return false;
-      if (!sf.namedParameters.isEmpty) {
-        // Since named parameters are globally ordered we can determine the
-        // subset relation with a linear search for [:sf.NamedParameters:]
-        // within [:tf.NamedParameters:].
-        Link<SourceString> tNames = tf.namedParameters;
-        Link<DartType> tTypes = tf.namedParameterTypes;
-        Link<SourceString> sNames = sf.namedParameters;
-        Link<DartType> sTypes = sf.namedParameterTypes;
-        while (!tNames.isEmpty && !sNames.isEmpty) {
-          if (sNames.head == tNames.head) {
-            if (!isAssignable(tTypes.head, sTypes.head)) return false;
+    return t.accept(this, s);
+  }
 
-            sNames = sNames.tail;
-            sTypes = sTypes.tail;
-          }
-          tNames = tNames.tail;
-          tTypes = tTypes.tail;
-        }
-        if (!sNames.isEmpty) {
-          // We didn't find all names.
+  bool isAssignable(DartType t, DartType s) {
+    return isSubtype(t, s) || isSubtype(s, t);
+  }
+
+  bool visitType(DartType t, DartType s) {
+    throw 'internal error: unknown type kind ${t.kind}';
+  }
+
+  bool visitVoidType(VoidType t, DartType s) {
+    assert(s is! VoidType);
+    return false;
+  }
+
+  bool visitInterfaceType(InterfaceType t, DartType s) {
+    if (s is !InterfaceType) return false;
+
+    bool checkTypeArguments(InterfaceType instance) {
+      Link<DartType> tTypeArgs = instance.typeArguments;
+      Link<DartType> sTypeArgs = s.typeArguments;
+      while (!tTypeArgs.isEmpty) {
+        assert(!sTypeArgs.isEmpty);
+        if (!isSubtype(tTypeArgs.head, sTypeArgs.head)) {
           return false;
         }
+        tTypeArgs = tTypeArgs.tail;
+        sTypeArgs = sTypeArgs.tail;
       }
-      if (!sf.optionalParameterTypes.isEmpty) {
-        Link<DartType> tOptionalParameterType = tf.optionalParameterTypes;
-        Link<DartType> sOptionalParameterType = sf.optionalParameterTypes;
-        while (!tOptionalParameterType.isEmpty &&
-               !sOptionalParameterType.isEmpty) {
-          if (!isAssignable(tOptionalParameterType.head,
-                            sOptionalParameterType.head)) {
-            return false;
-          }
-          sOptionalParameterType = sOptionalParameterType.tail;
-          tOptionalParameterType = tOptionalParameterType.tail;
-        }
-        if (!sOptionalParameterType.isEmpty) {
-          // We didn't find enough optional parameters.
-          return false;
-        }
-      }
+      assert(sTypeArgs.isEmpty);
       return true;
-    } else if (t is TypeVariableType) {
-      if (s is !TypeVariableType) return false;
-      return (identical(t.element, s.element));
-    } else {
-      throw 'internal error: unknown type kind';
     }
+
+    // TODO(johnniwinther): Currently needed since literal types like int,
+    // double, bool etc. might not have been resolved yet.
+    t.element.ensureResolved(compiler);
+
+    InterfaceType instance = t.asInstanceOf(s.element);
+    return instance != null && checkTypeArguments(instance);
+  }
+
+  bool visitFunctionType(FunctionType t, DartType s) {
+    if (identical(s.element, compiler.functionClass)) return true;
+    if (s is !FunctionType) return false;
+    FunctionType tf = t;
+    FunctionType sf = s;
+    Link<DartType> tps = tf.parameterTypes;
+    Link<DartType> sps = sf.parameterTypes;
+    while (!tps.isEmpty && !sps.isEmpty) {
+      if (!isAssignable(tps.head, sps.head)) return false;
+      tps = tps.tail;
+      sps = sps.tail;
+    }
+    if (!tps.isEmpty || !sps.isEmpty) return false;
+    // TODO(johnniwinther): Handle the void type correctly.
+    if (!isAssignable(tf.returnType, sf.returnType)) return false;
+    if (!sf.namedParameters.isEmpty) {
+      // Since named parameters are globally ordered we can determine the
+      // subset relation with a linear search for [:sf.NamedParameters:]
+      // within [:tf.NamedParameters:].
+      Link<SourceString> tNames = tf.namedParameters;
+      Link<DartType> tTypes = tf.namedParameterTypes;
+      Link<SourceString> sNames = sf.namedParameters;
+      Link<DartType> sTypes = sf.namedParameterTypes;
+      while (!tNames.isEmpty && !sNames.isEmpty) {
+        if (sNames.head == tNames.head) {
+          if (!isAssignable(tTypes.head, sTypes.head)) return false;
+
+          sNames = sNames.tail;
+          sTypes = sTypes.tail;
+        }
+        tNames = tNames.tail;
+        tTypes = tTypes.tail;
+      }
+      if (!sNames.isEmpty) {
+        // We didn't find all names.
+        return false;
+      }
+    }
+    if (!sf.optionalParameterTypes.isEmpty) {
+      Link<DartType> tOptionalParameterType = tf.optionalParameterTypes;
+      Link<DartType> sOptionalParameterType = sf.optionalParameterTypes;
+      while (!tOptionalParameterType.isEmpty &&
+             !sOptionalParameterType.isEmpty) {
+        if (!isAssignable(tOptionalParameterType.head,
+                          sOptionalParameterType.head)) {
+          return false;
+        }
+        sOptionalParameterType = sOptionalParameterType.tail;
+        tOptionalParameterType = tOptionalParameterType.tail;
+      }
+      if (!sOptionalParameterType.isEmpty) {
+        // We didn't find enough optional parameters.
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool visitTypeVariableType(TypeVariableType t, DartType s) {
+    if (s is !TypeVariableType) return false;
+    return (identical(t.element, s.element));
+  }
+}
+
+class Types {
+  final Compiler compiler;
+  // TODO(karlklose): should we have a class Void?
+  final VoidType voidType;
+  final DynamicType dynamicType;
+  final SubtypeVisitor subtypeVisitor;
+
+  factory Types(Compiler compiler, ClassElement dynamicElement) {
+    LibraryElement library = new LibraryElementX(new Script(null, null));
+    VoidType voidType = new VoidType(new VoidElementX(library));
+    DynamicType dynamicType = new DynamicType(dynamicElement);
+    dynamicElement.rawType = dynamicElement.thisType = dynamicType;
+    SubtypeVisitor subtypeVisitor = new SubtypeVisitor(compiler, dynamicType);
+    return new Types.internal(compiler, voidType, dynamicType, subtypeVisitor);
+  }
+
+  Types.internal(this.compiler, this.voidType, this.dynamicType,
+                 this.subtypeVisitor);
+
+  /** Returns true if t is a subtype of s */
+  bool isSubtype(DartType t, DartType s) {
+    return subtypeVisitor.isSubtype(t, s);
   }
 
   bool isAssignable(DartType r, DartType s) {
-    return isSubtype(r, s) || isSubtype(s, r);
+    return subtypeVisitor.isAssignable(r, s);
   }
 
 
diff --git a/sdk/lib/_internal/compiler/implementation/deferred_load.dart b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
new file mode 100644
index 0000000..c623bd8
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
@@ -0,0 +1,106 @@
+// 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 deferred_load;
+
+import 'dart:uri';
+
+import 'dart2jslib.dart'
+       show Compiler,
+            CompilerTask,
+            ConstructedConstant,
+            MessageKind,
+            SourceString,
+            StringConstant;
+
+import 'elements/elements.dart'
+       show ClassElement,
+            Element,
+            LibraryElement,
+            MetadataAnnotation;
+
+import 'util/util.dart'
+       show Link;
+
+import 'tree/tree.dart'
+       show LibraryTag;
+
+class DeferredLoadTask extends CompilerTask {
+  final Set<LibraryElement> deferredLibraries = new Set<LibraryElement>();
+
+  ClassElement cachedDeferredLibraryClass;
+
+  DeferredLoadTask(Compiler compiler) : super(compiler);
+
+  String get name => 'Lazy';
+
+  /// DeferredLibrary from dart:async
+  ClassElement get deferredLibraryClass {
+    if (cachedDeferredLibraryClass == null) {
+      cachedDeferredLibraryClass = findDeferredLibraryClass();
+    }
+    return cachedDeferredLibraryClass;
+  }
+
+  ClassElement findDeferredLibraryClass() {
+    var uri = new Uri.fromComponents(scheme: 'dart', path: 'async');
+    LibraryElement asyncLibrary =
+        compiler.libraryLoader.loadLibrary(uri, null, uri);
+    var element = asyncLibrary.find(const SourceString('DeferredLibrary'));
+    if (element == null) {
+      compiler.internalErrorOnElement(
+          asyncLibrary,
+          'dart:async library does not contain required class: '
+          'DeferredLibrary');
+    }
+    return element;
+  }
+
+  bool isDeferred(Element element) {
+    // TODO(ahe): This is really a graph coloring problem. We should
+    // make sure that libraries and elements only used by a deferred
+    // library are also deferred.
+    // Also, if something is deferred depends on your
+    // perspective. Inside a deferred library, other elements of the
+    // same library are not deferred. We should add an extra parameter
+    // to this method to indicate "from where".
+    return deferredLibraries.contains(element.getLibrary());
+  }
+
+  void registerMainApp(LibraryElement mainApp) {
+    if (mainApp == null) return;
+    measureElement(mainApp, () {
+      deferredLibraries.addAll(findDeferredLibraries(mainApp));
+    });
+  }
+
+  Link<LibraryElement> findDeferredLibraries(LibraryElement library) {
+    Link<LibraryElement> link = const Link<LibraryElement>();
+    for (LibraryTag tag in library.tags) {
+      Link<MetadataAnnotation> metadata = tag.metadata;
+      if (metadata == null) continue;
+      for (MetadataAnnotation metadata in tag.metadata) {
+        metadata.ensureResolved(compiler);
+        Element element = metadata.value.computeType(compiler).element;
+        if (element == deferredLibraryClass) {
+          ConstructedConstant value = metadata.value;
+          StringConstant nameField = value.fields[0];
+          SourceString expectedName = nameField.toDartString().source;
+          LibraryElement deferredLibrary = library.getLibraryFromTag(tag);
+          link = link.prepend(deferredLibrary);
+          SourceString actualName =
+              new SourceString(deferredLibrary.getLibraryOrScriptName());
+          if (expectedName != actualName) {
+            compiler.reportErrorCode(
+                metadata,
+                MessageKind.DEFERRED_LIBRARY_NAME_MISMATCH,
+                { 'expectedName': expectedName.slowToString(),
+                  'actualName': actualName.slowToString()});
+          }
+        }
+      }
+    }
+    return link;
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 312b35b..6432679 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -553,6 +553,13 @@
   void addTag(LibraryTag tag, DiagnosticListener listener);
   void addImport(Element element, DiagnosticListener listener);
 
+  /// Record which element an import or export tag resolved to.
+  /// (Belongs on builder object).
+  void recordResolvedTag(LibraryDependency tag, LibraryElement library);
+
+  /// Return the library element corresponding to an import or export.
+  LibraryElement getLibraryFromTag(LibraryDependency tag);
+
   void addMember(Element element, DiagnosticListener listener);
   void addToScope(Element element, DiagnosticListener listener);
 
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index ce9984d..00bcbd2 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -5,6 +5,7 @@
 library elements.modelx;
 
 import 'dart:uri';
+import 'dart:collection' show LinkedHashMap;
 
 import 'elements.dart';
 import '../../compiler.dart' as api;
@@ -564,6 +565,9 @@
    */
   Link<Element> slotForExports;
 
+  final Map<LibraryDependency, LibraryElement> tagMapping =
+      new LinkedHashMap<LibraryDependency, LibraryElement>();
+
   LibraryElementX(Script script, [Uri canonicalUri, LibraryElement this.origin])
     : this.canonicalUri = ((canonicalUri == null) ? script.uri : canonicalUri),
       importScope = new Map<SourceString, Element>(),
@@ -590,6 +594,13 @@
     tags = tags.prepend(tag);
   }
 
+  void recordResolvedTag(LibraryDependency tag, LibraryElement library) {
+    assert(tagMapping[tag] == null);
+    tagMapping[tag] = library;
+  }
+
+  LibraryElement getLibraryFromTag(LibraryDependency tag) => tagMapping[tag];
+
   /**
    * Adds [element] to the import scope of this library.
    *
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index 5ea86e3..e22fb11 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -67,6 +67,7 @@
     // runtime type.
     if (element.isGetter() && element.name == Compiler.RUNTIME_TYPE) {
       compiler.enabledRuntimeType = true;
+      compiler.backend.registerRuntimeType();
     } else if (element == compiler.functionApplyMethod) {
       compiler.enabledFunctionApply = true;
     } else if (element == compiler.invokeOnMethod) {
@@ -89,8 +90,8 @@
     if (universe.instantiatedClasses.contains(cls)) return;
     if (!cls.isAbstract(compiler)) {
       universe.instantiatedClasses.add(cls);
-      onRegisterInstantiatedClass(cls);
     }
+    onRegisterInstantiatedClass(cls);
     compiler.backend.registerInstantiatedClass(cls, this);
   }
 
@@ -120,9 +121,12 @@
     if (isProcessed(member)) return;
     if (!member.isInstanceMember()) return;
     if (member.isField()) {
-      // Native fields need to go into instanceMembersByName as they are virtual
-      // instantiation points and escape points.
-      // Test the enclosing class, since the metadata has not been parsed yet.
+      // Fields are implicitly used by the constructor of the
+      // instantiated class they are part of.
+      compiler.world.registerUsedElement(member);
+      // Native fields need to go into instanceMembersByName as they
+      // are virtual instantiation points and escape points. Test the
+      // enclosing class, since the metadata has not been parsed yet.
       if (!member.enclosingElement.isNative()) return;
     }
 
@@ -182,7 +186,7 @@
     }
 
     // The element is not yet used. Add it to the list of instance
-    // members to still be processed. 
+    // members to still be processed.
     Link<Element> members = instanceMembersByName.putIfAbsent(
         memberName, () => const Link<Element>());
     instanceMembersByName[memberName] = members.prepend(member);
@@ -205,22 +209,6 @@
         if (isResolutionQueue) {
           compiler.resolver.checkClass(cls);
         }
-
-        if (compiler.enableTypeAssertions) {
-          // We need to register is checks and helpers for checking
-          // assignments to fields.
-          // TODO(ngeoffray): This should really move to the backend.
-          cls.forEachLocalMember((Element member) {
-            if (!member.isInstanceMember() || !member.isField()) return;
-            DartType type = member.computeType(compiler);
-            registerIsCheck(type);
-            SourceString helper = compiler.backend.getCheckedModeHelper(type);
-            if (helper != null) {
-              Element helperElement = compiler.findHelper(helper);
-              registerStaticUse(helperElement);
-            }
-          });
-        }
       }
       processClass(cls);
       for (Link<DartType> supertypes = cls.allSupertypes;
@@ -364,6 +352,12 @@
 
   void registerIsCheck(DartType type) {
     universe.isChecks.add(type);
+    compiler.backend.registerIsCheck(type, this);
+  }
+
+  void registerAsCheck(DartType type) {
+    registerIsCheck(type);
+    compiler.backend.registerAsCheck(type);
   }
 
   void forEach(f(WorkItem work));
@@ -473,11 +467,8 @@
 
   void enableNoSuchMethod(Element element) {
     if (compiler.enabledNoSuchMethod) return;
+    if (element.getEnclosingClass() == compiler.objectClass) return;
     Selector selector = new Selector.noSuchMethod();
-    if (identical(element.getEnclosingClass(), compiler.objectClass)) {
-      registerDynamicInvocationOf(element, selector);
-      return;
-    }
     compiler.enabledNoSuchMethod = true;
     registerInvocation(Compiler.NO_SUCH_METHOD, selector);
 
@@ -513,7 +504,8 @@
       : super('codegen enqueuer', compiler, itemCompilationContextCreator),
         queue = new Queue<CodegenWorkItem>();
 
-  bool isProcessed(Element member) => generatedCode.containsKey(member);
+  bool isProcessed(Element member) =>
+      member.isAbstract(compiler) || generatedCode.containsKey(member);
 
   bool addElementToWorkList(Element element, [TreeElements elements]) {
     if (queueIsClosed) {
diff --git a/sdk/lib/_internal/compiler/implementation/js/nodes.dart b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
index da8cd44..ccf91b9 100644
--- a/sdk/lib/_internal/compiler/implementation/js/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
@@ -59,6 +59,8 @@
   T visitObjectInitializer(ObjectInitializer node);
   T visitProperty(Property node);
   T visitRegExpLiteral(RegExpLiteral node);
+
+  T visitComment(Comment node);
 }
 
 class BaseVisitor<T> implements NodeVisitor<T> {
@@ -141,6 +143,9 @@
   T visitObjectInitializer(ObjectInitializer node) => visitExpression(node);
   T visitProperty(Property node) => visitNode(node);
   T visitRegExpLiteral(RegExpLiteral node) => visitExpression(node);
+
+  // Ignore comments by default.
+  T visitComment(Comment node) {}
 }
 
 abstract class Node {
@@ -151,6 +156,10 @@
   void visitChildren(NodeVisitor visitor);
 
   VariableUse asVariableUse() => null;
+
+  Statement toStatement() {
+    throw new UnsupportedError('toStatement');
+  }
 }
 
 class Program extends Node {
@@ -164,6 +173,7 @@
 }
 
 abstract class Statement extends Node {
+  Statement toStatement() => this;
 }
 
 class Block extends Statement {
@@ -432,8 +442,71 @@
 abstract class Expression extends Node {
   int get precedenceLevel;
 
-  PropertyAccess dot(String name) => new PropertyAccess.field(this, name);
   Call callWith(List<Expression> arguments) => new Call(this, arguments);
+
+  New newWith(List<Expression> arguments) => new New(this, arguments);
+
+  PropertyAccess operator [](expression) {
+    if (expression is Expression) {
+      return new PropertyAccess(this, expression);
+    } else if (expression is int) {
+      return new PropertyAccess.indexed(this, expression);
+    } else if (expression is String) {
+      return new PropertyAccess.field(this, expression);
+    } else {
+      throw new ArgumentError('Expected an int, String, or Expression');
+    }
+  }
+
+  Statement toStatement() => new ExpressionStatement(this);
+
+  Call call([expression]) {
+    List<Expression> arguments;
+    if (expression == null) {
+      arguments = <Expression>[];
+    } else if (expression is List) {
+      arguments = expression.map(js.toExpression).toList();
+    } else {
+      arguments = <Expression>[js.toExpression(expression)];
+    }
+    return callWith(arguments);
+  }
+
+  Expression equals(expression) => binary('==', expression);
+
+  Expression strictEquals(expression) => binary('===', expression);
+
+  Expression notEquals(expression) => binary('!=', expression);
+
+  Expression operator +(expression) => binary('+', expression);
+
+  Expression operator -(expression) => binary('-', expression);
+
+  Expression operator &(expression) => binary('&', expression);
+
+  Expression operator <(expression) => binary('<', expression);
+
+  Expression operator >(expression) => binary('>', expression);
+
+  Expression operator >=(expression) => binary('>=', expression);
+
+  Expression binary(String operator, expression) {
+    return new Binary(operator, this, js.toExpression(expression));
+  }
+
+  Expression assign(expression) {
+    return new Assignment(this, js.toExpression(expression));
+  }
+
+  Expression update(String operator, expression) {
+    return new Assignment.compound(this, operator, js.toExpression(expression));
+  }
+
+  Expression get plusPlus => new Postfix('++', this);
+
+  Prefix get typeof => new Prefix('typeof', this);
+
+  Prefix get not => new Prefix('!', this);
 }
 
 class LiteralExpression extends Expression {
@@ -798,8 +871,8 @@
 }
 
 /**
- * An expression inside an [ArrayInitialization]. An [ArrayElement] knows
- * its position in the containing [ArrayInitialization].
+ * An expression inside an [ArrayInitializer]. An [ArrayElement] knows
+ * its position in the containing [ArrayInitializer].
  */
 class ArrayElement extends Node {
   int index;
@@ -859,48 +932,562 @@
   int get precedenceLevel => PRIMARY;
 }
 
-Prefix typeOf(Expression argument) => new Prefix('typeof', argument);
+/**
+ * A comment.
+ *
+ * Extends [Statement] so we can add comments before statements in
+ * [Block] and [Program].
+ */
+class Comment extends Statement {
+  final String comment;
 
-Binary equals(Expression left, Expression right) {
-  return new Binary('==', left, right);
+  Comment(this.comment);
+
+  accept(NodeVisitor visitor) => visitor.visitComment(this);
+
+  void visitChildren(NodeVisitor visitor) {}
 }
 
-Binary strictEquals(Expression left, Expression right) {
-  return new Binary('===', left, right);
+class JsBuilder {
+  const JsBuilder();
+
+  Expression operator [](String source) {
+    return new MiniJsParser(source).expression();
+  }
+
+  // TODO(ahe): Remove this method.
+  Binary equals(Expression left, Expression right) {
+    return new Binary('==', left, right);
+  }
+
+  // TODO(ahe): Remove this method.
+  Binary strictEquals(Expression left, Expression right) {
+    return new Binary('===', left, right);
+  }
+
+  LiteralString string(String value) => new LiteralString('"$value"');
+
+  If if_(condition, thenPart, [elsePart]) {
+    condition = toExpression(condition);
+    return (elsePart == null)
+        ? new If.noElse(condition, toStatement(thenPart))
+        : new If(condition, toStatement(thenPart), toStatement(elsePart));
+  }
+
+  Return return_([value]) {
+    return new Return(value == null ? null : toExpression(value));
+  }
+
+  Block block(statement) {
+    if (statement is Block) {
+      return statement;
+    } else if (statement is List) {
+      return new Block(statement.map(toStatement).toList());
+    } else {
+      return new Block(<Statement>[toStatement(statement)]);
+    }
+  }
+
+  Fun fun(parameters, body) {
+    Parameter toParameter(parameter) {
+      if (parameter is String) {
+        return new Parameter(parameter);
+      } else if (parameter is Parameter) {
+        return parameter;
+      } else {
+        throw new ArgumentError('parameter should be a String or a Parameter');
+      }
+    }
+    if (parameters is! List) {
+      parameters = [parameters];
+    }
+    return new Fun(parameters.map(toParameter).toList(), block(body));
+  }
+
+  Assignment assign(Expression leftHandSide, Expression value) {
+    return new Assignment(leftHandSide, value);
+  }
+
+  Expression undefined() => new Prefix('void', new LiteralNumber('0'));
+
+  VariableDeclarationList defineVar(String name, [initializer]) {
+    if (initializer != null) {
+      initializer = toExpression(initializer);
+    }
+    var declaration = new VariableDeclaration(name);
+    var initialization = [new VariableInitialization(declaration, initializer)];
+    return new VariableDeclarationList(initialization);
+  }
+
+  Statement toStatement(statement) {
+    if (statement is List) {
+      return new Block(statement.map(toStatement).toList());
+    } else if (statement is Node) {
+      return statement.toStatement();
+    } else {
+      throw new ArgumentError('statement');
+    }
+  }
+
+  Expression toExpression(expression) {
+    if (expression is Expression) {
+      return expression;
+    } else if (expression is String) {
+      return this[expression];
+    } else if (expression is num) {
+      return new LiteralNumber('$expression');
+    } else if (expression is bool) {
+      return new LiteralBool(expression);
+    } else if (expression is Map) {
+      if (!expression.isEmpty) {
+        throw new ArgumentError('expression should be an empty Map');
+      }
+      return new ObjectInitializer([]);
+    } else {
+      throw new ArgumentError('expression should be an Expression, '
+                              'a String, a num, a bool, or a Map');
+    }
+  }
+
+  ForIn forIn(String name, object, statement) {
+    return new ForIn(defineVar(name),
+                     toExpression(object),
+                     toStatement(statement));
+  }
+
+  For for_(init, condition, update, statement) {
+    return new For(
+        toExpression(init), toExpression(condition), toExpression(update),
+        toStatement(statement));
+  }
+
+  Try try_(body, {catchPart, finallyPart}) {
+    if (catchPart != null) catchPart = toStatement(catchPart);
+    if (finallyPart != null) finallyPart = toStatement(finallyPart);
+    return new Try(toStatement(body), catchPart, finallyPart);
+  }
+
+  Comment comment(String text) => new Comment(text);
 }
 
-LiteralString string(String value) => new LiteralString('"$value"');
+const JsBuilder js = const JsBuilder();
 
-If if_(Expression condition, Node then, [Node otherwise]) {
-  return (otherwise == null)
-      ? new If.noElse(condition, then)
-      : new If(condition, then, otherwise);
+LiteralString string(String value) => js.string(value);
+
+class MiniJsParserError {
+  MiniJsParserError(this.parser, this.message) { }
+
+  MiniJsParser parser;
+  String message;
+
+  String toString() {
+    var codes =
+        new List.fixedLength(parser.lastPosition, fill: charCodes.$SPACE);
+    var spaces = new String.fromCharCodes(codes);
+    return "Error in MiniJsParser:\n${parser.src}\n$spaces^\n$spaces$message\n";
+  }
 }
 
-Return return_([Expression value]) => new Return(value);
+/// Mini JavaScript parser for tiny snippets of code that we want to make into
+/// AST nodes.  Handles:
+/// * identifiers.
+/// * dot access.
+/// * method calls.
+/// * [] access.
+/// * array, string, boolean, null and numeric literals (no hex).
+/// * most operators.
+/// * brackets.
+/// * var declarations.
+/// Notable things it can't do yet include:
+/// * operator precedence.
+/// * non-empty object literals.
+/// * throw, return.
+/// * statements, including any flow control (if, while, for, etc.)
+/// * the 'in' keyword.
+///
+/// It's a fairly standard recursive descent parser.
+///
+/// Literal strings are passed through to the final JS source code unchanged,
+/// including the choice of surrounding quotes, so if you parse
+/// r'var x = "foo\n\"bar\""' you will end up with
+///   var x = "foo\n\"bar\"" in the final program.  String literals are
+/// restricted to a small subset of the full set of allowed JS escapes in order
+/// to get early errors for unintentional escape sequences without complicating
+/// this parser unneccessarily.
+class MiniJsParser {
+  MiniJsParser(this.src)
+      : lastCategory = NONE,
+        lastToken = null,
+        lastPosition = 0,
+        position = 0 {
+    getSymbol();
+  }
 
-VariableUse use(String name) => new VariableUse(name);
+  int lastCategory;
+  String lastToken;
+  int lastPosition;
+  int position;
+  String src;
 
-PropertyAccess fieldAccess(Expression receiver, String fieldName) {
-  return new PropertyAccess.field(receiver, fieldName);
+  static const NONE = -1;
+  static const ALPHA = 0;
+  static const NUMERIC = 1;
+  static const STRING = 2;
+  static const SYMBOL = 3;
+  static const RELATION = 4;
+  static const DOT = 5;
+  static const LPAREN = 6;
+  static const RPAREN = 7;
+  static const LBRACE = 8;
+  static const RBRACE = 9;
+  static const LSQUARE = 10;
+  static const RSQUARE = 11;
+  static const COMMA = 12;
+  static const QUERY = 13;
+  static const COLON = 14;
+  static const OTHER = 15;
+
+  // Make sure that ]] is two symbols.
+  bool singleCharCategory(int category) => category >= DOT;
+
+  static String categoryToString(int cat) {
+    switch (cat) {
+      case NONE: return "NONE";
+      case ALPHA: return "ALPHA";
+      case NUMERIC: return "NUMERIC";
+      case SYMBOL: return "SYMBOL";
+      case RELATION: return "RELATION";
+      case DOT: return "DOT";
+      case LPAREN: return "LPAREN";
+      case RPAREN: return "RPAREN";
+      case LBRACE: return "LBRACE";
+      case RBRACE: return "RBRACE";
+      case RSQUARE: return "RSQUARE";
+      case STRING: return "STRING";
+      case COMMA: return "COMMA";
+      case QUERY: return "QUERY";
+      case COLON: return "COLON";
+      case OTHER: return "OTHER";
+    }
+    return "Unknown: $cat";
+  }
+
+  static const CATEGORIES = const <int>[
+      OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,       // 0-7
+      OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,       // 8-15
+      OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,       // 16-23
+      OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,       // 24-31
+      OTHER, RELATION, OTHER, OTHER, ALPHA, SYMBOL, SYMBOL, OTHER,  //  !"#$%&´
+      LPAREN, RPAREN, SYMBOL, SYMBOL, COMMA, SYMBOL, DOT, SYMBOL,   // ()*+,-./
+      NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC,                  // 01234
+      NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC,                  // 56789
+      COLON, OTHER, RELATION, RELATION, RELATION, QUERY, OTHER,     // :;<=>?@
+      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // ABCDEFGH
+      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // IJKLMNOP
+      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // QRSTUVWX
+      ALPHA, ALPHA, LSQUARE, OTHER, RSQUARE, SYMBOL, ALPHA, OTHER,  // YZ[\]^_'
+      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // abcdefgh
+      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // ijklmnop
+      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // qrstuvwx
+      ALPHA, ALPHA, LBRACE, SYMBOL, RBRACE, SYMBOL];                // yz{|}~
+
+  static final BINARY_OPERATORS = [
+      '+', '-', '*', '/', '%', '^', '|', '&', '||', '&&',
+      '<<', '>>', '+=', '-=', '*=', '/=', '^=', '|=', '&=', '<<=', '>>=',
+      '=', '!=', '==', '!==', '===', '<', '<=', '>=', '>'].toSet();
+  static final UNARY_OPERATORS = ['++', '--', '+', '-', '~', '!'].toSet();
+
+  // For sanity we only allow \\, \', \" and \n in string literals.
+  static final STRING_LITERAL_PATTERN =
+      new RegExp('^[\'"](?:[^\\\\]|\\\\[\\\\n\'"])*[\'"]\$');
+
+  static int category(int code) {
+    if (code >= CATEGORIES.length) return OTHER;
+    return CATEGORIES[code];
+  }
+
+  void getSymbol() {
+    while (position < src.length &&
+           src.codeUnitAt(position) == charCodes.$SPACE) {
+      position++;
+    }
+    if (position == src.length) {
+      lastCategory = NONE;
+      lastToken = null;
+      lastPosition = position;
+      return;
+    }
+    int code = src.codeUnitAt(position);
+    lastPosition = position;
+    if (code == charCodes.$SQ || code == charCodes.$DQ) {
+      int currentCode;
+      do {
+        position++;
+        if (position >= src.length) {
+          throw new MiniJsParserError(this, "Unterminated string");
+        }
+        currentCode = src.codeUnitAt(position);
+        if (currentCode == charCodes.$BACKSLASH) {
+          if (++position >= src.length) {
+            throw new MiniJsParserError(this, "Unterminated string");
+          }
+        }
+      } while (currentCode != code);
+      lastCategory = STRING;
+      position++;
+      lastToken = src.substring(lastPosition, position);
+      if (!STRING_LITERAL_PATTERN.hasMatch(lastToken)) {
+        throw new MiniJsParserError(
+            this,
+            "Only escapes allowed in string literals are \\, \', \" and \n");
+      }
+    } else {
+      int cat = category(src.codeUnitAt(position));
+      int newCat;
+      do {
+        position++;
+        if (position == src.length) break;
+        newCat = category(src.codeUnitAt(position));
+      } while (!singleCharCategory(cat) &&
+               (cat == newCat ||
+                (cat == ALPHA && newCat == NUMERIC) ||    // eg. level42.
+                (cat == NUMERIC && newCat == DOT) ||      // eg. 3.1415
+                (cat == SYMBOL && newCat == RELATION)));  // eg. +=.
+      lastCategory = cat;
+      lastToken = src.substring(lastPosition, position);
+      if (cat == NUMERIC) {
+        double.parse(lastToken, (_) {
+          throw new MiniJsParserError(this, "Unparseable number");
+        });
+      } else if (cat == SYMBOL || cat == RELATION) {
+        if (!BINARY_OPERATORS.contains(lastToken) &&
+            !UNARY_OPERATORS.contains(lastToken)) {
+          throw new MiniJsParserError(this, "Unknown operator");
+        }
+      }
+    }
+  }
+
+  void expectCategory(int cat) {
+    if (cat != lastCategory) {
+      throw new MiniJsParserError(this, "Expected ${categoryToString(cat)}");
+    }
+    getSymbol();
+  }
+
+  bool acceptCategory(int cat) {
+    if (cat == lastCategory) {
+      getSymbol();
+      return true;
+    }
+    return false;
+  }
+
+  bool acceptString(String string) {
+    if (lastToken == string) {
+      getSymbol();
+      return true;
+    }
+    return false;
+  }
+
+  Expression parsePrimary() {
+    String last = lastToken;
+    if (acceptCategory(ALPHA)) {
+      if (last == "true") {
+        return new LiteralBool(true);
+      } else if (last == "false") {
+        return new LiteralBool(false);
+      } else if (last == "null") {
+        return new LiteralNull();
+      } else {
+        return new VariableUse(last);
+      }
+    } else if (acceptCategory(LPAREN)) {
+      Expression expression = parseExpression();
+      expectCategory(RPAREN);
+      return expression;
+    } else if (acceptCategory(STRING)) {
+      return new LiteralString(last);
+    } else if (acceptCategory(NUMERIC)) {
+      return new LiteralNumber(last);
+    } else if (acceptCategory(LBRACE)) {
+      expectCategory(RBRACE);
+      return new ObjectInitializer([]);
+    } else if (acceptCategory(LSQUARE)) {
+      var values = <ArrayElement>[];
+      if (!acceptCategory(RSQUARE)) {
+        do {
+          values.add(new ArrayElement(values.length, parseExpression()));
+        } while (acceptCategory(COMMA));
+        expectCategory(RSQUARE);
+      }
+      return new ArrayInitializer(values.length, values);
+    } else {
+      throw new MiniJsParserError(this, "Expected primary expression");
+    }
+  }
+
+  Expression parseMember() {
+    Expression receiver = parsePrimary();
+    while (true) {
+      if (acceptCategory(DOT)) {
+        String identifier = lastToken;
+        expectCategory(ALPHA);
+        receiver = new PropertyAccess.field(receiver, identifier);
+      } else if (acceptCategory(LSQUARE)) {
+        Expression inBraces = parseExpression();
+        expectCategory(RSQUARE);
+        receiver = new PropertyAccess(receiver, inBraces);
+      } else {
+        return receiver;
+      }
+    }
+  }
+
+  Expression parseCall() {
+    bool constructor = acceptString("new");
+    Expression receiver = parseMember();
+    if (acceptCategory(LPAREN)) {
+      final arguments = <Expression>[];
+      if (!acceptCategory(RPAREN)) {
+        while (true) {
+          Expression argument = parseExpression();
+          arguments.add(argument);
+          if (acceptCategory(RPAREN)) break;
+          expectCategory(COMMA);
+        }
+      }
+      return constructor ?
+             new New(receiver, arguments) :
+             new Call(receiver, arguments);
+    } else {
+      if (constructor) {
+        // JS allows new without (), but we don't.
+        throw new MiniJsParserError(this, "Parentheses are required for new");
+      }
+      return receiver;
+    }
+  }
+
+  Expression parsePostfix() {
+    Expression expression = parseCall();
+    String operator = lastToken;
+    if (lastCategory == SYMBOL && (acceptString("++") || acceptString("--"))) {
+      return new Postfix(operator, expression);
+    }
+    return expression;
+  }
+
+  Expression parseUnary() {
+    String operator = lastToken;
+    if (lastCategory == ALPHA) {
+     if (acceptString("typeof") || acceptString("void") ||
+         acceptString("delete")) {
+        return new Prefix(operator, parsePostfix());
+     }
+    } else if (lastCategory == SYMBOL) {
+      if (acceptString("~") || acceptString("-") || acceptString("++") ||
+          acceptString("--") || acceptString("+")) {
+        return new Prefix(operator, parsePostfix());
+      }
+    } else if (acceptString("!")) {
+      return new Prefix(operator, parsePostfix());
+    }
+    return parsePostfix();
+  }
+
+  Expression parseBinary() {
+    // Since we don't handle precedence we don't allow two different symbols
+    // without parentheses.
+    Expression lhs = parseUnary();
+    String firstSymbol = lastToken;
+    while (true) {
+      String symbol = lastToken;
+      if (!acceptCategory(SYMBOL)) return lhs;
+      if (!BINARY_OPERATORS.contains(symbol)) {
+        throw new MiniJsParserError(this, "Unknown binary operator");
+      }
+      if (symbol != firstSymbol) {
+        throw new MiniJsParserError(
+            this, "Mixed $firstSymbol and $symbol operators without ()");
+      }
+      Expression rhs = parseUnary();
+      if (symbol.endsWith("=")) {
+        // +=, -=, *= etc.
+        lhs = new Assignment.compound(lhs,
+                                      symbol.substring(0, symbol.length - 1),
+                                      rhs);
+      } else {
+        lhs = new Binary(symbol, lhs, rhs);
+      }
+    }
+  }
+
+  Expression parseRelation() {
+    Expression lhs = parseBinary();
+    String relation = lastToken;
+    // The lexer returns "=" as a relational operator because it looks a bit
+    // like ==, <=, etc.  But we don't want to handle it here (that would give
+    // it the wrong prescedence), so we just return if we see it.
+    if (relation == "=" || !acceptCategory(RELATION)) return lhs;
+    Expression rhs = parseBinary();
+    if (relation == "<<=" || relation == ">>=") {
+      return new Assignment.compound(lhs,
+                                     relation.substring(0, relation.length - 1),
+                                     rhs);
+    } else {
+      // Regular binary operation.
+      return new Binary(relation, lhs, rhs);
+    }
+  }
+
+  Expression parseConditional() {
+    Expression lhs = parseRelation();
+    if (!acceptCategory(QUERY)) return lhs;
+    Expression ifTrue = parseAssignment();
+    expectCategory(COLON);
+    Expression ifFalse = parseAssignment();
+    return new Conditional(lhs, ifTrue, ifFalse);
+  }
+
+
+  Expression parseAssignment() {
+    Expression lhs = parseConditional();
+    if (acceptString("=")) {
+      return new Assignment(lhs, parseAssignment());
+    }
+    return lhs;
+  }
+
+  Expression parseExpression() => parseAssignment();
+
+  Expression parseVarDeclarationOrExpression() {
+    if (acceptString("var")) {
+      var initialization = [];
+      do {
+        String variable = lastToken;
+        expectCategory(ALPHA);
+        Expression initializer = null;
+        if (acceptString("=")) {
+          initializer = parseExpression();
+        }
+        var declaration = new VariableDeclaration(variable);
+        initialization.add(
+            new VariableInitialization(declaration, initializer));
+      } while (acceptCategory(COMMA));
+      return new VariableDeclarationList(initialization);
+    } else {
+      return parseExpression();
+    }
+  }
+
+  Expression expression() {
+    Expression expression = parseVarDeclarationOrExpression();
+    if (lastCategory != NONE || position != src.length) {
+      throw new MiniJsParserError(
+          this, "Unparsed junk: ${categoryToString(lastCategory)}");
+    }
+    return expression;
+  }
 }
-
-Block emptyBlock() => new Block.empty();
-
-Block block1(Statement statement) => new Block(<Statement>[statement]);
-
-Block block2(Statement s1, Statement s2) => new Block(<Statement>[s1, s2]);
-
-Call call(Expression target, List<Expression> arguments) {
-  return new Call(target, arguments);
-}
-
-Fun fun(List<String> parameterNames, Block body) {
-  return new Fun(parameterNames.map((n) => new Parameter(n)).toList(), body);
-}
-
-Assignment assign(Expression leftHandSide, Expression value) {
-  return new Assignment(leftHandSide, value);
-}
-
-Expression undefined() => new Prefix('void', new LiteralNumber('0'));
diff --git a/sdk/lib/_internal/compiler/implementation/js/printer.dart b/sdk/lib/_internal/compiler/implementation/js/printer.dart
index 8595174..5af3a42 100644
--- a/sdk/lib/_internal/compiler/implementation/js/printer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/printer.dart
@@ -851,6 +851,19 @@
   visitLiteralStatement(LiteralStatement node) {
     outLn(node.code);
   }
+
+  void visitComment(Comment node) {
+    if (shouldCompressOutput) return;
+    String comment = node.comment.trim();
+    if (comment.isEmpty) return;
+    for (var line in comment.split('\n')) {
+      if (comment.startsWith('//')) {
+        outIndentLn(line.trim());
+      } else {
+        outIndentLn('// ${line.trim()}');
+      }
+    }
+  }
 }
 
 
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 9f8155d..a66ab80 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -77,10 +77,10 @@
       : types = null,
         namedArguments = null;
 
-  factory HTypeList.fromStaticInvocation(HInvokeStatic node, HTypeMap types) {
+  factory HTypeList.fromStaticInvocation(HInvokeStatic node) {
     bool allUnknown = true;
     for (int i = 1; i < node.inputs.length; i++) {
-      if (types[node.inputs[i]] != HType.UNKNOWN) {
+      if (node.inputs[i].instructionType != HType.UNKNOWN) {
         allUnknown = false;
         break;
       }
@@ -89,14 +89,13 @@
 
     HTypeList result = new HTypeList(node.inputs.length - 1);
     for (int i = 0; i < result.types.length; i++) {
-      result.types[i] = types[node.inputs[i + 1]];
+      result.types[i] = node.inputs[i + 1].instructionType;
     }
     return result;
   }
 
   factory HTypeList.fromDynamicInvocation(HInvokeDynamic node,
-                                          Selector selector,
-                                          HTypeMap types) {
+                                          Selector selector) {
     HTypeList result;
     int argumentsCount = node.inputs.length - 1;
     int startInvokeIndex = HInvoke.ARGUMENTS_OFFSET;
@@ -115,7 +114,7 @@
     }
 
     for (int i = 0; i < result.types.length; i++) {
-      result.types[i] = types[node.inputs[i + startInvokeIndex]];
+      result.types[i] = node.inputs[i + startInvokeIndex].instructionType;
     }
     return result;
   }
@@ -330,7 +329,7 @@
         && initializerType == null
         && constructorType == null
         && setterType == null) {
-      // Don't register UNKONWN if there is currently no type information
+      // Don't register UNKNOWN if there is currently no type information
       // present for the field. Instead register the function holding the
       // setter for recompilation if better type information for the field
       // becomes available.
@@ -456,11 +455,11 @@
     return true;
   }
 
-  void registerStaticInvocation(HInvokeStatic node, HTypeMap types) {
+  void registerStaticInvocation(HInvokeStatic node) {
     Element element = node.element;
     assert(invariant(node, element.isDeclaration));
     HTypeList oldTypes = staticTypeMap[element];
-    HTypeList newTypes = new HTypeList.fromStaticInvocation(node, types);
+    HTypeList newTypes = new HTypeList.fromStaticInvocation(node);
     if (oldTypes == null) {
       staticTypeMap[element] = newTypes;
     } else if (updateTypes(oldTypes, newTypes, element, staticTypeMap)) {
@@ -501,7 +500,7 @@
 
     // Run through all optimized functions and figure out if they need
     // to be recompiled because of this new invocation.
-    optimizedFunctions.filterBySelector(selector).forEach((Element element) {
+    for (Element element in optimizedFunctions.filter(selector)) {
       // TODO(kasperl): Maybe check if the element is already marked for
       // recompilation? Could be pretty cheap compared to computing
       // union types.
@@ -521,7 +520,7 @@
         }
       }
       if (recompile) backend.scheduleForRecompilation(element);
-    });
+    }
   }
 
   HTypeList parameterTypes(FunctionElement element,
@@ -585,7 +584,7 @@
     }
 
     // TODO(kasperl): What kind of non-members do we get here?
-    if (!element.isMember()) return;
+    if (!element.isInstanceMember()) return;
 
     if (parameterTypes.allUnknown) {
       optimizedFunctions.remove(element);
@@ -607,12 +606,10 @@
 }
 
 class JavaScriptItemCompilationContext extends ItemCompilationContext {
-  final HTypeMap types;
   final Set<HInstruction> boundsChecked;
 
   JavaScriptItemCompilationContext()
-      : types = new HTypeMap(),
-        boundsChecked = new Set<HInstruction>();
+      : boundsChecked = new Set<HInstruction>();
 }
 
 class JavaScriptBackend extends Backend {
@@ -624,15 +621,15 @@
   /**
    * The generated code as a js AST for compiled methods.
    */
-  Map<Element, js.Expression> get generatedCode {
+  Map<Element, jsAst.Expression> get generatedCode {
     return compiler.enqueuer.codegen.generatedCode;
   }
 
   /**
    * The generated code as a js AST for compiled bailout methods.
    */
-  final Map<Element, js.Expression> generatedBailoutCode =
-      new Map<Element, js.Expression>();
+  final Map<Element, jsAst.Expression> generatedBailoutCode =
+      new Map<Element, jsAst.Expression>();
 
   ClassElement jsStringClass;
   ClassElement jsArrayClass;
@@ -685,7 +682,7 @@
    * A collection of selectors that must have a one shot interceptor
    * generated.
    */
-  final Set<Selector> oneShotInterceptors;
+  final Map<String, Selector> oneShotInterceptors;
 
   /**
    * The members of instantiated interceptor classes: maps a member
@@ -711,6 +708,14 @@
    */
   final Map<ClassElement, ClassElement> interceptedClasses;
 
+  /**
+   * Set of selectors that are used from within loops. Used by the
+   * builder to allow speculative optimizations for functions without
+   * loops themselves.
+   */
+  final Map<SourceString, Set<Selector>> selectorsCalledInLoop =
+      new Map<SourceString, Set<Selector>>();
+
   List<CompilerTask> get tasks {
     return <CompilerTask>[builder, optimizer, generator, emitter];
   }
@@ -722,7 +727,7 @@
         returnInfo = new Map<Element, ReturnInfo>(),
         invalidateAfterCodegen = new List<Element>(),
         usedInterceptors = new Set<Selector>(),
-        oneShotInterceptors = new Set<Selector>(),
+        oneShotInterceptors = new Map<String, Selector>(),
         interceptedElements = new Map<SourceString, Set<Element>>(),
         rti = new RuntimeTypeInformation(compiler),
         specializedGetInterceptors =
@@ -730,7 +735,8 @@
         interceptedClasses = new LinkedHashMap<ClassElement, ClassElement>(),
         super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM) {
     emitter = disableEval
-        ? new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap)
+        // TODO(8522): Restore --disallow-unsafe-eval.
+        ? null // new CodeEmitterNoEvalTask(compiler, namer, generateSourceMap)
         : new CodeEmitterTask(compiler, namer, generateSourceMap);
     builder = new SsaBuilderTask(this);
     optimizer = new SsaOptimizerTask(this);
@@ -754,34 +760,54 @@
     usedInterceptors.add(selector);
   }
 
-  void addOneShotInterceptor(Selector selector) {
-    oneShotInterceptors.add(selector);
+  String registerOneShotInterceptor(Selector selector) {
+    Set<ClassElement> classes = getInterceptedClassesOn(selector);
+    String name = namer.getOneShotInterceptorName(selector, classes);
+    if (!oneShotInterceptors.containsKey(name)) {
+      registerSpecializedGetInterceptor(classes);
+      oneShotInterceptors[name] = selector;
+    }
+    return name;
   }
 
+  final Map<Selector, Set<ClassElement>> interceptedClassesCache =
+      new Map<Selector, Set<ClassElement>>();
+  final Map<Selector, Set<ClassElement>> interceptedClassesNonNullCache =
+      new Map<Selector, Set<ClassElement>>();
+
   /**
    * Returns a set of interceptor classes that contain a member whose
    * signature matches the given [selector]. Returns [:null:] if there
    * is no class.
    */
-  Set<ClassElement> getInterceptedClassesOn(Selector selector) {
+  Set<ClassElement> getInterceptedClassesOn(Selector selector,
+                                            {bool canBeNull: true}) {
     Set<Element> intercepted = interceptedElements[selector.name];
     if (intercepted == null) return null;
+    // Pick the right cache and query it.
+    Map<Selector, Set<ClassElement>> cache = canBeNull
+        ? interceptedClassesCache
+        : interceptedClassesNonNullCache;
+    if (cache.containsKey(selector)) return cache[selector];
+    // Populate the cache by running through all the elements and
+    // determine if the given selector applies to them.
     Set<ClassElement> result = new Set<ClassElement>();
     for (Element element in intercepted) {
-      if (selector.applies(element, compiler)) {
-        result.add(element.getEnclosingClass());
-      }
+      ClassElement enclosing = element.getEnclosingClass();
+      // We have to treat null as a bottom type, so we use the untyped
+      // applies method for those elements that are implemented on the
+      // null class.
+      bool applies = (enclosing == jsNullClass)
+          ? canBeNull && selector.appliesUntyped(element, compiler)
+          : selector.applies(element, compiler);
+      if (applies) result.add(enclosing);
     }
-    if (result.isEmpty) return null;
+    if (result.isEmpty) result = null;
+    cache[selector] = result;
+    assert(cache.containsKey(selector));
     return result;
   }
 
-  List<ClassElement> getListOfInterceptedClasses() {
-      return <ClassElement>[jsStringClass, jsArrayClass, jsIntClass,
-                            jsDoubleClass, jsNumberClass, jsNullClass,
-                            jsFunctionClass, jsBoolClass];
-  }
-
   void initializeInterceptorElements() {
     objectInterceptorClass =
         compiler.findInterceptor(const SourceString('ObjectInterceptor'));
@@ -875,19 +901,39 @@
       initializeNoSuchMethod();
       seenAnyClass = true;
     }
+
+    // Register any helper that will be needed by the backend.
+    if (enqueuer.isResolutionQueue) {
+      if (cls == compiler.intClass
+          || cls == compiler.doubleClass
+          || cls == compiler.numClass) {
+        // The backend will try to optimize number operations and use the
+        // `iae` helper directly.
+        enqueuer.registerStaticUse(
+            compiler.findHelper(const SourceString('iae')));
+      } else if (cls == compiler.listClass
+                 || cls == compiler.stringClass) {
+        // The backend will try to optimize array and string access and use the
+        // `ioore` and `iae` helpers directly.
+        enqueuer.registerStaticUse(
+            compiler.findHelper(const SourceString('ioore')));
+        enqueuer.registerStaticUse(
+            compiler.findHelper(const SourceString('iae')));
+      } else if (cls == compiler.functionClass) {
+        enqueuer.registerInstantiatedClass(compiler.closureClass);
+      } else if (cls == compiler.mapClass) {
+        // The backend will use a literal list to initialize the entries
+        // of the map.
+        enqueuer.registerInstantiatedClass(compiler.listClass);
+        enqueuer.registerInstantiatedClass(compiler.mapLiteralClass);
+        enqueueInResolution(getMapMaker());
+      }
+    }
     ClassElement result = null;
     if (cls == compiler.stringClass) {
       addInterceptors(jsStringClass, enqueuer);
     } else if (cls == compiler.listClass) {
       addInterceptors(jsArrayClass, enqueuer);
-      // The backend will try to optimize array access and use the
-      // `ioore` and `iae` helpers directly.
-      if (enqueuer.isResolutionQueue) {
-        enqueuer.registerStaticUse(
-            compiler.findHelper(const SourceString('ioore')));
-        enqueuer.registerStaticUse(
-            compiler.findHelper(const SourceString('iae')));
-      }
     } else if (cls == compiler.intClass) {
       addInterceptors(jsIntClass, enqueuer);
       addInterceptors(jsNumberClass, enqueuer);
@@ -905,17 +951,16 @@
       addInterceptors(jsDoubleClass, enqueuer);
       addInterceptors(jsNumberClass, enqueuer);
     } else if (cls == compiler.mapClass) {
-      // The backend will use a literal list to initialize the entries
-      // of the map.
-      if (enqueuer.isResolutionQueue) {
-        enqueuer.registerInstantiatedClass(compiler.listClass);
-        enqueuer.registerInstantiatedClass(compiler.mapLiteralClass);
-      }
     }
-  }
 
-  Element get cyclicThrowHelper {
-    return compiler.findHelper(const SourceString("throwCyclicInit"));
+    if (compiler.enableTypeAssertions) {
+      // We need to register is checks for assignments to fields.
+      cls.forEachLocalMember((Element member) {
+        if (!member.isInstanceMember() || !member.isField()) return;
+        DartType type = member.computeType(compiler);
+        enqueuer.registerIsCheck(type);
+      });
+    }
   }
 
   JavaScriptItemCompilationContext createItemCompilationContext() {
@@ -923,22 +968,114 @@
   }
 
   void enqueueHelpers(ResolutionEnqueuer world) {
-    enqueueAllTopLevelFunctions(compiler.jsHelperLibrary, world);
-
     jsIndexingBehaviorInterface =
         compiler.findHelper(const SourceString('JavaScriptIndexingBehavior'));
     if (jsIndexingBehaviorInterface != null) {
       world.registerIsCheck(jsIndexingBehaviorInterface.computeType(compiler));
     }
 
-    for (var helper in [const SourceString('Closure'),
-                        const SourceString('ConstantMap'),
-                        const SourceString('ConstantProtoMap')]) {
-      var e = compiler.findHelper(helper);
-      if (e != null) world.registerInstantiatedClass(e);
+    if (compiler.enableTypeAssertions) {
+      // Unconditionally register the helper that checks if the
+      // expression in an if/while/for is a boolean.
+      // TODO(ngeoffray): Should we have the resolver register those instead?
+      Element e =
+          compiler.findHelper(const SourceString('boolConversionCheck'));
+      if (e != null) world.addToWorkList(e);
     }
   }
 
+  void registerStringInterpolation() {
+    enqueueInResolution(getStringInterpolationHelper());
+  }
+
+  void registerCatchStatement() {
+    enqueueInResolution(getExceptionUnwrapper());
+  }
+
+  void registerThrow() {
+    enqueueInResolution(getThrowHelper());
+  }
+
+  void registerLazyField() {
+    enqueueInResolution(getCyclicThrowHelper());
+  }
+
+  void registerTypeLiteral() {
+    enqueueInResolution(getCreateRuntimeType());
+  }
+
+  void registerStackTraceInCatch() {
+    enqueueInResolution(getTraceFromException());
+  }
+
+  void registerRuntimeType() {
+    enqueueInResolution(getSetRuntimeTypeInfo());
+    enqueueInResolution(getGetRuntimeTypeInfo());
+    enqueueInResolution(getGetRuntimeTypeArgument());
+    compiler.enqueuer.resolution.registerInstantiatedClass(compiler.listClass);
+  }
+
+  void registerIsCheck(DartType type, Enqueuer world) {
+    if (!type.isRaw) {
+      enqueueInResolution(getSetRuntimeTypeInfo());
+      enqueueInResolution(getGetRuntimeTypeInfo());
+      enqueueInResolution(getGetRuntimeTypeArgument());
+      enqueueInResolution(getCheckArguments());
+      world.registerInstantiatedClass(compiler.listClass);
+    }
+    // [registerIsCheck] is also called for checked mode checks, so we
+    // need to register checked mode helpers.
+    if (compiler.enableTypeAssertions) {
+      Element e = getCheckedModeHelper(type, typeCast: false);
+      if (e != null) world.addToWorkList(e);
+      // We also need the native variant of the check (for DOM types).
+      e = getNativeCheckedModeHelper(type, typeCast: false);
+      if (e != null) world.addToWorkList(e);
+    }
+  }
+
+  void registerAsCheck(DartType type) {
+    Element e = getCheckedModeHelper(type, typeCast: true);
+    enqueueInResolution(e);
+    // We also need the native variant of the check (for DOM types).
+    e = getNativeCheckedModeHelper(type, typeCast: true);
+    enqueueInResolution(e);
+  }
+
+  void registerThrowNoSuchMethod() {
+    enqueueInResolution(getThrowNoSuchMethod());
+  }
+
+  void registerThrowRuntimeError() {
+    enqueueInResolution(getThrowRuntimeError());
+  }
+
+  void registerAbstractClassInstantiation() {
+    enqueueInResolution(getThrowAbstractClassInstantiationError());
+  }
+
+  void registerFallThroughError() {
+    enqueueInResolution(getFallThroughError());
+  }
+
+  void registerSuperNoSuchMethod() {
+    enqueueInResolution(getCreateInvocationMirror());
+    enqueueInResolution(
+        compiler.objectClass.lookupLocalMember(Compiler.NO_SUCH_METHOD));
+    compiler.enqueuer.resolution.registerInstantiatedClass(compiler.listClass);
+  }
+
+  void enqueueInResolution(Element e) {
+    if (e != null) compiler.enqueuer.resolution.addToWorkList(e);
+  }
+
+  void registerConstantMap() {
+    Element e = compiler.findHelper(const SourceString('ConstantMap'));
+    if (e != null) compiler.enqueuer.resolution.registerInstantiatedClass(e);
+    e = compiler.findHelper(const SourceString('ConstantProtoMap'));
+    if (e != null) compiler.enqueuer.resolution.registerInstantiatedClass(e);
+  }
+
   void codegen(CodegenWorkItem work) {
     Element element = work.element;
     if (element.kind.category == ElementCategory.VARIABLE) {
@@ -950,7 +1087,7 @@
         // go through the builder (below) to generate the lazy initializer for
         // the static variable.
         // We also need to register the use of the cyclic-error helper.
-        compiler.enqueuer.codegen.registerStaticUse(cyclicThrowHelper);
+        compiler.enqueuer.codegen.registerStaticUse(getCyclicThrowHelper());
       }
     }
 
@@ -958,12 +1095,12 @@
     optimizer.optimize(work, graph, false);
     if (work.allowSpeculativeOptimization
         && optimizer.trySpeculativeOptimizations(work, graph)) {
-      js.Expression code = generator.generateBailoutMethod(work, graph);
+      jsAst.Expression code = generator.generateBailoutMethod(work, graph);
       generatedBailoutCode[element] = code;
       optimizer.prepareForSpeculativeOptimizations(work, graph);
       optimizer.optimize(work, graph, true);
     }
-    js.Expression code = generator.generateCode(work, graph);
+    jsAst.Expression code = generator.generateCode(work, graph);
     generatedCode[element] = code;
     invalidateAfterCodegen.forEach(eagerRecompile);
     invalidateAfterCodegen.clear();
@@ -984,7 +1121,7 @@
    */
   String assembleCode(Element element) {
     assert(invariant(element, element.isDeclaration));
-    return js.prettyPrint(generatedCode[element], compiler).getText();
+    return jsAst.prettyPrint(generatedCode[element], compiler).getText();
   }
 
   void assembleProgram() {
@@ -1007,11 +1144,9 @@
    *  Register a dynamic invocation and collect the provided types for the
    *  named selector.
    */
-  void registerDynamicInvocation(HInvokeDynamic node,
-                                 Selector selector,
-                                 HTypeMap types) {
+  void registerDynamicInvocation(HInvokeDynamic node, Selector selector) {
     HTypeList providedTypes =
-        new HTypeList.fromDynamicInvocation(node, selector, types);
+        new HTypeList.fromDynamicInvocation(node, selector);
     argumentTypes.registerDynamicInvocation(providedTypes, selector);
   }
 
@@ -1019,8 +1154,8 @@
    *  Register a static invocation and collect the provided types for the
    *  named selector.
    */
-  void registerStaticInvocation(HInvokeStatic node, HTypeMap types) {
-    argumentTypes.registerStaticInvocation(node, types);
+  void registerStaticInvocation(HInvokeStatic node) {
+    argumentTypes.registerStaticInvocation(node);
   }
 
   /**
@@ -1141,54 +1276,126 @@
   }
 
   /**
-   * Return the checked mode helper name that will be needed to do a
-   * type check on [type] at runtime. Note that this method is being
-   * called both by the resolver with interface types (int, String,
-   * ...), and by the SSA backend with implementation types (JSInt,
-   * JSString, ...).
+   * Returns the checked mode helper that will be needed to do a type check/type
+   * cast on [type] at runtime. Note that this method is being called both by
+   * the resolver with interface types (int, String, ...), and by the SSA
+   * backend with implementation types (JSInt, JSString, ...).
    */
-  SourceString getCheckedModeHelper(DartType type) {
+  Element getCheckedModeHelper(DartType type, {bool typeCast}) {
+    return compiler.findHelper(getCheckedModeHelperName(
+        type, typeCast: typeCast, nativeCheckOnly: false));
+  }
+
+  /**
+   * Returns the native checked mode helper that will be needed to do a type
+   * check/type cast on [type] at runtime. If no native helper exists for
+   * [type], [:null:] is returned.
+   */
+  Element getNativeCheckedModeHelper(DartType type, {bool typeCast}) {
+    SourceString sourceName = getCheckedModeHelperName(
+        type, typeCast: typeCast, nativeCheckOnly: true);
+    if (sourceName == null) return null;
+    return compiler.findHelper(sourceName);
+  }
+
+  /**
+   * Returns the name of the type check/type cast helper method for [type]. If
+   * [nativeCheckOnly] is [:true:], only names for native helpers are returned.
+   */
+  SourceString getCheckedModeHelperName(DartType type,
+                                        {bool typeCast,
+                                         bool nativeCheckOnly}) {
     Element element = type.element;
-    bool nativeCheck =
-          emitter.nativeEmitter.requiresNativeIsCheck(element);
+    bool nativeCheck = nativeCheckOnly ||
+        emitter.nativeEmitter.requiresNativeIsCheck(element);
     if (type.isMalformed) {
       // Check for malformed types first, because the type may be a list type
       // with a malformed argument type.
-      return const SourceString('malformedTypeCheck');
+      if (nativeCheckOnly) return null;
+      return typeCast
+          ? const SourceString('malformedTypeCast')
+          : const SourceString('malformedTypeCheck');
     } else if (type == compiler.types.voidType) {
+      assert(!typeCast); // Cannot cast to void.
+      if (nativeCheckOnly) return null;
       return const SourceString('voidTypeCheck');
     } else if (element == jsStringClass || element == compiler.stringClass) {
-      return const SourceString('stringTypeCheck');
+      if (nativeCheckOnly) return null;
+      return typeCast
+          ? const SourceString("stringTypeCast")
+          : const SourceString('stringTypeCheck');
     } else if (element == jsDoubleClass || element == compiler.doubleClass) {
-      return const SourceString('doubleTypeCheck');
+      if (nativeCheckOnly) return null;
+      return typeCast
+          ? const SourceString("doubleTypeCast")
+          : const SourceString('doubleTypeCheck');
     } else if (element == jsNumberClass || element == compiler.numClass) {
-      return const SourceString('numTypeCheck');
+      if (nativeCheckOnly) return null;
+      return typeCast
+          ? const SourceString("numTypeCast")
+          : const SourceString('numTypeCheck');
     } else if (element == jsBoolClass || element == compiler.boolClass) {
-      return const SourceString('boolTypeCheck');
-    } else if (element == jsFunctionClass
-               || element == compiler.functionClass) {
-      return const SourceString('functionTypeCheck');
+      if (nativeCheckOnly) return null;
+      return typeCast
+          ? const SourceString("boolTypeCast")
+          : const SourceString('boolTypeCheck');
+    } else if (element == jsFunctionClass ||
+               element == compiler.functionClass) {
+      if (nativeCheckOnly) return null;
+      return typeCast
+          ? const SourceString("functionTypeCast")
+          : const SourceString('functionTypeCheck');
     } else if (element == jsIntClass || element == compiler.intClass) {
-      return const SourceString('intTypeCheck');
+      if (nativeCheckOnly) return null;
+      return typeCast ?
+          const SourceString("intTypeCast") :
+          const SourceString('intTypeCheck');
     } else if (Elements.isNumberOrStringSupertype(element, compiler)) {
-      return nativeCheck
-          ? const SourceString('numberOrStringSuperNativeTypeCheck')
+      if (nativeCheck) {
+        return typeCast
+            ? const SourceString("numberOrStringSuperNativeTypeCast")
+            : const SourceString('numberOrStringSuperNativeTypeCheck');
+      } else {
+        return typeCast
+          ? const SourceString("numberOrStringSuperTypeCast")
           : const SourceString('numberOrStringSuperTypeCheck');
+      }
     } else if (Elements.isStringOnlySupertype(element, compiler)) {
-      return nativeCheck
-          ? const SourceString('stringSuperNativeTypeCheck')
-          : const SourceString('stringSuperTypeCheck');
+      if (nativeCheck) {
+        return typeCast
+            ? const SourceString("stringSuperNativeTypeCast")
+            : const SourceString('stringSuperNativeTypeCheck');
+      } else {
+        return typeCast
+            ? const SourceString("stringSuperTypeCast")
+            : const SourceString('stringSuperTypeCheck');
+      }
     } else if (element == compiler.listClass || element == jsArrayClass) {
-      return const SourceString('listTypeCheck');
+      if (nativeCheckOnly) return null;
+      return typeCast
+          ? const SourceString("listTypeCast")
+          : const SourceString('listTypeCheck');
     } else {
       if (Elements.isListSupertype(element, compiler)) {
-        return nativeCheck
-            ? const SourceString('listSuperNativeTypeCheck')
-            : const SourceString('listSuperTypeCheck');
+        if (nativeCheck) {
+          return typeCast
+              ? const SourceString("listSuperNativeTypeCast")
+              : const SourceString('listSuperNativeTypeCheck');
+        } else {
+          return typeCast
+              ? const SourceString("listSuperTypeCast")
+              : const SourceString('listSuperTypeCheck');
+        }
       } else {
-        return nativeCheck
-            ? const SourceString('callTypeCheck')
-            : const SourceString('propertyTypeCheck');
+        if (nativeCheck) {
+          return typeCast
+              ? const SourceString("callTypeCast")
+              : const SourceString('callTypeCheck');
+        } else {
+          return typeCast
+              ? const SourceString("propertyTypeCast")
+              : const SourceString('propertyTypeCheck');
+        }
       }
     }
   }
@@ -1226,6 +1433,14 @@
         const SourceString('throwAbstractClassInstantiationError'));
   }
 
+  Element getStringInterpolationHelper() {
+    return compiler.findHelper(const SourceString('S'));
+  }
+
+  Element getThrowHelper() {
+    return compiler.findHelper(const SourceString(r'$throw'));
+  }
+
   Element getClosureConverter() {
     return compiler.findHelper(const SourceString('convertDartClosureToJS'));
   }
@@ -1250,6 +1465,30 @@
     return compiler.findHelper(const SourceString('getRuntimeTypeArgument'));
   }
 
+  Element getCheckArguments() {
+    return compiler.findHelper(const SourceString('checkArguments'));
+  }
+
+  Element getThrowNoSuchMethod() {
+    return compiler.findHelper(const SourceString('throwNoSuchMethod'));
+  }
+
+  Element getCreateRuntimeType() {
+    return compiler.findHelper(const SourceString('createRuntimeType'));
+  }
+
+  Element getFallThroughError() {
+    return compiler.findHelper(const SourceString("getFallThroughError"));
+  }
+
+  Element getCreateInvocationMirror() {
+    return compiler.findHelper(Compiler.CREATE_INVOCATION_MIRROR);
+  }
+
+  Element getCyclicThrowHelper() {
+    return compiler.findHelper(const SourceString("throwCyclicInit"));
+  }
+
   /**
    * Remove [element] from the set of generated code, and put it back
    * into the worklist.
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
index 86717ae..9f3ea2e 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
@@ -19,7 +19,7 @@
    * canonical name unless the constant can be emitted multiple times (as for
    * numbers and strings).
    */
-  js.Expression reference(Constant constant) {
+  jsAst.Expression reference(Constant constant) {
     return _referenceEmitter.generate(constant);
   }
 
@@ -27,14 +27,14 @@
    * Constructs an expression like [reference], but the expression is valid
    * during isolate initialization.
    */
-  js.Expression referenceInInitializationContext(Constant constant) {
+  jsAst.Expression referenceInInitializationContext(Constant constant) {
     return _referenceEmitter.generateInInitializationContext(constant);
   }
 
   /**
    * Constructs an expression used to initialize a canonicalized constant.
    */
-  js.Expression initializationExpression(Constant constant) {
+  jsAst.Expression initializationExpression(Constant constant) {
     return _initializerEmitter.generate(constant);
   }
 }
@@ -43,74 +43,68 @@
  * Visitor for generating JavaScript expressions to refer to [Constant]s.
  * Do not use directly, use methods from [ConstantEmitter].
  */
-class ConstantReferenceEmitter implements ConstantVisitor<js.Expression> {
+class ConstantReferenceEmitter implements ConstantVisitor<jsAst.Expression> {
   final Compiler compiler;
   final Namer namer;
-  bool inIsolateInitializationContext = false;
 
   ConstantReferenceEmitter(this.compiler, this.namer);
 
-  js.Expression generate(Constant constant) {
-    inIsolateInitializationContext = false;
+  jsAst.Expression generate(Constant constant) {
     return _visit(constant);
   }
 
-  js.Expression generateInInitializationContext(Constant constant) {
-    inIsolateInitializationContext = true;
+  jsAst.Expression generateInInitializationContext(Constant constant) {
     return _visit(constant);
   }
 
-  js.Expression _visit(Constant constant) {
+  jsAst.Expression _visit(Constant constant) {
     return constant.accept(this);
   }
 
-  js.Expression visitSentinel(SentinelConstant constant) {
-    return new js.VariableUse(namer.CURRENT_ISOLATE);
+  jsAst.Expression visitSentinel(SentinelConstant constant) {
+    return new jsAst.VariableUse(namer.CURRENT_ISOLATE);
   }
 
-  js.Expression visitFunction(FunctionConstant constant) {
-    return inIsolateInitializationContext
-        ? new js.VariableUse(namer.isolatePropertiesAccess(constant.element))
-        : new js.VariableUse(namer.isolateAccess(constant.element));
+  jsAst.Expression visitFunction(FunctionConstant constant) {
+    return new jsAst.VariableUse(namer.isolateAccess(constant.element));
   }
 
-  js.Expression visitNull(NullConstant constant) {
-    return new js.LiteralNull();
+  jsAst.Expression visitNull(NullConstant constant) {
+    return new jsAst.LiteralNull();
   }
 
-  js.Expression visitInt(IntConstant constant) {
-    return new js.LiteralNumber('${constant.value}');
+  jsAst.Expression visitInt(IntConstant constant) {
+    return new jsAst.LiteralNumber('${constant.value}');
   }
 
-  js.Expression visitDouble(DoubleConstant constant) {
+  jsAst.Expression visitDouble(DoubleConstant constant) {
     double value = constant.value;
     if (value.isNaN) {
-      return new js.LiteralNumber("(0/0)");
+      return new jsAst.LiteralNumber("(0/0)");
     } else if (value == double.INFINITY) {
-      return new js.LiteralNumber("(1/0)");
+      return new jsAst.LiteralNumber("(1/0)");
     } else if (value == -double.INFINITY) {
-      return new js.LiteralNumber("(-1/0)");
+      return new jsAst.LiteralNumber("(-1/0)");
     } else {
-      return new js.LiteralNumber("$value");
+      return new jsAst.LiteralNumber("$value");
     }
   }
 
-  js.Expression visitTrue(TrueConstant constant) {
+  jsAst.Expression visitTrue(TrueConstant constant) {
     if (compiler.enableMinification) {
       // Use !0 for true.
-      return new js.Prefix("!", new js.LiteralNumber("0"));
+      return js["!0"];
     } else {
-      return new js.LiteralBool(true);
+      return new jsAst.LiteralBool(true);
     }
-
   }
 
-  js.Expression visitFalse(FalseConstant constant) {
+  jsAst.Expression visitFalse(FalseConstant constant) {
     if (compiler.enableMinification) {
       // Use !1 for false.
-      return new js.Prefix("!", new js.LiteralNumber("1"));
+      return js["!1"];
     } else {
-      return new js.LiteralBool(false);
+      return new jsAst.LiteralBool(false);
     }
   }
 
@@ -119,44 +113,34 @@
    * a form that is valid as JavaScript string literal content.
    * The string is assumed quoted by double quote characters.
    */
-  js.Expression visitString(StringConstant constant) {
+  jsAst.Expression visitString(StringConstant constant) {
     // TODO(sra): If the string is long *and repeated* (and not on a hot path)
     // then it should be assigned to a name.  We don't have reference counts (or
     // profile information) here, so this is the wrong place.
     StringBuffer sb = new StringBuffer();
     writeJsonEscapedCharsOn(constant.value.slowToString(), sb);
-    return new js.LiteralString('"$sb"');
+    return new jsAst.LiteralString('"$sb"');
   }
 
-  js.Expression emitCanonicalVersion(Constant constant) {
+  jsAst.Expression emitCanonicalVersion(Constant constant) {
     String name = namer.constantName(constant);
-    if (inIsolateInitializationContext) {
-      //  $isolateName.$isolatePropertiesName.$name
-      return new js.PropertyAccess.field(
-          new js.PropertyAccess.field(
-              new js.VariableUse(namer.isolateName),
-              namer.isolatePropertiesName),
-          name);
-    } else {
-      return new js.PropertyAccess.field(
-          new js.VariableUse(namer.CURRENT_ISOLATE),
-          name);
-    }
+    return new jsAst.PropertyAccess.field(
+        new jsAst.VariableUse(namer.CURRENT_ISOLATE), name);
   }
 
-  js.Expression visitList(ListConstant constant) {
+  jsAst.Expression visitList(ListConstant constant) {
     return emitCanonicalVersion(constant);
   }
 
-  js.Expression visitMap(MapConstant constant) {
+  jsAst.Expression visitMap(MapConstant constant) {
     return emitCanonicalVersion(constant);
   }
 
-  js.Expression visitType(TypeConstant constant) {
+  jsAst.Expression visitType(TypeConstant constant) {
     return emitCanonicalVersion(constant);
   }
 
-  js.Expression visitConstructed(ConstructedConstant constant) {
+  jsAst.Expression visitConstructed(ConstructedConstant constant) {
     return emitCanonicalVersion(constant);
   }
 }
@@ -165,90 +149,90 @@
  * Visitor for generating JavaScript expressions to initialize [Constant]s.
  * Do not use directly; use methods from [ConstantEmitter].
  */
-class ConstantInitializerEmitter implements ConstantVisitor<js.Expression> {
+class ConstantInitializerEmitter implements ConstantVisitor<jsAst.Expression> {
   final Compiler compiler;
   final Namer namer;
   final ConstantReferenceEmitter referenceEmitter;
 
   ConstantInitializerEmitter(this.compiler, this.namer, this.referenceEmitter);
 
-  js.Expression generate(Constant constant) {
+  jsAst.Expression generate(Constant constant) {
     return _visit(constant);
   }
 
-  js.Expression _visit(Constant constant) {
+  jsAst.Expression _visit(Constant constant) {
     return constant.accept(this);
   }
 
-  js.Expression _reference(Constant constant) {
+  jsAst.Expression _reference(Constant constant) {
     return referenceEmitter.generateInInitializationContext(constant);
   }
 
-  js.Expression visitSentinel(SentinelConstant constant) {
+  jsAst.Expression visitSentinel(SentinelConstant constant) {
     compiler.internalError(
         "The parameter sentinel constant does not need specific JS code");
   }
 
-  js.Expression visitFunction(FunctionConstant constant) {
+  jsAst.Expression visitFunction(FunctionConstant constant) {
     compiler.internalError(
         "The function constant does not need specific JS code");
   }
 
-  js.Expression visitNull(NullConstant constant) {
+  jsAst.Expression visitNull(NullConstant constant) {
     return _reference(constant);
   }
 
-  js.Expression visitInt(IntConstant constant) {
+  jsAst.Expression visitInt(IntConstant constant) {
     return _reference(constant);
   }
 
-  js.Expression visitDouble(DoubleConstant constant) {
+  jsAst.Expression visitDouble(DoubleConstant constant) {
     return _reference(constant);
   }
 
-  js.Expression visitTrue(TrueConstant constant) {
+  jsAst.Expression visitTrue(TrueConstant constant) {
     return _reference(constant);
   }
 
-  js.Expression visitFalse(FalseConstant constant) {
+  jsAst.Expression visitFalse(FalseConstant constant) {
     return _reference(constant);
   }
 
-  js.Expression visitString(StringConstant constant) {
+  jsAst.Expression visitString(StringConstant constant) {
     // TODO(sra): Some larger strings are worth sharing.
     return _reference(constant);
   }
 
-  js.Expression visitList(ListConstant constant) {
-    return new js.Call(
-        new js.PropertyAccess.field(
-            new js.VariableUse(namer.isolateName),
+  jsAst.Expression visitList(ListConstant constant) {
+    return new jsAst.Call(
+        new jsAst.PropertyAccess.field(
+            new jsAst.VariableUse(namer.isolateName),
             'makeConstantList'),
-        [new js.ArrayInitializer.from(_array(constant.entries))]);
+        [new jsAst.ArrayInitializer.from(_array(constant.entries))]);
   }
 
   String getJsConstructor(ClassElement element) {
-    return namer.isolatePropertiesAccess(element);
+    return namer.isolateAccess(element);
   }
 
-  js.Expression visitMap(MapConstant constant) {
-    js.Expression jsMap() {
-      List<js.Property> properties = <js.Property>[];
+  jsAst.Expression visitMap(MapConstant constant) {
+    jsAst.Expression jsMap() {
+      List<jsAst.Property> properties = <jsAst.Property>[];
       int valueIndex = 0;
       for (int i = 0; i < constant.keys.entries.length; i++) {
         StringConstant key = constant.keys.entries[i];
         if (key.value == MapConstant.PROTO_PROPERTY) continue;
 
         // Keys in literal maps must be emitted in place.
-        js.Literal keyExpression = _visit(key);
-        js.Expression valueExpression =
+        jsAst.Literal keyExpression = _visit(key);
+        jsAst.Expression valueExpression =
             _reference(constant.values[valueIndex++]);
-        properties.add(new js.Property(keyExpression, valueExpression));
+        properties.add(new jsAst.Property(keyExpression, valueExpression));
       }
       if (valueIndex != constant.values.length) {
         compiler.internalError("Bad value count.");
       }
-      return new js.ObjectInitializer(properties);
+      return new jsAst.ObjectInitializer(properties);
     }
 
     void badFieldCountError() {
@@ -258,7 +242,7 @@
 
     ClassElement classElement = constant.type.element;
 
-    List<js.Expression> arguments = <js.Expression>[];
+    List<jsAst.Expression> arguments = <jsAst.Expression>[];
 
     // The arguments of the JavaScript constructor for any given Dart class
     // are in the same order as the members of the class element.
@@ -267,7 +251,7 @@
         (ClassElement enclosing, Element field) {
           if (field.name == MapConstant.LENGTH_NAME) {
             arguments.add(
-                new js.LiteralNumber('${constant.keys.entries.length}'));
+                new jsAst.LiteralNumber('${constant.keys.entries.length}'));
           } else if (field.name == MapConstant.JS_OBJECT_NAME) {
             arguments.add(jsMap());
           } else if (field.name == MapConstant.KEYS_NAME) {
@@ -288,35 +272,34 @@
       badFieldCountError();
     }
 
-    return new js.New(
-        new js.VariableUse(getJsConstructor(classElement)),
+    return new jsAst.New(
+        new jsAst.VariableUse(getJsConstructor(classElement)),
         arguments);
   }
 
-  js.Expression visitType(TypeConstant constant) {
-    SourceString helperSourceName = const SourceString('createRuntimeType');
-    Element helper = compiler.findHelper(helperSourceName);
+  jsAst.Expression visitType(TypeConstant constant) {
     JavaScriptBackend backend = compiler.backend;
+    Element helper = backend.getCreateRuntimeType();
     String helperName = backend.namer.getName(helper);
     DartType type = constant.representedType;
     Element element = type.element;
     String name = backend.rti.getRawTypeRepresentation(type);
-    js.Expression typeName = new js.LiteralString("'$name'");
-    return new js.Call(
-        new js.PropertyAccess.field(
-            new js.VariableUse(namer.CURRENT_ISOLATE),
+    jsAst.Expression typeName = new jsAst.LiteralString("'$name'");
+    return new jsAst.Call(
+        new jsAst.PropertyAccess.field(
+            new jsAst.VariableUse(namer.CURRENT_ISOLATE),
             helperName),
         [typeName]);
   }
 
-  js.Expression visitConstructed(ConstructedConstant constant) {
-    return new js.New(
-        new js.VariableUse(getJsConstructor(constant.type.element)),
+  jsAst.Expression visitConstructed(ConstructedConstant constant) {
+    return new jsAst.New(
+        new jsAst.VariableUse(getJsConstructor(constant.type.element)),
         _array(constant.fields));
   }
 
-  List<js.Expression> _array(List<Constant> values) {
-    List<js.Expression> valueList = <js.Expression>[];
+  List<jsAst.Expression> _array(List<Constant> values) {
+    List<jsAst.Expression> valueList = <jsAst.Expression>[];
     for (int i = 0; i < values.length; i++) {
       valueList.add(_reference(values[i]));
     }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart
index 30c8bc5..fa5384f 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart
@@ -144,9 +144,6 @@
 class JavaScriptConstantSystem extends ConstantSystem {
   const int BITS31 = 0x8FFFFFFF;
   const int BITS32 = 0xFFFFFFFF;
-  // The maximum integer value a double can represent without losing
-  // precision.
-  const int BITS53 = 0x1FFFFFFFFFFFFF;
 
   final add = const JavaScriptBinaryArithmeticOperation(const AddOperation());
   final bitAnd = const JavaScriptBinaryBitOperation(const BitAndOperation());
@@ -185,7 +182,9 @@
    */
   bool integerFitsIntoDouble(int value) {
     int absValue = value.abs();
-    return (absValue & BITS53) == absValue;
+    double doubleValue = absValue.toDouble();
+    if (doubleValue.isNaN || doubleValue.isInfinite) return false;
+    return value.toDouble().floor().toInt() == value;
   }
 
   NumConstant convertToJavaScriptConstant(NumConstant constant) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index b238df6..64a6aa6 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -27,20 +27,22 @@
 /**
  * A convenient type alias for some functions that emit keyed values.
  */
-typedef void DefineStubFunction(String invocationName, js.Expression value);
+typedef void DefineStubFunction(String invocationName, jsAst.Expression value);
 
 /**
  * A data structure for collecting fragments of a class definition.
  */
 class ClassBuilder {
-  final List<js.Property> properties = <js.Property>[];
+  final List<jsAst.Property> properties = <jsAst.Property>[];
 
   // Has the same signature as [DefineStubFunction].
-  void addProperty(String name, js.Expression value) {
-    properties.add(new js.Property(js.string(name), value));
+  void addProperty(String name, jsAst.Expression value) {
+    properties.add(new jsAst.Property(js.string(name), value));
   }
 
-  js.Expression toObjectInitializer() => new js.ObjectInitializer(properties);
+  jsAst.Expression toObjectInitializer() {
+    return new jsAst.ObjectInitializer(properties);
+  }
 }
 
 /**
@@ -59,6 +61,7 @@
   NativeEmitter nativeEmitter;
   CodeBuffer boundClosureBuffer;
   CodeBuffer mainBuffer;
+  final CodeBuffer deferredBuffer = new CodeBuffer();
   /** Shorter access to [isolatePropertiesName]. Both here in the code, as
       well as in the generated code. */
   String isolateProperties;
@@ -67,6 +70,8 @@
   // TODO(ngeoffray): remove this field.
   Set<ClassElement> instantiatedClasses;
 
+  JavaScriptBackend get backend => compiler.backend;
+
   String get _ => compiler.enableMinification ? "" : " ";
   String get n => compiler.enableMinification ? "" : "\n";
   String get N => compiler.enableMinification ? "\n" : ";\n";
@@ -113,6 +118,10 @@
     nativeEmitter = new NativeEmitter(this);
   }
 
+  void addComment(String comment, CodeBuffer buffer) {
+    buffer.add(jsAst.prettyPrint(js.comment(comment), compiler));
+  }
+
   void computeRequiredTypeChecks() {
     assert(checkedClasses == null);
     checkedClasses = new Set<ClassElement>();
@@ -126,28 +135,26 @@
     });
   }
 
-  js.Expression constantReference(Constant value) {
+  jsAst.Expression constantReference(Constant value) {
     return constantEmitter.reference(value);
   }
 
-  js.Expression constantInitializerExpression(Constant value) {
+  jsAst.Expression constantInitializerExpression(Constant value) {
     return constantEmitter.initializationExpression(value);
   }
 
   String get name => 'CodeEmitter';
 
-  String get defineClassName
-      => '${namer.isolateName}.\$defineClass';
   String get currentGenerateAccessorName
       => '${namer.CURRENT_ISOLATE}.\$generateAccessor';
   String get generateAccessorHolder
       => '$isolatePropertiesName.\$generateAccessor';
+  String get finishClassesProperty
+      => r'$finishClasses';
   String get finishClassesName
-      => '${namer.isolateName}.\$finishClasses';
+      => '${namer.isolateName}.$finishClassesProperty';
   String get finishIsolateConstructorName
       => '${namer.isolateName}.\$finishIsolateConstructor';
-  String get pendingClassesName
-      => '${namer.isolateName}.\$pendingClasses';
   String get isolatePropertiesName
       => '${namer.isolateName}.${namer.isolatePropertiesName}';
   String get supportsProtoName
@@ -176,38 +183,55 @@
   String needsSetterCode(String variable) => '($variable & 2) == 0';
   String isRenaming(String variable) => '($variable & $RENAMING_FLAG) != 0';
 
-  String get generateAccessorFunction {
-    return """
-function generateAccessor(field, prototype) {
-  var len = field.length;
-  var lastCharCode = field.charCodeAt(len - 1);
-  var needsAccessor = (lastCharCode & $SUFFIX_MASK) >= $FIRST_SUFFIX_CODE;
-  if (needsAccessor) {
-    var needsGetter = ${needsGetterCode('lastCharCode')};
-    var needsSetter = ${needsSetterCode('lastCharCode')};
-    var renaming = ${isRenaming('lastCharCode')};
-    var accessorName = field = field.substring(0, len - 1);
-    if (renaming) {
-      var divider = field.indexOf(":");
-      accessorName = field.substring(0, divider);
-      field = field.substring(divider + 1);
-    }
-    if (needsGetter) {
-      var getterString = "return this." + field + ";";
-      prototype["${namer.getterPrefix}" + accessorName] =
-          new Function(getterString);
-    }
-    if (needsSetter) {
-      var setterString = "this." + field + " = v;";
-      prototype["${namer.setterPrefix}" + accessorName] =
-          new Function("v", setterString);
-    }
-  }
-  return field;
-}""";
+  jsAst.FunctionDeclaration get generateAccessorFunction {
+    // function generateAccessor(field, prototype) {
+    jsAst.Fun fun = js.fun(['field', 'prototype'], [
+      js['var len = field.length'],
+      js['var lastCharCode = field.charCodeAt(len - 1)'],
+      js['var needsAccessor = '
+                '(lastCharCode & $SUFFIX_MASK) >= $FIRST_SUFFIX_CODE'],
+
+      // if (needsAccessor) {
+      js.if_('needsAccessor', [
+        js['var needsGetter = ${needsGetterCode("lastCharCode")}'],
+        js['var needsSetter = ${needsSetterCode("lastCharCode")}'],
+        js['var renaming = ${isRenaming("lastCharCode")}'],
+        js['var accessorName = field = field.substring(0, len - 1)'],
+
+        // if (renaming) {
+        js.if_('renaming', [
+          js['var divider = field.indexOf(":")'],
+          js['accessorName = field.substring(0, divider)'],
+          js['field = field.substring(divider + 1)']
+        ]),
+
+        // if (needsGetter) {
+        js.if_('needsGetter', [
+          js['var getterString = "return this." + field'],
+          js['prototype["${namer.getterPrefix}" + accessorName] = '
+                 'new Function(getterString)']
+        ]),
+
+        // if (needsSetter) {
+        js.if_('needsSetter', [
+          // var setterString = "this." + field + " = v;";
+          js['var setterString = "this." + field + "$_=${_}v"'],
+          js['prototype["${namer.setterPrefix}" + accessorName] = '
+                 'new Function("v", setterString)']
+        ]),
+
+      ]),
+
+      // return field;
+      js.return_('field')
+    ]);
+
+    return new jsAst.FunctionDeclaration(
+        new jsAst.VariableDeclaration('generateAccessor'),
+        fun);
   }
 
-  String get defineClassFunction {
+  jsAst.Fun get defineClassFunction {
     // First the class name, then the field names in an array and the members
     // (inside an Object literal).
     // The caller can also pass in the constructor as a function if needed.
@@ -221,33 +245,44 @@
     //   this.x = t - v;
     //  },
     // });
-    return """
-function(cls, fields, prototype) {
-  var constructor;
-  if (typeof fields == 'function') {
-    constructor = fields;
-  } else {
-    var str = "function " + cls + "(";
-    var body = "";
-    for (var i = 0; i < fields.length; i++) {
-      if (i != 0) str += ", ";
-      var field = fields[i];
-      field = generateAccessor(field, prototype);
-      str += field;
-      body += "this." + field + " = " + field + ";\\n";
-    }
-    str += ") {" + body + "}\\n";
-    str += "return " + cls + ";";
-    constructor = new Function(str)();
-  }
-  constructor.prototype = prototype;
-  constructor.builtin\$cls = cls;
-  return constructor;
-}""";
+
+    // function(cls, fields, prototype) {
+    return js.fun(['cls', 'fields', 'prototype'], [
+      js['var constructor'],
+
+      // if (typeof fields == 'function') {
+      js.if_(js["typeof fields == 'function'"], [
+        js['constructor = fields']
+      ], /* else */ [
+        js['var str = "function " + cls + "("'],
+        js['var body = ""'],
+
+        // for (var i = 0; i < fields.length; i++) {
+        js.for_(js['var i = 0'], js['i < fields.length'], js['i++'], [
+          // if (i != 0) str += ", ";
+          js.if_(js['i != 0'], js['str += ", "']),
+
+          js['var field = fields[i]'],
+          js['field = generateAccessor(field, prototype)'],
+          js['str += field'],
+          js['body += ("this." + field + " = " + field + ";\\n")']
+        ]),
+
+        js['str += (") {" + body + "}\\nreturn " + cls)'],
+
+        js['constructor = (new Function(str))()']
+      ]),
+
+      js['constructor.prototype = prototype'],
+      js['constructor.builtin\$cls = cls'],
+
+      // return constructor;
+      js.return_('constructor')
+    ]);
   }
 
   /** Needs defineClass to be defined. */
-  String get protoSupportCheck {
+  List buildProtoSupportCheck() {
     // On Firefox and Webkit browsers we can manipulate the __proto__
     // directly. Opera claims to have __proto__ support, but it is buggy.
     // So we have to do more checks.
@@ -256,21 +291,25 @@
     // If the browser does not support __proto__ we need to instantiate an
     // object with the correct (internal) prototype set up correctly, and then
     // copy the members.
+    // TODO(8541): Remove this work around.
 
-    return '''
-var $supportsProtoName = false;
-var tmp = $defineClassName('c', ['f?'], {}).prototype;
-if (tmp.__proto__) {
-  tmp.__proto__ = {};
-  if (typeof tmp.get\$f !== 'undefined') $supportsProtoName = true;
-}
-''';
+    return [
+      js['var $supportsProtoName = false'],
+      js["var tmp = (defineClass('c', ['f?'], {})).prototype"],
+
+      js.if_(js['tmp.__proto__'], [
+        js['tmp.__proto__ = {}'],
+        js.if_(js[r"typeof tmp.get$f != 'undefined'"],
+               js['$supportsProtoName = true'])
+
+      ])
+    ];
   }
 
-  String get finishClassesFunction {
-    // 'defineClass' does not require the classes to be constructed in order.
-    // Classes are initially just stored in the 'pendingClasses' field.
-    // 'finishClasses' takes all pending classes and sets up the prototype.
+  jsAst.Fun get finishClassesFunction {
+    // Class descriptions are collected in a JS object.
+    // 'finishClasses' takes all collected descriptions and sets up
+    // the prototype.
     // Once set up, the constructors prototype field satisfy:
     //  - it contains all (local) members.
     //  - its internal prototype (__proto__) points to the superclass'
@@ -280,67 +319,124 @@
     // For engines where we have access to the '__proto__' we can manipulate
     // the object literal directly. For other engines we have to create a new
     // object and copy over the members.
-    return '''
-function(collectedClasses) {
-  var hasOwnProperty = Object.prototype.hasOwnProperty;
-  for (var cls in collectedClasses) {
-    if (hasOwnProperty.call(collectedClasses, cls)) {
-      var desc = collectedClasses[cls];
-'''/* The 'fields' are either a constructor function or a string encoding
-      fields, constructor and superclass.  Get the superclass and the fields
-      in the format Super;field1,field2 from the null-string property on the
-      descriptor. */'''
-      var fields = desc[''], supr;
-      if (typeof fields == 'string') {
-        var s = fields.split(';'); supr = s[0];
-        fields = s[1] == '' ? [] : s[1].split(',');
-      } else {
-        supr = desc['super'];
-      }
-      $isolatePropertiesName[cls] = $defineClassName(cls, fields, desc);
-      if (supr) $pendingClassesName[cls] = supr;
-    }
-  }
-  var pendingClasses = $pendingClassesName;
-'''/* FinishClasses can be called multiple times. This means that we need to
-      clear the pendingClasses property. */'''
-  $pendingClassesName = {};
-  var finishedClasses = {};
-  function finishClass(cls) {
-'''/* Opera does not support 'getOwnPropertyNames'. Therefore we use
-      hasOwnProperty instead. */'''
-    var hasOwnProperty = Object.prototype.hasOwnProperty;
-    if (hasOwnProperty.call(finishedClasses, cls)) return;
-    finishedClasses[cls] = true;
-    var superclass = pendingClasses[cls];
-'''/* The superclass is only false (empty string) for Dart's Object class. */'''
-    if (!superclass) return;
-    finishClass(superclass);
-    var constructor = $isolatePropertiesName[cls];
-    var superConstructor = $isolatePropertiesName[superclass];
-    var prototype = constructor.prototype;
-    if ($supportsProtoName) {
-      prototype.__proto__ = superConstructor.prototype;
-      prototype.constructor = constructor;
-    } else {
-      function tmp() {};
-      tmp.prototype = superConstructor.prototype;
-      var newPrototype = new tmp();
-      constructor.prototype = newPrototype;
-      newPrototype.constructor = constructor;
-      for (var member in prototype) {
-        if (!member) continue;  '''/* Short version of: if (member == '') */'''
-        if (hasOwnProperty.call(prototype, member)) {
-          newPrototype[member] = prototype[member];
-        }
-      }
-    }
-  }
-  for (var cls in pendingClasses) finishClass(cls);
-}''';
+
+    // function(collectedClasses,
+    //          isolateProperties,
+    //          existingIsolateProperties) {
+    return js.fun(['collectedClasses', 'isolateProperties',
+                   'existingIsolateProperties'], [
+      js['var pendingClasses = {}'],
+
+      js['var hasOwnProperty = Object.prototype.hasOwnProperty'],
+
+      // for (var cls in collectedClasses) {
+      js.forIn('cls', 'collectedClasses', [
+        // if (hasOwnProperty.call(collectedClasses, cls)) {
+        js.if_(js['hasOwnProperty.call(collectedClasses, cls)'], [
+          js['var desc = collectedClasses[cls]'],
+
+          /* The 'fields' are either a constructor function or a
+           * string encoding fields, constructor and superclass.  Get
+           * the superclass and the fields in the format
+           * Super;field1,field2 from the null-string property on the
+           * descriptor.
+           */
+          // var fields = desc[''], supr;
+          js["var fields = desc[''], supr"],
+
+          js.if_(js["typeof fields == 'string'"], [
+            js['var s = fields.split(";")'],
+            js['supr = s[0]'],
+            js["fields = s[1] == '' ? [] : s[1].split(',')"],
+          ], /* else */ [
+            js['supr = desc.super']
+          ]),
+
+          js['isolateProperties[cls] = defineClass(cls, fields, desc)'],
+
+          // if (supr) pendingClasses[cls] = supr;
+          js.if_(js['supr'], js['pendingClasses[cls] = supr'])
+        ])
+      ]),
+
+      js['var finishedClasses = {}'],
+
+      // function finishClass(cls) { ... }
+      buildFinishClass(),
+
+      // for (var cls in pendingClasses) finishClass(cls);
+      js.forIn('cls', 'pendingClasses', js['finishClass']('cls'))
+    ]);
   }
 
-  String get finishIsolateConstructorFunction {
+  jsAst.FunctionDeclaration buildFinishClass() {
+    // function finishClass(cls) {
+    jsAst.Fun fun = js.fun(['cls'], [
+
+      // TODO(8540): Remove this work around.
+      /* Opera does not support 'getOwnPropertyNames'. Therefore we use
+         hasOwnProperty instead. */
+      js['var hasOwnProperty = Object.prototype.hasOwnProperty'],
+
+      // if (hasOwnProperty.call(finishedClasses, cls)) return;
+      js.if_(js['hasOwnProperty.call(finishedClasses, cls)'],
+             js.return_()),
+
+      js['finishedClasses[cls] = true'],
+      js['var superclass = pendingClasses[cls]'],
+
+      /* The superclass is only false (empty string) for Dart's Object class. */
+      js.if_(js['!superclass'], js.return_()),
+      js['finishClass(superclass)'],
+      js['var constructor = isolateProperties[cls]'],
+      js['var superConstructor = isolateProperties[superclass]'],
+
+      // if (!superConstructor)
+      //   superConstructor = existingIsolateProperties[superclass];
+      js.if_(js['superConstructor'].not,
+             js['superConstructor'].assign(
+                 js['existingIsolateProperties'][js['superclass']])),
+
+      js['var prototype = constructor.prototype'],
+
+      // if ($supportsProtoName) {
+      js.if_(supportsProtoName, [
+        js['prototype.__proto__ = superConstructor.prototype'],
+        js['prototype.constructor = constructor'],
+
+      ], /* else */ [
+        // function tmp() {};
+        new jsAst.FunctionDeclaration(
+            new jsAst.VariableDeclaration('tmp'),
+            js.fun([], [])),
+
+        js['tmp.prototype = superConstructor.prototype'],
+        js['var newPrototype = new tmp()'],
+
+        js['constructor.prototype = newPrototype'],
+        js['newPrototype.constructor = constructor'],
+
+        // for (var member in prototype) {
+        js.forIn('member', 'prototype', [
+          /* Short version of: if (member == '') */
+          // if (!member) continue;
+          js.if_(js['!member'], new jsAst.Continue(null)),
+
+          // if (hasOwnProperty.call(prototype, member)) {
+          js.if_(js['hasOwnProperty.call(prototype, member)'], [
+            js['newPrototype[member] = prototype[member]']
+          ])
+        ])
+
+      ])
+    ]);
+
+    return new jsAst.FunctionDeclaration(
+        new jsAst.VariableDeclaration('finishClass'),
+        fun);
+  }
+
+  jsAst.Fun get finishIsolateConstructorFunction {
     String isolate = namer.isolateName;
     // We replace the old Isolate function with a new one that initializes
     // all its field with the initial (and often final) value of all globals.
@@ -362,91 +458,146 @@
     //
     // We also copy over old values like the prototype, and the
     // isolateProperties themselves.
-    return """function(oldIsolate) {
-  var isolateProperties = oldIsolate.${namer.isolatePropertiesName};
-  var isolatePrototype = oldIsolate.prototype;
-  var str = "{\\n";
-  str += "var properties = $isolate.${namer.isolatePropertiesName};\\n";
-  for (var staticName in isolateProperties) {
-    if (Object.prototype.hasOwnProperty.call(isolateProperties, staticName)) {
-      str += "this." + staticName + "= properties." + staticName + ";\\n";
-    }
-  }
-  str += "}\\n";
-  var newIsolate = new Function(str);
-  newIsolate.prototype = isolatePrototype;
-  isolatePrototype.constructor = newIsolate;
-  newIsolate.${namer.isolatePropertiesName} = isolateProperties;
-  return newIsolate;
-}""";
-  }
 
-  String get lazyInitializerFunction {
-    String isolate = namer.CURRENT_ISOLATE;
-    return """
-function(prototype, staticName, fieldName, getterName, lazyValue) {
-  var getter = new Function("{ return $isolate." + fieldName + ";}");
-$lazyInitializerLogic
-}""";
-  }
-
-  String get lazyInitializerLogic {
-    String isolate = namer.CURRENT_ISOLATE;
-    JavaScriptBackend backend = compiler.backend;
-    String cyclicThrow = namer.isolateAccess(backend.cyclicThrowHelper);
-    return """
-  var sentinelUndefined = {};
-  var sentinelInProgress = {};
-  prototype[fieldName] = sentinelUndefined;
-  prototype[getterName] = function() {
-    var result = $isolate[fieldName];
-    try {
-      if (result === sentinelUndefined) {
-        $isolate[fieldName] = sentinelInProgress;
-        try {
-          result = $isolate[fieldName] = lazyValue();
-        } finally {
-""" // Use try-finally, not try-catch/throw as it destroys the stack trace.
-"""
-          if (result === sentinelUndefined) {
-            if ($isolate[fieldName] === sentinelInProgress) {
-              $isolate[fieldName] = null;
-            }
-          }
-        }
-      } else if (result === sentinelInProgress) {
-        $cyclicThrow(staticName);
-      }
-      return result;
-    } finally {
-      $isolate[getterName] = getter;
-    }
-  };""";
-  }
-
-  void addDefineClassAndFinishClassFunctionsIfNecessary(CodeBuffer buffer) {
+    List copyFinishClasses = [];
     if (needsDefineClass) {
-      // Declare function called generateAccessor.  This is used in
+      copyFinishClasses.add(
+          // newIsolate.$finishClasses = oldIsolate.\$finishClasses;
+          js['newIsolate'][finishClassesProperty].assign(
+              js['oldIsolate'][finishClassesProperty]));
+    }
+
+    // function(oldIsolate) {
+    return js.fun('oldIsolate', [
+      js['var isolateProperties = oldIsolate.${namer.isolatePropertiesName}'],
+
+      js[r'isolateProperties.$currentScript ='
+              'typeof document == "object" ?'
+              '(document.currentScript ||'
+                     'document.scripts[document.scripts.length - 1]) :'
+              'null'],
+
+      js['var isolatePrototype = oldIsolate.prototype'],
+      js['var str = "{\\n"'],
+      js['str += '
+             '"var properties = $isolate.${namer.isolatePropertiesName};\\n"'],
+      js['var hasOwnProperty = Object.prototype.hasOwnProperty'],
+
+      // for (var staticName in isolateProperties) {
+      js.forIn('staticName', 'isolateProperties', [
+        js.if_(js['hasOwnProperty.call(isolateProperties, staticName)'], [
+          js['str += ("this." + staticName + "= properties." + staticName + '
+                          '";\\n")']
+        ])
+      ]),
+
+      js['str += "}\\n"'],
+
+      js['var newIsolate = new Function(str)'],
+      js['newIsolate.prototype = isolatePrototype'],
+      js['isolatePrototype.constructor = newIsolate'],
+      js['newIsolate.${namer.isolatePropertiesName} = isolateProperties'],
+    ]..addAll(copyFinishClasses)
+     ..addAll([
+
+      // return newIsolate;
+      js.return_('newIsolate')
+    ]));
+  }
+
+  jsAst.Fun get lazyInitializerFunction {
+    String isolate = namer.CURRENT_ISOLATE;
+
+    // function(prototype, staticName, fieldName, getterName, lazyValue) {
+    var parameters = <String>['prototype', 'staticName', 'fieldName',
+                              'getterName', 'lazyValue'];
+    return js.fun(parameters, [
+      js['var getter = new Function("{ return $isolate." + fieldName + ";}")'],
+    ]..addAll(addLazyInitializerLogic())
+    );
+  }
+
+  List addLazyInitializerLogic() {
+    String isolate = namer.CURRENT_ISOLATE;
+    String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper());
+
+    return [
+      js['var sentinelUndefined = {}'],
+      js['var sentinelInProgress = {}'],
+      js['prototype[fieldName] = sentinelUndefined'],
+
+      // prototype[getterName] = function() {
+      js['prototype'][js['getterName']].assign(js.fun([], [
+        js['var result = $isolate[fieldName]'],
+
+        // try {
+        js.try_([
+          js.if_(js['result === sentinelUndefined'], [
+            js['$isolate[fieldName] = sentinelInProgress'],
+
+            // try {
+            js.try_([
+              js['result = $isolate[fieldName] = lazyValue()'],
+
+            ], finallyPart: [
+              // Use try-finally, not try-catch/throw as it destroys the
+              // stack trace.
+
+              // if (result === sentinelUndefined) {
+              js.if_(js['result === sentinelUndefined'], [
+                // if ($isolate[fieldName] === sentinelInProgress) {
+                js.if_(js['$isolate[fieldName] === sentinelInProgress'], [
+                  js['$isolate[fieldName] = null'],
+                ])
+              ])
+            ])
+          ], /* else */ [
+            js.if_(js['result === sentinelInProgress'],
+              js['$cyclicThrow(staticName)']
+            )
+          ]),
+
+          // return result;
+          js.return_('result')
+
+        ], finallyPart: [
+          js['$isolate[getterName] = getter']
+        ])
+      ]))
+    ];
+  }
+
+  List buildDefineClassAndFinishClassFunctionsIfNecessary() {
+    if (!needsDefineClass) return [];
+    return [
+      // Declare a function called "generateAccessor".  This is used in
       // defineClassFunction (it's a local declaration in init()).
-      buffer.add("$generateAccessorFunction$N");
-      buffer.add("$generateAccessorHolder = generateAccessor$N");
-      buffer.add("$defineClassName = $defineClassFunction$N");
-      buffer.add(protoSupportCheck);
-      buffer.add("$pendingClassesName = {}$N");
-      buffer.add("$finishClassesName = $finishClassesFunction$N");
-    }
+      generateAccessorFunction,
+
+      js['$generateAccessorHolder = generateAccessor'],
+
+      // function defineClass ...
+      new jsAst.FunctionDeclaration(
+          new jsAst.VariableDeclaration('defineClass'), defineClassFunction)
+    ]
+    ..addAll(buildProtoSupportCheck())
+    ..addAll([
+      js[finishClassesName].assign(finishClassesFunction)
+    ]);
   }
 
-  void addLazyInitializerFunctionIfNecessary(CodeBuffer buffer) {
-    if (needsLazyInitializer) {
-      buffer.add("$lazyInitializerName = $lazyInitializerFunction$N");
-    }
+  List buildLazyInitializerFunctionIfNecessary() {
+    if (!needsLazyInitializer) return [];
+
+    // $lazyInitializerName = $lazyInitializerFunction
+    return [js[lazyInitializerName].assign(lazyInitializerFunction)];
   }
 
-  void emitFinishIsolateConstructor(CodeBuffer buffer) {
-    String name = finishIsolateConstructorName;
-    String value = finishIsolateConstructorFunction;
-    buffer.add("$name = $value$N");
+  List buildFinishIsolateConstructor() {
+    return [
+      // $finishIsolateConstructorName = $finishIsolateConstructorFunction
+      js[finishIsolateConstructorName].assign(finishIsolateConstructorFunction)
+    ];
   }
 
   void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) {
@@ -486,7 +637,6 @@
     if (alreadyGenerated.contains(invocationName)) return;
     alreadyGenerated.add(invocationName);
 
-    JavaScriptBackend backend = compiler.backend;
     bool isInterceptorClass =
         backend.isInterceptorClass(member.getEnclosingClass());
 
@@ -499,19 +649,19 @@
     String receiverArgumentName = r'$receiver';
 
     // The parameters that this stub takes.
-    List<js.Parameter> parametersBuffer =
-        new List<js.Parameter>.fixedLength(
+    List<jsAst.Parameter> parametersBuffer =
+        new List<jsAst.Parameter>.fixedLength(
             selector.argumentCount + extraArgumentCount);
     // The arguments that will be passed to the real method.
-    List<js.Expression> argumentsBuffer =
-        new List<js.Expression>.fixedLength(
+    List<jsAst.Expression> argumentsBuffer =
+        new List<jsAst.Expression>.fixedLength(
             parameters.parameterCount + extraArgumentCount);
 
     int count = 0;
     if (isInterceptorClass) {
       count++;
-      parametersBuffer[0] = new js.Parameter(receiverArgumentName);
-      argumentsBuffer[0] = new js.VariableUse(receiverArgumentName);
+      parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName);
+      argumentsBuffer[0] = js[receiverArgumentName];
     }
 
     int indexOfLastOptionalArgumentInParameters = positionalArgumentCount - 1;
@@ -523,17 +673,17 @@
       assert(jsName != receiverArgumentName);
       int optionalParameterStart = positionalArgumentCount + extraArgumentCount;
       if (count < optionalParameterStart) {
-        parametersBuffer[count] = new js.Parameter(jsName);
-        argumentsBuffer[count] = new js.VariableUse(jsName);
+        parametersBuffer[count] = new jsAst.Parameter(jsName);
+        argumentsBuffer[count] = js[jsName];
       } else {
         int index = names.indexOf(element.name);
         if (index != -1) {
           indexOfLastOptionalArgumentInParameters = count;
           // The order of the named arguments is not the same as the
           // one in the real method (which is in Dart source order).
-          argumentsBuffer[count] = new js.VariableUse(jsName);
+          argumentsBuffer[count] = js[jsName];
           parametersBuffer[optionalParameterStart + index] =
-              new js.Parameter(jsName);
+              new jsAst.Parameter(jsName);
         // Note that [elements] may be null for a synthesized [member].
         } else if (elements != null && elements.isParameterChecked(element)) {
           argumentsBuffer[count] = constantReference(SentinelConstant.SENTINEL);
@@ -554,20 +704,16 @@
       count++;
     });
 
-    List<js.Statement> body;
+    List body;
     if (member.hasFixedBackendName()) {
       body = nativeEmitter.generateParameterStubStatements(
           member, invocationName, parametersBuffer, argumentsBuffer,
           indexOfLastOptionalArgumentInParameters);
     } else {
-      body = <js.Statement>[
-          new js.Return(
-              new js.VariableUse('this')
-                  .dot(namer.getName(member))
-                  .callWith(argumentsBuffer))];
+      body = [js.return_(js['this'][namer.getName(member)](argumentsBuffer))];
     }
 
-    js.Fun function = new js.Fun(parametersBuffer, new js.Block(body));
+    jsAst.Fun function = js.fun(parametersBuffer, body);
 
     defineStub(invocationName, function);
   }
@@ -725,8 +871,7 @@
         || member.isGenerativeConstructorBody()
         || member.isAccessor()) {
       if (member.isAbstract(compiler)) return;
-      JavaScriptBackend backend = compiler.backend;
-      js.Expression code = backend.generatedCode[member];
+      jsAst.Expression code = backend.generatedCode[member];
       if (code == null) return;
       builder.addProperty(namer.getName(member), code);
       code = backend.generatedBailoutCode[member];
@@ -753,7 +898,6 @@
   void emitInstanceMembers(ClassElement classElement,
                            ClassBuilder builder) {
     assert(invariant(classElement, classElement.isDeclaration));
-    JavaScriptBackend backend = compiler.backend;
     if (classElement == backend.objectInterceptorClass) {
       emitInterceptorMethods(builder);
       // The ObjectInterceptor does not have any instance methods.
@@ -788,12 +932,12 @@
         includeSuperMembers: false);
 
     void generateIsTest(Element other) {
-      js.Expression code;
+      jsAst.Expression code;
       if (compiler.objectClass == other) return;
       if (nativeEmitter.requiresNativeIsCheck(other)) {
-        code = js.fun([], js.block1(js.return_(new js.LiteralBool(true))));
+        code = js.fun([], [js.return_(true)]);
       } else {
-        code = new js.LiteralBool(true);
+        code = new jsAst.LiteralBool(true);
       }
       builder.addProperty(namer.operatorIs(other), code);
     }
@@ -801,21 +945,20 @@
     void generateSubstitution(Element other, {bool emitNull: false}) {
       RuntimeTypeInformation rti = backend.rti;
       // TODO(karlklose): support typedefs with variables.
-      js.Expression expression;
+      jsAst.Expression expression;
       bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
       if (other.kind == ElementKind.CLASS) {
         String substitution = rti.getSupertypeSubstitution(classElement, other,
             alwaysGenerateFunction: true);
         if (substitution != null) {
-          expression = new js.LiteralExpression(substitution);
+          expression = new jsAst.LiteralExpression(substitution);
         } else if (emitNull || needsNativeCheck) {
-          expression = new js.LiteralNull();
+          expression = new jsAst.LiteralNull();
         }
       }
       if (expression != null) {
         if (needsNativeCheck) {
-          expression =
-              new js.Fun([], new js.Block([new js.Return(expression)]));
+          expression = js.fun([], js.return_(expression));
         }
         builder.addProperty(namer.substitutionName(other), expression);
       }
@@ -847,12 +990,11 @@
           ? js.equals
           : js.strictEquals;
       builder.addProperty(name, js.fun(['receiver', 'a'],
-          js.block1(js.return_(kind(js.use('receiver'), js.use('a'))))));
+          js.block(js.return_(kind(js['receiver'], js['a'])))));
     }
   }
 
   void emitRuntimeClassesAndTests(CodeBuffer buffer) {
-    JavaScriptBackend backend = compiler.backend;
     RuntimeTypeInformation rti = backend.rti;
     TypeChecks typeChecks = rti.getRequiredChecks();
 
@@ -1009,17 +1151,14 @@
                       ClassBuilder builder) {
     String getterName = namer.getterNameFromAccessorName(accessorName);
     builder.addProperty(getterName,
-        js.fun([], js.block1(js.return_(js.use('this').dot(fieldName)))));
+        js.fun([], js.return_(js['this'][fieldName])));
   }
 
   void generateSetter(Element member, String fieldName, String accessorName,
                       ClassBuilder builder) {
     String setterName = namer.setterNameFromAccessorName(accessorName);
     builder.addProperty(setterName,
-        js.fun(['v'],
-            js.block1(
-                new js.ExpressionStatement(
-                    js.assign(js.use('this').dot(fieldName), js.use('v'))))));
+        js.fun(['v'], js['this'][fieldName].assign('v')));
   }
 
   bool canGenerateCheckedSetter(Element member) {
@@ -1041,22 +1180,17 @@
     DartType type = member.computeType(compiler);
     // TODO(ahe): Generate a dynamic type error here.
     if (type.element.isErroneous()) return;
-    SourceString helper = compiler.backend.getCheckedModeHelper(type);
-    FunctionElement helperElement = compiler.findHelper(helper);
+    FunctionElement helperElement
+        = backend.getCheckedModeHelper(type, typeCast: false);
     String helperName = namer.isolateAccess(helperElement);
-    List<js.Expression> arguments = <js.Expression>[js.use('v')];
+    List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']];
     if (helperElement.computeSignature(compiler).parameterCount != 1) {
       arguments.add(js.string(namer.operatorIs(type.element)));
     }
 
     String setterName = namer.setterNameFromAccessorName(accessorName);
     builder.addProperty(setterName,
-        js.fun(['v'],
-            js.block1(
-                new js.ExpressionStatement(
-                    js.assign(
-                        js.use('this').dot(fieldName),
-                        js.call(js.use(helperName), arguments))))));
+        js.fun(['v'], js['this'][fieldName].assign(js[helperName](arguments))));
   }
 
   void emitClassConstructor(ClassElement classElement, ClassBuilder builder) {
@@ -1074,7 +1208,7 @@
     bool isFirstField = true;
     StringBuffer buffer = new StringBuffer();
     if (!classIsNative) {
-      buffer.add('$superClass;');
+      buffer.write('$superClass;');
     }
     visitClassFields(classElement, (Element member,
                                     String name,
@@ -1093,30 +1227,30 @@
         if (isFirstField) {
           isFirstField = false;
         } else {
-          buffer.add(',');
+          buffer.write(',');
         }
         int flag = 0;
         if (!needsAccessor) {
           // Emit field for constructor generation.
           assert(!classIsNative);
-          buffer.add(name);
+          buffer.write(name);
         } else {
           // Emit (possibly renaming) field name so we can add accessors at
           // runtime.
-          buffer.add(accessorName);
+          buffer.write(accessorName);
           if (name != accessorName) {
-            buffer.add(':$name');
+            buffer.write(':$name');
             // Only the native classes can have renaming accessors.
             assert(classIsNative);
             flag = RENAMING_FLAG;
           }
         }
         if (needsGetter && needsSetter) {
-          buffer.addCharCode(GETTER_SETTER_CODE + flag);
+          buffer.writeCharCode(GETTER_SETTER_CODE + flag);
         } else if (needsGetter) {
-          buffer.addCharCode(GETTER_CODE + flag);
+          buffer.writeCharCode(GETTER_CODE + flag);
         } else if (needsSetter) {
-          buffer.addCharCode(SETTER_CODE + flag);
+          buffer.writeCharCode(SETTER_CODE + flag);
         }
       }
     });
@@ -1188,11 +1322,9 @@
     emitClassGettersSetters(classElement, builder);
     emitInstanceMembers(classElement, builder);
 
-    js.Expression init =
-        js.assign(
-            js.use(classesCollector).dot(className),
-            builder.toObjectInitializer());
-    buffer.add(js.prettyPrint(init, compiler));
+    jsAst.Expression init =
+        js[classesCollector][className].assign(builder.toObjectInitializer());
+    buffer.add(jsAst.prettyPrint(init, compiler));
     buffer.add('$N$n');
   }
 
@@ -1213,34 +1345,33 @@
   }
 
   void emitInterceptorMethods(ClassBuilder builder) {
-    JavaScriptBackend backend = compiler.backend;
     // Emit forwarders for the ObjectInterceptor class. We need to
-    // emit all possible sends on intercepted methods.
+    // emit all possible sends on intercepted methods. Because of
+    // typed selectors we have to avoid generating the same forwarder
+    // multiple times.
+    Set<String> alreadyGenerated = new Set<String>();
     for (Selector selector in
          backend.usedInterceptors.toList()..sort(_compareSelectorNames)) {
-      List<js.Parameter> parameters = <js.Parameter>[];
-      List<js.Expression> arguments = <js.Expression>[];
-      parameters.add(new js.Parameter('receiver'));
-
       String name = backend.namer.invocationName(selector);
+      if (alreadyGenerated.contains(name)) continue;
+      alreadyGenerated.add(name);
+
+      List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
+      List<jsAst.Expression> arguments = <jsAst.Expression>[];
+      parameters.add(new jsAst.Parameter('receiver'));
+
       if (selector.isSetter()) {
-        parameters.add(new js.Parameter('value'));
-        arguments.add(new js.VariableUse('value'));
+        parameters.add(new jsAst.Parameter('value'));
+        arguments.add(js['value']);
       } else {
         for (int i = 0; i < selector.argumentCount; i++) {
           String argName = 'a$i';
-          parameters.add(new js.Parameter(argName));
-          arguments.add(new js.VariableUse(argName));
+          parameters.add(new jsAst.Parameter(argName));
+          arguments.add(js[argName]);
         }
       }
-      js.Fun function =
-          new js.Fun(parameters,
-              new js.Block(
-                  <js.Statement>[
-                      new js.Return(
-                          new js.VariableUse('receiver')
-                              .dot(name)
-                              .callWith(arguments))]));
+      jsAst.Fun function =
+          js.fun(parameters, js.return_(js['receiver'][name](arguments)));
       builder.addProperty(name, function);
     }
   }
@@ -1270,8 +1401,7 @@
       emitSubstitution(cls);
     }
 
-    JavaScriptBackend jsBackend = compiler.backend;
-    RuntimeTypeInformation rti = jsBackend.rti;
+    RuntimeTypeInformation rti = backend.rti;
     ClassElement superclass = cls.superclass;
 
     bool haveSameTypeVariables(ClassElement a, ClassElement b) {
@@ -1386,8 +1516,6 @@
     // constructor that always throws. We never need to emit it.
     unneededClasses.add(compiler.boolClass);
 
-    JavaScriptBackend backend = compiler.backend;
-
     // Go over specialized interceptors and then constants to know which
     // interceptors are needed.
     Set<ClassElement> needed = new Set<ClassElement>();
@@ -1449,20 +1577,23 @@
     }
 
     for (ClassElement element in sortedClasses) {
-      generateClass(element, buffer);
+      generateClass(element, bufferForElement(element, buffer));
     }
 
     // The closure class could have become necessary because of the generation
     // of stubs.
     ClassElement closureClass = compiler.closureClass;
     if (needsClosureClass && !instantiatedClasses.contains(closureClass)) {
-      generateClass(closureClass, buffer);
+      generateClass(closureClass, bufferForElement(closureClass, buffer));
     }
   }
 
   void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) {
     if (needsDefineClass) {
-      buffer.add("$finishClassesName($classesCollector)$N");
+      buffer.add('$finishClassesName($classesCollector,'
+                 '$_$isolateProperties,'
+                 '${_}null)$N');
+
       // Reset the map.
       buffer.add("$classesCollector$_=$_{}$N");
     }
@@ -1470,15 +1601,14 @@
 
   void emitStaticFunction(CodeBuffer buffer,
                           String name,
-                          js.Expression functionExpression) {
-    js.Expression assignment =
-        js.assign(js.use(isolateProperties).dot(name), functionExpression);
-    buffer.add(js.prettyPrint(assignment, compiler));
+                          jsAst.Expression functionExpression) {
+    jsAst.Expression assignment =
+        js[isolateProperties][name].assign(functionExpression);
+    buffer.add(jsAst.prettyPrint(assignment, compiler));
     buffer.add('$N$n');
   }
 
-  void emitStaticFunctions(CodeBuffer buffer) {
-    JavaScriptBackend backend = compiler.backend;
+  void emitStaticFunctions(CodeBuffer eagerBuffer) {
     bool isStaticFunction(Element element) =>
         !element.isInstanceMember() && !element.isField();
 
@@ -1490,9 +1620,10 @@
             .toSet();
 
     for (Element element in Elements.sortedByPosition(elements)) {
-      js.Expression code = backend.generatedCode[element];
+      CodeBuffer buffer = bufferForElement(element, eagerBuffer);
+      jsAst.Expression code = backend.generatedCode[element];
       emitStaticFunction(buffer, namer.getName(element), code);
-      js.Expression bailoutCode = backend.generatedBailoutCode[element];
+      jsAst.Expression bailoutCode = backend.generatedBailoutCode[element];
       if (bailoutCode != null) {
         pendingElementsWithBailouts.remove(element);
         emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
@@ -1502,7 +1633,8 @@
     // Is it possible the primary function was inlined but the bailout was not?
     for (Element element in
              Elements.sortedByPosition(pendingElementsWithBailouts)) {
-      js.Expression bailoutCode = backend.generatedBailoutCode[element];
+      CodeBuffer buffer = bufferForElement(element, eagerBuffer);
+      jsAst.Expression bailoutCode = backend.generatedBailoutCode[element];
       emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
     }
   }
@@ -1512,6 +1644,8 @@
         compiler.codegenWorld.staticFunctionsNeedingGetter;
     for (FunctionElement element in
              Elements.sortedByPosition(functionsNeedingGetter)) {
+      // TODO(ahe): Defer loading of these getters.
+
       // The static function does not have the correct name. Since
       // [addParameterStubs] use the name to create its stubs we simply
       // create a fake element with the correct name.
@@ -1524,13 +1658,11 @@
       String fieldAccess = '$isolateProperties.$staticName';
       buffer.add("$fieldAccess.$invocationName$_=$_$fieldAccess$N");
 
-      addParameterStubs(callElement, (String name, js.Expression value) {
-        js.Expression assignment =
-            js.assign(
-                js.use(isolateProperties).dot(staticName).dot(name),
-                value);
+      addParameterStubs(callElement, (String name, jsAst.Expression value) {
+        jsAst.Expression assignment =
+            js[isolateProperties][staticName][name].assign(value);
         buffer.add(
-            js.prettyPrint(new js.ExpressionStatement(assignment), compiler));
+            jsAst.prettyPrint(assignment.toStatement(), compiler));
         buffer.add('$N');
       });
 
@@ -1591,7 +1723,6 @@
     String extraArg = null;
     // Methods on interceptor classes take an extra parameter, which is the
     // actual receiver of the call.
-    JavaScriptBackend backend = compiler.backend;
     bool inInterceptor = backend.isInterceptorClass(member.getEnclosingClass());
     if (inInterceptor) {
       cache = interceptorClosureCache;
@@ -1649,37 +1780,32 @@
       String invocationName = namer.instanceMethodName(callElement);
 
       List<String> parameters = <String>[];
-      List<js.Expression> arguments = <js.Expression>[];
+      List<jsAst.Expression> arguments = <jsAst.Expression>[];
       if (inInterceptor) {
-        arguments.add(js.use('this').dot(fieldNames[2]));
+        arguments.add(js['this'][fieldNames[2]]);
       }
       for (int i = 0; i < parameterCount; i++) {
         String name = 'p$i';
         parameters.add(name);
-        arguments.add(js.use(name));
+        arguments.add(js[name]);
       }
 
-      js.Expression fun =
-          js.fun(parameters,
-              js.block1(
-                  js.return_(
-                      new js.PropertyAccess(
-                          js.use('this').dot(fieldNames[0]),
-                          js.use('this').dot(fieldNames[1]))
-                      .callWith(arguments))));
+      jsAst.Expression fun = js.fun(
+          parameters,
+          js.return_(
+              js['this'][fieldNames[0]][js['this'][fieldNames[1]]](arguments)));
       boundClosureBuilder.addProperty(invocationName, fun);
 
       addParameterStubs(callElement, boundClosureBuilder.addProperty);
       typedefChecks.forEach((Element typedef) {
         String operator = namer.operatorIs(typedef);
-        boundClosureBuilder.addProperty(operator, new js.LiteralBool(true));
+        boundClosureBuilder.addProperty(operator, new jsAst.LiteralBool(true));
       });
 
-      js.Expression init =
-          js.assign(
-              js.use(classesCollector).dot(mangledName),
+      jsAst.Expression init =
+          js[classesCollector][mangledName].assign(
               boundClosureBuilder.toObjectInitializer());
-      boundClosureBuffer.add(js.prettyPrint(init, compiler));
+      boundClosureBuffer.add(jsAst.prettyPrint(init, compiler));
       boundClosureBuffer.add("$N");
 
       closureClass = namer.isolateAccess(closureClassElement);
@@ -1695,19 +1821,17 @@
     String targetName = namer.instanceMethodName(member);
 
     List<String> parameters = <String>[];
-    List<js.Expression> arguments = <js.Expression>[];
-    arguments.add(js.use('this'));
+    List<jsAst.Expression> arguments = <jsAst.Expression>[];
+    arguments.add(js['this']);
     arguments.add(js.string(targetName));
     if (inInterceptor) {
       parameters.add(extraArg);
-      arguments.add(js.use(extraArg));
+      arguments.add(js[extraArg]);
     }
 
-    js.Expression getterFunction =
-        js.fun(parameters,
-            js.block1(
-                js.return_(
-                    new js.New(js.use(closureClass), arguments))));
+    jsAst.Expression getterFunction = js.fun(
+        parameters,
+        js.return_(js[closureClass].newWith(arguments)));
 
     defineStub(getterName, getterFunction);
   }
@@ -1722,7 +1846,6 @@
                              DefineStubFunction defineStub) {
     assert(invariant(member, member.isDeclaration));
     LibraryElement memberLibrary = member.getLibrary();
-    JavaScriptBackend backend = compiler.backend;
     // If the class is an interceptor class, the stub gets the
     // receiver explicitely and we need to pass it to the getter call.
     bool isInterceptorClass =
@@ -1730,18 +1853,18 @@
 
     const String receiverArgumentName = r'$receiver';
 
-    js.Expression buildGetter() {
+    jsAst.Expression buildGetter() {
       if (member.isGetter()) {
         String getterName = namer.getterName(member);
-        return new js.VariableUse('this').dot(getterName).callWith(
+        return js['this'][getterName](
             isInterceptorClass
-                ? <js.Expression>[new js.VariableUse(receiverArgumentName)]
-                : <js.Expression>[]);
+                ? <jsAst.Expression>[js[receiverArgumentName]]
+                : <jsAst.Expression>[]);
       } else {
         String fieldName = member.hasFixedBackendName()
             ? member.fixedBackendName()
             : namer.instanceFieldName(member);
-        return new js.VariableUse('this').dot(fieldName);
+        return js['this'][fieldName];
       }
     }
 
@@ -1760,25 +1883,21 @@
         Selector callSelector = new Selector.callClosureFrom(selector);
         String closureCallName = namer.invocationName(callSelector);
 
-        List<js.Parameter> parameters = <js.Parameter>[];
-        List<js.Expression> arguments = <js.Expression>[];
+        List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
+        List<jsAst.Expression> arguments = <jsAst.Expression>[];
         if (isInterceptorClass) {
-          parameters.add(new js.Parameter(receiverArgumentName));
+          parameters.add(new jsAst.Parameter(receiverArgumentName));
         }
 
         for (int i = 0; i < selector.argumentCount; i++) {
           String name = 'arg$i';
-          parameters.add(new js.Parameter(name));
-          arguments.add(new js.VariableUse(name));
+          parameters.add(new jsAst.Parameter(name));
+          arguments.add(js[name]);
         }
 
-        js.Fun function =
-            new js.Fun(parameters,
-                new js.Block(
-                    <js.Statement>[
-                        new js.Return(
-                            buildGetter().dot(closureCallName)
-                                .callWith(arguments))]));
+        jsAst.Fun function = js.fun(
+            parameters,
+            js.return_(buildGetter()[closureCallName](arguments)));
 
         defineStub(invocationName, function);
       }
@@ -1792,13 +1911,10 @@
     for (Element element in Elements.sortedByPosition(staticNonFinalFields)) {
       compiler.withCurrentElement(element, () {
         Constant initialValue = handler.getInitialValueFor(element);
-        js.Expression init =
-            new js.Assignment(
-                new js.PropertyAccess.field(
-                    new js.VariableUse(isolateProperties),
-                    namer.getName(element)),
-                constantEmitter.referenceInInitializationContext(initialValue));
-        buffer.add(js.prettyPrint(init, compiler));
+        jsAst.Expression init =
+          js[isolateProperties][namer.getName(element)].assign(
+              constantEmitter.referenceInInitializationContext(initialValue));
+        buffer.add(jsAst.prettyPrint(init, compiler));
         buffer.add('$N');
       });
     }
@@ -1808,36 +1924,35 @@
     ConstantHandler handler = compiler.constantHandler;
     List<VariableElement> lazyFields =
         handler.getLazilyInitializedFieldsForEmission();
-    JavaScriptBackend backend = compiler.backend;
     if (!lazyFields.isEmpty) {
       needsLazyInitializer = true;
       for (VariableElement element in Elements.sortedByPosition(lazyFields)) {
         assert(backend.generatedBailoutCode[element] == null);
-        js.Expression code = backend.generatedCode[element];
+        jsAst.Expression code = backend.generatedCode[element];
         assert(code != null);
         // The code only computes the initial value. We build the lazy-check
         // here:
         //   lazyInitializer(prototype, 'name', fieldName, getterName, initial);
         // The name is used for error reporting. The 'initial' must be a
         // closure that constructs the initial value.
-        List<js.Expression> arguments = <js.Expression>[];
-        arguments.add(js.use(isolateProperties));
+        List<jsAst.Expression> arguments = <jsAst.Expression>[];
+        arguments.add(js[isolateProperties]);
         arguments.add(js.string(element.name.slowToString()));
         arguments.add(js.string(namer.getName(element)));
         arguments.add(js.string(namer.getLazyInitializerName(element)));
         arguments.add(code);
-        js.Expression getter = buildLazyInitializedGetter(element);
+        jsAst.Expression getter = buildLazyInitializedGetter(element);
         if (getter != null) {
           arguments.add(getter);
         }
-        js.Expression init = js.call(js.use(lazyInitializerName), arguments);
-        buffer.add(js.prettyPrint(init, compiler));
+        jsAst.Expression init = js[lazyInitializerName](arguments);
+        buffer.add(jsAst.prettyPrint(init, compiler));
         buffer.add("$N");
       }
     }
   }
 
-  js.Expression buildLazyInitializedGetter(VariableElement element) {
+  jsAst.Expression buildLazyInitializedGetter(VariableElement element) {
     // Nothing to do, the 'lazy' function will create the getter.
     return null;
   }
@@ -1861,13 +1976,9 @@
         addedMakeConstantList = true;
         emitMakeConstantList(buffer);
       }
-      js.Expression init =
-          new js.Assignment(
-              new js.PropertyAccess.field(
-                  new js.VariableUse(isolateProperties),
-                  name),
-              constantInitializerExpression(constant));
-      buffer.add(js.prettyPrint(init, compiler));
+      jsAst.Expression init = js[isolateProperties][name].assign(
+          constantInitializerExpression(constant));
+      buffer.add(jsAst.prettyPrint(init, compiler));
       buffer.add('$N');
     }
   }
@@ -1917,35 +2028,17 @@
     // do not introduce duplicates (bad for code size).
     Set<String> addedJsNames = new Set<String>();
 
-    // Keep track of the noSuchMethod holders for each possible
-    // receiver type.
-    Map<ClassElement, Set<ClassElement>> noSuchMethodHolders =
-        new Map<ClassElement, Set<ClassElement>>();
-    Set<ClassElement> noSuchMethodHoldersFor(DartType type) {
-      ClassElement element = type.element;
-      Set<ClassElement> result = noSuchMethodHolders[element];
-      if (result == null) {
-        // For now, we check the entire world to see if an object of
-        // the given type may have a user-defined noSuchMethod
-        // implementation. We could do better by only looking at
-        // instantiated (or otherwise needed) classes.
-        result = compiler.world.findNoSuchMethodHolders(type);
-        noSuchMethodHolders[element] = result;
-      }
-      return result;
-    }
-
-    js.Expression generateMethod(String jsName, Selector selector) {
+    jsAst.Expression generateMethod(String jsName, Selector selector) {
       // Values match JSInvocationMirror in js-helper library.
       int type = selector.invocationMirrorKind;
       String methodName = selector.invocationMirrorMemberName;
-      List<js.Parameter> parameters = <js.Parameter>[];
+      List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
       CodeBuffer args = new CodeBuffer();
       for (int i = 0; i < selector.argumentCount; i++) {
-        parameters.add(new js.Parameter('\$$i'));
+        parameters.add(new jsAst.Parameter('\$$i'));
       }
 
-      List<js.Expression> argNames =
+      List<jsAst.Expression> argNames =
           selector.getOrderedNamedArguments().map((SourceString name) =>
               js.string(name.slowToString())).toList();
 
@@ -1954,26 +2047,15 @@
       String createInvocationMirror = namer.getName(
           compiler.createInvocationMirrorElement);
 
-      js.Expression expression =
-          new js.This()
-          .dot(noSuchMethodName)
-          .callWith(
-              <js.Expression>[
-                  new js.VariableUse(namer.CURRENT_ISOLATE)
-                  .dot(createInvocationMirror)
-                  .callWith(
-                      <js.Expression>[
-                          js.string(methodName),
-                          js.string(internalName),
-                          new js.LiteralNumber('$type'),
-                          new js.ArrayInitializer.from(
-                              parameters.map((param) => js.use(param.name))
-                                        .toList()),
-                          new js.ArrayInitializer.from(argNames)])]);
-      js.Expression function =
-          new js.Fun(parameters,
-              new js.Block(<js.Statement>[new js.Return(expression)]));
-      return function;
+      jsAst.Expression expression = js['this.$noSuchMethodName'](
+          js[namer.CURRENT_ISOLATE][createInvocationMirror]([
+              js.string(methodName),
+              js.string(internalName),
+              type,
+              new jsAst.ArrayInitializer.from(
+                  parameters.map((param) => js[param.name]).toList()),
+              new jsAst.ArrayInitializer.from(argNames)]));
+      return js.fun(parameters, js.return_(expression));
     }
 
     void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) {
@@ -2011,11 +2093,10 @@
         // If the selector is typed, we check to see if that type may
         // have a user-defined noSuchMethod implementation. If not, we
         // skip the selector altogether.
-        DartType receiverType = objectType;
         ClassElement receiverClass = objectClass;
         if (selector is TypedSelector) {
           TypedSelector typedSelector = selector;
-          receiverType = typedSelector.receiverType;
+          DartType receiverType = typedSelector.receiverType;
           receiverClass = receiverType.element;
         }
 
@@ -2061,11 +2142,12 @@
         // If we're calling bar on an object of type A we do need the
         // handler because we may have to call B.noSuchMethod since B
         // does not implement bar.
-        Set<ClassElement> holders = noSuchMethodHoldersFor(receiverType);
+        Iterable<ClassElement> holders =
+            compiler.world.locateNoSuchMethodHolders(selector);
         if (holders.every(hasMatchingMember)) continue;
         String jsName = namer.invocationMirrorInternalName(selector);
         if (!addedJsNames.contains(jsName)) {
-          js.Expression method = generateMethod(jsName, selector);
+          jsAst.Expression method = generateMethod(jsName, selector);
           defineStub(jsName, method);
           addedJsNames.add(jsName);
         }
@@ -2103,14 +2185,7 @@
     } else {
       mainCall = '${namer.isolateAccess(main)}()';
     }
-    if (!compiler.enableMinification) {
-      buffer.add("""
-
-//
-// BEGIN invoke [main].
-//
-""");
-    }
+    addComment('BEGIN invoke [main].', buffer);
     buffer.add("""
 if (typeof document !== 'undefined' && document.readyState !== 'complete') {
   document.addEventListener('readystatechange', function () {
@@ -2130,50 +2205,39 @@
   }
 }
 """);
-    if (!compiler.enableMinification) {
-      buffer.add("""
-//
-// END invoke [main].
-//
-
-""");
-    }
+    addComment('END invoke [main].', buffer);
   }
 
   void emitGetInterceptorMethod(CodeBuffer buffer,
                                 String objectName,
                                 String key,
                                 Collection<ClassElement> classes) {
-    js.Statement buildReturnInterceptor(ClassElement cls) {
-      return js.return_(js.fieldAccess(js.use(namer.isolateAccess(cls)),
-                                       'prototype'));
+    jsAst.Statement buildReturnInterceptor(ClassElement cls) {
+      return js.return_(js[namer.isolateAccess(cls)]['prototype']);
     }
 
-    js.VariableUse receiver = js.use('receiver');
-    JavaScriptBackend backend = compiler.backend;
-
+    jsAst.VariableUse receiver = js['receiver'];
     /**
      * Build a JavaScrit AST node for doing a type check on
      * [cls]. [cls] must be an interceptor class.
      */
-    js.Statement buildInterceptorCheck(ClassElement cls) {
-      js.Expression condition;
+    jsAst.Statement buildInterceptorCheck(ClassElement cls) {
+      jsAst.Expression condition;
       assert(backend.isInterceptorClass(cls));
       if (cls == backend.jsBoolClass) {
-        condition = js.equals(js.typeOf(receiver), js.string('boolean'));
+        condition = receiver.typeof.equals(js.string('boolean'));
       } else if (cls == backend.jsIntClass ||
                  cls == backend.jsDoubleClass ||
                  cls == backend.jsNumberClass) {
         throw 'internal error';
       } else if (cls == backend.jsArrayClass) {
-        condition = js.equals(js.fieldAccess(receiver, 'constructor'),
-                              js.use('Array'));
+        condition = receiver['constructor'].equals('Array');
       } else if (cls == backend.jsStringClass) {
-        condition = js.equals(js.typeOf(receiver), js.string('string'));
+        condition = receiver.typeof.equals(js.string('string'));
       } else if (cls == backend.jsNullClass) {
-        condition = js.equals(receiver, new js.LiteralNull());
+        condition = receiver.equals(new jsAst.LiteralNull());
       } else if (cls == backend.jsFunctionClass) {
-        condition = js.equals(js.typeOf(receiver), js.string('function'));
+        condition = receiver.typeof.equals(js.string('function'));
       } else {
         throw 'internal error';
       }
@@ -2205,31 +2269,28 @@
     }
     if (hasInt) hasNumber = true;
 
-    js.Block block = new js.Block.empty();
+    jsAst.Block block = new jsAst.Block.empty();
 
     if (hasNumber) {
-      js.Statement whenNumber;
+      jsAst.Statement whenNumber;
 
       /// Note: there are two number classes in play: Dart's [num],
       /// and JavaScript's Number (typeof receiver == 'number').  This
       /// is the fallback used when we have determined that receiver
       /// is a JavaScript Number.
-      js.Return returnNumberClass = buildReturnInterceptor(
+      jsAst.Return returnNumberClass = buildReturnInterceptor(
           hasDouble ? backend.jsDoubleClass : backend.jsNumberClass);
 
       if (hasInt) {
-        js.Expression isInt =
-            js.equals(js.call(js.fieldAccess(js.use('Math'), 'floor'),
-                              [receiver]),
-                      receiver);
-        (whenNumber = js.emptyBlock()).statements
-          ..add(js.if_(isInt, buildReturnInterceptor(backend.jsIntClass)))
-          ..add(returnNumberClass);
+        jsAst.Expression isInt = js['Math']['floor'](receiver).equals(receiver);
+        whenNumber = js.block([
+            js.if_(isInt, buildReturnInterceptor(backend.jsIntClass)),
+            returnNumberClass]);
       } else {
         whenNumber = returnNumberClass;
       }
       block.statements.add(
-          js.if_(js.equals(js.typeOf(receiver), js.string('number')),
+          js.if_(receiver.typeof.equals(js.string('number')),
                  whenNumber));
     }
 
@@ -2242,7 +2303,7 @@
       // Returning "undefined" here will provoke a JavaScript
       // TypeError which is later identified as a null-error by
       // [unwrapException] in js_helper.dart.
-      block.statements.add(js.if_(js.equals(receiver, new js.LiteralNull()),
+      block.statements.add(js.if_(receiver.equals(new jsAst.LiteralNull()),
                                   js.return_(js.undefined())));
     }
     if (hasFunction) {
@@ -2256,12 +2317,11 @@
     if (hasArray) {
       block.statements.add(buildInterceptorCheck(backend.jsArrayClass));
     }
-    block.statements.add(js.return_(js.fieldAccess(js.use(objectName),
-                                                   'prototype')));
+    block.statements.add(js.return_(js[objectName]['prototype']));
 
-    js.PropertyAccess name = js.fieldAccess(js.use(isolateProperties), key);
-    buffer.add(js.prettyPrint(js.assign(name, js.fun(['receiver'], block)),
-                              compiler));
+    buffer.add(jsAst.prettyPrint(
+        js[isolateProperties][key].assign(js.fun(['receiver'], block)),
+        compiler));
     buffer.add(N);
   }
 
@@ -2269,7 +2329,6 @@
    * Emit all versions of the [:getInterceptor:] method.
    */
   void emitGetInterceptorMethods(CodeBuffer buffer) {
-    JavaScriptBackend backend = compiler.backend;
     // If no class needs to be intercepted, just return.
     if (backend.objectInterceptorClass == null) return;
     String objectName = namer.isolateAccess(backend.objectInterceptorClass);
@@ -2299,7 +2358,6 @@
     int comparison = _compareSelectorNames(selector1, selector2);
     if (comparison != 0) return comparison;
 
-    JavaScriptBackend backend = compiler.backend;
     Set<ClassElement> classes1 = backend.getInterceptedClassesOn(selector1);
     Set<ClassElement> classes2 = backend.getInterceptedClassesOn(selector2);
     if (classes1.length != classes2.length) {
@@ -2312,55 +2370,213 @@
     return Comparable.compare(getInterceptor1, getInterceptor2);
   }
 
+  // Optimize performance critical one shot interceptors.
+  jsAst.Statement tryOptimizeOneShotInterceptor(Selector selector,
+                                                Set<ClassElement> classes) {
+    jsAst.Expression isNumber(String variable) {
+      return js[variable].typeof.equals(js.string('number'));
+    }
+
+    jsAst.Expression isNotObject(String variable) {
+      return js[variable].typeof.equals(js.string('object')).not;
+    }
+
+    jsAst.Expression isInt(String variable) {
+      jsAst.Expression receiver = js[variable];
+      return isNumber(variable).binary('&&',
+          js['Math']['floor'](receiver).equals(receiver));
+    }
+    
+    jsAst.Expression tripleShiftZero(jsAst.Expression receiver) {
+      return receiver.binary('>>>', js.toExpression(0));
+    }
+
+    if (selector.isOperator()) {
+      String name = selector.name.stringValue;
+      if (name == '==') {
+        // Unfolds to:
+        // [: if (receiver == null) return a0 == null;
+        //    if (typeof receiver != 'object') {
+        //      return a0 != null && receiver === a0;
+        //    }
+        // :].
+        List<jsAst.Statement> body = <jsAst.Statement>[];
+        body.add(js.if_(js['receiver'].equals(new jsAst.LiteralNull()),
+                        js.return_(js['a0'].equals(new jsAst.LiteralNull()))));
+        body.add(js.if_(
+            isNotObject('receiver'),
+            js.return_(js['a0'].equals(new jsAst.LiteralNull()).not.binary(
+                '&&', js['receiver'].strictEquals(js['a0'])))));
+        return new jsAst.Block(body);
+      }
+      if (!classes.contains(backend.jsIntClass)
+          && !classes.contains(backend.jsNumberClass)
+          && !classes.contains(backend.jsDoubleClass)) {
+        return null;
+      }
+      if (selector.argumentCount == 1) {
+        // The following operators do not map to a JavaScript
+        // operator.
+        if (name != '~/' && name != '<<' && name != '%' && name != '>>') {
+          jsAst.Expression result = js['receiver'].binary(name, js['a0']);
+          if (name == '&' || name == '|' || name == '^') {
+            result = tripleShiftZero(result);
+          }
+          // Unfolds to:
+          // [: if (typeof receiver == "number" && typeof a0 == "number")
+          //      return receiver op a0;
+          // :].
+          return js.if_(
+              isNumber('receiver').binary('&&', isNumber('a0')),
+              js.return_(result));
+        }
+      } else if (name == 'unary-') {
+        // operator~ does not map to a JavaScript operator.
+        // Unfolds to:
+        // [: if (typeof receiver == "number") return -receiver:].
+        return js.if_(
+            isNumber('receiver'),
+            js.return_(new jsAst.Prefix('-', js['receiver'])));
+      } else {
+        assert(name == '~');
+        return js.if_(
+            isInt('receiver'),
+            js.return_(
+                tripleShiftZero(new jsAst.Prefix(name, js['receiver']))));
+      }
+    } else if (selector.isIndex() || selector.isIndexSet()) {
+      // For an index operation, this code generates:
+      //
+      // [: if (receiver.constructor == Array || typeof receiver == "string") {
+      //      if (a0 >>> 0 === a0 && a0 < receiver.length) {
+      //        return receiver[a0];
+      //      }
+      //    }
+      // :]
+      //
+      // For an index set operation, this code generates:
+      //
+      // [: if (receiver.constructor == Array && !receiver.immutable$list) {
+      //      if (a0 >>> 0 === a0 && a0 < receiver.length) {
+      //        return receiver[a0] = a1;
+      //      }
+      //    }
+      // :]
+      bool containsArray = classes.contains(backend.jsArrayClass);
+      bool containsString = classes.contains(backend.jsStringClass);
+      // The index set operator requires a check on its set value in
+      // checked mode, so we don't optimize the interceptor if the
+      // compiler has type assertions enabled.
+      if (selector.isIndexSet()
+          && (compiler.enableTypeAssertions || !containsArray)) {
+        return null;
+      }
+      if (!containsArray && !containsString) {
+        return null;
+      }
+      jsAst.Expression receiver = js['receiver'];
+      jsAst.Expression arg0 = js['a0'];
+      jsAst.Expression isIntAndAboveZero =
+          arg0.binary('>>>', js.toExpression(0)).strictEquals(arg0);
+      jsAst.Expression belowLength = arg0.binary('<', receiver['length']);
+      jsAst.Expression arrayCheck = receiver['constructor'].equals('Array');
+
+      if (selector.isIndex()) {
+        jsAst.Expression stringCheck =
+            receiver.typeof.equals(js.string('string'));
+        jsAst.Expression typeCheck;
+        if (containsArray) {
+          if (containsString) {
+            typeCheck = arrayCheck.binary('||', stringCheck);
+          } else {
+            typeCheck = arrayCheck;
+          }
+        } else {
+          assert(containsString);
+          typeCheck = stringCheck;
+        }
+
+        return js.if_(typeCheck,
+                      js.if_(isIntAndAboveZero.binary('&&', belowLength),
+                             js.return_(receiver[arg0])));
+      } else {
+        jsAst.Expression isImmutableArray = arrayCheck.binary(
+            '&&', receiver[r'immutable$list'].not);
+        return js.if_(isImmutableArray.binary(
+                      '&&', isIntAndAboveZero.binary('&&', belowLength)),
+                      js.return_(receiver[arg0].assign(js['a1'])));
+      }
+    }
+    return null;
+  }
+
   void emitOneShotInterceptors(CodeBuffer buffer) {
-    JavaScriptBackend backend = compiler.backend;
-    for (Selector selector in
-         backend.oneShotInterceptors.toList()..sort(_compareSelectors)) {
-      Set<ClassElement> classes = backend.getInterceptedClassesOn(selector);
-      String oneShotInterceptorName = namer.oneShotInterceptorName(selector);
+    List<String> names = backend.oneShotInterceptors.keys.toList();
+    names.sort();
+    for (String name in names) {
+      Selector selector = backend.oneShotInterceptors[name];
+      Set<ClassElement> classes =
+          backend.getInterceptedClassesOn(selector);
       String getInterceptorName =
           namer.getInterceptorName(backend.getInterceptorMethod, classes);
 
-      List<js.Parameter> parameters = <js.Parameter>[];
-      List<js.Expression> arguments = <js.Expression>[];
-      parameters.add(new js.Parameter('receiver'));
-      arguments.add(js.use('receiver'));
+      List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
+      List<jsAst.Expression> arguments = <jsAst.Expression>[];
+      parameters.add(new jsAst.Parameter('receiver'));
+      arguments.add(js['receiver']);
 
       if (selector.isSetter()) {
-        parameters.add(new js.Parameter('value'));
-        arguments.add(js.use('value'));
+        parameters.add(new jsAst.Parameter('value'));
+        arguments.add(js['value']);
       } else {
         for (int i = 0; i < selector.argumentCount; i++) {
           String argName = 'a$i';
-          parameters.add(new js.Parameter(argName));
-          arguments.add(js.use(argName));
+          parameters.add(new jsAst.Parameter(argName));
+          arguments.add(js[argName]);
         }
       }
 
+      List<jsAst.Statement> body = <jsAst.Statement>[];
+      jsAst.Statement optimizedPath =
+          tryOptimizeOneShotInterceptor(selector, classes);
+      if (optimizedPath != null) {
+        body.add(optimizedPath);
+      }
+
       String invocationName = backend.namer.invocationName(selector);
-      js.Fun function =
-          new js.Fun(parameters,
-              js.block1(js.return_(
-                        js.use(isolateProperties)
-                            .dot(getInterceptorName)
-                            .callWith([js.use('receiver')])
-                            .dot(invocationName)
-                            .callWith(arguments))));
+      body.add(js.return_(
+          js[isolateProperties][getInterceptorName]('receiver')[invocationName](
+              arguments)));
 
-      js.PropertyAccess property =
-          js.fieldAccess(js.use(isolateProperties), oneShotInterceptorName);
+      jsAst.Fun function = js.fun(parameters, body);
 
-      buffer.add(js.prettyPrint(js.assign(property, function), compiler));
+      jsAst.PropertyAccess property =
+          js[isolateProperties][name];
+
+      buffer.add(jsAst.prettyPrint(property.assign(function), compiler));
       buffer.add(N);
     }
   }
 
+  void emitInitFunction(CodeBuffer buffer) {
+    jsAst.Fun fun = js.fun([], [
+      js['$isolateProperties = {}'],
+    ]
+    ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary())
+    ..addAll(buildLazyInitializerFunctionIfNecessary())
+    ..addAll(buildFinishIsolateConstructor())
+    );
+    jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration(
+        new jsAst.VariableDeclaration('init'), fun);
+    buffer.add(jsAst.prettyPrint(decl, compiler).getText());
+  }
+
   String assembleProgram() {
     measure(() {
       computeNeededClasses();
 
       mainBuffer.add(GENERATED_BY);
-      if (!compiler.enableMinification) mainBuffer.add(HOOKS_API_USAGE);
+      addComment(HOOKS_API_USAGE, mainBuffer);
       mainBuffer.add('function ${namer.isolateName}()$_{}\n');
       mainBuffer.add('init()$N$n');
       // Shorten the code by using "$$" as temporary.
@@ -2392,8 +2608,10 @@
       // The following code should not use the short-hand for the
       // initialStatics.
       mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=${_}null$N');
-      mainBuffer.add(boundClosureBuffer);
-      emitFinishClassesInvocationIfNecessary(mainBuffer);
+      if (!boundClosureBuffer.isEmpty) {
+        mainBuffer.add(boundClosureBuffer);
+        emitFinishClassesInvocationIfNecessary(mainBuffer);
+      }
       // After this assignment we will produce invalid JavaScript code if we use
       // the classesCollector variable.
       classesCollector = 'classesCollector should not be used from now on';
@@ -2404,30 +2622,83 @@
 
       nativeEmitter.assembleCode(mainBuffer);
       emitMain(mainBuffer);
-      mainBuffer.add('function init()$_{\n');
-      mainBuffer.add('$isolateProperties$_=$_{}$N');
-      addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer);
-      addLazyInitializerFunctionIfNecessary(mainBuffer);
-      emitFinishIsolateConstructor(mainBuffer);
-      mainBuffer.add('}\n');
+      emitInitFunction(mainBuffer);
       compiler.assembledCode = mainBuffer.getText();
+      outputSourceMap(mainBuffer, compiler.assembledCode, '');
 
-      if (generateSourceMap) {
-        SourceFile compiledFile = new SourceFile(null, compiler.assembledCode);
-        String sourceMap = buildSourceMap(mainBuffer, compiledFile);
-        compiler.outputProvider('', 'js.map')
-            ..add(sourceMap)
-            ..close();
-      }
+      emitDeferredCode(deferredBuffer);
+
     });
     return compiler.assembledCode;
   }
 
+  CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) {
+    if (!isDeferred(element)) return eagerBuffer;
+    emitDeferredPreambleWhenEmpty(deferredBuffer);
+    return deferredBuffer;
+  }
+
+  void emitDeferredCode(CodeBuffer buffer) {
+    if (buffer.isEmpty) return;
+
+    if (needsDefineClass) {
+      buffer.add('$finishClassesName(\$\$,'
+                 '$_${namer.CURRENT_ISOLATE},'
+                 '$_$isolatePropertiesName)$N');
+      // Reset the map.
+      buffer.add("\$\$$_=$_{}$N");
+    }
+
+    buffer.add('${namer.CURRENT_ISOLATE}$_=${_}old${namer.CURRENT_ISOLATE}$N');
+
+    String code = buffer.getText();
+    compiler.outputProvider('part', 'js')
+      ..add(code)
+      ..close();
+    outputSourceMap(buffer, compiler.assembledCode, 'part');
+  }
+
+  void emitDeferredPreambleWhenEmpty(CodeBuffer buffer) {
+    if (!buffer.isEmpty) return;
+    final classesCollector = r"$$";
+
+    buffer.add('$classesCollector$_=$_{}$N');
+    buffer.add('var old${namer.CURRENT_ISOLATE}$_='
+               '$_${namer.CURRENT_ISOLATE}$N');
+
+    // TODO(ahe): This defines a lot of properties on the
+    // Isolate.prototype object.  We know this will turn it into a
+    // slow object in V8, so instead we should do something similar to
+    // Isolate.$finishIsolateConstructor.
+    buffer.add('${namer.CURRENT_ISOLATE}$_='
+               '$_${namer.isolateName}.prototype$N$n');
+  }
+
   String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) {
     SourceMapBuilder sourceMapBuilder = new SourceMapBuilder();
     buffer.forEachSourceLocation(sourceMapBuilder.addMapping);
     return sourceMapBuilder.build(compiledFile);
   }
+
+  void outputSourceMap(CodeBuffer buffer, String code, String name) {
+    if (!generateSourceMap) return;
+    SourceFile compiledFile = new SourceFile(null, compiler.assembledCode);
+    String sourceMap = buildSourceMap(mainBuffer, compiledFile);
+    compiler.outputProvider(name, 'js.map')
+        ..add(sourceMap)
+        ..close();
+  }
+
+  bool isDeferred(Element element) {
+    return compiler.deferredLoadTask.isDeferred(element);
+  }
+
+  // TODO(ahe): Remove this when deferred loading is fully implemented.
+  void warnNotImplemented(Element element, String message) {
+    compiler.reportMessage(compiler.spanFromSpannable(element),
+                           MessageKind.GENERIC.error({'text': message}),
+                           api.Diagnostic.WARNING);
+  }
 }
 
 const String GENERATED_BY = """
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
index 52e6ee0..8a2f2b8 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
@@ -10,15 +10,18 @@
 import '../../compiler.dart' as api;
 import '../elements/elements.dart';
 import '../elements/modelx.dart' show FunctionElementX;
-import '../dart2jslib.dart' hide Selector;
+
+// TODO(ahe): There seems to be a bug in the VM, so we have to hide "js".
+import '../dart2jslib.dart' hide Selector, js;
 import '../dart_types.dart';
-import '../js/js.dart' as js;
+import '../js/js.dart' as jsAst;
+import '../js/js.dart' show js; // TODO(ahe): VM bug, see above.
 import '../native_handler.dart' as native;
 import '../source_file.dart';
 import '../source_map_builder.dart';
-import '../ssa/ssa.dart';
+import '../ssa/ssa.dart' hide js; // TODO(ahe): VM bug, see above.
 import '../tree/tree.dart';
-import '../universe/universe.dart';
+import '../universe/universe.dart' hide js; // TODO(ahe): VM bug, see above.
 import '../util/characters.dart';
 import '../util/util.dart';
 
@@ -26,7 +29,8 @@
 part 'constant_emitter.dart';
 part 'constant_system_javascript.dart';
 part 'emitter.dart';
-part 'emitter_no_eval.dart';
+// TODO(8522): Restore --disallow-unsafe-eval.
+// part 'emitter_no_eval.dart';
 part 'minify_namer.dart';
 part 'namer.dart';
 part 'native_emitter.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index aca3e61..4ac6919 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -185,7 +185,6 @@
    */
   final Compiler compiler;
   final Map<Element, String> globals;
-  final Map<Selector, String> oneShotInterceptorNames;
   final Map<String, LibraryElement> shortPrivateNameOwners;
 
   final Set<String> usedGlobalNames;
@@ -194,7 +193,7 @@
   final Map<String, String> suggestedGlobalNames;
   final Map<String, String> instanceNameMap;
   final Map<String, String> suggestedInstanceNames;
-      
+
   final Map<String, String> operatorNameMap;
   final Map<String, int> popularNameCounters;
 
@@ -204,7 +203,6 @@
 
   Namer(this.compiler)
       : globals = new Map<Element, String>(),
-        oneShotInterceptorNames = new Map<Selector, String>(),
         shortPrivateNameOwners = new Map<String, LibraryElement>(),
         bailoutNames = new Map<Element, String>(),
         usedGlobalNames = new Set<String>(),
@@ -323,7 +321,7 @@
         !signature.optionalParameters.isEmpty) {
       StringBuffer buffer = new StringBuffer();
       signature.orderedOptionalParameters.forEach((Element element) {
-        buffer.add('\$${safeName(element.name.slowToString())}');
+        buffer.write('\$${safeName(element.name.slowToString())}');
       });
       methodName = '$methodName$buffer';
     }
@@ -362,7 +360,7 @@
       assert(name == operatorNameToIdentifier(name));
       StringBuffer buffer = new StringBuffer();
       for (SourceString argumentName in selector.getOrderedNamedArguments()) {
-        buffer.add(r'$');
+        buffer.write(r'$');
         argumentName.printOn(buffer);
       }
       String suffix = '\$${selector.argumentCount}$buffer';
@@ -534,22 +532,40 @@
     return name;
   }
 
+  String getInterceptorSuffix(Collection<ClassElement> classes) {
+    String abbreviate(ClassElement cls) {
+      if (cls == compiler.objectClass) return "o";
+      JavaScriptBackend backend = compiler.backend;
+      if (cls == backend.jsStringClass) return "s";
+      if (cls == backend.jsArrayClass) return "a";
+      if (cls == backend.jsDoubleClass) return "d";
+      if (cls == backend.jsNumberClass) return "n";
+      if (cls == backend.jsNullClass) return "u";
+      if (cls == backend.jsFunctionClass) return "f";
+      if (cls == backend.jsBoolClass) return "b";
+      return cls.name.slowToString();
+    }
+    // Sort the names of the classes after abbreviating them to ensure
+    // the suffix is stable and predictable for the suggested names.
+    List<String> names = classes.map(abbreviate).toList();
+    names.sort();
+    return names.join();
+  }
+
   String getInterceptorName(Element element, Collection<ClassElement> classes) {
     if (classes.contains(compiler.objectClass)) {
       // If the object class is in the set of intercepted classes, we
       // need to go through the generic getInterceptorMethod.
       return getName(element);
     }
-    // Use the unminified names here to construct the interceptor names.  This
-    // helps ensure that they don't all suddenly change names due to a name
-    // clash in the minifier, which would affect the diff size.  Sort the names
-    // of the classes to ensure name is stable and predicatble for the suggested
-    // names.
-    StringBuffer buffer = new StringBuffer('${element.name.slowToString()}\$');
-    List<String> names = classes.map((cls) => cls.name.slowToString()).toList();
-    names.sort();
-    names.forEach(buffer.add);
-    return getMappedGlobalName(buffer.toString());
+    String suffix = getInterceptorSuffix(classes);
+    return getMappedGlobalName("${element.name.slowToString()}\$$suffix");
+  }
+
+  String getOneShotInterceptorName(Selector selector,
+                                   Collection<ClassElement> classes) {
+    String suffix = getInterceptorSuffix(classes);
+    return getMappedGlobalName("${invocationName(selector)}\$$suffix");
   }
 
   String getBailoutName(Element element) {
@@ -700,19 +716,6 @@
   String safeName(String name) => _safeName(name, jsReserved);
   String safeVariableName(String name) => _safeName(name, jsVariableReserved);
 
-  String oneShotInterceptorName(Selector selector) {
-    // TODO(ngeoffray): What to do about typed selectors? We could
-    // filter them out, or keep them and hope the generated one shot
-    // interceptor takes advantage of the type.
-    String cached = oneShotInterceptorNames[selector];
-    if (cached != null) return cached;
-    SourceString name = operatorNameToIdentifier(selector.name);
-    String result = getFreshName(name.slowToString(), usedGlobalNames,
-                                 suggestedGlobalNames);
-    oneShotInterceptorNames[selector] = result;
-    return result;
-  }
-
   SourceString operatorNameToIdentifier(SourceString name) {
     if (name == null) return null;
     String value = name.stringValue;
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
index 0343457..6500fc3 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
@@ -138,11 +138,11 @@
     if (builder.properties.isEmpty) return;
 
     String nativeTag = toNativeTag(classElement);
-    js.Expression definition =
-        js.call(js.use(defineNativeClassName),
-                [js.string(nativeTag), builder.toObjectInitializer()]);
+    jsAst.Expression definition =
+        js[defineNativeClassName](
+            [js.string(nativeTag), builder.toObjectInitializer()]);
 
-    nativeBuffer.add(js.prettyPrint(definition, compiler));
+    nativeBuffer.add(jsAst.prettyPrint(definition, compiler));
     nativeBuffer.add('$N$n');
 
     classesWithDynamicDispatch.add(classElement);
@@ -153,9 +153,10 @@
     return result == null ? const<ClassElement>[] : result;
   }
 
-  void potentiallyConvertDartClosuresToJs(List<js.Statement> statements,
-                                          FunctionElement member,
-                                          List<js.Parameter> stubParameters) {
+  void potentiallyConvertDartClosuresToJs(
+      List<jsAst.Statement> statements,
+      FunctionElement member,
+      List<jsAst.Parameter> stubParameters) {
     FunctionSignature parameters = member.computeSignature(compiler);
     Element converter =
         compiler.findHelper(const SourceString('convertDartClosureToJS'));
@@ -166,7 +167,7 @@
       String name = parameter.name.slowToString();
       // If [name] is not in [stubParameters], then the parameter is an optional
       // parameter that was not provided for this stub.
-      for (js.Parameter stubParameter in stubParameters) {
+      for (jsAst.Parameter stubParameter in stubParameters) {
         if (stubParameter.name == name) {
           DartType type = parameter.computeType(compiler).unalias(compiler);
           if (type is FunctionType) {
@@ -175,11 +176,12 @@
             int arity = type.computeArity();
 
             statements.add(
-                new js.ExpressionStatement(
+                new jsAst.ExpressionStatement(
                     js.assign(
-                        js.use(name),
-                        js.use(closureConverter).callWith(
-                            [js.use(name), new js.LiteralNumber('$arity')]))));
+                        js[name],
+                        js[closureConverter](
+                            [js[name],
+                             new jsAst.LiteralNumber('$arity')]))));
             break;
           }
         }
@@ -187,11 +189,11 @@
     });
   }
 
-  List<js.Statement> generateParameterStubStatements(
+  List<jsAst.Statement> generateParameterStubStatements(
       Element member,
       String invocationName,
-      List<js.Parameter> stubParameters,
-      List<js.Expression> argumentsBuffer,
+      List<jsAst.Parameter> stubParameters,
+      List<jsAst.Expression> argumentsBuffer,
       int indexOfLastOptionalArgumentInParameters) {
     // The target JS function may check arguments.length so we need to
     // make sure not to pass any unspecified optional arguments to it.
@@ -205,11 +207,11 @@
     ClassElement classElement = member.enclosingElement;
     String nativeTagInfo = classElement.nativeTagInfo.slowToString();
 
-    List<js.Statement> statements = <js.Statement>[];
+    List<jsAst.Statement> statements = <jsAst.Statement>[];
     potentiallyConvertDartClosuresToJs(statements, member, stubParameters);
 
     String target;
-    List<js.Expression> arguments;
+    List<jsAst.Expression> arguments;
 
     if (!nativeMethods.contains(member)) {
       // When calling a method that has a native body, we call it with our
@@ -224,16 +226,16 @@
           0, indexOfLastOptionalArgumentInParameters + 1);
     }
     statements.add(
-        new js.Return(
-            new js.VariableUse('this').dot(target).callWith(arguments)));
+        new jsAst.Return(
+            new jsAst.VariableUse('this')[target](arguments)));
 
     if (!overriddenMethods.contains(member)) {
       // Call the method directly.
       return statements;
     } else {
-      return <js.Statement>[
+      return <jsAst.Statement>[
           generateMethodBodyWithPrototypeCheck(
-              invocationName, new js.Block(statements), stubParameters)];
+              invocationName, new jsAst.Block(statements), stubParameters)];
     }
   }
 
@@ -242,26 +244,23 @@
   // super class. If the method is not available, we make a direct call to
   // Object.prototype.$methodName.  This method will patch the prototype of
   // 'this' to the real method.
-  js.Statement generateMethodBodyWithPrototypeCheck(
+  jsAst.Statement generateMethodBodyWithPrototypeCheck(
       String methodName,
-      js.Statement body,
-      List<js.Parameter> parameters) {
+      jsAst.Statement body,
+      List<jsAst.Parameter> parameters) {
     return js.if_(
-        js.use('Object').dot('getPrototypeOf')
-            .callWith([js.use('this')])
-            .dot('hasOwnProperty').callWith([js.string(methodName)]),
+        js['(Object.getPrototypeOf(this)).hasOwnProperty("$methodName")'],
         body,
         js.return_(
-            js.use('Object').dot('prototype').dot(methodName).dot('call')
-            .callWith(
-                <js.Expression>[js.use('this')]..addAll(
-                    parameters.map((param) => js.use(param.name))))));
+            js['Object.prototype.$methodName.call'](
+                <jsAst.Expression>[js['this']]..addAll(
+                    parameters.map((param) => js[param.name])))));
   }
 
-  js.Block generateMethodBodyWithPrototypeCheckForElement(
+  jsAst.Block generateMethodBodyWithPrototypeCheckForElement(
       FunctionElement element,
-      js.Block body,
-      List<js.Parameter> parameters) {
+      jsAst.Block body,
+      List<jsAst.Parameter> parameters) {
     ElementKind kind = element.kind;
     if (kind != ElementKind.FUNCTION &&
         kind != ElementKind.GETTER &&
@@ -270,7 +269,7 @@
     }
 
     String methodName = backend.namer.getName(element);
-    return new js.Block(
+    return new jsAst.Block(
         [generateMethodBodyWithPrototypeCheck(methodName, body, parameters)]);
   }
 
@@ -322,23 +321,23 @@
     // Temporary variables for common substrings.
     List<String> varNames = <String>[];
     // Values of temporary variables.
-    Map<String, js.Expression> varDefns = new Map<String, js.Expression>();
+    Map<String, jsAst.Expression> varDefns = new Map<String, jsAst.Expression>();
 
     // Expression to compute tags string for a class.  The expression will
     // initially be a string or expression building a string, but may be
     // replaced with a variable reference to the common substring.
-    Map<ClassElement, js.Expression> tagDefns =
-        new Map<ClassElement, js.Expression>();
+    Map<ClassElement, jsAst.Expression> tagDefns =
+        new Map<ClassElement, jsAst.Expression>();
 
-    js.Expression makeExpression(ClassElement classElement) {
+    jsAst.Expression makeExpression(ClassElement classElement) {
       // Expression fragments for this set of cls keys.
-      List<js.Expression> expressions = <js.Expression>[];
+      List<jsAst.Expression> expressions = <jsAst.Expression>[];
       // TODO: Remove if cls is abstract.
       List<String> subtags = [toNativeTag(classElement)];
       void walk(ClassElement cls) {
         for (final ClassElement subclass in getDirectSubclasses(cls)) {
           ClassElement tag = subclass;
-          js.Expression existing = tagDefns[tag];
+          jsAst.Expression existing = tagDefns[tag];
           if (existing == null) {
             // [subclass] is still within the subtree between dispatch classes.
             subtags.add(toNativeTag(tag));
@@ -346,19 +345,19 @@
           } else {
             // [subclass] is one of the preorderDispatchClasses, so CSE this
             // reference with the previous reference.
-            js.VariableUse use = existing.asVariableUse();
+            jsAst.VariableUse use = existing.asVariableUse();
             if (use != null && varDefns.containsKey(use.name)) {
               // We end up here if the subclasses have a DAG structure.  We
               // don't have DAGs yet, but if the dispatch is used for mixins
               // that will be a possibility.
               // Re-use the previously created temporary variable.
-              expressions.add(new js.VariableUse(use.name));
+              expressions.add(new jsAst.VariableUse(use.name));
             } else {
               String varName = 'v${varNames.length}_${tag.name.slowToString()}';
               varNames.add(varName);
               varDefns[varName] = existing;
-              tagDefns[tag] = new js.VariableUse(varName);
-              expressions.add(new js.VariableUse(varName));
+              tagDefns[tag] = new jsAst.VariableUse(varName);
+              expressions.add(new jsAst.VariableUse(varName));
             }
           }
         }
@@ -368,12 +367,12 @@
       if (!subtags.isEmpty) {
         expressions.add(js.string(subtags.join('|')));
       }
-      js.Expression expression;
+      jsAst.Expression expression;
       if (expressions.length == 1) {
         expression = expressions[0];
       } else {
-        js.Expression array = new js.ArrayInitializer.from(expressions);
-        expression = js.call(array.dot('join'), [js.string('|')]);
+        jsAst.Expression array = new jsAst.ArrayInitializer.from(expressions);
+        expression = array['join']([js.string('|')]);
       }
       return expression;
     }
@@ -384,46 +383,47 @@
 
     // Write out a thunk that builds the metadata.
     if (!tagDefns.isEmpty) {
-      List<js.Statement> statements = <js.Statement>[];
+      List<jsAst.Statement> statements = <jsAst.Statement>[];
 
-      List<js.VariableInitialization> initializations =
-          <js.VariableInitialization>[];
+      List<jsAst.VariableInitialization> initializations =
+          <jsAst.VariableInitialization>[];
       for (final String varName in varNames) {
         initializations.add(
-            new js.VariableInitialization(
-                new js.VariableDeclaration(varName),
+            new jsAst.VariableInitialization(
+                new jsAst.VariableDeclaration(varName),
                 varDefns[varName]));
       }
       if (!initializations.isEmpty) {
         statements.add(
-            new js.ExpressionStatement(
-                new js.VariableDeclarationList(initializations)));
+            new jsAst.ExpressionStatement(
+                new jsAst.VariableDeclarationList(initializations)));
       }
 
       // [table] is a list of lists, each inner list of the form:
       //   [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag]
       // E.g.
       //   [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...]
-      js.Expression table =
-          new js.ArrayInitializer.from(
+      jsAst.Expression table =
+          new jsAst.ArrayInitializer.from(
               preorderDispatchClasses.map((cls) =>
-                  new js.ArrayInitializer.from([
+                  new jsAst.ArrayInitializer.from([
                       js.string(toNativeTag(cls)),
                       tagDefns[cls]])));
 
       //  $.dynamicSetMetadata(table);
       statements.add(
-          new js.ExpressionStatement(
-              new js.Call(
-                  new js.VariableUse(dynamicSetMetadataName),
+          new jsAst.ExpressionStatement(
+              new jsAst.Call(
+                  new jsAst.VariableUse(dynamicSetMetadataName),
                   [table])));
 
       //  (function(){statements})();
       if (emitter.compiler.enableMinification) nativeBuffer.add(';');
       nativeBuffer.add(
-          js.prettyPrint(
-              new js.ExpressionStatement(
-                  new js.Call(new js.Fun([], new js.Block(statements)), [])),
+          jsAst.prettyPrint(
+              new jsAst.ExpressionStatement(
+                  new jsAst.Call(new jsAst.Fun([], new jsAst.Block(statements)),
+                                 [])),
               compiler));
     }
   }
@@ -460,10 +460,10 @@
     targetBuffer.add('$defineNativeClassName = '
                      '$defineNativeClassFunction$N$n');
 
-    List<js.Property> objectProperties = <js.Property>[];
+    List<jsAst.Property> objectProperties = <jsAst.Property>[];
 
-    void addProperty(String name, js.Expression value) {
-      objectProperties.add(new js.Property(js.string(name), value));
+    void addProperty(String name, jsAst.Expression value) {
+      objectProperties.add(new jsAst.Property(js.string(name), value));
     }
 
     // Because of native classes, we have to generate some is checks
@@ -478,16 +478,14 @@
         if (element.isObject(compiler)) continue;
         String name = backend.namer.operatorIs(element);
         addProperty(name,
-            js.fun([], js.block1(js.return_(new js.LiteralBool(false)))));
+            js.fun([], js.return_(js['false'])));
       }
     }
     emitIsChecks();
 
-    js.Expression makeCallOnThis(String functionName) =>
-        js.fun([],
-            js.block1(
-                js.return_(
-                    js.call(js.use(functionName), [js.use('this')]))));
+    jsAst.Expression makeCallOnThis(String functionName) {
+      return js.fun([], js.return_(js['$functionName(this)']));
+    }
 
     // In order to have the toString method on every native class,
     // we must patch the JS Object prototype with a helper method.
@@ -503,8 +501,8 @@
     // Same as above, but for operator==.
     String equalsName = backend.namer.publicInstanceMethodNameByArity(
         const SourceString('=='), 1);
-    addProperty(equalsName, js.fun(['a'], js.block1(
-        js.return_(js.strictEquals(new js.This(), js.use('a'))))));
+    addProperty(equalsName, js.fun(['a'],
+        js.return_(js['this === a'])));
 
     // If the native emitter has been asked to take care of the
     // noSuchMethod handlers, we do that now.
@@ -515,28 +513,21 @@
     // If we have any properties to add to Object.prototype, we run
     // through them and add them using defineProperty.
     if (!objectProperties.isEmpty) {
-      js.Expression init =
-          js.call(
-              js.fun(['table'],
-                  js.block1(
-                      new js.ForIn(
-                          new js.VariableDeclarationList(
-                              [new js.VariableInitialization(
-                                  new js.VariableDeclaration('key'),
-                                  null)]),
-                          js.use('table'),
-                          new js.ExpressionStatement(
-                              js.call(
-                                  js.use(defPropName),
-                                  [js.use('Object').dot('prototype'),
-                                   js.use('key'),
-                                   new js.PropertyAccess(js.use('table'),
-                                                         js.use('key'))]))))),
-              [new js.ObjectInitializer(objectProperties)]);
+      jsAst.Expression init =
+          js.fun(['table'],
+              new jsAst.ForIn(
+                  new jsAst.VariableDeclarationList(
+                      [new jsAst.VariableInitialization(
+                          new jsAst.VariableDeclaration('key'),
+                          null)]),
+                  js['table'],
+                  new jsAst.ExpressionStatement(
+                      js['$defPropName(Object.prototype, key, table[key])'])))(
+              new jsAst.ObjectInitializer(objectProperties));
 
       if (emitter.compiler.enableMinification) targetBuffer.add(';');
-      targetBuffer.add(js.prettyPrint(
-          new js.ExpressionStatement(init), compiler));
+      targetBuffer.add(jsAst.prettyPrint(
+          new jsAst.ExpressionStatement(init), compiler));
       targetBuffer.add('\n');
     }
 
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
index b1cb9eb..bfad207 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
@@ -81,7 +81,7 @@
         addAllInterfaceTypeArguments(type, instantiatedArguments);
       }
     }
-    for (ClassElement cls in instantiatedArguments) {
+    for (ClassElement cls in instantiatedArguments.toList()) {
       for (DartType type in cls.allSupertypes) {
         addAllInterfaceTypeArguments(type, instantiatedArguments);
       }
@@ -234,25 +234,25 @@
     StringBuffer builder = new StringBuffer();
     void build(DartType part) {
       if (part is TypeVariableType) {
-        builder.add(onVariable(part));
+        builder.write(onVariable(part));
       } else {
         bool hasArguments = part is InterfaceType && !part.isRaw;
         Element element = part.element;
         if (element == compiler.dynamicClass) {
-          builder.add('null');
+          builder.write('null');
         } else {
           String name = getJsName(element);
           if (!hasArguments) {
-            builder.add(name);
+            builder.write(name);
           } else {
-            builder.add('[');
-            builder.add(name);
+            builder.write('[');
+            builder.write(name);
             InterfaceType interface = part;
             for (DartType argument in interface.typeArguments) {
-              builder.add(', ');
+              builder.write(', ');
               build(argument);
             }
-            builder.add(']');
+            builder.write(']');
           }
         }
       }
diff --git a/sdk/lib/_internal/compiler/implementation/lib/async_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/async_patch.dart
index 0e0a70d..cd63a24 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/async_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/async_patch.dart
@@ -4,7 +4,8 @@
 
 // Patch file for the dart:async library.
 
-import 'dart:_isolate_helper' show TimerImpl;
+import 'dart:_isolate_helper' show IsolateNatives, TimerImpl;
+import 'dart:_foreign_helper' show JS, DART_CLOSURE_TO_JS;
 
 typedef void _TimerCallback0();
 typedef void _TimerCallback1(Timer timer);
@@ -38,3 +39,59 @@
     return new TimerImpl.repeating(milliseconds, callback);
   }
 }
+
+patch class DeferredLibrary {
+  patch Future<bool> load() {
+    return _load(libraryName, uri);
+  }
+}
+
+// TODO(ahe): This should not only apply to this isolate.
+final _loadedLibraries = <String, Completer<bool>>{};
+
+Future<bool> _load(String libraryName, String uri) {
+  // TODO(ahe): Validate libraryName.  Kasper points out that you want
+  // to be able to experiment with the effect of toggling @DeferLoad,
+  // so perhaps we should silently ignore "bad" library names.
+  Completer completer = new Completer<bool>();
+  Future<bool> future = _loadedLibraries[libraryName];
+  if (future != null) {
+    future.then((_) { completer.complete(false); });
+    return completer.future;
+  }
+  _loadedLibraries[libraryName] = completer.future;
+
+  if (uri == null) {
+    uri = IsolateNatives.thisScript;
+    int index = uri.lastIndexOf('/');
+    uri = '${uri.substring(0, index + 1)}part.js';
+  }
+
+  if (_hasDocument) {
+    // Inject a script tag.
+    var script = JS('', 'document.createElement("script")');
+    JS('', '#.type = "text/javascript"', script);
+    JS('', '#.async = "async"', script);
+    JS('', '#.src = #', script, uri);
+    var onLoad = JS('', '#.bind(null, #)',
+                    DART_CLOSURE_TO_JS(_onDeferredLibraryLoad), completer);
+    JS('', '#.addEventListener("load", #, false)', script, onLoad);
+    JS('', 'document.body.appendChild(#)', script);
+  } else if (JS('String', 'typeof load') == 'function') {
+    new Timer(0, (_) {
+      JS('void', 'load(#)', uri);
+      completer.complete(true);
+    });
+  } else {
+    throw new UnsupportedError('load not supported');
+  }
+  return completer.future;
+}
+
+/// Used to implement deferred loading. Used as callback on "load"
+/// event above in [load].
+_onDeferredLibraryLoad(Completer<bool> completer, event) {
+  completer.complete(true);
+}
+
+bool get _hasDocument => JS('String', 'typeof document') == 'object';
diff --git a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
index b0f09ccf..fad1d02 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
@@ -240,3 +240,50 @@
 
   patch String toString() => _contents;
 }
+
+patch class NoSuchMethodError {
+  patch String toString() {
+    StringBuffer sb = new StringBuffer();
+    int i = 0;
+    if (_arguments != null) {
+      for (; i < _arguments.length; i++) {
+        if (i > 0) {
+          sb.add(", ");
+        }
+        sb.add(Error.safeToString(_arguments[i]));
+      }
+    }
+    if (_namedArguments != null) {
+      _namedArguments.forEach((String key, var value) {
+        if (i > 0) {
+          sb.add(", ");
+        }
+        sb.add(key);
+        sb.add(": ");
+        sb.add(Error.safeToString(value));
+        i++;
+      });
+    }
+    if (_existingArgumentNames == null) {
+      return "NoSuchMethodError : method not found: '$_memberName'\n"
+          "Receiver: ${Error.safeToString(_receiver)}\n"
+          "Arguments: [$sb]";
+    } else {
+      String actualParameters = sb.toString();
+      sb = new StringBuffer();
+      for (int i = 0; i < _existingArgumentNames.length; i++) {
+        if (i > 0) {
+          sb.add(", ");
+        }
+        sb.add(_existingArgumentNames[i]);
+      }
+      String formalParameters = sb.toString();
+      return "NoSuchMethodError: incorrect number of arguments passed to "
+          "method named '$_memberName'\n"
+          "Receiver: ${Error.safeToString(_receiver)}\n"
+          "Tried calling: $_memberName($actualParameters)\n"
+          "Found: $_memberName($formalParameters)";
+    }
+  }
+}
+
diff --git a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
index 97700a7..ac14c32 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
@@ -96,7 +96,13 @@
 /**
  * Returns the isolate in which this code is running.
  */
-dynamic JS_CURRENT_ISOLATE() {}
+IsolateContext JS_CURRENT_ISOLATE() {}
+
+abstract class IsolateContext {
+  /// Holds a (native) JavaScript instance of Isolate, see
+  /// finishIsolateConstructorFunction in emitter.dart.
+  get isolateStatics;
+}
 
 /**
  * Invokes [function] in the context of [isolate].
diff --git a/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart
index 0374de5..00ed800 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -166,23 +166,43 @@
   }
 }
 
+patch class RawServerSocket {
+  patch static Future<RawServerSocket> bind([String address = "127.0.0.1",
+                                             int port = 0,
+                                             int backlog = 0]) {
+    throw new UnsupportedError("RawServerSocket.bind");
+  }
+}
+
 patch class ServerSocket {
-  patch factory ServerSocket(String bindAddress, int port, int backlog) {
-    throw new UnsupportedError("ServerSocket constructor");
+  patch static Future<ServerSocket> bind([String address = "127.0.0.1",
+                                          int port = 0,
+                                          int backlog = 0]) {
+    throw new UnsupportedError("ServerSocket.bind");
+  }
+}
+
+patch class RawSocket {
+  patch static Future<RawSocket> connect(String host, int port) {
+    throw new UnsupportedError("RawSocket constructor");
   }
 }
 
 patch class Socket {
-  patch factory Socket(String host, int port) {
+  patch static Future<Socket> connect(String host, int port) {
     throw new UnsupportedError("Socket constructor");
   }
 }
 
 patch class SecureSocket {
+  patch factory SecureSocket._(RawSecureSocket rawSocket) {
+    throw new UnsupportedError("SecureSocket constructor");
+  }
+
   patch static void initialize({String database,
                                 String password,
                                 bool useBuiltinRoots: true}) {
-    throw new UnsupportedError("SecureSocket.setCertificateDatabase");
+    throw new UnsupportedError("SecureSocket.initialize");
   }
 }
 
@@ -193,13 +213,13 @@
 }
 
 patch class _StdIOUtils {
-  patch static InputStream _getStdioInputStream() {
+  patch static Stream<List<int>> _getStdioInputStream() {
     throw new UnsupportedError("StdIOUtils._getStdioInputStream");
   }
-  patch static OutputStream _getStdioOutputStream(int fd) {
+  patch static IOSink _getStdioOutputStream(int fd) {
     throw new UnsupportedError("StdIOUtils._getStdioOutputStream");
   }
-  patch static int _socketType(Socket socket) {
+  patch static int _socketType(nativeSocket) {
     throw new UnsupportedError("StdIOUtils._socketType");
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
index 54bbdc1..539e7b4 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
@@ -12,7 +12,9 @@
 import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS,
                                    JS,
                                    JS_CREATE_ISOLATE,
-                                   JS_SET_CURRENT_ISOLATE;
+                                   JS_CURRENT_ISOLATE,
+                                   JS_SET_CURRENT_ISOLATE,
+                                   IsolateContext;
 
 ReceivePort lazyPort;
 
@@ -202,7 +204,7 @@
 }
 
 /** Context information tracked for each isolate. */
-class _IsolateContext {
+class _IsolateContext implements IsolateContext {
   /** Current isolate id. */
   int id;
 
@@ -406,23 +408,46 @@
    * JavaScript workers.
    */
   static String computeThisScript() {
-    // TODO(7369): Find a cross-platform non-brittle way of getting the
-    // currently running script.
-    var scripts = JS('', r"document.getElementsByTagName('script')");
-    // The scripts variable only contains the scripts that have already been
-    // executed. The last one is the currently running script.
-    for (int i = 0, len = JS('int', '#.length', scripts); i < len; i++) {
-      var script = JS('', '#[#]', scripts, i);
-      var src = JS('String|Null', '# && #.src', script, script);
-      // Filter out the test controller script, and the Dart
-      // bootstrap script.
-      if (src != null
-          && !src.endsWith('test_controller.js')
-          && !src.endsWith('dart.js')) {
-        return src;
-      }
+    var currentScript = JS('', r'$.$currentScript');
+    if (currentScript != null) {
+      return JS('String', 'String(#.src)', currentScript);
     }
-    return null;
+
+    // TODO(ahe): The following is for supporting command-line engines
+    // such as d8 and jsshell. We should move this code to a helper
+    // library that is only loaded when testing on those engines.
+
+    var stack = JS('String|Null', 'new Error().stack');
+    if (stack == null) {
+      // According to Internet Explorer documentation, the stack
+      // property is not set until the exception is thrown. The stack
+      // property was not provided until IE10.
+      stack = JS('String',
+                 '(function() {'
+                 'try { throw new Error() } catch(e) { return e.stack }'
+                 '})()');
+    }
+    var pattern, matches;
+
+    // This pattern matches V8, Chrome, and Internet Explorer stack
+    // traces that look like this:
+    // Error
+    //     at methodName (URI:LINE:COLUMN)
+    pattern = JS('',
+                 r'new RegExp("^ *at [^(]*\\((.*):[0-9]*:[0-9]*\\)$", "m")');
+
+
+    matches = JS('=List|Null', '#.match(#)', stack, pattern);
+    if (matches != null) return JS('String', '#[1]', matches);
+
+    // This pattern matches Firefox stack traces that look like this:
+    // methodName@URI:LINE
+    pattern = JS('', r'new RegExp("^[^@]*@(.*):[0-9]*$", "m")');
+
+    matches = JS('=List|Null', '#.match(#)', stack, pattern);
+    if (matches != null) return JS('String', '#[1]', matches);
+
+    throw new UnsupportedError('Cannot extract URI from "$stack"');
   }
 
   static computeGlobalThis() => JS('', 'function() { return this; }()');
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
index 75724a7..19f6ce8 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
@@ -805,7 +805,9 @@
     // we're dealing with we fall back on looking at the exception
     // message if it is available and a string.
     if (message is String) {
-      if (message.endsWith('is null') ||
+      if (message == 'null has no properties' ||
+          message == "'null' is not an object" ||
+          message.endsWith('is null') ||
           message.endsWith('is undefined') ||
           message.endsWith('is null or undefined') ||
           message.endsWith('of undefined') ||
@@ -1336,6 +1338,11 @@
   throwMalformedSubtypeError(value, type, reasons);
 }
 
+malformedTypeCast(value, type, reasons) {
+  if (value == null) return value;
+  throw new CastErrorImplementation.malformedTypeCast(value, type, reasons);
+}
+
 /**
  * Special interface recognized by the compiler and implemented by DOM
  * objects that support integer indexing. This interface is not
@@ -1372,17 +1379,27 @@
 /** Thrown by the 'as' operator if the cast isn't valid. */
 class CastErrorImplementation implements CastError {
   // TODO(lrn): Rename to CastError (and move implementation into core).
-  // TODO(lrn): Change actualType and expectedType to "Type" when reified
-  // types are available.
-  final Object actualType;
-  final Object expectedType;
+  final String message;
 
-  CastErrorImplementation(this.actualType, this.expectedType);
+  /**
+   * Normal cast error caused by a failed type cast.
+   */
+  CastErrorImplementation(Object actualType, Object expectedType)
+      : message = "CastError: Casting value of type $actualType to"
+                  " incompatible type $expectedType";
 
-  String toString() {
-    return "CastError: Casting value of type $actualType to"
-           " incompatible type $expectedType";
-  }
+
+  /**
+   * Cast error caused by a type cast to a malformed type.
+   */
+  CastErrorImplementation.malformedTypeCast(Object value,
+                                            String type, String reasons)
+      : message = "CastError: Type '${Primitives.objectTypeName(value)}' "
+                  "cannot be cast to type '$type' because '$type' is "
+                  "malformed: $reasons.";
+
+
+  String toString() => message;
 }
 
 class FallThroughErrorImplementation implements FallThroughError {
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
index c15fcae..a8bfc13 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
@@ -220,17 +220,17 @@
 
   num operator &(num other) {
     if (other is !num) throw new ArgumentError(other);
-    return JS('num', r'(# & #) >>> 0', this, other);    
+    return JS('num', r'(# & #) >>> 0', this, other);
   }
 
   num operator |(num other) {
     if (other is !num) throw new ArgumentError(other);
-    return JS('num', r'(# | #) >>> 0', this, other);    
+    return JS('num', r'(# | #) >>> 0', this, other);
   }
 
   num operator ^(num other) {
     if (other is !num) throw new ArgumentError(other);
-    return JS('num', r'(# ^ #) >>> 0', this, other);    
+    return JS('num', r'(# ^ #) >>> 0', this, other);
   }
 
   bool operator <(num other) {
diff --git a/sdk/lib/_internal/compiler/implementation/lib/string_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/string_helper.dart
index 6e4dccf..9749028 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/string_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/string_helper.dart
@@ -77,7 +77,7 @@
   return JS('String', r'#.replace(#, #)', receiver, replacer, to);
 }
 
-final RegExp quoteRegExp = new JSSyntaxRegExp(r'[-[\]{}()*+?.,\\^$|#\s]');
+final RegExp quoteRegExp = const JSSyntaxRegExp(r'[-[\]{}()*+?.,\\^$|#\s]');
 
 stringReplaceAllUnchecked(receiver, from, to) {
   checkString(to);
diff --git a/sdk/lib/_internal/compiler/implementation/library_loader.dart b/sdk/lib/_internal/compiler/implementation/library_loader.dart
index e5854b5..216bba8 100644
--- a/sdk/lib/_internal/compiler/implementation/library_loader.dart
+++ b/sdk/lib/_internal/compiler/implementation/library_loader.dart
@@ -796,6 +796,9 @@
   void registerDependency(LibraryElement library,
                           LibraryDependency tag,
                           LibraryElement loadedLibrary) {
+    if (tag != null) {
+      library.recordResolvedTag(tag, loadedLibrary);
+    }
     if (tag is Export) {
       // [loadedLibrary] is exported by [library].
       LibraryDependencyNode exportingNode = nodeMap[library];
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index adce296..0d5b232 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -373,6 +373,7 @@
     staticUse(const SourceString('defineProperty'));
     staticUse(const SourceString('toStringForNativeObject'));
     staticUse(const SourceString('hashCodeForNativeObject'));
+    staticUse(const SourceString('convertDartClosureToJS'));
 
     addNativeExceptions();
   }
@@ -478,7 +479,8 @@
       || libraryName == 'dart:html_common'
       || libraryName == 'dart:indexed_db'
       || libraryName == 'dart:svg'
-      || libraryName == 'dart:web_audio') {
+      || libraryName == 'dart:web_audio'
+      || libraryName == 'dart:web_sql') {
     library.canUseNative = true;
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index c00f783..54055cd 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -384,6 +384,14 @@
     ResolverVisitor visitor = visitorFor(element);
     initializerDo(tree, visitor.visit);
 
+    if (Elements.isStaticOrTopLevelField(element)) {
+      if (tree.asSendSet() != null) {
+        // TODO(ngeoffray): We could do better here by using the
+        // constant handler to figure out if it's a lazy field or not.
+        compiler.backend.registerLazyField();
+      }
+    }
+
     // Perform various checks as side effect of "computing" the type.
     element.computeType(compiler);
 
@@ -923,12 +931,12 @@
 
 class InitializerResolver {
   final ResolverVisitor visitor;
-  final Map<SourceString, Node> initialized;
+  final Map<Element, Node> initialized;
   Link<Node> initializers;
   bool hasSuper;
 
   InitializerResolver(this.visitor)
-    : initialized = new Map<SourceString, Node>(), hasSuper = false;
+    : initialized = new Map<Element, Node>(), hasSuper = false;
 
   error(Node node, MessageKind kind, [arguments = const {}]) {
     visitor.error(node, kind, arguments);
@@ -945,13 +953,31 @@
     return node.receiver.asIdentifier().isThis();
   }
 
-  void checkForDuplicateInitializers(SourceString name, Node init) {
-    if (initialized.containsKey(name)) {
-      error(init, MessageKind.DUPLICATE_INITIALIZER, {'fieldName': name});
-      warning(initialized[name], MessageKind.ALREADY_INITIALIZED,
-              {'fieldName': name});
+  reportDuplicateInitializerError(Element field, Node init, Node existing) {
+    visitor.compiler.reportError(
+        init,
+        new ResolutionError(MessageKind.DUPLICATE_INITIALIZER,
+                            {'fieldName': field.name}));
+    visitor.compiler.reportMessage(
+        visitor.compiler.spanFromNode(existing),
+        new ResolutionError(MessageKind.ALREADY_INITIALIZED,
+                            {'fieldName': field.name}),
+        Diagnostic.INFO);
+  }
+
+  void checkForDuplicateInitializers(Element field, Node init) {
+    // [field] can be null if it could not be resolved.
+    if (field == null) return;
+    SourceString name = field.name;
+    if (initialized.containsKey(field)) {
+      reportDuplicateInitializerError(field, init, initialized[field]);
+    } else if (field.modifiers.isFinal()) {
+      Node fieldNode = field.parseNode(visitor.compiler).asSendSet();
+      if (fieldNode != null) {
+        reportDuplicateInitializerError(field, init, fieldNode);
+      }
     }
-    initialized[name] = init;
+    initialized[field] = init;
   }
 
   void resolveFieldInitializer(FunctionElement constructor, SendSet init) {
@@ -974,7 +1000,7 @@
     }
     visitor.useElement(init, target);
     visitor.world.registerStaticUse(target);
-    checkForDuplicateInitializers(name, init);
+    checkForDuplicateInitializers(target, init);
     // Resolve initializing value.
     visitor.visitInStaticContext(init.arguments.head);
   }
@@ -1113,7 +1139,8 @@
         constructor.computeSignature(visitor.compiler);
     functionParameters.forEachParameter((Element element) {
       if (identical(element.kind, ElementKind.FIELD_PARAMETER)) {
-        checkForDuplicateInitializers(element.name,
+        FieldParameterElement fieldParameter = element;
+        checkForDuplicateInitializers(fieldParameter.fieldElement,
                                       element.parseNode(visitor.compiler));
       }
     });
@@ -1428,7 +1455,8 @@
           type = new MalformedType(
               new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH,
                   {'type': node}, typeName.source, enclosingElement),
-              new InterfaceType(cls.declaration, arguments.toLink()));
+              new InterfaceType.userProvidedBadType(cls.declaration,
+                                                    arguments.toLink()));
         } else {
           if (arguments.isEmpty) {
             type = cls.rawType;
@@ -1448,7 +1476,7 @@
           type = new MalformedType(
               new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH,
                   {'type': node}, typeName.source, enclosingElement),
-              new TypedefType(typdef, arguments.toLink()));
+              new TypedefType.userProvidedBadType(typdef, arguments.toLink()));
         } else {
           if (arguments.isEmpty) {
             type = typdef.rawType;
@@ -1458,6 +1486,7 @@
         }
       } else if (element.isTypeVariable()) {
         if (enclosingElement.isInStaticMember()) {
+          compiler.backend.registerThrowRuntimeError();
           compiler.reportWarning(node,
               MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER.message(
                   {'typeVariableName': node}));
@@ -1539,6 +1568,7 @@
   ClassElement currentClass;
   ExpressionStatement currentExpressionStatement;
   bool typeRequired = false;
+  bool sendIsMemberAccess = false;
   StatementScope statementScope;
   int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
       | ElementCategory.IMPLIES_TYPE;
@@ -1642,6 +1672,7 @@
           element = warnAndCreateErroneousElement(node, node.source,
                                                   MessageKind.CANNOT_RESOLVE,
                                                   {'name': node});
+          compiler.backend.registerThrowNoSuchMethod();
         }
       } else if (element.isErroneous()) {
         // Use the erroneous element.
@@ -1652,8 +1683,7 @@
                 {'text': "is not an expression $element"});
         }
       }
-      if (!Elements.isUnresolved(element)
-          && element.kind == ElementKind.CLASS) {
+      if (!Elements.isUnresolved(element) && element.isClass()) {
         ClassElement classElement = element;
         classElement.ensureResolved(compiler);
       }
@@ -1833,7 +1863,6 @@
     } else {
       name = node.name.asIdentifier().source;
     }
-
     FunctionElement function = new FunctionElementX.node(
         name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
         enclosingElement);
@@ -1925,9 +1954,12 @@
       target = currentClass.lookupSuperMember(name);
       // [target] may be null which means invoking noSuchMethod on
       // super.
+      if (target == null) {
+        compiler.backend.registerSuperNoSuchMethod();
+      }
     } else if (Elements.isUnresolved(resolvedReceiver)) {
       return null;
-    } else if (identical(resolvedReceiver.kind, ElementKind.CLASS)) {
+    } else if (resolvedReceiver.isClass()) {
       ClassElement receiverClass = resolvedReceiver;
       receiverClass.ensureResolved(compiler);
       if (node.isOperator) {
@@ -1941,6 +1973,7 @@
       }
       target = receiverClass.lookupLocalMember(name);
       if (target == null || target.isInstanceMember()) {
+        compiler.backend.registerThrowNoSuchMethod();
         // TODO(johnniwinther): With the simplified [TreeElements] invariant,
         // try to resolve injected elements if [currentClass] is in the patch
         // library of [receiverClass].
@@ -1959,6 +1992,7 @@
       PrefixElement prefix = resolvedReceiver;
       target = prefix.lookupLocalMember(name);
       if (Elements.isUnresolved(target)) {
+        compiler.backend.registerThrowNoSuchMethod();
         return warnAndCreateErroneousElement(
             node, name, MessageKind.NO_SUCH_LIBRARY_MEMBER,
             {'libraryName': prefix.name, 'memberName': name});
@@ -2063,26 +2097,38 @@
   }
 
   visitSend(Send node) {
+    bool oldSendIsMemberAccess = sendIsMemberAccess;
+    sendIsMemberAccess = node.isPropertyAccess || node.isCall;
     Element target = resolveSend(node);
-    if (!Elements.isUnresolved(target)
-        && target.kind == ElementKind.ABSTRACT_FIELD) {
-      AbstractFieldElement field = target;
-      target = field.getter;
-      if (target == null && !inInstanceContext) {
-        target =
-            warnAndCreateErroneousElement(node.selector, field.name,
-                                          MessageKind.CANNOT_RESOLVE_GETTER);
+    sendIsMemberAccess = oldSendIsMemberAccess;
+
+    if (!Elements.isUnresolved(target)) {
+      if (target.isAbstractField()) {
+        AbstractFieldElement field = target;
+        target = field.getter;
+        if (target == null && !inInstanceContext) {
+          compiler.backend.registerThrowNoSuchMethod();
+          target =
+              warnAndCreateErroneousElement(node.selector, field.name,
+                                            MessageKind.CANNOT_RESOLVE_GETTER);
+        }
+      } else if (target.impliesType() && !sendIsMemberAccess) {
+        compiler.backend.registerTypeLiteral();
       }
     }
 
     bool resolvedArguments = false;
     if (node.isOperator) {
       String operatorString = node.selector.asOperator().source.stringValue;
-      if (identical(operatorString, 'is') || identical(operatorString, 'as')) {
+      if (operatorString == 'is' || operatorString == 'as') {
         assert(node.arguments.tail.isEmpty);
         DartType type = resolveTypeTest(node.arguments.head);
         if (type != null) {
-          compiler.enqueuer.resolution.registerIsCheck(type);
+          if (operatorString == 'as') {
+            compiler.enqueuer.resolution.registerAsCheck(type);
+          } else {
+            compiler.enqueuer.resolution.registerIsCheck(type);
+          }
         }
         resolvedArguments = true;
       } else if (identical(operatorString, '?')) {
@@ -2141,6 +2187,7 @@
   }
 
   void warnArgumentMismatch(Send node, Element target) {
+    compiler.backend.registerThrowNoSuchMethod();
     // TODO(karlklose): we can be more precise about the reason of the
     // mismatch.
     warning(node.argumentsNode, MessageKind.INVALID_ARGUMENTS,
@@ -2163,20 +2210,30 @@
     SourceString operatorName = node.assignmentOperator.source;
     String source = operatorName.stringValue;
     bool isComplex = !identical(source, '=');
-    if (!Elements.isUnresolved(target)
-        && target.kind == ElementKind.ABSTRACT_FIELD) {
-      AbstractFieldElement field = target;
-      setter = field.setter;
-      getter = field.getter;
-      if (setter == null && !inInstanceContext) {
+    if (!Elements.isUnresolved(target)) {
+      if (target.isAbstractField()) {
+        AbstractFieldElement field = target;
+        setter = field.setter;
+        getter = field.getter;
+        if (setter == null && !inInstanceContext) {
+          setter =
+              warnAndCreateErroneousElement(node.selector, field.name,
+                                            MessageKind.CANNOT_RESOLVE_SETTER);
+          compiler.backend.registerThrowNoSuchMethod();
+        }
+        if (isComplex && getter == null && !inInstanceContext) {
+          getter =
+              warnAndCreateErroneousElement(node.selector, field.name,
+                                            MessageKind.CANNOT_RESOLVE_GETTER);
+          compiler.backend.registerThrowNoSuchMethod();
+        }
+      } else if (target.impliesType()) {
+        compiler.backend.registerThrowNoSuchMethod();
+      } else if (target.modifiers.isFinal() || target.modifiers.isConst()) {
         setter =
-            warnAndCreateErroneousElement(node.selector, field.name,
+            warnAndCreateErroneousElement(node.selector, target.name,
                                           MessageKind.CANNOT_RESOLVE_SETTER);
-      }
-      if (isComplex && getter == null && !inInstanceContext) {
-        getter =
-            warnAndCreateErroneousElement(node.selector, field.name,
-                                          MessageKind.CANNOT_RESOLVE_GETTER);
+        compiler.backend.registerThrowNoSuchMethod();
       }
     }
 
@@ -2328,6 +2385,7 @@
     if (!inCatchBlock && node.expression == null) {
       error(node, MessageKind.THROW_WITHOUT_EXPRESSION);
     }
+    compiler.backend.registerThrow();
     visit(node.expression);
   }
 
@@ -2353,7 +2411,10 @@
   }
 
   visitParenthesizedExpression(ParenthesizedExpression node) {
+    bool oldSendIsMemberAccess = sendIsMemberAccess;
+    sendIsMemberAccess = false;
     visit(node.expression);
+    sendIsMemberAccess = oldSendIsMemberAccess;
   }
 
   visitNewExpression(NewExpression node) {
@@ -2363,26 +2424,34 @@
     resolveArguments(node.send.argumentsNode);
     useElement(node.send, constructor);
     if (Elements.isUnresolved(constructor)) return constructor;
-    // TODO(karlklose): handle optional arguments.
-    if (node.send.argumentCount() != constructor.parameterCount(compiler)) {
-      // TODO(ngeoffray): resolution error with wrong number of
-      // parameters. We cannot do this rigth now because of the
-      // List constructor.
+    Selector callSelector = mapping.getSelector(node.send);
+    if (!callSelector.applies(constructor, compiler)) {
+      warnArgumentMismatch(node.send, constructor);
+      compiler.backend.registerThrowNoSuchMethod();
     }
-    // [constructor] might be the implementation element and only declaration
-    // elements may be registered.
-    world.registerStaticUse(constructor.declaration);
     compiler.withCurrentElement(constructor, () {
       FunctionExpression tree = constructor.parseNode(compiler);
       compiler.resolver.resolveConstructorImplementation(constructor, tree);
     });
+
+    if (constructor.defaultImplementation != constructor) {
+      // Support for deprecated interface support.
+      // TODO(ngeoffray): Remove once we remove such support.
+      world.registerStaticUse(constructor.declaration);
+      world.registerInstantiatedClass(
+          constructor.getEnclosingClass().declaration);
+      constructor = constructor.defaultImplementation;
+    }
     // [constructor.defaultImplementation] might be the implementation element
     // and only declaration elements may be registered.
-    world.registerStaticUse(constructor.defaultImplementation.declaration);
-    ClassElement cls = constructor.defaultImplementation.getEnclosingClass();
+    world.registerStaticUse(constructor.declaration);
+    ClassElement cls = constructor.getEnclosingClass();
     // [cls] might be the implementation element and only declaration elements
     // may be registered.
     world.registerInstantiatedClass(cls.declaration);
+    if (cls.isAbstract(compiler)) {
+      compiler.backend.registerAbstractClassInstantiation();
+    }
     // [cls] might be the declaration element and we want to include injected
     // members.
     cls.implementation.forEachInstanceField(
@@ -2485,6 +2554,7 @@
 
   visitStringInterpolation(StringInterpolation node) {
     world.registerInstantiatedClass(compiler.stringClass);
+    compiler.backend.registerStringInterpolation();
     node.visitChildren(this);
   }
 
@@ -2625,6 +2695,9 @@
 
   visitLiteralMap(LiteralMap node) {
     world.registerInstantiatedClass(compiler.mapClass);
+    if (node.isConst()) {
+      compiler.backend.registerConstantMap();
+    }
     node.visitChildren(this);
   }
 
@@ -2702,6 +2775,9 @@
         mapping.remove(label.label);
       }
     });
+    // TODO(ngeoffray): We should check here instead of the SSA backend if
+    // there might be an error.
+    compiler.backend.registerFallThroughError();
   }
 
   visitSwitchCase(SwitchCase node) {
@@ -2725,17 +2801,20 @@
   }
 
   visitCatchBlock(CatchBlock node) {
+    compiler.backend.registerCatchStatement();
     // Check that if catch part is present, then
     // it has one or two formal parameters.
     if (node.formals != null) {
       if (node.formals.isEmpty) {
         error(node, MessageKind.EMPTY_CATCH_DECLARATION);
       }
-      if (!node.formals.nodes.tail.isEmpty &&
-          !node.formals.nodes.tail.tail.isEmpty) {
-        for (Node extra in node.formals.nodes.tail.tail) {
-          error(extra, MessageKind.EXTRA_CATCH_DECLARATION);
+      if (!node.formals.nodes.tail.isEmpty) {
+        if (!node.formals.nodes.tail.tail.isEmpty) {
+          for (Node extra in node.formals.nodes.tail.tail) {
+            error(extra, MessageKind.EXTRA_CATCH_DECLARATION);
+          }
         }
+        compiler.backend.registerStackTraceInCatch();
       }
 
       // Check that the formals aren't optional and that they have no
@@ -2749,7 +2828,7 @@
         if (nodeList != null) {
           error(nodeList, MessageKind.OPTIONAL_PARAMETER_IN_CATCH);
         } else {
-        VariableDefinitions declaration = link.head;
+          VariableDefinitions declaration = link.head;
           for (Node modifier in declaration.modifiers.nodes) {
             error(modifier, MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH);
           }
@@ -3514,6 +3593,11 @@
   failOrReturnErroneousElement(Element enclosing, Node diagnosticNode,
                                SourceString targetName, MessageKind kind,
                                Map arguments) {
+    if (kind == MessageKind.CANNOT_FIND_CONSTRUCTOR) {
+      compiler.backend.registerThrowNoSuchMethod();
+    } else {
+      compiler.backend.registerThrowRuntimeError();
+    }
     if (inConstContext) {
       error(diagnosticNode, kind, arguments);
     } else {
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart b/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart
index e9f5930..6f47f73 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart
@@ -106,7 +106,7 @@
   Iterator<int> get iterator => new StringCodeIterator(syntax);
 
   void printOn(StringBuffer sb) {
-    sb.add(syntax);
+    sb.write(syntax);
   }
 
   String toString() => syntax;
@@ -203,19 +203,19 @@
 
   String toString() {
     StringBuffer sb = new StringBuffer();
-    sb.add("[");
+    sb.write("[");
     if (keyword != null) {
-      sb.add("*");
-      sb.add(keyword);
-      sb.add(" ");
+      sb.write("*");
+      sb.write(keyword);
+      sb.write(" ");
     }
     List<KeywordState> foo = table;
     for (int i = 0; i < foo.length; i++) {
       if (foo[i] != null) {
-        sb.add("${new String.fromCharCodes([i + $a])}: ${foo[i]}; ");
+        sb.write("${new String.fromCharCodes([i + $a])}: ${foo[i]}; ");
       }
     }
-    sb.add("]");
+    sb.write("]");
     return sb.toString();
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
index 5a85e00..8955b00 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
@@ -556,7 +556,7 @@
    * Returns true if the stringValue of the [token] is [value].
    */
   bool optional(String value, Token token) {
-      return identical(value, token.stringValue);
+    return identical(value, token.stringValue);
   }
 
   /**
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart b/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart
index 10ad12a..5d1a42a 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart
@@ -75,7 +75,7 @@
   }
 
   void printOn(StringBuffer sb) {
-    sb.add(internalString.substring(begin, end));
+    sb.write(internalString.substring(begin, end));
   }
 
   String slowToString() {
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/token.dart b/sdk/lib/_internal/compiler/implementation/scanner/token.dart
index c4fda3c..fcf4e87 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/token.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/token.dart
@@ -219,7 +219,7 @@
   Iterator<int> get iterator => new StringCodeIterator(stringValue);
 
   void printOn(StringBuffer sb) {
-    sb.add(stringValue);
+    sb.write(stringValue);
   }
 
   String toString() => stringValue;
diff --git a/sdk/lib/_internal/compiler/implementation/source_file.dart b/sdk/lib/_internal/compiler/implementation/source_file.dart
index 14a4175..ca6d614 100644
--- a/sdk/lib/_internal/compiler/implementation/source_file.dart
+++ b/sdk/lib/_internal/compiler/implementation/source_file.dart
@@ -76,7 +76,7 @@
     var buf = new StringBuffer(
         '${filename}:${line + 1}:${column + 1}: $message');
     if (includeText) {
-      buf.add('\n');
+      buf.write('\n');
       var textLine;
       // +1 for 0-indexing, +1 again to avoid the last line of the file
       if ((line + 2) < _lineStarts.length) {
@@ -86,17 +86,17 @@
       }
 
       int toColumn = min(column + (end-start), textLine.length);
-      buf.add(textLine.substring(0, column));
-      buf.add(color(textLine.substring(column, toColumn)));
-      buf.add(textLine.substring(toColumn));
+      buf.write(textLine.substring(0, column));
+      buf.write(color(textLine.substring(column, toColumn)));
+      buf.write(textLine.substring(toColumn));
 
       int i = 0;
       for (; i < column; i++) {
-        buf.add(' ');
+        buf.write(' ');
       }
 
       for (; i < toColumn; i++) {
-        buf.add(color('^'));
+        buf.write(color('^'));
       }
     }
 
diff --git a/sdk/lib/_internal/compiler/implementation/source_map_builder.dart b/sdk/lib/_internal/compiler/implementation/source_map_builder.dart
index 80960d3..6f379b2 100644
--- a/sdk/lib/_internal/compiler/implementation/source_map_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/source_map_builder.dart
@@ -54,15 +54,15 @@
 
   void printStringListOn(List<String> strings, StringBuffer buffer) {
     bool first = true;
-    buffer.add('[');
+    buffer.write('[');
     for (String string in strings) {
-      if (!first) buffer.add(',');
-      buffer.add('"');
+      if (!first) buffer.write(',');
+      buffer.write('"');
       writeJsonEscapedCharsOn(string, buffer);
-      buffer.add('"');
+      buffer.write('"');
       first = false;
     }
-    buffer.add(']');
+    buffer.write(']');
   }
 
   String build(SourceFile targetFile) {
@@ -70,18 +70,18 @@
     entries.forEach((SourceMapEntry entry) => writeEntry(entry, targetFile,
                                                          mappingsBuffer));
     StringBuffer buffer = new StringBuffer();
-    buffer.add('{\n');
-    buffer.add('  "version": 3,\n');
-    buffer.add('  "sourceRoot": "",\n');
-    buffer.add('  "sources": ');
+    buffer.write('{\n');
+    buffer.write('  "version": 3,\n');
+    buffer.write('  "sourceRoot": "",\n');
+    buffer.write('  "sources": ');
     printStringListOn(sourceUrlList, buffer);
-    buffer.add(',\n');
-    buffer.add('  "names": ');
+    buffer.write(',\n');
+    buffer.write('  "names": ');
     printStringListOn(sourceNameList, buffer);
-    buffer.add(',\n');
-    buffer.add('  "mappings": "');
-    buffer.add(mappingsBuffer);
-    buffer.add('"\n}\n');
+    buffer.write(',\n');
+    buffer.write('  "mappings": "');
+    buffer.write(mappingsBuffer);
+    buffer.write('"\n}\n');
     return buffer.toString();
   }
 
@@ -91,7 +91,7 @@
 
     if (targetLine > previousTargetLine) {
       for (int i = previousTargetLine; i < targetLine; ++i) {
-        output.add(';');
+        output.write(';');
       }
       previousTargetLine = targetLine;
       previousTargetColumn = 0;
@@ -99,7 +99,7 @@
     }
 
     if (!firstEntryInLine) {
-      output.add(',');
+      output.write(',');
     }
     firstEntryInLine = false;
 
@@ -152,7 +152,7 @@
       if (value > 0) {
         digit |= VLQ_CONTINUATION_BIT;
       }
-      output.add(BASE64_DIGITS[digit]);
+      output.write(BASE64_DIGITS[digit]);
     } while (value > 0);
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
index 0e10ecf..78ecae6 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
@@ -58,39 +58,51 @@
 
 /**
  * Visits the graph in dominator order and inserts TypeGuards in places where
- * we consider the guard to be of value.
- *
- * Might modify the [types] in an inconsistent way. No further analysis should
- * rely on them.
+ * we consider the guard to be of value. This phase also does type
+ * propagation to help find valuable type guards.
  */
-class SsaTypeGuardInserter extends HGraphVisitor implements OptimizationPhase {
-  final Compiler compiler;
+class SsaTypeGuardInserter extends SsaNonSpeculativeTypePropagator
+    implements OptimizationPhase {
   final String name = 'SsaTypeGuardInserter';
   final CodegenWorkItem work;
-  final HTypeMap types;
   bool calledInLoop = false;
   bool isRecursiveMethod = false;
   int stateId = 1;
+  Map<HInstruction, HType> savedTypes = new Map<HInstruction, HType>();
 
-  SsaTypeGuardInserter(this.compiler, this.work, this.types);
+  SsaTypeGuardInserter(compiler, this.work) : super(compiler);
 
   void visitGraph(HGraph graph) {
+    // Run the speculative type propagator. This does in-place
+    // update of the type of the instructions, and saves the
+    // previous types in the [savedTypes] map.
+    SsaTypePropagator propagator =
+        new SsaSpeculativeTypePropagator(compiler, savedTypes);
+    propagator.visitGraph(graph);
+
+    // Put back the original types in the instructions, and save the
+    // speculated types in [savedTypes].
+    Map<HInstruction, HType> speculativeTypes = new Map<HInstruction, HType>();
+
+    savedTypes.forEach((HInstruction instruction, HType type) {
+      speculativeTypes[instruction] = instruction.instructionType;
+      instruction.instructionType = type;
+    });
+    savedTypes = speculativeTypes;
+
+    // Propagate types again, and insert type guards in the graph.
     isRecursiveMethod = graph.isRecursiveMethod;
     calledInLoop = graph.calledInLoop;
     work.guards = <HTypeGuard>[];
     visitDominatorTree(graph);
-  }
 
-  void visitBasicBlock(HBasicBlock block) {
-    block.forEachPhi(visitInstruction);
+    // We need to disable the guards, and therefore re-run a
+    // non-speculative type propagator that will not use the
+    // speculated types.
+    work.guards.forEach((HTypeGuard guard) { guard.disable(); });
 
-    HInstruction instruction = block.first;
-    while (instruction != null) {
-      // Note that visitInstruction (from the phis and here) might insert an
-      // HTypeGuard instruction. We have to skip those.
-      if (instruction is !HTypeGuard) visitInstruction(instruction);
-      instruction = instruction.next;
-    }
+    propagator = new SsaNonSpeculativeTypePropagator(compiler);
+    propagator.visitGraph(graph);
   }
 
   // Primitive types that are not null are valuable. These include
@@ -147,10 +159,10 @@
       if (isNested(userLoopHeader, currentLoopHeader)) return true;
     }
 
-    bool isIndexOperatorOnIndexablePrimitive(instruction, types) {
+    bool isIndexOperatorOnIndexablePrimitive(instruction) {
       return instruction is HIndex
           || (instruction is HInvokeDynamicMethod
-              && instruction.isIndexOperatorOnIndexablePrimitive(types));
+              && instruction.isIndexOperatorOnIndexablePrimitive());
     }
 
     // To speed up computations on values loaded from arrays, we
@@ -161,7 +173,7 @@
     // type guard is much smaller than the first one that causes the
     // generation of a bailout method.
     if (hasTypeGuards
-        && isIndexOperatorOnIndexablePrimitive(instruction, types)) {
+        && isIndexOperatorOnIndexablePrimitive(instruction)) {
       HBasicBlock loopHeader = instruction.block.enclosingLoopHeader;
       if (loopHeader != null && loopHeader.parentLoopHeader != null) {
         return true;
@@ -183,34 +195,21 @@
     return calledInLoop;
   }
 
-  bool shouldInsertTypeGuard(HInstruction instruction,
-                             HType speculativeType,
-                             HType computedType) {
+  bool shouldInsertTypeGuard(HInstruction instruction, HType speculativeType) {
     if (!speculativeType.isUseful()) return false;
     // If the types agree we don't need to check.
-    if (speculativeType == computedType) return false;
+    if (speculativeType == instruction.instructionType) return false;
     // If a bailout check is more expensive than doing the actual operation
     // don't do it either.
     return typeGuardWouldBeValuable(instruction, speculativeType);
   }
 
-  void visitInstruction(HInstruction instruction) {
-    HType speculativeType = types[instruction];
-    HType computedType = instruction.computeTypeFromInputTypes(types, compiler);
-    // Currently the type in [types] is the speculative type each instruction
-    // would like to have. We start by recomputing the type non-speculatively.
-    // If we add a type guard then the guard will expose the speculative type.
-    // If we don't add a type guard then this avoids that subsequent
-    // instructions use the wrong (speculative) type.
-    //
-    // Note that just setting the speculative type of the instruction is not
-    // complete since the type could lead to a phi node which in turn could
-    // change the speculative type. In this case we might miss some guards we
-    // would have liked to insert. Most of the time this should however be
-    // fine, due to dominator-order visiting.
-    types[instruction] = computedType;
+  bool updateType(HInstruction instruction) {
+    bool hasChanged = super.updateType(instruction);
+    HType speculativeType = savedTypes[instruction];
+    if (speculativeType == null) return hasChanged;
 
-    if (shouldInsertTypeGuard(instruction, speculativeType, computedType)) {
+    if (shouldInsertTypeGuard(instruction, speculativeType)) {
       HInstruction insertionPoint;
       if (instruction is HPhi) {
         insertionPoint = instruction.block.first;
@@ -238,11 +237,16 @@
         insertionPoint.block.addBefore(insertionPoint, target);
       }
       HTypeGuard guard = new HTypeGuard(speculativeType, instruction, target);
-      types[guard] = speculativeType;
       work.guards.add(guard);
+      // By setting the type of the guard to the speculated type, we
+      // help the analysis find valuable type guards. This however
+      // requires to run a non-speculative type propagation again
+      // after this analysis.
+      guard.instructionType = speculativeType;
       instruction.block.rewrite(instruction, guard);
       insertionPoint.block.addBefore(insertionPoint, guard);
     }
+    return hasChanged;
   }
 }
 
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 264334a..0c387a8 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -21,17 +21,12 @@
 
 class SsaBuilderTask extends CompilerTask {
   final CodeEmitterTask emitter;
-  // Loop tracking information.
-  final Set<FunctionElement> functionsCalledInLoop;
-  final Map<SourceString, Selector> selectorsCalledInLoop;
   final JavaScriptBackend backend;
 
   String get name => 'SSA builder';
 
   SsaBuilderTask(JavaScriptBackend backend)
     : emitter = backend.emitter,
-      functionsCalledInLoop = new Set<FunctionElement>(),
-      selectorsCalledInLoop = new Map<SourceString, Selector>(),
       backend = backend,
       super(backend.compiler);
 
@@ -58,12 +53,9 @@
       }
       assert(graph.isValid());
       if (!identical(kind, ElementKind.FIELD)) {
-        bool inLoop = functionsCalledInLoop.contains(element.declaration);
-        if (!inLoop) {
-          Selector selector = selectorsCalledInLoop[element.name];
-          inLoop = selector != null && selector.applies(element, compiler);
-        }
-        graph.calledInLoop = inLoop;
+        Set<Selector> selectors = backend.selectorsCalledInLoop[element.name];
+        graph.calledInLoop = selectors != null &&
+            selectors.any((selector) => selector.applies(element, compiler));
 
         // If there is an estimate of the parameter types assume these types
         // when compiling.
@@ -92,7 +84,7 @@
           if (!parameterTypes.allUnknown) {
             int i = 0;
             signature.forEachParameter((Element param) {
-              builder.parameters[param].guaranteedType = parameterTypes[i++];
+              builder.parameters[param].instructionType = parameterTypes[i++];
             });
           }
           backend.registerParameterTypesOptimization(
@@ -250,21 +242,27 @@
 
   HType cachedTypeOfThis;
 
-  HType computeTypeOfThis() {
-    Element element = closureData.thisElement;
-    ClassElement cls = element.enclosingElement.getEnclosingClass();
-    Compiler compiler = builder.compiler;
-    DartType type = cls.computeType(compiler);
-    if (compiler.world.isUsedAsMixin(cls)) {
-      // If the enclosing class is used as a mixin, [:this:] can be
-      // of the class that mixins the enclosing class. These two
-      // classes do not have a subclass relationship, so, for
-      // simplicity, we mark the type as an interface type.
-      cachedTypeOfThis = new HType.nonNullSubtype(type, compiler);
-    } else {
-      cachedTypeOfThis = new HType.nonNullSubclass(type, compiler);
+  HType getTypeOfThis() {
+    HType result = cachedTypeOfThis;
+    if (result == null) {
+      Element element = closureData.thisElement;
+      ClassElement cls = element.enclosingElement.getEnclosingClass();
+      Compiler compiler = builder.compiler;
+      // Use the raw type because we don't have the type context for the
+      // type parameters.
+      DartType type = cls.rawType;
+      if (compiler.world.isUsedAsMixin(cls)) {
+        // If the enclosing class is used as a mixin, [:this:] can be
+        // of the class that mixins the enclosing class. These two
+        // classes do not have a subclass relationship, so, for
+        // simplicity, we mark the type as an interface type.
+        result = new HType.nonNullSubtype(type, compiler);
+      } else {
+        result = new HType.nonNullSubclass(type, compiler);
+      }
+      cachedTypeOfThis = result;
     }
-    return cachedTypeOfThis;
+    return result;
   }
 
   /**
@@ -295,8 +293,8 @@
         HInstruction parameter = builder.addParameter(parameterElement);
         builder.parameters[parameterElement] = parameter;
         directLocals[parameterElement] = parameter;
-        parameter.guaranteedType =
-            builder.getGuaranteedTypeOfElement(parameterElement);
+        parameter.instructionType =
+            new HType.inferredForElement(parameterElement, compiler);
       });
     }
 
@@ -320,7 +318,7 @@
       // not have any thisElement if the closure was created inside a static
       // context.
       HThis thisInstruction = new HThis(
-          closureData.thisElement, computeTypeOfThis());
+          closureData.thisElement, getTypeOfThis());
       builder.graph.thisInstruction = thisInstruction;
       builder.graph.entry.addAtEntry(thisInstruction);
       directLocals[closureData.thisElement] = thisInstruction;
@@ -351,7 +349,7 @@
       builder.graph.entry.addAfter(
           directLocals[closureData.thisElement], value);
       directLocals[closureData.thisElement] = value;
-      value.guaranteedType = type;
+      value.instructionType = type;
     }
   }
 
@@ -434,11 +432,8 @@
 
   HInstruction readThis() {
     HInstruction res = readLocal(closureData.thisElement);
-    if (res.guaranteedType == null) {
-      if (cachedTypeOfThis == null) {
-        computeTypeOfThis();
-      }
-      res.guaranteedType = cachedTypeOfThis;
+    if (res.instructionType == null) {
+      res.instructionType = getTypeOfThis();
     }
     return res;
   }
@@ -1009,6 +1004,12 @@
                                                   compiledArguments);
     assert(succeeded);
 
+    // Create the inlining state after evaluating the arguments, that
+    // may have an impact on the state of the current method.
+    InliningState state = new InliningState(
+        function, returnElement, returnType, elements, stack, localsHandler);
+    localsHandler = new LocalsHandler.from(localsHandler);
+
     FunctionSignature signature = function.computeSignature(compiler);
     int index = 0;
     signature.orderedForEachParameter((Element parameter) {
@@ -1036,8 +1037,6 @@
         }
       }
     }
-    InliningState state =
-        new InliningState(function, returnElement, returnType, elements, stack);
 
     // TODO(kasperl): Bad smell. We shouldn't be constructing elements here.
     returnElement = new ElementX(const SourceString("result"),
@@ -1063,6 +1062,7 @@
     assert(stack.length == 1);
     state.oldStack.add(stack[0]);
     stack = state.oldStack;
+    localsHandler = state.oldLocalsHandler;
   }
 
   /**
@@ -1073,6 +1073,12 @@
                        Selector selector,
                        Link<Node> arguments,
                        Node currentNode) {
+    // We cannot inline a method from a deferred library into a method
+    // which isn't deferred.
+    // TODO(ahe): But we should still inline into the same
+    // connected-component of the deferred library.
+    if (compiler.deferredLoadTask.isDeferred(element)) return false;
+
     if (compiler.disableInlining) return false;
     // Ensure that [element] is an implementation element.
     element = element.implementation;
@@ -2322,9 +2328,7 @@
           buildInvokeDynamic(send, selector, left, [right]),
           op);
     if (op.source.stringValue == '!=') {
-      HBoolify bl = new HBoolify(pop());
-      add(bl);
-      pushWithPosition(new HNot(bl), op);
+      pushWithPosition(new HNot(popBoolified()), op);
     }
   }
 
@@ -2367,22 +2371,23 @@
     Set<ClassElement> interceptedClasses = getInterceptedClassesOn(selector);
 
     bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector);
+    HInstruction instruction;
     if (interceptedClasses != null) {
       // If we're using an interceptor class, emit a call to the
       // interceptor method and then the actual dynamic call on the
       // interceptor object.
-      HInstruction instruction =
+      instruction =
           invokeInterceptor(interceptedClasses, receiver, send);
       instruction = new HInvokeDynamicGetter(
           selector, null, instruction, !hasGetter);
       // Add the receiver as an argument to the getter call on the
       // interceptor.
       instruction.inputs.add(receiver);
-      pushWithPosition(instruction, send);
     } else {
-      pushWithPosition(
-          new HInvokeDynamicGetter(selector, null, receiver, !hasGetter), send);
+      instruction = new HInvokeDynamicGetter(
+          selector, null, receiver, !hasGetter);
     }
+    pushWithPosition(instruction, send);
   }
 
   void generateGetter(Send send, Element element) {
@@ -2655,8 +2660,7 @@
 
         void argumentsCheck() {
           HInstruction typeInfo = getRuntimeTypeInfo(expression);
-          Element helper =
-              compiler.findHelper(const SourceString('checkArguments'));
+          Element helper = backend.getCheckArguments();
           HInstruction helperCall = new HStatic(helper);
           add(helperCall);
           List<HInstruction> representations =
@@ -2789,26 +2793,28 @@
     }
   }
 
-  visitDynamicSend(Send node) {
+  bool isThisSend(Send send) {
+    Node receiver = send.receiver;
+    if (receiver == null) return true;
+    Identifier identifier = receiver.asIdentifier();
+    return identifier != null && identifier.isThis();
+  }
+
+  visitDynamicSend(Send node, {bool inline: true}) {
     Selector selector = elements.getSelector(node);
 
-    SourceString dartMethodName;
-    bool isNotEquals = false;
-    if (node.isIndex && !node.arguments.tail.isEmpty) {
-      dartMethodName = Elements.constructOperatorName(
-          const SourceString('[]='), false);
-    } else if (node.selector.asOperator() != null) {
-      SourceString name = node.selector.asIdentifier().source;
-      isNotEquals = identical(name.stringValue, '!=');
-      dartMethodName = Elements.constructOperatorName(
-          name, node.argumentsNode is Prefix);
-    } else {
-      dartMethodName = node.selector.asIdentifier().source;
+    // TODO(kasperl): It would be much better to try to get the
+    // guaranteed type of the receiver after we've evaluated it, but
+    // because of the way inlining currently works that is hard to do
+    // with re-evaluating the receiver.
+    if (isThisSend(node)) {
+      HType receiverType = localsHandler.getTypeOfThis();
+      selector = receiverType.refine(selector, compiler);
     }
 
-    Element element = elements[node];
+    Element element = compiler.world.locateSingleElement(selector);
     bool isClosureCall = false;
-    if (element != null && compiler.world.hasNoOverridingMember(element)) {
+    if (inline && element != null) {
       if (tryInlineMethod(element, selector, node.arguments, node)) {
         if (element.isGetter()) {
           // If the element is a getter, we are doing a closure call
@@ -2845,11 +2851,6 @@
     }
 
     pushWithPosition(invoke, node);
-
-    if (isNotEquals) {
-      HNot not = new HNot(popBoolified());
-      push(not);
-    }
   }
 
   visitClosureSend(Send node) {
@@ -2887,7 +2888,7 @@
 
     native.NativeBehavior nativeBehavior =
         compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
-    HType ssaType = mapNativeBehaviorType(nativeBehavior);
+    HType ssaType = new HType.fromNativeBehavior(nativeBehavior, compiler);
     if (code is StringNode) {
       StringNode codeString = code;
       if (!codeString.isInterpolation) {
@@ -3069,8 +3070,7 @@
     Constant internalNameConstant =
         constantSystem.createString(new DartString.literal(internalName), node);
 
-    Element createInvocationMirror =
-        compiler.findHelper(Compiler.CREATE_INVOCATION_MIRROR);
+    Element createInvocationMirror = backend.getCreateInvocationMirror();
 
     var arguments = new List<HInstruction>();
     if (node.argumentsNode != null) {
@@ -3375,7 +3375,7 @@
       }
 
       HInvokeStatic instruction = new HInvokeStatic(inputs, HType.UNKNOWN);
-      HType returnType = getGuaranteedTypeOfElement(element);
+      HType returnType = new HType.inferredForElement(element, compiler);
       if (returnType.isUnknown()) {
         // TODO(ngeoffray): Only do this if knowing the return type is
         // useful.
@@ -3383,7 +3383,7 @@
             builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange(
                 currentElement, element);
       }
-      if (returnType != null) instruction.guaranteedType = returnType;
+      if (returnType != null) instruction.instructionType = returnType;
       pushWithPosition(instruction, node);
     } else {
       generateGetter(node, element);
@@ -3456,8 +3456,7 @@
                                  {Link<Node> argumentNodes,
                                   List<HInstruction> argumentValues,
                                   List<String> existingArguments}) {
-    Element helper =
-        compiler.findHelper(const SourceString('throwNoSuchMethod'));
+    Element helper = backend.getThrowNoSuchMethod();
     Constant receiverConstant =
         constantSystem.createString(new DartString.empty(), diagnosticNode);
     HInstruction receiver = graph.addConstant(receiverConstant);
@@ -3574,14 +3573,7 @@
     }
     inputs.add(receiver);
     inputs.addAll(arguments);
-    HInstruction invoke = new HInvokeDynamicMethod(
-        selector, inputs, isIntercepted);
-    HType returnType = mapInferredType(
-        compiler.typesTask.getGuaranteedTypeOfNode(work.element, node));
-    if (returnType != null) {
-      invoke.guaranteedType = returnType;
-    }
-    return invoke;
+    return new HInvokeDynamicMethod(selector, inputs, isIntercepted);
   }
 
   visitSendSet(SendSet node) {
@@ -3594,7 +3586,9 @@
     }
     Operator op = node.assignmentOperator;
     if (node.isSuperCall) {
-      if (element == null) return generateSuperNoSuchMethodSend(node);
+      if (Elements.isUnresolved(element)) {
+        return generateSuperNoSuchMethodSend(node);
+      }
       HInstruction target = new HStatic(element);
       HInstruction context = localsHandler.readThis();
       add(target);
@@ -3607,7 +3601,9 @@
       push(new HInvokeSuper(inputs, isSetter: true));
     } else if (node.isIndex) {
       if (const SourceString("=") == op.source) {
-        visitDynamicSend(node);
+        // TODO(kasperl): We temporarily disable inlining because the
+        // code here cannot deal with it yet.
+        visitDynamicSend(node, inline: false);
         HInvokeDynamicMethod method = pop();
         // Push the value.
         stack.add(method.inputs.last);
@@ -3620,7 +3616,6 @@
         // Compound assignments are considered as being prefix.
         bool isCompoundAssignment = op.source.stringValue.endsWith('=');
         bool isPrefix = !node.isPostfix;
-        Element getter = elements[node.selector];
         if (isCompoundAssignment) {
           value = pop();
           index = pop();
@@ -3644,7 +3639,6 @@
         }
       }
     } else if (const SourceString("=") == op.source) {
-      Element element = elements[node];
       Link<Node> link = node.arguments;
       assert(!link.isEmpty && link.tail.isEmpty);
       visit(link.head);
@@ -3656,13 +3650,11 @@
       assert(const SourceString("++") == op.source ||
              const SourceString("--") == op.source ||
              node.assignmentOperator.source.stringValue.endsWith("="));
-      Element element = elements[node];
       bool isCompoundAssignment = !node.arguments.isEmpty;
       bool isPrefix = !node.isPostfix;  // Compound assignments are prefix.
 
       // [receiver] is only used if the node is an instance send.
       HInstruction receiver = null;
-      Element selectorElement = elements[node];
       if (Elements.isInstanceSend(node, elements)) {
         receiver = generateInstanceSendReceiver(node);
         generateInstanceGetterWithCompiledReceiver(node, receiver);
@@ -3932,12 +3924,12 @@
       bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector);
       if (interceptedClasses == null) {
         iterator =
-            new HInvokeDynamicGetter(selector, null, receiver, hasGetter);
+            new HInvokeDynamicGetter(selector, null, receiver, !hasGetter);
       } else {
         HInterceptor interceptor =
             invokeInterceptor(interceptedClasses, receiver, null);
         iterator =
-            new HInvokeDynamicGetter(selector, null, interceptor, hasGetter);
+            new HInvokeDynamicGetter(selector, null, interceptor, !hasGetter);
         // Add the receiver as an argument to the getter call on the
         // interceptor.
         iterator.inputs.add(receiver);
@@ -3948,7 +3940,6 @@
       SourceString name = const SourceString('moveNext');
       Selector selector = new Selector.call(
           name, currentElement.getLibrary(), 0);
-      bool hasGetter = compiler.world.hasAnyUserDefinedGetter(selector);
       push(new HInvokeDynamicMethod(selector, <HInstruction>[iterator]));
       return popBoolified();
     }
@@ -3956,7 +3947,7 @@
       SourceString name = const SourceString('current');
       Selector call = new Selector.getter(name, currentElement.getLibrary());
       bool hasGetter = compiler.world.hasAnyUserDefinedGetter(call);
-      push(new HInvokeDynamicGetter(call, null, iterator, hasGetter));
+      push(new HInvokeDynamicGetter(call, null, iterator, !hasGetter));
 
       Element variable;
       if (node.declaredIdentifier.asSend() != null) {
@@ -4186,8 +4177,7 @@
     List<List<Constant>> matchExpressions = <List<Constant>>[];
     List<HStatementInformation> statements = <HStatementInformation>[];
     bool hasDefault = false;
-    Element getFallThroughErrorElement =
-        compiler.findHelper(const SourceString("getFallThroughError"));
+    Element getFallThroughErrorElement = backend.getFallThroughError();
     HasNextIterator<Node> caseIterator =
         new HasNextIterator<Node>(node.cases.iterator);
     while (caseIterator.hasNext) {
@@ -4480,14 +4470,19 @@
         if (catchBlock.onKeyword != null) {
           DartType type = elements.getType(catchBlock.type);
           if (type == null) {
-            compiler.cancel('On with unresolved type',
-                            node: catchBlock.type);
+            compiler.internalError('On with no type', node: catchBlock.type);
           }
-          HInstruction condition =
-              new HIs(type, <HInstruction>[unwrappedException]);
-          push(condition);
-        }
-        else {
+          if (type.isMalformed) {
+            // TODO(johnniwinther): Handle malformed types in [HIs] instead.
+            HInstruction condition =
+                graph.addConstantBool(true, constantSystem);
+            stack.add(condition);
+          } else {
+            HInstruction condition =
+                new HIs(type, <HInstruction>[unwrappedException]);
+            push(condition);
+          }
+        } else {
           VariableDefinitions declaration = catchBlock.formals.nodes.head;
           HInstruction condition = null;
           if (declaration.type == null) {
@@ -4512,6 +4507,21 @@
       void visitThen() {
         CatchBlock catchBlock = link.head;
         link = link.tail;
+
+        if (compiler.enableTypeAssertions) {
+          // In checked mode: throw a type error if the on-catch type is
+          // malformed.
+          if (catchBlock.onKeyword != null) {
+            DartType type = elements.getType(catchBlock.type);
+            if (type != null && type.isMalformed) {
+              String reasons = Types.fetchReasonsFromMalformedType(type);
+              generateMalformedSubtypeError(node,
+                  unwrappedException, type, reasons);
+              pop();
+              return;
+            }
+          }
+        }
         if (catchBlock.exception != null) {
           localsHandler.updateLocal(elements[catchBlock.exception],
                                     unwrappedException);
@@ -4639,64 +4649,6 @@
   visitTypeVariable(TypeVariable node) {
     compiler.internalError('SsaBuilder.visitTypeVariable');
   }
-
-  HType mapBaseType(BaseType baseType) {
-    if (!baseType.isClass()) return HType.UNKNOWN;
-    ClassBaseType classBaseType = baseType;
-    ClassElement cls = classBaseType.element;
-    // Special case the list and map classes that are used as types
-    // for literals in the type inferrer.
-    if (cls == compiler.listClass) {
-      return HType.READABLE_ARRAY;
-    } else if (cls == compiler.mapClass) {
-      // TODO(ngeoffray): get the actual implementation of a map
-      // literal.
-      return new HType.nonNullSubtype(
-          compiler.mapLiteralClass.computeType(compiler), compiler);
-    } else {
-      return new HType.nonNullExactClass(
-          cls.computeType(compiler), compiler);
-    }
-  }
-
-  HType mapInferredType(ConcreteType concreteType) {
-    if (concreteType == null) return HType.UNKNOWN;
-    HType ssaType = HType.CONFLICTING;
-    for (BaseType baseType in concreteType.baseTypes) {
-      ssaType = ssaType.union(mapBaseType(baseType), compiler);
-    }
-    if (ssaType.isConflicting()) return HType.UNKNOWN;
-    return ssaType;
-  }
-
-  HType getGuaranteedTypeOfElement(Element element) {
-    return mapInferredType(
-        compiler.typesTask.getGuaranteedTypeOfElement(element));
-  }
-
-  // [type] is either an instance of [DartType] or special objects
-  // like [native.SpecialType.JsObject], or [native.SpecialType.JsArray].
-  HType mapNativeType(type) {
-    if (type == native.SpecialType.JsObject) {
-      return new HType.nonNullExactClass(
-          compiler.objectClass.computeType(compiler), compiler);
-    } else if (type == native.SpecialType.JsArray) {
-      return HType.READABLE_ARRAY;
-    } else {
-      return new HType.nonNullSubclass(type, compiler);
-    }
-  }
-
-  HType mapNativeBehaviorType(native.NativeBehavior nativeBehavior) {
-    if (nativeBehavior.typesInstantiated.isEmpty) return HType.UNKNOWN;
-
-    HType ssaType = HType.CONFLICTING;
-    for (final type in nativeBehavior.typesInstantiated) {
-      ssaType = ssaType.union(mapNativeType(type), compiler);
-    }
-    assert(!ssaType.isConflicting());
-    return ssaType;
-  }
 }
 
 /**
@@ -4838,12 +4790,14 @@
   final DartType oldReturnType;
   final TreeElements oldElements;
   final List<HInstruction> oldStack;
+  final LocalsHandler oldLocalsHandler;
 
   InliningState(this.function,
                 this.oldReturnElement,
                 this.oldReturnType,
                 this.oldElements,
-                this.oldStack) {
+                this.oldStack,
+                this.oldLocalsHandler) {
     assert(function.isImplementation);
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index def1a12..527ce59 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -162,7 +162,6 @@
 
   final JavaScriptBackend backend;
   final CodegenWorkItem work;
-  final HTypeMap types;
 
   final Set<HInstruction> generateAtUseSite;
   final Set<HInstruction> controlFlowOperators;
@@ -207,8 +206,6 @@
 
   SsaCodeGenerator(this.backend, CodegenWorkItem work)
     : this.work = work,
-      this.types =
-          (work.compilationContext as JavaScriptItemCompilationContext).types,
       declaredLocals = new Set<String>(),
       collectedVariableDeclarations = new OrderedSet<String>(),
       currentContainer = new js.Block.empty(),
@@ -338,9 +335,9 @@
   endLabeledBlock(HLabeledBlockInformation labeledBlockInfo);
 
   void preGenerateMethod(HGraph graph) {
-    new SsaInstructionMerger(types, generateAtUseSite).visitGraph(graph);
+    new SsaInstructionMerger(generateAtUseSite).visitGraph(graph);
     new SsaConditionMerger(
-        types, generateAtUseSite, controlFlowOperators).visitGraph(graph);
+        generateAtUseSite, controlFlowOperators).visitGraph(graph);
     SsaLiveIntervalBuilder intervalBuilder =
         new SsaLiveIntervalBuilder(compiler, generateAtUseSite);
     intervalBuilder.visitGraph(graph);
@@ -361,7 +358,8 @@
       HInstruction last = block.last;
       assert(last is HGoto || last is HReturn);
       if (last is HReturn) {
-        backend.registerReturnType(work.element, types[last.inputs[0]]);
+        backend.registerReturnType(
+            work.element, last.inputs[0].instructionType);
       } else {
         backend.registerReturnType(work.element, HType.NULL);
       }
@@ -1269,13 +1267,15 @@
     }
   }
 
-  void emitIdentityComparison(HInstruction left, HInstruction right) {
-    String op = singleIdentityComparison(left, right, types);
+  void emitIdentityComparison(HInstruction left,
+                              HInstruction right,
+                              bool inverse) {
+    String op = singleIdentityComparison(left, right);
     if (op != null) {
       use(left);
       js.Expression jsLeft = pop();
       use(right);
-      push(new js.Binary(op, jsLeft, pop()));
+      push(new js.Binary(mapRelationalOperator(op, inverse), jsLeft, pop()));
     } else {
       assert(NullConstant.JsNull == 'null');
       use(left);
@@ -1283,17 +1283,19 @@
           new js.Binary("==", pop(), new js.LiteralNull());
       use(right);
       js.Binary rightEqualsNull =
-          new js.Binary("==", pop(), new js.LiteralNull());
+          new js.Binary(mapRelationalOperator("==", inverse),
+                        pop(), new js.LiteralNull());
       use(right);
       use(left);
-      js.Binary tripleEq = new js.Binary("===", pop(), pop());
+      js.Binary tripleEq = new js.Binary(mapRelationalOperator("===", inverse),
+                                         pop(), pop());
 
       push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq));
     }
   }
 
   visitIdentity(HIdentity node) {
-    emitIdentityComparison(node.left, node.right);
+    emitIdentityComparison(node.left, node.right, false);
   }
 
   visitAdd(HAdd node)               => visitInvokeBinary(node, '+');
@@ -1566,11 +1568,9 @@
   void visitOneShotInterceptor(HOneShotInterceptor node) {
     List<js.Expression> arguments = visitArguments(node.inputs);
     var isolate = new js.VariableUse(backend.namer.CURRENT_ISOLATE);
-    Selector selector = node.selector;
-    String methodName = backend.namer.oneShotInterceptorName(selector);
+    Selector selector = getOptimizedSelectorFor(node, node.selector);
+    String methodName = backend.registerOneShotInterceptor(selector);
     push(jsPropertyCall(isolate, methodName, arguments), node);
-    backend.registerSpecializedGetInterceptor(node.interceptedClasses);
-    backend.addOneShotInterceptor(selector);
     if (selector.isGetter()) {
       registerGetter(node);
     } else if (selector.isSetter()) {
@@ -1580,51 +1580,35 @@
     }
   }
 
-  Selector getOptimizedSelectorFor(HInvokeDynamic node,
-                                   Selector defaultSelector) {
+  Selector getOptimizedSelectorFor(HInvokeDynamic node, Selector selector) {
     // If [JSInvocationMirror.invokeOn] has been called, we must not create a
     // typed selector based on the receiver type.
     if (node.element == null && // Invocation is not exact.
         backend.compiler.enabledInvokeOn) {
-      return defaultSelector;
+      return selector;
     }
     int receiverIndex = node.isInterceptorCall ? 1 : 0;
-    HType receiverHType = types[node.inputs[receiverIndex]];
-    DartType receiverType = receiverHType.computeType(compiler);
-    if (receiverType != null && !receiverType.isMalformed) {
-      if (receiverHType.isExact()) {
-        return new TypedSelector.exact(receiverType, defaultSelector);
-      } else if (receiverHType.isInterfaceType()) {
-        return new TypedSelector.subtype(receiverType, defaultSelector);
-      } else {
-        return new TypedSelector.subclass(receiverType, defaultSelector);
-      }
-    } else {
-      return defaultSelector;
-    }
+    HType receiverType = node.inputs[receiverIndex].instructionType;
+    return receiverType.refine(selector, compiler);
   }
 
-  void registerInvoke(HInvokeDynamic node) {
+  void registerInvoke(HInvokeDynamic node, Selector selector) {
     bool inLoop = node.block.enclosingLoopHeader != null;
-    SourceString name = node.selector.name;
     if (inLoop) {
-      Element target = node.element;
-      if (target != null) {
-        backend.builder.functionsCalledInLoop.add(target);
-      } else {
-        backend.builder.selectorsCalledInLoop[name] = node.selector;
-      }
+      Set<Selector> selectors = backend.selectorsCalledInLoop.putIfAbsent(
+          selector.name, () => new Set<Selector>());
+      selectors.add(selector);
     }
 
     if (node.isInterceptorCall) {
-      backend.addInterceptedSelector(node.selector);
+      backend.addInterceptedSelector(selector);
     }
   }
 
   void registerMethodInvoke(HInvokeDynamic node) {
     Selector selector = getOptimizedSelectorFor(node, node.selector);
     // Register this invocation to collect the types used at all call sites.
-    backend.registerDynamicInvocation(node, selector, types);
+    backend.registerDynamicInvocation(node, selector);
 
     // If we don't know what we're calling or if we are calling a getter,
     // we need to register that fact that we may be calling a closure
@@ -1647,39 +1631,36 @@
       SourceString name = node.selector.name;
       world.registerDynamicInvocation(name, selector);
     }
-    registerInvoke(node);
+    registerInvoke(node, selector);
   }
 
   void registerSetter(HInvokeDynamic node) {
     Selector selector = getOptimizedSelectorFor(node, node.selector);
     world.registerDynamicSetter(selector.name, selector);
     HType valueType = node.isInterceptorCall
-        ? types[node.inputs[2]]
-        : types[node.inputs[1]];
+        ? node.inputs[2].instructionType
+        : node.inputs[1].instructionType;
     backend.addedDynamicSetter(selector, valueType);
-    registerInvoke(node);
+    registerInvoke(node, selector);
   }
 
   void registerGetter(HInvokeDynamic node) {
-    Selector getter = node.selector;
-    world.registerDynamicGetter(
-        getter.name, getOptimizedSelectorFor(node, getter));
+    Selector selector = getOptimizedSelectorFor(node, node.selector);
+    world.registerDynamicGetter(selector.name, selector);
     world.registerInstantiatedClass(compiler.functionClass);
-    registerInvoke(node);
+    registerInvoke(node, selector);
   }
 
   visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
     use(node.receiver);
-    Selector setter = node.selector;
-    String name = backend.namer.invocationName(setter);
+    String name = backend.namer.invocationName(node.selector);
     push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node);
     registerSetter(node);
   }
 
   visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
     use(node.receiver);
-    Selector getter = node.selector;
-    String name = backend.namer.invocationName(getter);
+    String name = backend.namer.invocationName(node.selector);
     push(jsPropertyCall(pop(), name, visitArguments(node.inputs)), node);
     registerGetter(node);
   }
@@ -1697,7 +1678,7 @@
   visitInvokeStatic(HInvokeStatic node) {
     if (node.typeCode() == HInstruction.INVOKE_STATIC_TYPECODE) {
       // Register this invocation to collect the types used at all call sites.
-      backend.registerStaticInvocation(node, types);
+      backend.registerStaticInvocation(node);
     }
     use(node.target);
     push(new js.Call(pop(), visitArguments(node.inputs)), node);
@@ -1748,7 +1729,7 @@
     } else {
       String name = _fieldPropertyName(element);
       push(new js.PropertyAccess.field(pop(), name), node);
-      DartType type = types[node.receiver].computeType(compiler);
+      DartType type = node.receiver.instructionType.computeType(compiler);
       if (type != null && !identical(type.kind, TypeKind.MALFORMED_TYPE)) {
         world.registerFieldGetter(element);
       }
@@ -1758,13 +1739,14 @@
   visitFieldSet(HFieldSet node) {
     Element element = node.element;
     String name = _fieldPropertyName(element);
-    DartType type = types[node.receiver].computeType(compiler);
+    DartType type = node.receiver.instructionType.computeType(compiler);
     if (type != null && !identical(type.kind, TypeKind.MALFORMED_TYPE)) {
       // Field setters in the generative constructor body are handled in a
       // step "SsaConstructionFieldTypes" in the ssa optimizer.
       if (!work.element.isGenerativeConstructorBody()) {
         world.registerFieldSetter(element);
-        backend.registerFieldSetter(work.element, element, types[node.value]);
+        backend.registerFieldSetter(
+            work.element, element, node.value.instructionType);
       }
     }
     use(node.receiver);
@@ -1813,7 +1795,7 @@
       }
       push(new js.LiteralExpression.withData(code, data), node);
     }
-    registerForeignType(types[node]);
+    registerForeignType(node.instructionType);
     // TODO(sra): Tell world.nativeEnqueuer about the types created here.
   }
 
@@ -1829,7 +1811,7 @@
     // TODO(floitsch): jsClassReference is an Access. We shouldn't treat it
     // as if it was a string.
     push(new js.New(new js.VariableUse(jsClassReference), arguments), node);
-    registerForeignType(types[node]);
+    registerForeignType(node.instructionType);
   }
 
   js.Expression newLiteralBool(bool value) {
@@ -1866,6 +1848,20 @@
     attachLocationToLast(node);
   }
 
+  static String mapRelationalOperator(String op, bool inverse) {
+    Map<String, String> inverseOperator = const <String, String>{
+      "==" : "!=",
+      "!=" : "==",
+      "===": "!==",
+      "!==": "===",
+      "<"  : ">=",
+      "<=" : ">",
+      ">"  : "<=",
+      ">=" : "<"
+    };
+    return inverse ? inverseOperator[op] : op;
+  }
+
   void generateNot(HInstruction input) {
     bool canGenerateOptimizedComparison(HInstruction instruction) {
       if (instruction is !HRelational) return false;
@@ -1874,28 +1870,21 @@
       HInstruction right = relational.right;
       // This optimization doesn't work for NaN, so we only do it if the
       // type is known to be an integer.
-      return types[left].isUseful() && left.isInteger(types)
-          && types[right].isUseful() && right.isInteger(types);
+      return left.instructionType.isUseful() && left.isInteger()
+          && right.instructionType.isUseful() && right.isInteger();
     }
 
-    if (input is HBoolify && isGenerateAtUseSite(input)) {
+    bool generateAtUseSite = isGenerateAtUseSite(input);
+    if (input is HIdentity && generateAtUseSite) {
+      emitIdentityComparison(input.left, input.right, true);
+    } else if (input is HBoolify && generateAtUseSite) {
       use(input.inputs[0]);
       push(new js.Binary("!==", pop(), newLiteralBool(true)), input);
-    } else if (canGenerateOptimizedComparison(input) &&
-               isGenerateAtUseSite(input)) {
-      Map<String, String> inverseOperator = const <String, String>{
-        "==" : "!=",
-        "!=" : "==",
-        "===": "!==",
-        "!==": "===",
-        "<"  : ">=",
-        "<=" : ">",
-        ">"  : "<=",
-        ">=" : "<"
-      };
+    } else if (canGenerateOptimizedComparison(input) && generateAtUseSite) {
       HRelational relational = input;
       BinaryOperation operation = relational.operation(backend.constantSystem);
-      visitRelational(input, inverseOperator[operation.name.stringValue]);
+      String op = mapRelationalOperator(operation.name.stringValue, true);
+      visitRelational(input, op);
     } else {
       use(input);
       push(new js.Prefix("!", pop()));
@@ -2113,10 +2102,10 @@
   }
 
   void useStringified(HInstruction node) {
-    if (node.isString(types)) {
+    if (node.isString()) {
       use(node);
     } else {
-      Element convertToString = compiler.findHelper(const SourceString("S"));
+      Element convertToString = backend.getStringInterpolationHelper();
       world.registerStaticUse(convertToString);
       js.VariableUse variableUse =
           new js.VariableUse(backend.namer.isolateAccess(convertToString));
@@ -2376,7 +2365,8 @@
       checkType(input, type);
       push(new js.Binary('&&', nullTest, pop()));
       attachLocationToLast(node);
-    } else if (types[input].canBePrimitive() || types[input].canBeNull()) {
+    } else if (input.instructionType.canBePrimitive()
+               || input.instructionType.canBeNull()) {
       checkObject(input, '===');
       js.Expression objectTest = pop();
       checkType(input, type);
@@ -2391,47 +2381,9 @@
     }
   }
 
-  // TODO(johnniwinther): Refactor this method.
   void visitTypeConversion(HTypeConversion node) {
-    Map<String, SourceString> castNames = const <String, SourceString> {
-      "stringTypeCheck":
-          const SourceString("stringTypeCast"),
-      "doubleTypeCheck":
-          const SourceString("doubleTypeCast"),
-      "numTypeCheck":
-          const SourceString("numTypeCast"),
-      "boolTypeCheck":
-          const SourceString("boolTypeCast"),
-      "functionTypeCheck":
-          const SourceString("functionTypeCast"),
-      "intTypeCheck":
-          const SourceString("intTypeCast"),
-      "numberOrStringSuperNativeTypeCheck":
-          const SourceString("numberOrStringSuperNativeTypeCast"),
-      "numberOrStringSuperTypeCheck":
-          const SourceString("numberOrStringSuperTypeCast"),
-      "stringSuperNativeTypeCheck":
-          const SourceString("stringSuperNativeTypeCast"),
-      "stringSuperTypeCheck":
-          const SourceString("stringSuperTypeCast"),
-      "listTypeCheck":
-          const SourceString("listTypeCast"),
-      "listSuperNativeTypeCheck":
-          const SourceString("listSuperNativeTypeCast"),
-      "listSuperTypeCheck":
-          const SourceString("listSuperTypeCast"),
-      "callTypeCheck":
-          const SourceString("callTypeCast"),
-      "propertyTypeCheck":
-          const SourceString("propertyTypeCast"),
-      // TODO(johnniwinther): Add a malformedTypeCast which produces a TypeError
-      // with another message.
-      "malformedTypeCheck":
-          const SourceString("malformedTypeCheck")
-    };
-
     if (node.isChecked) {
-      DartType type = node.type.computeType(compiler);
+      DartType type = node.instructionType.computeType(compiler);
       Element element = type.element;
       world.registerIsCheck(type);
 
@@ -2454,22 +2406,22 @@
       }
       assert(node.isCheckedModeCheck || node.isCastTypeCheck);
 
-      SourceString helper;
+      FunctionElement helperElement;
       if (node.isBooleanConversionCheck) {
-        helper = const SourceString('boolConversionCheck');
+        helperElement =
+            compiler.findHelper(const SourceString('boolConversionCheck'));
       } else {
-        helper = backend.getCheckedModeHelper(type);
-        if (node.isCastTypeCheck) {
-          helper = castNames[helper.stringValue];
-        }
+        helperElement = backend.getCheckedModeHelper(type,
+            typeCast: node.isCastTypeCheck);
       }
-      FunctionElement helperElement = compiler.findHelper(helper);
       world.registerStaticUse(helperElement);
       List<js.Expression> arguments = <js.Expression>[];
       use(node.checkedInput);
       arguments.add(pop());
       int parameterCount =
           helperElement.computeSignature(compiler).parameterCount;
+      // TODO(johnniwinther): Refactor this to avoid using the parameter count
+      // to determine how the helper should be called.
       if (parameterCount == 2) {
         // 2 arguments implies that the method is either [propertyTypeCheck]
         // or [propertyTypeCast].
@@ -2549,27 +2501,27 @@
     HInstruction input = node.guarded;
     DartType indexingBehavior =
         backend.jsIndexingBehaviorInterface.computeType(compiler);
-    if (node.isInteger(types)) {
+    if (node.isInteger()) {
       // if (input is !int) bailout
       checkInt(input, '!==');
       js.Statement then = bailout(node, 'Not an integer');
       pushStatement(new js.If.noElse(pop(), then), node);
-    } else if (node.isNumber(types)) {
+    } else if (node.isNumber()) {
       // if (input is !num) bailout
       checkNum(input, '!==');
       js.Statement then = bailout(node, 'Not a number');
       pushStatement(new js.If.noElse(pop(), then), node);
-    } else if (node.isBoolean(types)) {
+    } else if (node.isBoolean()) {
       // if (input is !bool) bailout
       checkBool(input, '!==');
       js.Statement then = bailout(node, 'Not a boolean');
       pushStatement(new js.If.noElse(pop(), then), node);
-    } else if (node.isString(types)) {
+    } else if (node.isString()) {
       // if (input is !string) bailout
       checkString(input, '!==');
       js.Statement then = bailout(node, 'Not a string');
       pushStatement(new js.If.noElse(pop(), then), node);
-    } else if (node.isExtendableArray(types)) {
+    } else if (node.isExtendableArray()) {
       // if (input is !Object || input is !Array || input.isFixed) bailout
       checkObject(input, '!==');
       js.Expression objectTest = pop();
@@ -2580,7 +2532,7 @@
       test = new js.Binary('||', test, pop());
       js.Statement then = bailout(node, 'Not an extendable array');
       pushStatement(new js.If.noElse(test, then), node);
-    } else if (node.isMutableArray(types)) {
+    } else if (node.isMutableArray()) {
       // if (input is !Object
       //     || ((input is !Array || input.isImmutable)
       //         && input is !JsIndexingBehavior)) bailout
@@ -2595,7 +2547,7 @@
       js.Binary test = new js.Binary('||', objectTest, notIndexing);
       js.Statement then = bailout(node, 'Not a mutable array');
       pushStatement(new js.If.noElse(test, then), node);
-    } else if (node.isReadableArray(types)) {
+    } else if (node.isReadableArray()) {
       // if (input is !Object
       //     || (input is !Array && input is !JsIndexingBehavior)) bailout
       checkObject(input, '!==');
@@ -2607,7 +2559,7 @@
       js.Binary test = new js.Binary('||', objectTest, notIndexing);
       js.Statement then = bailout(node, 'Not an array');
       pushStatement(new js.If.noElse(test, then), node);
-    } else if (node.isIndexablePrimitive(types)) {
+    } else if (node.isIndexablePrimitive()) {
       // if (input is !String
       //     && (input is !Object
       //         || (input is !Array && input is !JsIndexingBehavior))) bailout
@@ -3001,15 +2953,13 @@
   }
 }
 
-String singleIdentityComparison(HInstruction left,
-                                HInstruction right,
-                                HTypeMap propagatedTypes) {
+String singleIdentityComparison(HInstruction left, HInstruction right) {
   // Returns the single identity comparison (== or ===) or null if a more
   // complex expression is required.
   if ((left.isConstant() && left.isConstantSentinel()) ||
       (right.isConstant() && right.isConstantSentinel())) return '===';
-  HType leftType = propagatedTypes[left];
-  HType rightType = propagatedTypes[right];
+  HType leftType = left.instructionType;
+  HType rightType = right.instructionType;
   if (leftType.canBeNull() && rightType.canBeNull()) {
     if (left.isConstantNull() || right.isConstantNull() ||
         (leftType.isPrimitive() && leftType == rightType)) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
index 625eafb..fac0952 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
@@ -15,7 +15,6 @@
  *   t2 = add(4, 3);
  */
 class SsaInstructionMerger extends HBaseVisitor {
-  HTypeMap types;
   /**
    * List of [HInstruction] that the instruction merger expects in
    * order when visiting the inputs of an instruction.
@@ -34,7 +33,7 @@
     generateAtUseSite.add(instruction);
   }
 
-  SsaInstructionMerger(this.types, this.generateAtUseSite);
+  SsaInstructionMerger(this.generateAtUseSite);
 
   void visitGraph(HGraph graph) {
     visitDominatorTree(graph);
@@ -100,7 +99,7 @@
   void visitIdentity(HIdentity instruction) {
     HInstruction left = instruction.left;
     HInstruction right = instruction.right;
-    if (singleIdentityComparison(left, right, types) != null) {
+    if (singleIdentityComparison(left, right) != null) {
       super.visitIdentity(instruction);
     }
     // Do nothing.
@@ -215,7 +214,6 @@
  *  using these operators instead of nested ifs and boolean variables.
  */
 class SsaConditionMerger extends HGraphVisitor {
-  final HTypeMap types;
   Set<HInstruction> generateAtUseSite;
   Set<HInstruction> controlFlowOperators;
 
@@ -224,9 +222,7 @@
     generateAtUseSite.add(instruction);
   }
 
-  SsaConditionMerger(this.types,
-                     this.generateAtUseSite,
-                     this.controlFlowOperators);
+  SsaConditionMerger(this.generateAtUseSite, this.controlFlowOperators);
 
   void visitGraph(HGraph graph) {
     visitPostDominatorTree(graph);
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 375f617..234e7ab 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
@@ -15,19 +15,16 @@
 
   HType computeDesiredTypeForInput(HInvokeDynamic instruction,
                                    HInstruction input,
-                                   HTypeMap types,
                                    Compiler compiler) {
     return HType.UNKNOWN;
   }
 
   HType computeTypeFromInputTypes(HInvokeDynamic instruction,
-                                  HTypeMap types,
                                   Compiler compiler) {
-    return HType.UNKNOWN;
+    return instruction.instructionType;
   }
 
-  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
-                                   HTypeMap types) {
+  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) {
     return null;
   }
 
@@ -86,11 +83,10 @@
 
   HType computeDesiredTypeForInput(HInvokeDynamic instruction,
                                    HInstruction input,
-                                   HTypeMap types,
                                    Compiler compiler) {
     HInstruction index = instruction.inputs[2];
     if (input == instruction.inputs[1] &&
-        (index.isTypeUnknown(types) || index.isNumber(types))) {
+        (index.isTypeUnknown() || index.isNumber())) {
       return HType.MUTABLE_ARRAY;
     }
     // The index should be an int when the receiver is a string or array.
@@ -100,9 +96,8 @@
     return HType.UNKNOWN;
   }
 
-  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
-                                   HTypeMap types) {
-    if (instruction.inputs[1].isMutableArray(types)) {
+  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) {
+    if (instruction.inputs[1].isMutableArray()) {
       return new HIndexAssign(instruction.inputs[1],
                               instruction.inputs[2],
                               instruction.inputs[3]);
@@ -116,11 +111,10 @@
 
   HType computeDesiredTypeForInput(HInvokeDynamic instruction,
                                    HInstruction input,
-                                   HTypeMap types,
                                    Compiler compiler) {
     HInstruction index = instruction.inputs[2];
     if (input == instruction.inputs[1] &&
-        (index.isTypeUnknown(types) || index.isNumber(types))) {
+        (index.isTypeUnknown() || index.isNumber())) {
       return HType.INDEXABLE_PRIMITIVE;
     }
     // The index should be an int when the receiver is a string or array.
@@ -130,9 +124,8 @@
     return HType.UNKNOWN;
   }
 
-  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
-                                   HTypeMap types) {
-    if (instruction.inputs[1].isIndexablePrimitive(types)) {
+  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) {
+    if (instruction.inputs[1].isIndexablePrimitive()) {
       return new HIndex(instruction.inputs[1], instruction.inputs[2]);
     }
     return null;
@@ -148,10 +141,9 @@
 
   HType computeDesiredTypeForInput(HInvokeDynamic instruction,
                                    HInstruction input,
-                                   HTypeMap types,
                                    Compiler compiler) {
     if (input == instruction.inputs[1]) {
-      HType propagatedType = types[instruction];
+      HType propagatedType = instruction.instructionType;
       if (propagatedType.isUnknown() || propagatedType.isNumber()) {
         return HType.INTEGER;
       }
@@ -160,18 +152,16 @@
   }
 
   HType computeTypeFromInputTypes(HInvokeDynamic instruction,
-                                  HTypeMap types,
                                   Compiler compiler) {
     // All bitwise operations on primitive types either produce an
     // integer or throw an error.
-    if (instruction.inputs[1].isPrimitive(types)) return HType.INTEGER;
-    return HType.UNKNOWN;
+    if (instruction.inputs[1].isPrimitive()) return HType.INTEGER;
+    return instruction.instructionType;
   }
 
-  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
-                                   HTypeMap types) {
+  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) {
     HInstruction input = instruction.inputs[1];
-    if (input.isNumber(types)) return new HBitNot(input);
+    if (input.isNumber()) return new HBitNot(input);
     return null;
   }
 }
@@ -185,10 +175,9 @@
 
   HType computeDesiredTypeForInput(HInvokeDynamic instruction,
                                    HInstruction input,
-                                   HTypeMap types,
                                    Compiler compiler) {
     if (input == instruction.inputs[1]) {
-      HType propagatedType = types[instruction];
+      HType propagatedType = instruction.instructionType;
       // If the outgoing type should be a number (integer, double or both) we
       // want the outgoing type to be the input too.
       // If we don't know the outgoing type we try to make it a number.
@@ -199,17 +188,15 @@
   }
 
   HType computeTypeFromInputTypes(HInvokeDynamic instruction,
-                                  HTypeMap types,
                                   Compiler compiler) {
-    HType operandType = types[instruction.inputs[1]];
+    HType operandType = instruction.inputs[1].instructionType;
     if (operandType.isNumber()) return operandType;
-    return HType.UNKNOWN;
+    return instruction.instructionType;
   }
 
-  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
-                                   HTypeMap types) {
+  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) {
     HInstruction input = instruction.inputs[1];
-    if (input.isNumber(types)) return new HNegate(input);
+    if (input.isNumber()) return new HNegate(input);
     return null;
   }
 }
@@ -218,25 +205,23 @@
   const BinaryArithmeticSpecializer();
 
   HType computeTypeFromInputTypes(HInvokeDynamic instruction,
-                                  HTypeMap types,
                                   Compiler compiler) {
     HInstruction left = instruction.inputs[1];
     HInstruction right = instruction.inputs[2];
-    if (left.isInteger(types) && right.isInteger(types)) return HType.INTEGER;
-    if (left.isNumber(types)) {
-      if (left.isDouble(types) || right.isDouble(types)) return HType.DOUBLE;
+    if (left.isInteger() && right.isInteger()) return HType.INTEGER;
+    if (left.isNumber()) {
+      if (left.isDouble() || right.isDouble()) return HType.DOUBLE;
       return HType.NUMBER;
     }
-    return HType.UNKNOWN;
+    return instruction.instructionType;
   }
 
   HType computeDesiredTypeForInput(HInvokeDynamic instruction,
                                    HInstruction input,
-                                   HTypeMap types,
                                    Compiler compiler) {
     if (input == instruction.inputs[0]) return HType.UNKNOWN;
 
-    HType propagatedType = types[instruction];
+    HType propagatedType = instruction.instructionType;
     // If the desired output type should be an integer we want to get two
     // integers as arguments.
     if (propagatedType.isInteger()) return HType.INTEGER;
@@ -255,18 +240,17 @@
     // to the array case.
     HInstruction left = instruction.inputs[1];
     HInstruction right = instruction.inputs[2];
-    if (input == right && left.isNumber(types)) return HType.NUMBER;
+    if (input == right && left.isNumber()) return HType.NUMBER;
     return HType.UNKNOWN;
   }
 
-  bool isBuiltin(HInvokeDynamic instruction, HTypeMap types) {
-    return instruction.inputs[1].isNumber(types)
-        && instruction.inputs[2].isNumber(types);
+  bool isBuiltin(HInvokeDynamic instruction) {
+    return instruction.inputs[1].isNumber()
+        && instruction.inputs[2].isNumber();
   }
 
-  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
-                                   HTypeMap types) {
-    if (isBuiltin(instruction, types)) {
+  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) {
+    if (isBuiltin(instruction)) {
       HInstruction builtin =
           newBuiltinVariant(instruction.inputs[1], instruction.inputs[2]);
       if (builtin != null) return builtin;
@@ -303,22 +287,20 @@
   }
 
   HType computeTypeFromInputTypes(HInstruction instruction,
-                                  HTypeMap types,
                                   Compiler compiler) {
     HInstruction left = instruction.inputs[1];
-    if (left.isNumber(types)) return HType.DOUBLE;
-    return HType.UNKNOWN;
+    if (left.isNumber()) return HType.DOUBLE;
+    return instruction.instructionType;
   }
 
   HType computeDesiredTypeForInput(HInstruction instruction,
                                    HInstruction input,
-                                   HTypeMap types,
                                    Compiler compiler) {
     if (input == instruction.inputs[0]) return HType.UNKNOWN;
     // A division can never return an integer. So don't ask for integer inputs.
-    if (instruction.isInteger(types)) return HType.UNKNOWN;
+    if (instruction.isInteger()) return HType.UNKNOWN;
     return super.computeDesiredTypeForInput(
-        instruction, input, types, compiler);
+        instruction, input, compiler);
   }
 
   HInstruction newBuiltinVariant(HInstruction left, HInstruction right) {
@@ -380,21 +362,19 @@
   const BinaryBitOpSpecializer();
 
   HType computeTypeFromInputTypes(HInvokeDynamic instruction,
-                                  HTypeMap types,
                                   Compiler compiler) {
     // All bitwise operations on primitive types either produce an
     // integer or throw an error.
     HInstruction left = instruction.inputs[1];
-    if (left.isPrimitive(types)) return HType.INTEGER;
-    return HType.UNKNOWN;
+    if (left.isPrimitive()) return HType.INTEGER;
+    return instruction.instructionType;
   }
 
   HType computeDesiredTypeForInput(HInvokeDynamic instruction,
                                    HInstruction input,
-                                   HTypeMap types,
                                    Compiler compiler) {
     if (input == instruction.inputs[0]) return HType.UNKNOWN;
-    HType propagatedType = types[instruction];
+    HType propagatedType = instruction.instructionType;
     // If the outgoing type should be a number we can get that only if both
     // inputs are integers. If we don't know the outgoing type we try to make
     // it an integer.
@@ -412,11 +392,10 @@
     return constantSystem.shiftLeft;
   }
 
-  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
-                                   HTypeMap types) {
+  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) {
     HInstruction left = instruction.inputs[1];
     HInstruction right = instruction.inputs[2];
-    if (!left.isNumber(types) || !right.isConstantInteger()) return null;
+    if (!left.isNumber() || !right.isConstantInteger()) return null;
     HConstant rightConstant = right;
     IntConstant intConstant = rightConstant.constant;
     int count = intConstant.value;
@@ -484,35 +463,34 @@
   const RelationalSpecializer();
 
   HType computeTypeFromInputTypes(HInvokeDynamic instruction,
-                                  HTypeMap types,
                                   Compiler compiler) {
-    if (types[instruction.inputs[1]].isPrimitiveOrNull()) return HType.BOOLEAN;
-    return HType.UNKNOWN;
+    if (instruction.inputs[1].instructionType.isPrimitiveOrNull()) {
+      return HType.BOOLEAN;
+    }
+    return instruction.instructionType;
   }
 
   HType computeDesiredTypeForInput(HInvokeDynamic instruction,
                                    HInstruction input,
-                                   HTypeMap types,
                                    Compiler compiler) {
     if (input == instruction.inputs[0]) return HType.UNKNOWN;
-    HType propagatedType = types[instruction];
+    HType propagatedType = instruction.instructionType;
     // For all relational operations except HIdentity, we expect to get numbers
     // only. With numbers the outgoing type is a boolean. If something else
     // is desired, then numbers are incorrect, though.
     if (propagatedType.isUnknown() || propagatedType.isBoolean()) {
       HInstruction left = instruction.inputs[1];
-      if (left.isTypeUnknown(types) || left.isNumber(types)) {
+      if (left.isTypeUnknown() || left.isNumber()) {
         return HType.NUMBER;
       }
     }
     return HType.UNKNOWN;
   }
 
-  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
-                                   HTypeMap types) {
+  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) {
     HInstruction left = instruction.inputs[1];
     HInstruction right = instruction.inputs[2];
-    if (left.isNumber(types) && right.isNumber(types)) {
+    if (left.isNumber() && right.isNumber()) {
       return newBuiltinVariant(left, right);
     }
     return null;
@@ -526,37 +504,35 @@
 
   HType computeDesiredTypeForInput(HInvokeDynamic instruction,
                                    HInstruction input,
-                                   HTypeMap types,
                                    Compiler compiler) {
     HInstruction left = instruction.inputs[1];
     HInstruction right = instruction.inputs[2];
-    HType propagatedType = types[instruction];
-    if (input == left && types[right].isUseful()) {
+    HType propagatedType = instruction.instructionType;
+    if (input == left && right.instructionType.isUseful()) {
       // All our useful types have 'identical' semantics. But we don't want to
       // speculatively test for all possible types. Therefore we try to match
       // the two types. That is, if we see x == 3, then we speculatively test
       // if x is a number and bailout if it isn't.
       // If right is a number we don't need more than a number (no need to match
       // the exact type of right).
-      if (right.isNumber(types)) return HType.NUMBER;
-      return types[right];
+      if (right.isNumber()) return HType.NUMBER;
+      return right.instructionType;
     }
     // String equality testing is much more common than array equality testing.
-    if (input == left && left.isIndexablePrimitive(types)) {
+    if (input == left && left.isIndexablePrimitive()) {
       return HType.READABLE_ARRAY;
     }
     // String equality testing is much more common than array equality testing.
-    if (input == right && right.isIndexablePrimitive(types)) {
+    if (input == right && right.isIndexablePrimitive()) {
       return HType.STRING;
     }
     return HType.UNKNOWN;
   }
 
-  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
-                                   HTypeMap types) {
+  HInstruction tryConvertToBuiltin(HInvokeDynamic instruction) {
     HInstruction left = instruction.inputs[1];
     HInstruction right = instruction.inputs[2];
-    if (types[left].isPrimitiveOrNull() || right.isConstantNull()) {
+    if (left.instructionType.isPrimitiveOrNull() || right.isConstantNull()) {
       return newBuiltinVariant(left, right);
     }
     return null;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 4d83538..b6714b8 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -254,7 +254,7 @@
   visitInstruction(HInstruction instruction) {}
 
   visitBinaryArithmetic(HBinaryArithmetic node) => visitInvokeBinary(node);
-  visitBinaryBitOp(HBinaryBitOp node) => visitBinaryArithmetic(node);
+  visitBinaryBitOp(HBinaryBitOp node) => visitInvokeBinary(node);
   visitInvoke(HInvoke node) => visitInstruction(node);
   visitInvokeBinary(HInvokeBinary node) => visitInstruction(node);
   visitInvokeDynamic(HInvokeDynamic node) => visitInvoke(node);
@@ -867,84 +867,44 @@
   bool isControlFlow() => false;
 
   // All isFunctions work on the propagated types.
-  bool isArray(HTypeMap types) => types[this].isArray();
-  bool isReadableArray(HTypeMap types) => types[this].isReadableArray();
-  bool isMutableArray(HTypeMap types) => types[this].isMutableArray();
-  bool isExtendableArray(HTypeMap types) => types[this].isExtendableArray();
-  bool isFixedArray(HTypeMap types) => types[this].isFixedArray();
-  bool isBoolean(HTypeMap types) => types[this].isBoolean();
-  bool isInteger(HTypeMap types) => types[this].isInteger();
-  bool isDouble(HTypeMap types) => types[this].isDouble();
-  bool isNumber(HTypeMap types) => types[this].isNumber();
-  bool isNumberOrNull(HTypeMap types) => types[this].isNumberOrNull();
-  bool isString(HTypeMap types) => types[this].isString();
-  bool isTypeUnknown(HTypeMap types) => types[this].isUnknown();
-  bool isIndexablePrimitive(HTypeMap types)
-      => types[this].isIndexablePrimitive();
-  bool isPrimitive(HTypeMap types) => types[this].isPrimitive();
-  bool canBePrimitive(HTypeMap types) => types[this].canBePrimitive();
-  bool canBeNull(HTypeMap types) => types[this].canBeNull();
+  bool isArray() => instructionType.isArray();
+  bool isReadableArray() => instructionType.isReadableArray();
+  bool isMutableArray() => instructionType.isMutableArray();
+  bool isExtendableArray() => instructionType.isExtendableArray();
+  bool isFixedArray() => instructionType.isFixedArray();
+  bool isBoolean() => instructionType.isBoolean();
+  bool isInteger() => instructionType.isInteger();
+  bool isDouble() => instructionType.isDouble();
+  bool isNumber() => instructionType.isNumber();
+  bool isNumberOrNull() => instructionType.isNumberOrNull();
+  bool isString() => instructionType.isString();
+  bool isTypeUnknown() => instructionType.isUnknown();
+  bool isIndexablePrimitive() => instructionType.isIndexablePrimitive();
+  bool isPrimitive() => instructionType.isPrimitive();
+  bool canBePrimitive() => instructionType.canBePrimitive();
+  bool canBeNull() => instructionType.canBeNull();
 
   /**
-   * This is the type the instruction is guaranteed to have. It does not
-   * take any propagation into account.
+   * Type of the unstruction.
    */
-  HType guaranteedType = HType.UNKNOWN;
-  bool hasGuaranteedType() => !guaranteedType.isUnknown();
-
-  /**
-   * Some instructions have a good idea of their return type, but cannot
-   * guarantee the type. The computed does not need to be more specialized
-   * than the provided type for [this].
-   *
-   * Examples: the likely type of [:x == y:] is a boolean. In most cases this
-   * cannot be guaranteed, but when merging types we still want to use this
-   * information.
-   *
-   * Similarily the [HAdd] instruction is likely a number. Note that, even if
-   * the incoming type is already set to integer, the likely type might still
-   * just return the number type.
-   */
-  HType computeLikelyType(HTypeMap types, Compiler compiler) => types[this];
-
-  /**
-   * Compute the type of the instruction by propagating the input types through
-   * the instruction.
-   *
-   * By default just copy the guaranteed type.
-   */
-  HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
-    return guaranteedType;
-  }
-
-  /**
-   * Compute the desired type for the the given [input]. Aside from using
-   * other inputs to compute the desired type one should also use
-   * the given [types] which, during the invocation of this method,
-   * represents the desired type of [this].
-   */
-  HType computeDesiredTypeForInput(HInstruction input,
-                                   HTypeMap types,
-                                   Compiler compiler) {
-    return HType.UNKNOWN;
-  }
+  HType instructionType = HType.UNKNOWN;
 
   bool isInBasicBlock() => block != null;
 
   String inputsToString() {
     void addAsCommaSeparated(StringBuffer buffer, List<HInstruction> list) {
       for (int i = 0; i < list.length; i++) {
-        if (i != 0) buffer.add(', ');
-        buffer.add("@${list[i].id}");
+        if (i != 0) buffer.write(', ');
+        buffer.write("@${list[i].id}");
       }
     }
 
     StringBuffer buffer = new StringBuffer();
-    buffer.add('(');
+    buffer.write('(');
     addAsCommaSeparated(buffer, inputs);
-    buffer.add(') - used at [');
+    buffer.write(') - used at [');
     addAsCommaSeparated(buffer, usedBy);
-    buffer.add(']');
+    buffer.write(']');
     return buffer.toString();
   }
 
@@ -1151,12 +1111,12 @@
     if (identical(type.element, compiler.objectClass)) return this;
 
     // If the original can't be null, type conversion also can't produce null.
-    bool canBeNull = this.guaranteedType.canBeNull();
+    bool canBeNull = instructionType.canBeNull();
     HType convertedType = new HType.subtype(type, compiler);
 
     // No need to convert if we know the instruction has
     // [convertedType] as a bound.
-    if (this.guaranteedType == convertedType) {
+    if (instructionType == convertedType) {
       return this;
     }
 
@@ -1176,10 +1136,9 @@
   HBoolify(HInstruction value) : super(<HInstruction>[value]) {
     assert(!hasSideEffects());
     setUseGvn();
+    instructionType = HType.BOOLEAN;
   }
 
-  HType get guaranteedType => HType.BOOLEAN;
-
   accept(HVisitor visitor) => visitor.visitBoolify(this);
   int typeCode() => HInstruction.BOOLIFY_TYPECODE;
   bool typeEquals(other) => other is HBoolify;
@@ -1215,6 +1174,10 @@
     setUseGvn();
   }
 
+  void disable() {
+    isEnabled = false;
+  }
+
   bool isControlFlow() => isEnabled;
   bool isJsStatement() => isEnabled;
 
@@ -1225,7 +1188,7 @@
 }
 
 class HTypeGuard extends HCheck {
-  final HType guardedType;
+  HType guardedType;
   bool isEnabled = false;
 
   HTypeGuard(this.guardedType, HInstruction guarded, HInstruction bailoutTarget)
@@ -1236,11 +1199,15 @@
   HBailoutTarget get bailoutTarget => inputs[1];
   int get state => bailoutTarget.state;
 
-  HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
-    return isEnabled ? guardedType : types[guarded];
+  void enable() {
+    isEnabled = true;
+    instructionType = guardedType;
   }
 
-  HType get guaranteedType => isEnabled ? guardedType : HType.UNKNOWN;
+  void disable() {
+    isEnabled = false;
+    instructionType = guarded.instructionType;
+  }
 
   bool isControlFlow() => true;
   bool isJsStatement() => isEnabled;
@@ -1264,14 +1231,14 @@
    */
   int staticChecks = FULL_CHECK;
 
-  HBoundsCheck(length, index) : super(<HInstruction>[length, index]);
+  HBoundsCheck(length, index) : super(<HInstruction>[length, index]) {
+    instructionType = HType.INTEGER;
+  }
 
   HInstruction get length => inputs[1];
   HInstruction get index => inputs[0];
   bool isControlFlow() => true;
 
-  HType get guaranteedType => HType.INTEGER;
-
   accept(HVisitor visitor) => visitor.visitBoundsCheck(this);
   int typeCode() => HInstruction.BOUNDS_CHECK_TYPECODE;
   bool typeEquals(other) => other is HBoundsCheck;
@@ -1281,23 +1248,13 @@
 class HIntegerCheck extends HCheck {
   bool alwaysFalse = false;
 
-  HIntegerCheck(value) : super(<HInstruction>[value]);
+  HIntegerCheck(value) : super(<HInstruction>[value]) {
+    instructionType = HType.INTEGER;
+  }
 
   HInstruction get value => inputs[0];
   bool isControlFlow() => true;
 
-  HType get guaranteedType => HType.INTEGER;
-
-  HType computeDesiredTypeForInput(HInstruction input,
-                                   HTypeMap types,
-                                   Compiler compiler) {
-    // If the desired type of the input is already a number, we want
-    // to specialize it to an integer.
-    return input.isNumber(types)
-      ? HType.INTEGER
-      : super.computeDesiredTypeForInput(input, types, compiler);
-  }
-
   accept(HVisitor visitor) => visitor.visitIntegerCheck(this);
   int typeCode() => HInstruction.INTEGER_CHECK_TYPECODE;
   bool typeEquals(other) => other is HIntegerCheck;
@@ -1358,19 +1315,7 @@
   int typeCode() => HInstruction.INVOKE_DYNAMIC_TYPECODE;
   bool typeEquals(other) => other is HInvokeDynamic;
   bool dataEquals(HInvokeDynamic other) {
-    return selector == other.selector
-        && element == other.element;
-  }
-
-  HType computeDesiredTypeForInput(HInstruction input,
-                                   HTypeMap types,
-                                   Compiler compiler) {
-    return specializer.computeDesiredTypeForInput(this, input, types, compiler);
-  }
-
-  HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
-    HType type = specializer.computeTypeFromInputTypes(this, types, compiler);
-    return type.isUnknown() ? guaranteedType : type;
+    return selector == other.selector && element == other.element;
   }
 }
 
@@ -1391,11 +1336,11 @@
   String toString() => 'invoke dynamic method: $selector';
   accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this);
 
-  bool isIndexOperatorOnIndexablePrimitive(HTypeMap types) {
+  bool isIndexOperatorOnIndexablePrimitive() {
     return isInterceptorCall
         && selector.kind == SelectorKind.INDEX
         && selector.name == const SourceString('[]')
-        && inputs[1].isIndexablePrimitive(types);
+        && inputs[1].isIndexablePrimitive();
   }
 }
 
@@ -1442,7 +1387,7 @@
 class HInvokeStatic extends HInvoke {
   /** The first input must be the target. */
   HInvokeStatic(inputs, HType type) : super(inputs) {
-    guaranteedType = type;
+    instructionType = type;
   }
 
   toString() => 'invoke static: ${element.name}';
@@ -1543,16 +1488,16 @@
 
 class HForeign extends HInstruction {
   final DartString code;
-  final HType type;
   final bool isStatement;
 
   HForeign(this.code,
-           this.type,
+           HType type,
            List<HInstruction> inputs,
            {this.isStatement: false})
       : super(inputs) {
     setAllSideEffects();
     setDependsOnSomething();
+    instructionType = type;
   }
 
   HForeign.statement(code, List<HInstruction> inputs)
@@ -1560,8 +1505,6 @@
 
   accept(HVisitor visitor) => visitor.visitForeign(this);
 
-  HType get guaranteedType => type;
-
   bool isJsStatement() => isStatement;
   bool canThrow() => true;
 }
@@ -1588,13 +1531,6 @@
 
 abstract class HBinaryArithmetic extends HInvokeBinary {
   HBinaryArithmetic(HInstruction left, HInstruction right) : super(left, right);
-
-  HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
-    if (left.isInteger(types) && right.isInteger(types)) return HType.INTEGER;
-    if (left.isDouble(types)) return HType.DOUBLE;
-    return HType.NUMBER;
-  }
-
   BinaryOperation operation(ConstantSystem constantSystem);
 }
 
@@ -1610,11 +1546,11 @@
 }
 
 class HDivide extends HBinaryArithmetic {
-  HDivide(HInstruction left, HInstruction right) : super(left, right);
+  HDivide(HInstruction left, HInstruction right) : super(left, right) {
+    instructionType = HType.DOUBLE;
+  }
   accept(HVisitor visitor) => visitor.visitDivide(this);
 
-  HType get guaranteedType => HType.DOUBLE;
-
   BinaryOperation operation(ConstantSystem constantSystem)
       => constantSystem.divide;
   int typeCode() => HInstruction.DIVIDE_TYPECODE;
@@ -1667,13 +1603,9 @@
   String toString() => "HSwitch cases = $inputs";
 }
 
-// TODO(floitsch): Should HBinaryArithmetic really be the super class of
-// HBinaryBitOp?
-abstract class HBinaryBitOp extends HBinaryArithmetic {
-  HBinaryBitOp(HInstruction left, HInstruction right) : super(left, right);
-  HType get guaranteedType => HType.INTEGER;
-  HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
-    return guaranteedType;
+abstract class HBinaryBitOp extends HInvokeBinary {
+  HBinaryBitOp(HInstruction left, HInstruction right) : super(left, right) {
+    instructionType = HType.INTEGER;
   }
 }
 
@@ -1736,10 +1668,6 @@
   HNegate(HInstruction input) : super(input);
   accept(HVisitor visitor) => visitor.visitNegate(this);
 
-  HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
-    return types[operand];
-  }
-
   UnaryOperation operation(ConstantSystem constantSystem)
       => constantSystem.negate;
   int typeCode() => HInstruction.NEGATE_TYPECODE;
@@ -1748,10 +1676,11 @@
 }
 
 class HBitNot extends HInvokeUnary {
-  HBitNot(HInstruction input) : super(input);
+  HBitNot(HInstruction input) : super(input) {
+    instructionType = HType.INTEGER;
+  }
   accept(HVisitor visitor) => visitor.visitBitNot(this);
   
-  HType get guaranteedType => HType.INTEGER;
   UnaryOperation operation(ConstantSystem constantSystem)
       => constantSystem.bitNot;
   int typeCode() => HInstruction.BIT_NOT_TYPECODE;
@@ -1868,15 +1797,14 @@
 
 class HConstant extends HInstruction {
   final Constant constant;
-  final HType constantType;
-  HConstant.internal(this.constant, HType this.constantType)
-      : super(<HInstruction>[]);
+  HConstant.internal(this.constant, HType constantType)
+      : super(<HInstruction>[]) {
+    instructionType = constantType;
+  }
 
   toString() => 'literal: $constant';
   accept(HVisitor visitor) => visitor.visitConstant(this);
 
-  HType get guaranteedType => constantType;
-
   bool isConstant() => true;
   bool isConstantBoolean() => constant.isBool();
   bool isConstantNull() => constant.isNull();
@@ -1896,15 +1824,7 @@
 class HNot extends HInstruction {
   HNot(HInstruction value) : super(<HInstruction>[value]) {
     setUseGvn();
-  }
-
-  HType get guaranteedType => HType.BOOLEAN;
-
-  // 'Not' only works on booleans. That's what we want as input.
-  HType computeDesiredTypeForInput(HInstruction input,
-                                   HTypeMap types,
-                                   Compiler compiler) {
-    return HType.BOOLEAN;
+    instructionType = HType.BOOLEAN;
   }
 
   accept(HVisitor visitor) => visitor.visitNot(this);
@@ -1936,7 +1856,7 @@
 
 class HThis extends HParameterValue {
   HThis(Element element, [HType type = HType.UNKNOWN]) : super(element) {
-    guaranteedType = type;
+    instructionType = type;
   }
   toString() => 'this';
   accept(HVisitor visitor) => visitor.visitThis(this);
@@ -1968,58 +1888,6 @@
     input.usedBy.add(this);
   }
 
-  // Compute the (shared) type of the inputs if any. If all inputs
-  // have the same known type return it. If any two inputs have
-  // different known types, we'll return a conflict -- otherwise we'll
-  // simply return an unknown type.
-  HType computeInputsType(bool ignoreUnknowns,
-                          HTypeMap types,
-                          Compiler compiler) {
-    HType candidateType = HType.CONFLICTING;
-    for (int i = 0, length = inputs.length; i < length; i++) {
-      HType inputType = types[inputs[i]];
-      if (ignoreUnknowns && inputType.isUnknown()) continue;
-      // Phis need to combine the incoming types using the union operation.
-      // For example, if one incoming edge has type integer and the other has
-      // type double, then the phi is either an integer or double and thus has
-      // type number.
-      candidateType = candidateType.union(inputType, compiler);
-      if (candidateType.isUnknown()) return HType.UNKNOWN;
-    }
-    return candidateType;
-  }
-
-  HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
-    HType inputsType = computeInputsType(false, types, compiler);
-    if (inputsType.isConflicting()) return HType.UNKNOWN;
-    return inputsType;
-  }
-
-  HType computeDesiredTypeForInput(HInstruction input,
-                                   HTypeMap types,
-                                   Compiler compiler) {
-    HType propagatedType = types[this];
-    // Best case scenario for a phi is, when all inputs have the same type. If
-    // there is no desired outgoing type we therefore try to unify the input
-    // types (which is basically the [likelyType]).
-    if (propagatedType.isUnknown()) return computeLikelyType(types, compiler);
-    // When the desired outgoing type is conflicting we don't need to give any
-    // requirements on the inputs.
-    if (propagatedType.isConflicting()) return HType.UNKNOWN;
-    // Otherwise the input type must match the desired outgoing type.
-    return propagatedType;
-  }
-
-  HType computeLikelyType(HTypeMap types, Compiler compiler) {
-    HType agreedType = computeInputsType(true, types, compiler);
-    if (agreedType.isConflicting()) return HType.UNKNOWN;
-    // Don't be too restrictive. If the agreed type is integer or double just
-    // say that the likely type is number. If more is expected the type will be
-    // propagated back.
-    if (agreedType.isNumber()) return HType.NUMBER;
-    return agreedType;
-  }
-
   bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR;
 
   String logicalOperator() {
@@ -2035,8 +1903,9 @@
 
 abstract class HRelational extends HInvokeBinary {
   bool usesBoolifiedInterceptor = false;
-  HRelational(HInstruction left, HInstruction right) : super(left, right);
-  HType get guaranteedType => HType.BOOLEAN;
+  HRelational(HInstruction left, HInstruction right) : super(left, right) {
+    instructionType = HType.BOOLEAN;
+  }
 }
 
 class HIdentity extends HRelational {
@@ -2139,24 +2008,6 @@
   accept(HVisitor visitor) => visitor.visitInterceptor(this);
   HInstruction get receiver => inputs[0];
 
-  HType computeDesiredTypeForInput(HInstruction input,
-                                   HTypeMap types,
-                                   Compiler compiler) {
-    if (interceptedClasses.length != 1) return HType.UNKNOWN;
-    // If the only class being intercepted is of type number, we
-    // make this interceptor call say it wants that class as input.
-    Element interceptor = interceptedClasses.toList()[0];
-    JavaScriptBackend backend = compiler.backend;
-    if (interceptor == backend.jsNumberClass) {
-      return HType.NUMBER;
-    } else if (interceptor == backend.jsIntClass) {
-      return HType.INTEGER;
-    } else if (interceptor == backend.jsDoubleClass) {
-      return HType.DOUBLE;
-    }
-    return HType.UNKNOWN;
-  }
-
   int typeCode() => HInstruction.INTERCEPTOR_TYPECODE;
   bool typeEquals(other) => other is HInterceptor;
   bool dataEquals(HInterceptor other) {
@@ -2182,7 +2033,7 @@
                       this.interceptedClasses)
       : super(selector, null, inputs, true) {
     assert(inputs[0] is HConstant);
-    assert(inputs[0].guaranteedType == HType.NULL);
+    assert(inputs[0].instructionType == HType.NULL);
   }
 
   String toString() => 'one shot interceptor on $selector';
@@ -2225,11 +2076,11 @@
 }
 
 class HLiteralList extends HInstruction {
-  HLiteralList(inputs) : super(inputs);
+  HLiteralList(inputs) : super(inputs) {
+    instructionType = HType.EXTENDABLE_ARRAY;
+  }
   toString() => 'literal list';
   accept(HVisitor visitor) => visitor.visitLiteralList(this);
-
-  HType get guaranteedType => HType.EXTENDABLE_ARRAY;
 }
 
 /**
@@ -2282,6 +2133,7 @@
   HIs(this.typeExpression, List<HInstruction> inputs, {this.nullOk: false})
      : super(inputs) {
     setUseGvn();
+    instructionType = HType.BOOLEAN;
   }
 
   HInstruction get expression => inputs[0];
@@ -2289,8 +2141,6 @@
 
   bool hasArgumentsCheck() => inputs.length > 1;
 
-  HType get guaranteedType => HType.BOOLEAN;
-
   accept(HVisitor visitor) => visitor.visitIs(this);
 
   toString() => "$expression is $typeExpression";
@@ -2304,7 +2154,6 @@
 }
 
 class HTypeConversion extends HCheck {
-  final HType type;
   final int kind;
 
   static const int NO_CHECK = 0;
@@ -2313,10 +2162,11 @@
   static const int CAST_TYPE_CHECK = 3;
   static const int BOOLEAN_CONVERSION_CHECK = 4;
 
-  HTypeConversion(this.type, HInstruction input, [this.kind = NO_CHECK])
+  HTypeConversion(HType type, HInstruction input, [this.kind = NO_CHECK])
       : super(<HInstruction>[input]) {
     assert(type != null);
     sourceElement = input.sourceElement;
+    instructionType = type;
   }
   HTypeConversion.checkedModeCheck(HType type, HInstruction input)
       : this(type, input, CHECKED_MODE_CHECK);
@@ -2334,8 +2184,6 @@
   bool get isCastTypeCheck => kind == CAST_TYPE_CHECK;
   bool get isBooleanConversionCheck => kind == BOOLEAN_CONVERSION_CHECK;
 
-  HType get guaranteedType => type;
-
   accept(HVisitor visitor) => visitor.visitTypeConversion(this);
 
   bool isJsStatement() => kind == ARGUMENT_TYPE_CHECK;
@@ -2345,18 +2193,17 @@
   int typeCode() => HInstruction.TYPE_CONVERSION_TYPECODE;
   bool typeEquals(HInstruction other) => other is HTypeConversion;
   bool dataEquals(HTypeConversion other) {
-    return type == other.type && kind == other.kind;
+    return instructionType == other.instructionType && kind == other.kind;
   }
 }
 
 class HRangeConversion extends HCheck {
   HRangeConversion(HInstruction input) : super(<HInstruction>[input]) {
     sourceElement = input.sourceElement;
+    // We currently only do range analysis for integers.
+    instructionType = HType.INTEGER;
   }
   accept(HVisitor visitor) => visitor.visitRangeConversion(this);
-
-  // We currently only do range analysis for integers.
-  HType get guaranteedType => HType.INTEGER;
 }
 
 class HStringConcat extends HInstruction {
@@ -2365,8 +2212,8 @@
       : super(<HInstruction>[left, right]) {
     setAllSideEffects();
     setDependsOnSomething();
+    instructionType = HType.STRING;
   }
-  HType get guaranteedType => HType.STRING;
 
   HInstruction get left => inputs[0];
   HInstruction get right => inputs[1];
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index 1b2ae05..ced53a5 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -32,37 +32,36 @@
   void optimize(CodegenWorkItem work, HGraph graph, bool speculative) {
     ConstantSystem constantSystem = compiler.backend.constantSystem;
     JavaScriptItemCompilationContext context = work.compilationContext;
-    HTypeMap types = context.types;
     measure(() {
       List<OptimizationPhase> phases = <OptimizationPhase>[
           // Run trivial constant folding first to optimize
           // some patterns useful for type conversion.
-          new SsaConstantFolder(constantSystem, backend, work, types),
+          new SsaConstantFolder(constantSystem, backend, work),
           new SsaTypeConversionInserter(compiler),
-          new SsaTypePropagator(compiler, types),
-          new SsaConstantFolder(constantSystem, backend, work, types),
+          new SsaNonSpeculativeTypePropagator(compiler),
+          new SsaConstantFolder(constantSystem, backend, work),
           // The constant folder affects the types of instructions, so
           // we run the type propagator again. Note that this would
           // not be necessary if types were directly stored on
           // instructions.
-          new SsaTypePropagator(compiler, types),
-          new SsaCheckInserter(backend, work, types, context.boundsChecked),
+          new SsaNonSpeculativeTypePropagator(compiler),
+          new SsaCheckInserter(backend, work, context.boundsChecked),
           new SsaRedundantPhiEliminator(),
           new SsaDeadPhiEliminator(),
-          new SsaConstantFolder(constantSystem, backend, work, types),
-          new SsaTypePropagator(compiler, types),
+          new SsaConstantFolder(constantSystem, backend, work),
+          new SsaNonSpeculativeTypePropagator(compiler),
           new SsaReceiverSpecialization(compiler),
-          new SsaGlobalValueNumberer(compiler, types),
+          new SsaGlobalValueNumberer(compiler),
           new SsaCodeMotion(),
-          new SsaValueRangeAnalyzer(constantSystem, types, work),
+          new SsaValueRangeAnalyzer(constantSystem, work),
           // Previous optimizations may have generated new
           // opportunities for constant folding.
-          new SsaConstantFolder(constantSystem, backend, work, types),
-          new SsaSimplifyInterceptors(constantSystem, types),
-          new SsaDeadCodeEliminator(types)];
+          new SsaConstantFolder(constantSystem, backend, work),
+          new SsaSimplifyInterceptors(constantSystem),
+          new SsaDeadCodeEliminator()];
       runPhases(graph, phases);
       if (!speculative) {
-        runPhase(graph, new SsaConstructionFieldTypes(backend, work, types));
+        runPhase(graph, new SsaConstructionFieldTypes(backend, work));
       }
     });
   }
@@ -73,24 +72,15 @@
       return false;
     }
     JavaScriptItemCompilationContext context = work.compilationContext;
-    HTypeMap types = context.types;
     return measure(() {
       // Run the phases that will generate type guards.
       List<OptimizationPhase> phases = <OptimizationPhase>[
-          new SsaSpeculativeTypePropagator(compiler, types),
-          new SsaTypeGuardInserter(compiler, work, types),
+          new SsaTypeGuardInserter(compiler, work),
           new SsaEnvironmentBuilder(compiler),
-          // Change the propagated types back to what they were before we
-          // speculatively propagated, so that we can generate the bailout
-          // version.
-          // Note that we do this even if there were no guards inserted. If a
-          // guard is not beneficial enough we don't emit one, but there might
-          // still be speculative types on the instructions.
-          new SsaTypePropagator(compiler, types),
           // Then run the [SsaCheckInserter] because the type propagator also
           // propagated types non-speculatively. For example, it might have
           // propagated the type array for a call to the List constructor.
-          new SsaCheckInserter(backend, work, types, context.boundsChecked)];
+          new SsaCheckInserter(backend, work, context.boundsChecked)];
       runPhases(graph, phases);
       return !work.guards.isEmpty;
     });
@@ -98,14 +88,13 @@
 
   void prepareForSpeculativeOptimizations(CodegenWorkItem work, HGraph graph) {
     JavaScriptItemCompilationContext context = work.compilationContext;
-    HTypeMap types = context.types;
     measure(() {
       // In order to generate correct code for the bailout version, we did not
       // propagate types from the instruction to the type guard. We do it
       // now to be able to optimize further.
       work.guards.forEach((HTypeGuard guard) {
-        guard.bailoutTarget.isEnabled = false;
-        guard.isEnabled = true;
+        guard.bailoutTarget.disable();
+        guard.enable();
       });
       // We also need to insert range and integer checks for the type
       // guards. Now that they claim to have a certain type, some
@@ -114,8 +103,8 @@
       // Also run the type propagator, to please the codegen in case
       // no other optimization is run.
       runPhases(graph, <OptimizationPhase>[
-          new SsaCheckInserter(backend, work, types, context.boundsChecked),
-          new SsaTypePropagator(compiler, types)]);
+          new SsaCheckInserter(backend, work, context.boundsChecked),
+          new SsaNonSpeculativeTypePropagator(compiler)]);
     });
   }
 }
@@ -129,11 +118,10 @@
   final JavaScriptBackend backend;
   final CodegenWorkItem work;
   final ConstantSystem constantSystem;
-  final HTypeMap types;
   HGraph graph;
   Compiler get compiler => backend.compiler;
 
-  SsaConstantFolder(this.constantSystem, this.backend, this.work, this.types);
+  SsaConstantFolder(this.constantSystem, this.backend, this.work);
 
   void visitGraph(HGraph visitee) {
     graph = visitee;
@@ -150,10 +138,8 @@
 
         // If we can replace [instruction] with [replacement], then
         // [replacement]'s type can be narrowed.
-        types[replacement] = types[replacement].intersection(
-            types[instruction], compiler);
-        replacement.guaranteedType = replacement.guaranteedType.intersection(
-            instruction.guaranteedType, compiler);
+        replacement.instructionType = replacement.instructionType.intersection(
+            instruction.instructionType, compiler);
 
         // If the replacement instruction does not know its
         // source element, use the source element of the
@@ -187,7 +173,7 @@
     List<HInstruction> inputs = node.inputs;
     assert(inputs.length == 1);
     HInstruction input = inputs[0];
-    HType type = types[input];
+    HType type = input.instructionType;
     if (type.isBoolean()) return input;
     // All values !== true are boolified to false.
     if (!type.isBooleanOrNull() && !type.isUnknown()) {
@@ -225,9 +211,9 @@
     return null;
   }
 
-  HInstruction optimizeLengthInterceptedGetter(HInvokeDynamic node) {
+  HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) {
     HInstruction actualReceiver = node.inputs[1];
-    if (actualReceiver.isIndexablePrimitive(types)) {
+    if (actualReceiver.isIndexablePrimitive()) {
       if (actualReceiver.isConstantString()) {
         HConstant constantInput = actualReceiver;
         StringConstant constant = constantInput.constant;
@@ -239,24 +225,23 @@
       }
       Element element;
       bool isAssignable;
-      if (actualReceiver.isString(types)) {
+      if (actualReceiver.isString()) {
         element = backend.jsStringLength;
         isAssignable = false;
       } else {
         element = backend.jsArrayLength;
-        isAssignable = !actualReceiver.isFixedArray(types);
+        isAssignable = !actualReceiver.isFixedArray();
       }
       HFieldGet result = new HFieldGet(
           element, actualReceiver, isAssignable: isAssignable);
-      result.guaranteedType = HType.INTEGER;
-      types[result] = HType.INTEGER;
+      result.instructionType = HType.INTEGER;
       return result;
     } else if (actualReceiver.isConstantMap()) {
       HConstant constantInput = actualReceiver;
       MapConstant constant = constantInput.constant;
       return graph.addConstantInt(constant.length, constantSystem);
     }
-    return node;
+    return null;
   }
 
   HInstruction handleInterceptorCall(HInvokeDynamic node) {
@@ -271,38 +256,67 @@
 
     // Try converting the instruction to a builtin instruction.
     HInstruction instruction =
-        node.specializer.tryConvertToBuiltin(node, types);
+        node.specializer.tryConvertToBuiltin(node);
     if (instruction != null) return instruction;
 
     Selector selector = node.selector;
     var interceptor = node.inputs[0];
+    HInstruction input = node.inputs[1];
 
-    // If the intercepted call is through a constant interceptor, we
-    // know which element to call.
-    if (node is !HOneShotInterceptor
-        && interceptor.isConstant()
-        && selector.isCall()) {
-      DartType type = types[interceptor].computeType(compiler);
-      ClassElement cls = type.element;
-      node.element = cls.lookupSelector(selector);
+    if (selector.isCall()) {
+      Element target;
+      if (input.isExtendableArray()) {
+        if (selector.applies(backend.jsArrayRemoveLast, compiler)) {
+          target = backend.jsArrayRemoveLast;
+        } else if (selector.applies(backend.jsArrayAdd, compiler)) {
+          // The codegen special cases array calls, but does not
+          // inline argument type checks.
+          if (!compiler.enableTypeAssertions) {
+            target = backend.jsArrayAdd;
+          }
+        }
+      } else if (input.isString()) {
+        if (selector.applies(backend.jsStringSplit, compiler)) {
+          if (node.inputs[2].isString()) {
+            target = backend.jsStringSplit;
+          }
+        } else if (selector.applies(backend.jsStringConcat, compiler)) {
+          if (node.inputs[2].isString()) {
+            target = backend.jsStringConcat;
+          }
+        } else if (selector.applies(backend.jsStringToString, compiler)) {
+          return input;
+        }
+      }
+      if (target != null) {
+        // TODO(ngeoffray): There is a strong dependency between codegen
+        // and this optimization that the dynamic invoke does not need an
+        // interceptor. We currently need to keep a
+        // HInvokeDynamicMethod and not create a HForeign because
+        // HForeign is too opaque for the SsaCheckInserter (that adds a
+        // bounds check on removeLast). Once we start inlining, the
+        // bounds check will become explicit, so we won't need this
+        // optimization.
+        HInvokeDynamicMethod result = new HInvokeDynamicMethod(
+            node.selector, node.inputs.getRange(1, node.inputs.length - 1));
+        result.element = target;
+        return result;
+      }
+    } else if (selector.isGetter()) {
+      if (selector.applies(backend.jsArrayLength, compiler)) {
+        HInstruction optimized = tryOptimizeLengthInterceptedGetter(node);
+        if (optimized != null) return optimized;
+      }
     }
 
-    HInstruction input = node.inputs[1];
-    HType type = types[input];
     // Check if this call does not need to be intercepted.
-    if (interceptor is !HThis && !type.canBePrimitive()) {
-      // If the type can be null, and the intercepted method can be in
-      // the object class, keep the interceptor.
-      if (type.canBeNull()) {
-        Set<ClassElement> interceptedClasses;
-        if (interceptor is HInterceptor) {
-          interceptedClasses = interceptor.interceptedClasses;
-        } else if (node is HOneShotInterceptor) {
-          var oneShotInterceptor = node;
-          interceptedClasses = oneShotInterceptor.interceptedClasses;
-        }
-        if (interceptedClasses.contains(compiler.objectClass)) return node;
-      }
+    HType type = input.instructionType;
+    // TODO(kasperl): Get rid of this refinement once the receiver
+    // specialization phase takes care of it.
+    Selector refined = type.refine(selector, compiler);
+    Set<ClassElement> classes = backend.getInterceptedClassesOn(
+        refined, canBeNull: type.canBeNull());
+    if (classes == null) {
       if (selector.isGetter()) {
         // Change the call to a regular invoke dynamic call.
         return new HInvokeDynamicGetter(selector, null, input, false);
@@ -316,49 +330,14 @@
       }
     }
 
-    if (selector.isCall()) {
-      Element target;
-      if (input.isExtendableArray(types)) {
-        if (selector.applies(backend.jsArrayRemoveLast, compiler)) {
-          target = backend.jsArrayRemoveLast;
-        } else if (selector.applies(backend.jsArrayAdd, compiler)) {
-          // The codegen special cases array calls, but does not
-          // inline argument type checks.
-          if (!compiler.enableTypeAssertions) {
-            target = backend.jsArrayAdd;
-          }
-        }
-      } else if (input.isString(types)) {
-        if (selector.applies(backend.jsStringSplit, compiler)) {
-          if (node.inputs[2].isString(types)) {
-            target = backend.jsStringSplit;
-          }
-        } else if (selector.applies(backend.jsStringConcat, compiler)) {
-          if (node.inputs[2].isString(types)) {
-            target = backend.jsStringConcat;
-          }
-        } else if (selector.applies(backend.jsStringToString, compiler)) {
-          return input;
-        }
-      }
-      if (target != null) {
-        // TODO(ngeoffray): There is a strong dependency between codegen
-        // and this optimization that the dynamic invoke does not need an
-        // interceptor. We currently need to keep a
-        // HInvokeDynamicMethod and not create a HForeign because
-        // HForeign is too opaque for the SssaCheckInserter (that adds a
-        // bounds check on removeLast). Once we start inlining, the
-        // bounds check will become explicit, so we won't need this
-        // optimization.
-        HInvokeDynamicMethod result = new HInvokeDynamicMethod(
-            node.selector, node.inputs.getRange(1, node.inputs.length - 1));
-        result.element = target;
-        return result;
-      }
-    } else if (selector.isGetter()) {
-      if (selector.applies(backend.jsArrayLength, compiler)) {
-        return optimizeLengthInterceptedGetter(node);
-      }
+    // If the intercepted call is through a constant interceptor, we
+    // know which element to call.
+    if (node is !HOneShotInterceptor
+        && interceptor.isConstant()
+        && selector.isCall()) {
+      DartType type = interceptor.instructionType.computeType(compiler);
+      ClassElement cls = type.element;
+      node.element = cls.lookupSelector(selector);
     }
     return node;
   }
@@ -376,20 +355,21 @@
     // other optimizations to reason on a fixed length constructor
     // that we know takes an int.
     return element == backend.fixedLengthListConstructor
-        && node.inputs[1].isInteger(types);
+        && node.inputs[1].isInteger();
   }
 
   HInstruction visitInvokeStatic(HInvokeStatic node) {
     if (isFixedSizeListConstructor(node)) {
-      node.guaranteedType = HType.FIXED_ARRAY;
+      node.instructionType = HType.FIXED_ARRAY;
     }
     return node;
   }
 
   HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
     if (node.isInterceptorCall) return handleInterceptorCall(node);
-    HType receiverType = types[node.receiver];
-    Element element = receiverType.lookupSingleTarget(node.selector, compiler);
+    HType receiverType = node.receiver.instructionType;
+    Selector selector = receiverType.refine(node.selector, compiler);
+    Element element = compiler.world.locateSingleElement(selector);
     // TODO(ngeoffray): Also fold if it's a getter or variable.
     if (element != null && element.isFunction()) {
       FunctionElement method = element;
@@ -406,7 +386,7 @@
 
   HInstruction visitIntegerCheck(HIntegerCheck node) {
     HInstruction value = node.value;
-    if (value.isInteger(types)) return value;
+    if (value.isInteger()) return value;
     if (value.isConstant()) {
       HConstant constantInstruction = value;
       assert(!constantInstruction.constant.isInt());
@@ -461,16 +441,16 @@
   HInstruction handleIdentityCheck(HRelational node) {
     HInstruction left = node.left;
     HInstruction right = node.right;
-    HType leftType = types[left];
-    HType rightType = types[right];
+    HType leftType = left.instructionType;
+    HType rightType = right.instructionType;
 
     // We don't optimize on numbers to preserve the runtime semantics.
-    if (!(left.isNumberOrNull(types) && right.isNumberOrNull(types)) &&
+    if (!(left.isNumberOrNull() && right.isNumberOrNull()) &&
         leftType.intersection(rightType, compiler).isConflicting()) {
       return graph.addConstantBool(false, constantSystem);
     }
 
-    if (left.isConstantBoolean() && right.isBoolean(types)) {
+    if (left.isConstantBoolean() && right.isBoolean()) {
       HConstant constant = left;
       if (constant.constant.isTrue()) {
         return right;
@@ -479,7 +459,7 @@
       }
     }
 
-    if (right.isConstantBoolean() && left.isBoolean(types)) {
+    if (right.isConstantBoolean() && left.isBoolean()) {
       HConstant constant = right;
       if (constant.constant.isTrue()) {
         return left;
@@ -501,8 +481,9 @@
     // If the intersection of the types is still the incoming type then
     // the incoming type was a subtype of the guarded type, and no check
     // is required.
-    HType combinedType = types[value].intersection(node.guardedType, compiler);
-    return (combinedType == types[value]) ? value : node;
+    HType combinedType =
+        value.instructionType.intersection(node.guardedType, compiler);
+    return (combinedType == value.instructionType) ? value : node;
   }
 
   HInstruction visitIs(HIs node) {
@@ -514,7 +495,7 @@
       return node;
     }
 
-    HType expressionType = types[node.expression];
+    HType expressionType = node.expression.instructionType;
     if (identical(element, compiler.objectClass)
         || identical(element, compiler.dynamicClass)) {
       return graph.addConstantBool(true, constantSystem);
@@ -584,26 +565,24 @@
 
   HInstruction visitTypeConversion(HTypeConversion node) {
     HInstruction value = node.inputs[0];
-    DartType type = types[node].computeType(compiler);
+    DartType type = node.instructionType.computeType(compiler);
     if (identical(type.element, compiler.dynamicClass)
         || identical(type.element, compiler.objectClass)) {
       return value;
     }
-    if (types[value].canBeNull() && node.isBooleanConversionCheck) {
+    if (value.instructionType.canBeNull() && node.isBooleanConversionCheck) {
       return node;
     }
-    HType combinedType = types[value].intersection(types[node], compiler);
-    return (combinedType == types[value]) ? value : node;
+    HType combinedType =
+        value.instructionType.intersection(node.instructionType, compiler);
+    return (combinedType == value.instructionType) ? value : node;
   }
 
   Element findConcreteFieldForDynamicAccess(HInstruction receiver,
                                             Selector selector) {
-    HType receiverType = types[receiver];
-    if (!receiverType.isUseful()) return null;
-    DartType type = receiverType.computeType(compiler);
-    if (type == null) return null;
-    if (Elements.isErroneousElement(type.element)) return null;
-    return compiler.world.locateSingleField(type, selector);
+    HType receiverType = receiver.instructionType;
+    return compiler.world.locateSingleField(
+        receiverType.refine(selector, compiler));
   }
 
   HInstruction visitFieldGet(HFieldGet node) {
@@ -638,14 +617,19 @@
         field, node.inputs[0], isAssignable: !isFinalOrConst);
 
     if (field.getEnclosingClass().isNative()) {
-      result.guaranteedType =
+      result.instructionType =
           new HType.subtype(field.computeType(compiler), compiler);
     } else {
-      HType type = backend.optimisticFieldType(field);
+      HType type = new HType.inferredForElement(field, compiler);
+      if (type.isUnknown()) {
+        type = backend.optimisticFieldType(field);
+        if (type != null) {
+          backend.registerFieldTypesOptimization(
+              work.element, field, result.instructionType);
+        }
+      }
       if (type != null) {
-        backend.registerFieldTypesOptimization(
-            work.element, field, result.guaranteedType);
-        result.guaranteedType = type;
+        result.instructionType = type;
       }
     }
     return result;
@@ -694,7 +678,7 @@
 
   HInstruction tryComputeConstantInterceptor(HInstruction input,
                                              Set<ClassElement> intercepted) {
-    HType type = types[input];
+    HType type = input.instructionType;
     ClassElement constantInterceptor;
     if (type.isInteger()) {
       constantInterceptor = backend.jsIntClass;
@@ -758,7 +742,6 @@
 }
 
 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
-  final HTypeMap types;
   final Set<HInstruction> boundsChecked;
   final CodegenWorkItem work;
   final JavaScriptBackend backend;
@@ -767,7 +750,6 @@
 
   SsaCheckInserter(this.backend,
                    this.work,
-                   this.types,
                    this.boundsChecked);
 
   void visitGraph(HGraph graph) {
@@ -787,11 +769,11 @@
   HBoundsCheck insertBoundsCheck(HInstruction node,
                                  HInstruction receiver,
                                  HInstruction index) {
-    bool isAssignable = !receiver.isFixedArray(types);
+    bool isAssignable = !receiver.isFixedArray();
     HFieldGet length = new HFieldGet(
         backend.jsArrayLength, receiver, isAssignable: isAssignable);
-    length.guaranteedType = HType.INTEGER;
-    types[length] = HType.INTEGER;
+    length.instructionType = HType.INTEGER;
+    length.instructionType = HType.INTEGER;
     node.block.addBefore(node, length);
 
     HBoundsCheck check = new HBoundsCheck(index, length);
@@ -813,7 +795,7 @@
   void visitIndex(HIndex node) {
     if (boundsChecked.contains(node)) return;
     HInstruction index = node.index;
-    if (!node.index.isInteger(types)) {
+    if (!node.index.isInteger()) {
       index = insertIntegerCheck(node, index);
     }
     index = insertBoundsCheck(node, node.receiver, index);
@@ -821,10 +803,10 @@
   }
 
   void visitIndexAssign(HIndexAssign node) {
-    if (!node.receiver.isMutableArray(types)) return;
+    if (!node.receiver.isMutableArray()) return;
     if (boundsChecked.contains(node)) return;
     HInstruction index = node.index;
-    if (!node.index.isInteger(types)) {
+    if (!node.index.isInteger()) {
       index = insertIntegerCheck(node, index);
     }
     index = insertBoundsCheck(node, node.receiver, index);
@@ -842,10 +824,9 @@
 }
 
 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
-  final HTypeMap types;
   final String name = "SsaDeadCodeEliminator";
 
-  SsaDeadCodeEliminator(this.types);
+  SsaDeadCodeEliminator();
 
   bool isDeadCode(HInstruction instruction) {
     return !instruction.hasSideEffects()
@@ -977,13 +958,12 @@
 class SsaGlobalValueNumberer implements OptimizationPhase {
   final String name = "SsaGlobalValueNumberer";
   final Compiler compiler;
-  final HTypeMap types;
   final Set<int> visited;
 
   List<int> blockChangesFlags;
   List<int> loopChangesFlags;
 
-  SsaGlobalValueNumberer(this.compiler, this.types) : visited = new Set<int>();
+  SsaGlobalValueNumberer(this.compiler) : visited = new Set<int>();
 
   void visitGraph(HGraph graph) {
     computeChangesFlags(graph);
@@ -1323,7 +1303,6 @@
     extends HBaseVisitor implements OptimizationPhase {
   final JavaScriptBackend backend;
   final CodegenWorkItem work;
-  final HTypeMap types;
   final String name = "SsaConstructionFieldTypes";
   final Set<HInstruction> thisUsers;
   final Set<Element> allSetters;
@@ -1332,9 +1311,7 @@
   HGraph currentGraph;
   Map<Element, HType> currentFieldSetters;
 
-  SsaConstructionFieldTypes(JavaScriptBackend this.backend,
-         CodegenWorkItem this.work,
-         HTypeMap this.types)
+  SsaConstructionFieldTypes(this.backend, this.work)
       : thisUsers = new Set<HInstruction>(),
         allSetters = new Set<Element>(),
         blockFieldSetters = new Map<HBasicBlock, Map<Element, HType>>();
@@ -1417,7 +1394,8 @@
     int j = 0;
     node.element.forEachInstanceField(
         (ClassElement enclosingClass, Element element) {
-          backend.registerFieldInitializer(element, types[node.inputs[j]]);
+          backend.registerFieldInitializer(
+              element, node.inputs[j].instructionType);
           j++;
         },
         includeBackendMembers: false,
@@ -1427,14 +1405,14 @@
   visitFieldSet(HFieldSet node) {
     Element field = node.element;
     HInstruction value = node.value;
-    HType type = types[value];
+    HType type = value.instructionType;
     // [HFieldSet] is also used for variables in try/catch.
     if (field.isField()) allSetters.add(field);
     // Don't handle fields defined in superclasses. Given that the field is
     // always added to the [allSetters] set, setting a field defined in a
     // superclass will get an inferred type of UNKNOWN.
     if (identical(work.element.getEnclosingClass(), field.getEnclosingClass()) &&
-        value.hasGuaranteedType()) {
+        !value.instructionType.isUnknown()) {
       currentFieldSetters[field] = type;
     }
   }
@@ -1490,7 +1468,12 @@
         // double class.
         if (otherIntercepted.contains(backend.jsIntClass)
             || otherIntercepted.contains(backend.jsDoubleClass)) {
-          interceptor.interceptedClasses.addAll(user.interceptedClasses);
+          // We cannot modify the intercepted classes set without
+          // copying because it may be shared by multiple interceptors
+          // because of caching in the backend.
+          Set<ClassElement> copy = interceptor.interceptedClasses.toSet();
+          copy.addAll(user.interceptedClasses);
+          interceptor.interceptedClasses = copy;
         }
         user.interceptedClasses = interceptor.interceptedClasses;
       }
@@ -1509,10 +1492,9 @@
     implements OptimizationPhase {
   final String name = "SsaSimplifyInterceptors";
   final ConstantSystem constantSystem;
-  final HTypeMap types;
   HGraph graph;
 
-  SsaSimplifyInterceptors(this.constantSystem, this.types);
+  SsaSimplifyInterceptors(this.constantSystem);
 
   void visitGraph(HGraph graph) {
     this.graph = graph;
@@ -1539,8 +1521,7 @@
         user.selector, inputs, node.interceptedClasses);
     interceptor.sourcePosition = user.sourcePosition;
     interceptor.sourceElement = user.sourceElement;
-    interceptor.guaranteedType = user.guaranteedType;
-    types[interceptor] = types[user];
+    interceptor.instructionType = user.instructionType;
 
     HBasicBlock block = user.block;
     block.addAfter(user, interceptor);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
index 7a8f6bc..fb62f89 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
@@ -77,7 +77,6 @@
 
   void addInstructions(HInstructionStringifier stringifier,
                        HInstructionList list) {
-    HTypeMap types = context.types;
     for (HInstruction instruction = list.first;
          instruction != null;
          instruction = instruction.next) {
@@ -115,8 +114,8 @@
             String phiId = stringifier.temporaryId(phi);
             StringBuffer inputIds = new StringBuffer();
             for (int i = 0; i < phi.inputs.length; i++) {
-              inputIds.add(stringifier.temporaryId(phi.inputs[i]));
-              inputIds.add(" ");
+              inputIds.write(stringifier.temporaryId(phi.inputs[i]));
+              inputIds.write(" ");
             }
             println("${phi.id} $phiId [ $inputIds]");
           });
@@ -176,7 +175,7 @@
 
   String temporaryId(HInstruction instruction) {
     String prefix;
-    HType type = context.types[instruction];
+    HType type = instruction.instructionType;
     if (!type.isPrimitive()) {
       prefix = 'U';
     } else {
@@ -215,7 +214,7 @@
     StringBuffer envBuffer = new StringBuffer();
     List<HInstruction> inputs = node.inputs;
     for (int i = 0; i < inputs.length; i++) {
-      envBuffer.add(" ${temporaryId(inputs[i])}");
+      envBuffer.write(" ${temporaryId(inputs[i])}");
     }
     String on = node.isEnabled ? "enabled" : "disabled";
     return "BailoutTarget($on): id: ${node.state} env: $envBuffer";
@@ -316,8 +315,8 @@
                             List<HInstruction> arguments) {
     StringBuffer argumentsString = new StringBuffer();
     for (int i = 0; i < arguments.length; i++) {
-      if (i != 0) argumentsString.add(", ");
-      argumentsString.add(temporaryId(arguments[i]));
+      if (i != 0) argumentsString.write(", ");
+      argumentsString.write(temporaryId(arguments[i]));
     }
     return "$invokeType: $functionName($argumentsString)";
   }
@@ -397,8 +396,8 @@
   String visitLiteralList(HLiteralList node) {
     StringBuffer elementsString = new StringBuffer();
     for (int i = 0; i < node.inputs.length; i++) {
-      if (i != 0) elementsString.add(", ");
-      elementsString.add(temporaryId(node.inputs[i]));
+      if (i != 0) elementsString.write(", ");
+      elementsString.write(temporaryId(node.inputs[i]));
     }
     return "Literal list: [$elementsString]";
   }
@@ -429,12 +428,12 @@
 
   String visitPhi(HPhi phi) {
     StringBuffer buffer = new StringBuffer();
-    buffer.add("Phi(");
+    buffer.write("Phi(");
     for (int i = 0; i < phi.inputs.length; i++) {
-      if (i > 0) buffer.add(", ");
-      buffer.add(temporaryId(phi.inputs[i]));
+      if (i > 0) buffer.write(", ");
+      buffer.write(temporaryId(phi.inputs[i]));
     }
-    buffer.add(")");
+    buffer.write(")");
     return buffer.toString();
   }
 
@@ -466,17 +465,17 @@
 
   String visitSwitch(HSwitch node) {
     StringBuffer buf = new StringBuffer();
-    buf.add("Switch: (");
-    buf.add(temporaryId(node.inputs[0]));
-    buf.add(") ");
+    buf.write("Switch: (");
+    buf.write(temporaryId(node.inputs[0]));
+    buf.write(") ");
     for (int i = 1; i < node.inputs.length; i++) {
-      buf.add(temporaryId(node.inputs[i]));
-      buf.add(": B");
-      buf.add(node.block.successors[i - 1].id);
-      buf.add(", ");
+      buf.write(temporaryId(node.inputs[i]));
+      buf.write(": B");
+      buf.write(node.block.successors[i - 1].id);
+      buf.write(", ");
     }
-    buf.add("default: B");
-    buf.add(node.block.successors.last.id);
+    buf.write("default: B");
+    buf.write(node.block.successors.last.id);
     return buf.toString();
   }
 
@@ -539,7 +538,7 @@
     assert(inputs[0] == guarded);
     assert(inputs[1] == bailoutTarget);
     for (int i = 2; i < inputs.length; i++) {
-      envBuffer.add(" ${temporaryId(inputs[i])}");
+      envBuffer.write(" ${temporaryId(inputs[i])}");
     }
     String on = node.isEnabled ? "enabled" : "disabled";
     String guardedId = temporaryId(node.guarded);
@@ -554,7 +553,8 @@
   }
 
   String visitTypeConversion(HTypeConversion node) {
-    return "TypeConversion: ${temporaryId(node.checkedInput)} to ${node.type}";
+    return "TypeConversion: ${temporaryId(node.checkedInput)} to "
+      "${node.instructionType}";
   }
 
   String visitRangeConversion(HRangeConversion node) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index 8b55c23..8372c2b 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -29,7 +29,7 @@
     JavaScriptBackend backend = compiler.backend;
     if (element == compiler.intClass || element == backend.jsIntClass) {
       return canBeNull ? HType.INTEGER_OR_NULL : HType.INTEGER;
-    } else if (element == compiler.numClass 
+    } else if (element == compiler.numClass
                || element == backend.jsNumberClass) {
       return canBeNull ? HType.NUMBER_OR_NULL : HType.NUMBER;
     } else if (element == compiler.doubleClass
@@ -48,7 +48,7 @@
       return canBeNull
           ? HType.READABLE_ARRAY.union(HType.NULL, compiler)
           : HType.READABLE_ARRAY;
-    } else if (!isExact) {
+    } else if (isInterfaceType) {
       if (element == compiler.listClass
           || Elements.isListSupertype(element, compiler)) {
         return new HBoundedPotentialPrimitiveArray(
@@ -65,15 +65,16 @@
             type,
             canBeNull: canBeNull,
             isInterfaceType: isInterfaceType);
-      } else if (element == compiler.objectClass
-                 || element == compiler.dynamicClass) {
-        return new HBoundedPotentialPrimitiveType(
-            compiler.objectClass.computeType(compiler),
-            true,
-            canBeNull: canBeNull,
-            isInterfaceType: isInterfaceType);
       }
     }
+    if (!isExact && (element == compiler.objectClass ||
+                     element == compiler.dynamicClass)) {
+      return new HBoundedPotentialPrimitiveType(
+          compiler.objectClass.computeType(compiler),
+          true,
+          canBeNull: canBeNull,
+          isInterfaceType: isInterfaceType);
+    }
     return new HBoundedType(
         type,
         canBeNull: canBeNull,
@@ -117,6 +118,75 @@
         isInterfaceType: true);
   }
 
+  factory HType.fromBaseType(BaseType baseType, Compiler compiler) {
+    if (!baseType.isClass()) return HType.UNKNOWN;
+    ClassBaseType classBaseType = baseType;
+    ClassElement cls = classBaseType.element;
+    // Special case the list and map classes that are used as types
+    // for literals in the type inferrer.
+    if (cls == compiler.listClass) {
+      return HType.READABLE_ARRAY;
+    } else if (cls == compiler.mapClass) {
+      // TODO(ngeoffray): get the actual implementation of a map
+      // literal.
+      return new HType.nonNullSubtype(
+          compiler.mapLiteralClass.computeType(compiler), compiler);
+    } else {
+      return new HType.nonNullExactClass(
+          cls.computeType(compiler), compiler);
+    }
+  }
+
+  factory HType.fromInferredType(ConcreteType concreteType, Compiler compiler) {
+    if (concreteType == null) return HType.UNKNOWN;
+    HType ssaType = HType.CONFLICTING;
+    for (BaseType baseType in concreteType.baseTypes) {
+      ssaType = ssaType.union(
+          new HType.fromBaseType(baseType, compiler), compiler);
+    }
+    if (ssaType.isConflicting()) return HType.UNKNOWN;
+    return ssaType;
+  }
+
+  factory HType.inferredForElement(Element element, Compiler compiler) {
+    return new HType.fromInferredType(
+        compiler.typesTask.getGuaranteedTypeOfElement(element),
+        compiler);
+  }
+
+  factory HType.inferredForNode(
+      Element owner, Node node, Compiler compiler) {
+    return new HType.fromInferredType(
+        compiler.typesTask.getGuaranteedTypeOfNode(owner, node),
+        compiler);
+  }
+
+  // [type] is either an instance of [DartType] or special objects
+  // like [native.SpecialType.JsObject], or [native.SpecialType.JsArray].
+  factory HType.fromNativeType(type, Compiler compiler) {
+    if (type == native.SpecialType.JsObject) {
+      return new HType.nonNullExactClass(
+          compiler.objectClass.computeType(compiler), compiler);
+    } else if (type == native.SpecialType.JsArray) {
+      return HType.READABLE_ARRAY;
+    } else {
+      return new HType.nonNullSubclass(type, compiler);
+    }
+  }
+
+  factory HType.fromNativeBehavior(native.NativeBehavior nativeBehavior,
+                                   Compiler compiler) {
+    if (nativeBehavior.typesInstantiated.isEmpty) return HType.UNKNOWN;
+
+    HType ssaType = HType.CONFLICTING;
+    for (final type in nativeBehavior.typesInstantiated) {
+      ssaType = ssaType.union(
+          new HType.fromNativeType(type, compiler), compiler);
+    }
+    assert(!ssaType.isConflicting());
+    return ssaType;
+  }
+
   static const HType CONFLICTING = const HConflictingType();
   static const HType UNKNOWN = const HUnknownType();
   static const HType BOOLEAN = const HBooleanType();
@@ -169,27 +239,23 @@
   /** Alias for isReadableArray. */
   bool isArray() => isReadableArray();
 
-  Element lookupSingleTarget(Selector selector, Compiler compiler) {
-    if (isInterfaceType()) return null;
-    DartType type = computeType(compiler);
-    if (type == null) return null;
-    ClassElement cls = type.element;
-    Element member = cls.lookupSelector(selector);
-    if (member == null) return null;
-    // [:ClassElement.lookupSelector:] may return an abstract field,
-    // and selctors don't work well with them.
-    // TODO(ngeoffray): Clean up lookupSelector and selectors to know
-    // if it's a getter or a setter that we're interested in.
-    if (!member.isFunction()) return null;
-    if (!selector.applies(member, compiler)) return null;
-    if (!isExact() && !compiler.world.hasNoOverridingMember(member)) {
-      return null;
-    }
-    return member;
-  }
-
   DartType computeType(Compiler compiler);
 
+  Selector refine(Selector selector, Compiler compiler) {
+    DartType receiverType = computeType(compiler);
+    if (receiverType != null && !receiverType.isMalformed) {
+      if (isExact()) {
+        return new TypedSelector.exact(receiverType, selector);
+      } else if (isInterfaceType()) {
+        return new TypedSelector.subtype(receiverType, selector);
+      } else {
+        return new TypedSelector.subclass(receiverType, selector);
+      }
+    } else {
+      return selector;
+    }
+  }
+
   /**
    * The intersection of two types is the intersection of its values. For
    * example:
@@ -259,7 +325,7 @@
   const HNullType();
   bool canBeNull() => true;
   bool isNull() => true;
-  String toString() => 'null';
+  String toString() => 'null type';
 
   DartType computeType(Compiler compiler) {
     JavaScriptBackend backend = compiler.backend;
@@ -702,7 +768,7 @@
 
   DartType computeType(Compiler compiler) {
     JavaScriptBackend backend = compiler.backend;
-    return backend.jsArrayClass.computeType(compiler);
+    return backend.jsArrayClass.rawType;
   }
 
   HType union(HType other, Compiler compiler) {
@@ -1101,31 +1167,3 @@
     return super.intersection(other, compiler);
   }
 }
-
-class HTypeMap {
-  // Approximately 85% of methods in the sample "swarm" have less than
-  // 32 instructions.
-  static const int INITIAL_SIZE = 32;
-
-  List<HType> _list = new List<HType>()..length = INITIAL_SIZE;
-
-  operator [](HInstruction instruction) {
-    HType result;
-    if (instruction.id < _list.length) result = _list[instruction.id];
-    if (result == null) return instruction.guaranteedType;
-    return result;
-  }
-
-  operator []=(HInstruction instruction, HType value) {
-    int length = _list.length;
-    int id = instruction.id;
-    if (length <= id) {
-      if (id + 1 < length * 2) {
-        _list.length = length * 2;
-      } else {
-        _list.length = id + 1;
-      }
-    }
-    _list[id] = value;
-  }
-}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
index 223e017..71a20d6 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
@@ -4,62 +4,57 @@
 
 part of ssa;
 
-class SsaTypePropagator extends HGraphVisitor implements OptimizationPhase {
+abstract class SsaTypePropagator extends HBaseVisitor
+    implements OptimizationPhase {
 
   final Map<int, HInstruction> workmap;
   final List<int> worklist;
   final Map<HInstruction, Function> pendingOptimizations;
-  final HTypeMap types;
 
   final Compiler compiler;
   String get name => 'type propagator';
 
-  SsaTypePropagator(this.compiler, this.types)
+  SsaTypePropagator(this.compiler)
       : workmap = new Map<int, HInstruction>(),
         worklist = new List<int>(),
         pendingOptimizations = new Map<HInstruction, Function>();
 
+  // Compute the (shared) type of the inputs if any. If all inputs
+  // have the same known type return it. If any two inputs have
+  // different known types, we'll return a conflict -- otherwise we'll
+  // simply return an unknown type.
+  HType computeInputsType(HPhi phi, bool ignoreUnknowns) {
+    HType candidateType = HType.CONFLICTING;
+    for (int i = 0, length = phi.inputs.length; i < length; i++) {
+      HType inputType = phi.inputs[i].instructionType;
+      if (ignoreUnknowns && inputType.isUnknown()) continue;
+      // Phis need to combine the incoming types using the union operation.
+      // For example, if one incoming edge has type integer and the other has
+      // type double, then the phi is either an integer or double and thus has
+      // type number.
+      candidateType = candidateType.union(inputType, compiler);
+      if (candidateType.isUnknown()) return HType.UNKNOWN;
+    }
+    return candidateType;
+  }
+
   HType computeType(HInstruction instruction) {
-    return instruction.computeTypeFromInputTypes(types, compiler);
+    return instruction.accept(this);
   }
 
   // Re-compute and update the type of the instruction. Returns
   // whether or not the type was changed.
   bool updateType(HInstruction instruction) {
-    // The [updateType] method is invoked when one of the inputs of
-    // the instruction changes its type. That gives us a new
-    // opportunity to consider this instruction for optimizations.
-    considerForArgumentTypeOptimization(instruction);
     // Compute old and new types.
-    HType oldType = types[instruction];
+    HType oldType = instruction.instructionType;
     HType newType = computeType(instruction);
+    assert(newType != null);
     // We unconditionally replace the propagated type with the new type. The
     // computeType must make sure that we eventually reach a stable state.
-    types[instruction] = newType;
+    instruction.instructionType = newType;
     return oldType != newType;
   }
 
-  void considerForArgumentTypeOptimization(HInstruction instruction) {
-    // Update the pending optimizations map based on the potentially
-    // new types of the operands. If the operand types no longer allow
-    // us to optimize, we remove the pending optimization.
-    if (instruction is !HInvokeDynamicMethod) return;
-    HInvokeDynamicMethod invoke = instruction;
-    if (instruction.specializer is !BinaryArithmeticSpecializer) return;
-    HInstruction left = instruction.inputs[1];
-    HInstruction right = instruction.inputs[2];
-    if (left.isNumber(types) && !right.isNumber(types)) {
-      pendingOptimizations[instruction] = () {
-        // This callback function is invoked after we're done
-        // propagating types. The types shouldn't have changed.
-        assert(left.isNumber(types) && !right.isNumber(types));
-        convertInput(instruction, right, HType.NUMBER);
-      };
-    } else {
-      pendingOptimizations.remove(instruction);
-    }
-  }
-
   void visitGraph(HGraph graph) {
     visitDominatorTree(graph);
     processWorklist();
@@ -75,7 +70,7 @@
         // the type of all other incoming edges as "unitialized" and take this
         // into account when doing the propagation inside the phis. Just
         // setting the propagated type is however easier.
-        types[phi] = types[phi.inputs[0]];
+        phi.instructionType = phi.inputs[0].instructionType;
         addToWorkList(phi);
       });
     } else {
@@ -114,16 +109,11 @@
     } while (!worklist.isEmpty);
   }
 
-  void addDependentInstructionsToWorkList(HInstruction instruction) {
-    for (int i = 0, length = instruction.usedBy.length; i < length; i++) {
-      // The non-speculative type propagator only propagates types forward. We
-      // thus only need to add the users of the [instruction] to the list.
-      addToWorkList(instruction.usedBy[i]);
-    }
-  }
+  void addDependentInstructionsToWorkList(HInstruction instruction) {}
 
   void addToWorkList(HInstruction instruction) {
     final int id = instruction.id;
+
     if (!workmap.containsKey(id)) {
       worklist.add(id);
       workmap[id] = instruction;
@@ -135,6 +125,64 @@
     pendingOptimizations.clear();
   }
 
+  HType visitInvokeDynamic(HInvokeDynamic instruction) {
+    int receiverIndex = instruction.isInterceptorCall ? 1 : 0;
+    HType receiverType = instruction.inputs[receiverIndex].instructionType;
+    Selector refined = receiverType.refine(instruction.selector, compiler);
+    // TODO(kasperl): Ask the type inferrer about the type of the
+    // selector not the individual elements. This is basically code
+    // lifted out of the inferrer. Not good.
+    HType type = HType.CONFLICTING;
+    DartType functionType = compiler.functionClass.computeType(compiler);
+    for (Element each in compiler.world.allFunctions.filter(refined)) {
+      HType inferred = (refined.isGetter() && each.isFunction())
+          ? new HType.nonNullExactClass(functionType, compiler)
+          : new HType.inferredForElement(each, compiler);
+      type = type.union(inferred, compiler);
+      if (type.isUnknown()) break;
+    }
+    if (type.isUseful()) return type;
+    return instruction.specializer.computeTypeFromInputTypes(
+        instruction, compiler);
+  }
+
+  HType visitBinaryArithmetic(HBinaryArithmetic instruction) {
+    HInstruction left = instruction.left;
+    HInstruction right = instruction.right;
+    if (left.isInteger() && right.isInteger()) return HType.INTEGER;
+    if (left.isDouble()) return HType.DOUBLE;
+    return HType.NUMBER;
+  }
+
+  HType visitNegate(HNegate instruction) {
+    return instruction.operand.instructionType;
+  }
+
+  HType visitInstruction(HInstruction instruction) {
+    assert(instruction.instructionType != null);
+    return instruction.instructionType;
+  }
+
+  HType visitPhi(HPhi phi) {
+    HType inputsType = computeInputsType(phi, false);
+    if (inputsType.isConflicting()) return HType.UNKNOWN;
+    return inputsType;
+  }
+}
+
+class SsaNonSpeculativeTypePropagator extends SsaTypePropagator {
+  final String name = 'non speculative type propagator';
+  DesiredTypeVisitor desiredTypeVisitor;
+  SsaNonSpeculativeTypePropagator(Compiler compiler) : super(compiler);
+
+  void addDependentInstructionsToWorkList(HInstruction instruction) {
+    for (int i = 0, length = instruction.usedBy.length; i < length; i++) {
+      // The non-speculative type propagator only propagates types forward. We
+      // thus only need to add the users of the [instruction] to the list.
+      addToWorkList(instruction.usedBy[i]);
+    }
+  }
+
   void convertInput(HInstruction instruction, HInstruction input, HType type) {
     HTypeConversion converted =
         new HTypeConversion.argumentTypeCheck(type, input);
@@ -145,12 +193,114 @@
       addToWorkList(user);
     }
   }
+
+  HType visitInvokeDynamicMethod(HInvokeDynamicMethod instruction) {
+    // Update the pending optimizations map based on the potentially
+    // new types of the operands. If the operand types no longer allow
+    // us to optimize, we remove the pending optimization.
+    if (instruction.specializer is BinaryArithmeticSpecializer) {
+      HInstruction left = instruction.inputs[1];
+      HInstruction right = instruction.inputs[2];
+      if (left.isNumber() && !right.isNumber()) {
+        pendingOptimizations[instruction] = () {
+          // This callback function is invoked after we're done
+          // propagating types. The types shouldn't have changed.
+          assert(left.isNumber() && !right.isNumber());
+          convertInput(instruction, right, HType.NUMBER);
+        };
+      } else {
+        pendingOptimizations.remove(instruction);
+      }
+    }
+    return super.visitInvokeDynamicMethod(instruction);
+  }
+}
+
+/**
+ * Visitor whose methods return the desired type for the input of an
+ * instruction.
+ */
+class DesiredTypeVisitor extends HBaseVisitor {
+  final Compiler compiler;
+  final SsaTypePropagator propagator;
+  HInstruction input;
+
+  DesiredTypeVisitor(this.compiler, this.propagator);
+
+  HType visitInstruction(HInstruction instruction) {
+    return HType.UNKNOWN;
+  }
+
+  HType visitIntegerCheck(HIntegerCheck instruction) {
+    // If the desired type of the input is already a number, we want
+    // to specialize it to an integer.
+    return input.isNumber() ? HType.INTEGER : HType.UNKNOWN;
+  }
+
+  HType visitInvokeDynamic(HInvokeDynamic instruction) {
+    return instruction.specializer.computeDesiredTypeForInput(
+        instruction, input, compiler);
+  }
+
+  HType visitNot(HNot instruction) {
+    return HType.BOOLEAN;
+  }
+
+  HType visitPhi(HPhi phi) {
+    HType propagatedType = phi.instructionType;
+    // Best case scenario for a phi is, when all inputs have the same type. If
+    // there is no desired outgoing type we therefore try to unify the input
+    // types (which is basically the [likelyType]).
+    if (propagatedType.isUnknown()) return computeLikelyType(phi);
+    // When the desired outgoing type is conflicting we don't need to give any
+    // requirements on the inputs.
+    if (propagatedType.isConflicting()) return HType.UNKNOWN;
+    // Otherwise the input type must match the desired outgoing type.
+    return propagatedType;
+  }
+
+  HType computeLikelyType(HPhi phi) {
+    HType agreedType = propagator.computeInputsType(phi, true);
+    if (agreedType.isConflicting()) return HType.UNKNOWN;
+    // Don't be too restrictive. If the agreed type is integer or double just
+    // say that the likely type is number. If more is expected the type will be
+    // propagated back.
+    if (agreedType.isNumber()) return HType.NUMBER;
+    return agreedType;
+  }
+
+  HType visitInterceptor(HInterceptor instruction) {
+    if (instruction.interceptedClasses.length != 1) return HType.UNKNOWN;
+    // If the only class being intercepted is of type number, we
+    // make this interceptor call say it wants that class as input.
+    Element interceptor = instruction.interceptedClasses.toList()[0];
+    JavaScriptBackend backend = compiler.backend;
+    if (interceptor == backend.jsNumberClass) {
+      return HType.NUMBER;
+    } else if (interceptor == backend.jsIntClass) {
+      return HType.INTEGER;
+    } else if (interceptor == backend.jsDoubleClass) {
+      return HType.DOUBLE;
+    }
+    return HType.UNKNOWN;
+  }
+
+  HType computeDesiredTypeForInput(HInstruction user, HInstruction input) {
+    this.input = input;
+    HType desired = user.accept(this);
+    this.input = null;
+    return desired;
+  }
 }
 
 class SsaSpeculativeTypePropagator extends SsaTypePropagator {
   final String name = 'speculative type propagator';
-  SsaSpeculativeTypePropagator(Compiler compiler, HTypeMap types)
-      : super(compiler, types);
+  DesiredTypeVisitor desiredTypeVisitor;
+  final Map<HInstruction, HType> savedTypes;
+  SsaSpeculativeTypePropagator(Compiler compiler, this.savedTypes)
+      : super(compiler) {
+    desiredTypeVisitor = new DesiredTypeVisitor(compiler, this);
+  }
 
   void addDependentInstructionsToWorkList(HInstruction instruction) {
     // The speculative type propagator propagates types forward and backward.
@@ -168,16 +318,9 @@
   HType computeDesiredType(HInstruction instruction) {
     HType desiredType = HType.UNKNOWN;
     for (final user in instruction.usedBy) {
-      HType userType =
-          user.computeDesiredTypeForInput(instruction, types, compiler);
-      // Mainly due to the "if (true)" added by hackAroundPossiblyAbortingBody
-      // in builder.dart uninitialized variables will propagate a type of null
-      // which will result in a conflicting type when combined with a primitive
-      // type. Avoid this to improve generated code.
-      // TODO(sgjesse): Reconcider this when hackAroundPossiblyAbortingBody
-      // has been removed.
-      if (desiredType.isPrimitive() && userType == HType.NULL) continue;
-      desiredType = desiredType.intersection(userType, compiler);
+      HType userDesiredType =  desiredTypeVisitor.computeDesiredTypeForInput(
+          user, instruction);
+      desiredType = desiredType.intersection(userDesiredType, compiler);
       // No need to continue if two users disagree on the type.
       if (desiredType.isConflicting()) break;
     }
@@ -186,24 +329,27 @@
 
   HType computeType(HInstruction instruction) {
     // Once we are in a conflicting state don't update the type anymore.
-    HType oldType = types[instruction];
+    HType oldType = instruction.instructionType;
     if (oldType.isConflicting()) return oldType;
 
     HType newType = super.computeType(instruction);
+    if (oldType != newType && !savedTypes.containsKey(instruction)) {
+      savedTypes[instruction] = oldType;
+    }
     // [computeDesiredType] goes to all usedBys and lets them compute their
     // desired type. By setting the [newType] here we give them more context to
     // work with.
-    types[instruction] = newType;
+    instruction.instructionType = newType;
     HType desiredType = computeDesiredType(instruction);
     // If the desired type is conflicting just return the computed type.
     if (desiredType.isConflicting()) return newType;
     // TODO(ngeoffray): Allow speculative optimizations on
     // non-primitive types?
     if (!desiredType.isPrimitive()) return newType;
-    return newType.intersection(desiredType, compiler);
+    desiredType = newType.intersection(desiredType, compiler);
+    if (desiredType != newType && !savedTypes.containsKey(instruction)) {
+      savedTypes[instruction] = oldType;
+    }
+    return desiredType;
   }
-
-  // Do not use speculative argument type optimization for now.
-  void considerForArgumentTypeOptimization(HInstruction instruction) { }
-
 }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
index 7ea24ed..e8f3d55 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
@@ -552,13 +552,12 @@
   final Map<HInstruction, Range> ranges = new Map<HInstruction, Range>();
 
   final ConstantSystem constantSystem;
-  final HTypeMap types;
   final ValueRangeInfo info;
 
   CodegenWorkItem work;
   HGraph graph;
 
-  SsaValueRangeAnalyzer(constantSystem, this.types, this.work)
+  SsaValueRangeAnalyzer(constantSystem, this.work)
       : info = new ValueRangeInfo(constantSystem),
         this.constantSystem = constantSystem;
 
@@ -582,7 +581,7 @@
 
     void visit(HInstruction instruction) {
       Range range = instruction.accept(this);
-      if (instruction.isInteger(types)) {
+      if (instruction.isInteger()) {
         assert(range != null);
         ranges[instruction] = range;
       }
@@ -597,13 +596,13 @@
   }
 
   Range visitParameterValue(HParameterValue parameter) {
-    if (!parameter.isInteger(types)) return info.newUnboundRange();
+    if (!parameter.isInteger()) return info.newUnboundRange();
     Value value = info.newInstructionValue(parameter);
     return info.newRange(value, value);
   }
 
   Range visitPhi(HPhi phi) {
-    if (!phi.isInteger(types)) return info.newUnboundRange();
+    if (!phi.isInteger()) return info.newUnboundRange();
     if (phi.block.isLoopHeader()) {
       Range range = tryInferLoopPhiRange(phi);
       if (range == null) return info.newUnboundRange();
@@ -619,19 +618,19 @@
 
   Range tryInferLoopPhiRange(HPhi phi) {
     HInstruction update = phi.inputs[1];
-    return update.accept(new LoopUpdateRecognizer(phi, ranges, types, info));
+    return update.accept(new LoopUpdateRecognizer(phi, ranges, info));
   }
 
   Range visitConstant(HConstant constant) {
-    if (!constant.isInteger(types)) return info.newUnboundRange();
+    if (!constant.isInteger()) return info.newUnboundRange();
     IntConstant constantInt = constant.constant;
     Value value = info.newIntValue(constantInt.value);
     return info.newRange(value, value);
   }
 
   Range visitFieldGet(HFieldGet fieldGet) {
-    if (!fieldGet.isInteger(types)) return info.newUnboundRange();
-    if (!fieldGet.receiver.isIndexablePrimitive(types)) {
+    if (!fieldGet.isInteger()) return info.newUnboundRange();
+    if (!fieldGet.receiver.isIndexablePrimitive()) {
       return visitInstruction(fieldGet);
     }
     LengthValue value = info.newLengthValue(fieldGet);
@@ -647,8 +646,8 @@
     HInstruction next = check.next;
     Range indexRange = ranges[check.index];
     Range lengthRange = ranges[check.length];
-    assert(check.index.isInteger(types));
-    assert(check.length.isInteger(types));
+    assert(check.index.isInteger());
+    assert(check.length.isInteger());
 
     // Check if the index is strictly below the upper bound of the length
     // range.
@@ -703,8 +702,8 @@
   Range visitRelational(HRelational relational) {
     HInstruction right = relational.right;
     HInstruction left = relational.left;
-    if (!left.isInteger(types)) return info.newUnboundRange();
-    if (!right.isInteger(types)) return info.newUnboundRange();
+    if (!left.isInteger()) return info.newUnboundRange();
+    if (!right.isInteger()) return info.newUnboundRange();
     BinaryOperation operation = relational.operation(constantSystem);
     Range rightRange = ranges[relational.right];
     Range leftRange = ranges[relational.left];
@@ -734,7 +733,7 @@
   }
 
   Range handleBinaryOperation(HBinaryArithmetic instruction) {
-    if (!instruction.isInteger(types)) return info.newUnboundRange();
+    if (!instruction.isInteger()) return info.newUnboundRange();
     return instruction.operation(constantSystem).apply(
         ranges[instruction.left], ranges[instruction.right]);
   }
@@ -748,10 +747,10 @@
   }
 
   Range visitBitAnd(HBitAnd node) {
-    if (!node.isInteger(types)) return info.newUnboundRange();
+    if (!node.isInteger()) return info.newUnboundRange();
     HInstruction right = node.right;
     HInstruction left = node.left;
-    if (left.isInteger(types) && right.isInteger(types)) {
+    if (left.isInteger() && right.isInteger()) {
       return ranges[left] & ranges[right];
     }
 
@@ -765,9 +764,9 @@
       return info.newUnboundRange();
     }
 
-    if (left.isInteger(types)) {
+    if (left.isInteger()) {
       return tryComputeRange(left);
-    } else if (right.isInteger(types)) {
+    } else if (right.isInteger()) {
       return tryComputeRange(right);
     }
     return info.newUnboundRange();
@@ -835,8 +834,8 @@
     if (condition is HIdentity) return info.newUnboundRange();
     HInstruction right = condition.right;
     HInstruction left = condition.left;
-    if (!left.isInteger(types)) return info.newUnboundRange();
-    if (!right.isInteger(types)) return info.newUnboundRange();
+    if (!left.isInteger()) return info.newUnboundRange();
+    if (!right.isInteger()) return info.newUnboundRange();
 
     Range rightRange = ranges[right];
     Range leftRange = ranges[left];
@@ -899,9 +898,8 @@
 class LoopUpdateRecognizer extends HBaseVisitor {
   final HPhi loopPhi;
   final Map<HInstruction, Range> ranges;
-  final HTypeMap types;
   final ValueRangeInfo info;
-  LoopUpdateRecognizer(this.loopPhi, this.ranges, this.types, this.info);
+  LoopUpdateRecognizer(this.loopPhi, this.ranges, this.info);
 
   Range visitAdd(HAdd operation) {
     Range range = getRangeForRecognizableOperation(operation);
@@ -955,8 +953,8 @@
    * Otherwise returns [null].
    */
   Range getRangeForRecognizableOperation(HBinaryArithmetic operation) {
-    if (!operation.left.isInteger(types)) return null;
-    if (!operation.right.isInteger(types)) return null;
+    if (!operation.left.isInteger()) return null;
+    if (!operation.right.isInteger()) return null;
     HInstruction left = unwrap(operation.left);
     HInstruction right = unwrap(operation.right);
     // We only recognize operations that operate on the loop phi.
diff --git a/sdk/lib/_internal/compiler/implementation/tree/dartstring.dart b/sdk/lib/_internal/compiler/implementation/tree/dartstring.dart
index 5a3494d..70e2d69 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/dartstring.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/dartstring.dart
@@ -100,7 +100,7 @@
     StringBuffer buffer = new StringBuffer();
     StringEscapeIterator it = new StringEscapeIterator(source);
     while (it.moveNext()) {
-      buffer.addCharCode(it.current);
+      buffer.writeCharCode(it.current);
     }
     toStringCache = buffer.toString();
     return toStringCache;
diff --git a/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart b/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
index 129c637..62b6744 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
@@ -54,10 +54,10 @@
   void openNode(Node node, String type, [Map params]) {
     if (params == null) params = new Map();
     addCurrentIndent();
-    sb.add("<");
+    sb.write("<");
     addBeginAndEndTokensToParams(node, params);
     addTypeWithParams(type, params);
-    sb.add(">\n");
+    sb.write(">\n");
     pushTag(type);
   }
 
@@ -67,10 +67,10 @@
   void openAndCloseNode(Node node, String type, [Map params]) {
     if (params == null) params = new Map();
     addCurrentIndent();
-    sb.add("<");
+    sb.write("<");
     addBeginAndEndTokensToParams(node, params);
     addTypeWithParams(type, params);
-    sb.add("/>\n");
+    sb.write("/>\n");
   }
 
   /**
@@ -79,14 +79,14 @@
   void closeNode() {
     String tag = popTag();
     addCurrentIndent();
-    sb.add("</");
+    sb.write("</");
     addTypeWithParams(tag);
-    sb.add(">\n");
+    sb.write(">\n");
   }
 
   void addTypeWithParams(String type, [Map params]) {
     if (params == null) params = new Map();
-    sb.add("${type}");
+    sb.write("${type}");
     params.forEach((k, v) {
       String value;
       if (v != null) {
@@ -97,12 +97,12 @@
       } else {
         value = "[null]";
       }
-      sb.add(' $k="$value"');
+      sb.write(' $k="$value"');
     });
   }
 
   void addCurrentIndent() {
-    tagStack.forEach((_) { sb.add(INDENT); });
+    tagStack.forEach((_) { sb.write(INDENT); });
   }
 
   /**
@@ -318,12 +318,12 @@
   visitChildNode(Node node, String fieldName) {
     if (node == null) return;
     addCurrentIndent();
-    sb.add("<$fieldName>\n");
+    sb.write("<$fieldName>\n");
     pushTag(fieldName);
     node.accept(this);
     popTag();
     addCurrentIndent();
-    sb.add("</$fieldName>\n");
+    sb.write("</$fieldName>\n");
   }
 
   openSendNodeWithFields(Send node, String type) {
diff --git a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
index 9c20f2d..46eb2bf 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
@@ -26,7 +26,7 @@
     add(token.value);
     if (identical(token.kind, KEYWORD_TOKEN)
         || identical(token.kind, IDENTIFIER_TOKEN)) {
-      sb.add(' ');
+      sb.write(' ');
     }
   }
 
@@ -58,23 +58,23 @@
       visit(node.typeParameters);
     }
     if (node.extendsKeyword != null) {
-      sb.add(' ');
+      sb.write(' ');
       addToken(node.extendsKeyword);
       visit(node.superclass);
     }
     if (!node.interfaces.isEmpty) {
-      sb.add(' ');
+      sb.write(' ');
       visit(node.interfaces);
     }
     if (node.defaultClause != null) {
-      sb.add(' default ');
+      sb.write(' default ');
       visit(node.defaultClause);
     }
-    sb.add('{');
+    sb.write('{');
     for (final member in members) {
       visit(member);
     }
-    sb.add('}');
+    sb.write('}');
   }
 
   visitClassNode(ClassNode node) {
@@ -83,27 +83,27 @@
 
   visitMixinApplication(MixinApplication node) {
     visit(node.superclass);
-    sb.add(' with ');
+    sb.write(' with ');
     visit(node.mixins);
   }
 
   visitNamedMixinApplication(NamedMixinApplication node) {
-    sb.add('typedef ');
+    sb.write('typedef ');
     visit(node.name);
     if (node.typeParameters != null) {
       visit(node.typeParameters);
     }
-    sb.add(' = ');
+    sb.write(' = ');
     if (!node.modifiers.nodes.isEmpty) {
       visit(node.modifiers);
-      sb.add(' ');
+      sb.write(' ');
     }
     visit(node.mixinApplication);
     if (node.interfaces != null) {
-      sb.add(' implements ');
+      sb.write(' implements ');
       visit(node.interfaces);
     }
-    sb.add(';');
+    sb.write(';');
   }
 
   visitConditional(Conditional node) {
@@ -121,12 +121,12 @@
 
   visitFor(For node) {
     add(node.forToken.value);
-    sb.add('(');
+    sb.write('(');
     visit(node.initializer);
-    sb.add(';');
+    sb.write(';');
     visit(node.conditionStatement);
     visit(node.update);
-    sb.add(')');
+    sb.write(')');
     visit(node.body);
   }
 
@@ -145,15 +145,15 @@
       if (!send.isOperator) {
         // Looks like a factory method.
         visit(send.receiver);
-        sb.add('.');
+        sb.write('.');
       } else {
         visit(send.receiver);
         Identifier identifier = send.selector.asIdentifier();
         if (identical(identifier.token.kind, KEYWORD_TOKEN)) {
-          sb.add(' ');
+          sb.write(' ');
         } else if (identifier.source == const SourceString('negate')) {
           // TODO(ahe): Remove special case for negate.
-          sb.add(' ');
+          sb.write(' ');
         }
       }
       visit(send.selector);
@@ -165,15 +165,15 @@
   visitFunctionExpression(FunctionExpression node) {
     if (!node.modifiers.nodes.isEmpty) {
       visit(node.modifiers);
-      sb.add(' ');
+      sb.write(' ');
     }
     if (node.returnType != null) {
       visit(node.returnType);
-      sb.add(' ');
+      sb.write(' ');
     }
     if (node.getOrSet != null) {
       add(node.getOrSet.value);
-      sb.add(' ');
+      sb.write(' ');
     }
     unparseFunctionName(node.name);
     visit(node.parameters);
@@ -191,7 +191,7 @@
     visit(node.thenPart);
     if (node.hasElsePart) {
       add(node.elseToken.value);
-      if (node.elsePart is !Block) sb.add(' ');
+      if (node.elsePart is !Block) sb.write(' ');
       visit(node.elsePart);
     }
   }
@@ -218,7 +218,7 @@
 
   visitStringJuxtaposition(StringJuxtaposition node) {
     visit(node.first);
-    sb.add(" ");
+    sb.write(" ");
     visit(node.second);
   }
 
@@ -236,7 +236,7 @@
     visit(node.typeArguments);
     visit(node.elements);
     // If list is empty, emit space after [] to disambiguate cases like []==[].
-    if (node.elements.isEmpty) sb.add(' ');
+    if (node.elements.isEmpty) sb.write(' ');
   }
 
   visitModifiers(Modifiers node) => node.visitChildren(this);
@@ -249,7 +249,7 @@
     String delimiter = (node.delimiter == null) ? "" : "${node.delimiter}";
     visit(from.head);
     for (Link link = from.tail; !link.isEmpty; link = link.tail) {
-      sb.add(delimiter);
+      sb.write(delimiter);
       visit(link.head);
     }
   }
@@ -268,11 +268,11 @@
 
   visitReturn(Return node) {
     if (node.isRedirectingFactoryBody) {
-      sb.add(' ');
+      sb.write(' ');
     }
     add(node.beginToken.value);
     if (node.hasExpression && node.beginToken.stringValue != '=>') {
-      sb.add(' ');
+      sb.write(' ');
     }
     visit(node.expression);
     if (node.endToken != null) add(node.endToken.value);
@@ -285,9 +285,9 @@
     if (asCascadeReceiver != null) {
       add(asCascadeReceiver.cascadeOperator.value);
     } else if (node.selector.asOperator() == null) {
-      sb.add('.');
+      sb.write('.');
     } else if (spacesNeeded) {
-      sb.add(' ');
+      sb.write(' ');
     }
   }
 
@@ -299,14 +299,14 @@
     if (node.isPrefix) visit(node.selector);
     unparseSendReceiver(node, spacesNeeded: spacesNeeded);
     if (!node.isPrefix && !node.isIndex) visit(node.selector);
-    if (spacesNeeded) sb.add(' ');
+    if (spacesNeeded) sb.write(' ');
     // Also add a space for sequences like x + +1 and y - -y.
     // TODO(ahe): remove case for '+' when we drop the support for it.
     if (node.argumentsNode != null && (identical(opString, '-')
         || identical(opString, '+'))) {
       Token beginToken = node.argumentsNode.getBeginToken();
       if (beginToken != null && identical(beginToken.stringValue, opString)) {
-        sb.add(' ');
+        sb.write(' ');
       }
     }
     visit(node.argumentsNode);
@@ -314,21 +314,21 @@
 
   visitSendSet(SendSet node) {
     if (node.isPrefix) {
-      sb.add(' ');
+      sb.write(' ');
       visit(node.assignmentOperator);
     }
     unparseSendReceiver(node);
     if (node.isIndex) {
-      sb.add('[');
+      sb.write('[');
       visit(node.arguments.head);
-      sb.add(']');
+      sb.write(']');
       if (!node.isPrefix) visit(node.assignmentOperator);
       unparseNodeListFrom(node.argumentsNode, node.argumentsNode.nodes.tail);
     } else {
       visit(node.selector);
       if (!node.isPrefix) {
         visit(node.assignmentOperator);
-        if (node.assignmentOperator.source.slowToString() != '=') sb.add(' ');
+        if (node.assignmentOperator.source.slowToString() != '=') sb.write(' ');
       }
       visit(node.argumentsNode);
     }
@@ -337,7 +337,7 @@
   visitThrow(Throw node) {
     add(node.throwToken.value);
     if (node.expression != null) {
-      sb.add(' ');
+      sb.write(' ');
       visit(node.expression);
     }
     node.endToken.value.printOn(sb);
@@ -351,7 +351,7 @@
   visitTypeVariable(TypeVariable node) {
     visit(node.name);
     if (node.bound != null) {
-      sb.add(' extends ');
+      sb.write(' extends ');
       visit(node.bound);
     }
   }
@@ -359,22 +359,22 @@
   visitVariableDefinitions(VariableDefinitions node) {
     visit(node.modifiers);
     if (!node.modifiers.nodes.isEmpty) {
-      sb.add(' ');
+      sb.write(' ');
     }
     if (node.type != null) {
       visit(node.type);
-      sb.add(' ');
+      sb.write(' ');
     }
     visit(node.definitions);
   }
 
   visitDoWhile(DoWhile node) {
     add(node.doKeyword.value);
-    if (node.body is !Block) sb.add(' ');
+    if (node.body is !Block) sb.write(' ');
     visit(node.body);
     add(node.whileKeyword.value);
     visit(node.condition);
-    sb.add(node.endToken.value);
+    sb.write(node.endToken.value);
   }
 
   visitWhile(While node) {
@@ -395,9 +395,9 @@
   }
 
   visitStringInterpolationPart(StringInterpolationPart node) {
-    sb.add('\${'); // TODO(ahe): Preserve the real tokens.
+    sb.write('\${'); // TODO(ahe): Preserve the real tokens.
     visit(node.expression);
-    sb.add('}');
+    sb.write('}');
     visit(node.string);
   }
 
@@ -408,7 +408,7 @@
   visitGotoStatement(GotoStatement node) {
     add(node.keywordToken.value);
     if (node.target != null) {
-      sb.add(' ');
+      sb.write(' ');
       visit(node.target);
     }
     add(node.semicolonToken.value);
@@ -424,12 +424,12 @@
 
   visitForIn(ForIn node) {
     add(node.forToken.value);
-    sb.add('(');
+    sb.write('(');
     visit(node.declaredIdentifier);
-    sb.add(' ');
+    sb.write(' ');
     addToken(node.inToken);
     visit(node.expression);
-    sb.add(')');
+    sb.write(')');
     visit(node.body);
   }
 
@@ -470,27 +470,27 @@
   visitSwitchCase(SwitchCase node) {
     visit(node.labelsAndCases);
     if (node.isDefaultCase) {
-      sb.add('default:');
+      sb.write('default:');
     }
     visit(node.statements);
   }
 
   unparseImportTag(String uri, [String prefix]) {
     final suffix = prefix == null ? '' : ' as $prefix';
-    sb.add('import "$uri"$suffix;');
+    sb.write('import "$uri"$suffix;');
   }
 
   visitScriptTag(ScriptTag node) {
     add(node.beginToken.value);
     visit(node.tag);
-    sb.add('(');
+    sb.write('(');
     visit(node.argument);
     if (node.prefixIdentifier != null) {
       visit(node.prefixIdentifier);
-      sb.add(':');
+      sb.write(':');
       visit(node.prefix);
     }
-    sb.add(')');
+    sb.write(')');
     add(node.endToken.value);
   }
 
@@ -506,7 +506,7 @@
 
   visitCaseMatch(CaseMatch node) {
     add(node.caseKeyword.value);
-    sb.add(" ");
+    sb.write(" ");
     visit(node.expression);
     add(node.colonToken.value);
   }
@@ -515,7 +515,7 @@
     addToken(node.onKeyword);
     if (node.type != null) {
       visit(node.type);
-      sb.add(' ');
+      sb.write(' ');
     }
     addToken(node.catchKeyword);
     visit(node.formals);
@@ -526,7 +526,7 @@
     addToken(node.typedefKeyword);
     if (node.returnType != null) {
       visit(node.returnType);
-      sb.add(' ');
+      sb.write(' ');
     }
     visit(node.name);
     if (node.typeParameters != null) {
@@ -546,12 +546,12 @@
     addToken(node.importKeyword);
     visit(node.uri);
     if (node.prefix != null) {
-      sb.add(' ');
+      sb.write(' ');
       addToken(node.asKeyword);
       visit(node.prefix);
     }
     if (node.combinators != null) {
-      sb.add(' ');
+      sb.write(' ');
       visit(node.combinators);
     }
     add(node.getEndToken().value);
@@ -561,7 +561,7 @@
     addToken(node.exportKeyword);
     visit(node.uri);
     if (node.combinators != null) {
-      sb.add(' ');
+      sb.write(' ');
       visit(node.combinators);
     }
     add(node.getEndToken().value);
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index 76f0c1b..6e79532 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -33,6 +33,80 @@
   CancelTypeCheckException(this.node, this.reason);
 }
 
+/**
+ * [ElementAccess] represents the access of [element], either as a property
+ * access or invocation.
+ */
+abstract class ElementAccess {
+  Element get element;
+
+  DartType computeType(Compiler compiler);
+
+  /// Returns [: true :] if the element can be access as an invocation.
+  bool isCallable(Compiler compiler) {
+    if (element.isAbstractField()) {
+      AbstractFieldElement abstractFieldElement = element;
+      if (abstractFieldElement.getter == null) {
+        // Setters cannot be invoked as function invocations.
+        return false;
+      }
+    }
+    return compiler.types.isAssignable(
+        computeType(compiler), compiler.functionClass.computeType(compiler));
+  }
+}
+
+/// An access of a instance member.
+class MemberAccess extends ElementAccess {
+  final Member member;
+
+  MemberAccess(Member this.member);
+
+  Element get element => member.element;
+
+  DartType computeType(Compiler compiler) => member.computeType(compiler);
+}
+
+/// An access of an unresolved element.
+class DynamicAccess implements ElementAccess {
+  const DynamicAccess();
+
+  Element get element => null;
+
+  DartType computeType(Compiler compiler) => compiler.types.dynamicType;
+
+  bool isCallable(Compiler compiler) => true;
+}
+
+/**
+ * An access of a resolved top-level or static property or function, or an
+ * access of a resolved element through [:this:].
+ */
+class ResolvedAccess extends ElementAccess {
+  final Element element;
+
+  ResolvedAccess(Element this.element) {
+    assert(element != null);
+  }
+
+  DartType computeType(Compiler compiler) => element.computeType(compiler);
+}
+
+/**
+ * An access of a resolved top-level or static property or function, or an
+ * access of a resolved element through [:this:].
+ */
+class TypeAccess extends ElementAccess {
+  final DartType type;
+  TypeAccess(DartType this.type) {
+    assert(type != null);
+  }
+
+  Element get element => type.element;
+
+  DartType computeType(Compiler compiler) => type;
+}
+
 class TypeCheckerVisitor implements Visitor<DartType> {
   final Compiler compiler;
   final TreeElements elements;
@@ -238,37 +312,26 @@
     return unhandledStatement();
   }
 
-  DartType lookupMethodType(Node node, ClassElement classElement,
-                            SourceString name) {
-    Element member = classElement.lookupLocalMember(name);
-    if (member == null) {
-      classElement.ensureResolved(compiler);
-      for (Link<DartType> supertypes = classElement.allSupertypes;
-           !supertypes.isEmpty && member == null;
-           supertypes = supertypes.tail) {
-        ClassElement lookupTarget = supertypes.head.element;
-        member = lookupTarget.lookupLocalMember(name);
-      }
+  ElementAccess lookupMethod(Node node, DartType type, SourceString name) {
+    if (identical(type, types.dynamicType)) {
+      return const DynamicAccess();
     }
-    if (member != null && member.kind == ElementKind.FUNCTION) {
-      return computeType(member);
+    Member member = type.lookupMember(name);
+    if (member != null) {
+      return new MemberAccess(member);
     }
     reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND,
-                      {'className': classElement.name, 'memberName': name});
-    return types.dynamicType;
+                      {'className': type.name, 'memberName': name});
+    return const DynamicAccess();
   }
 
   // TODO(johnniwinther): Provide the element from which the type came in order
   // to give better error messages.
   void analyzeArguments(Send send, DartType type) {
     Link<Node> arguments = send.arguments;
-    if (type == null || identical(type, types.dynamicType)) {
-      while(!arguments.isEmpty) {
-        analyze(arguments.head);
-        arguments = arguments.tail;
-      }
-    } else {
-      FunctionType funType = type;
+    DartType unaliasedType = type.unalias(compiler);
+    if (identical(unaliasedType.kind, TypeKind.FUNCTION)) {
+      FunctionType funType = unaliasedType;
       Link<DartType> parameterTypes = funType.parameterTypes;
       Link<DartType> optionalParameterTypes = funType.optionalParameterTypes;
       while (!arguments.isEmpty) {
@@ -315,6 +378,28 @@
         reportTypeWarning(send, MessageKind.MISSING_ARGUMENT,
             {'argumentType': parameterTypes.head});
       }
+    } else {
+      while(!arguments.isEmpty) {
+        analyze(arguments.head);
+        arguments = arguments.tail;
+      }
+    }
+  }
+
+  DartType analyzeInvocation(Send node, ElementAccess elementAccess) {
+    DartType type = elementAccess.computeType(compiler);
+    if (elementAccess.isCallable(compiler)) {
+      analyzeArguments(node, type);
+    } else {
+      reportTypeWarning(node, MessageKind.NOT_CALLABLE,
+          {'elementName': elementAccess.element.name});
+      analyzeArguments(node, types.dynamicType);
+    }
+    if (identical(type.kind, TypeKind.FUNCTION)) {
+      FunctionType funType = type;
+      return funType.returnType;
+    } else {
+      return types.dynamicType;
     }
   }
 
@@ -322,8 +407,14 @@
     Element element = elements[node];
 
     if (Elements.isClosureSend(node, element)) {
-      // TODO(karlklose): Finish implementation.
-      return types.dynamicType;
+      if (element != null) {
+        // foo() where foo is a local or a parameter.
+        return analyzeInvocation(node, new ResolvedAccess(element));
+      } else {
+        // exp() where exp is some complex expression like (o) or foo().
+        DartType type = analyze(node.selector);
+        return analyzeInvocation(node, new TypeAccess(type));
+      }
     }
 
     Identifier selector = node.selector.asIdentifier();
@@ -340,17 +431,22 @@
       final DartType secondArgumentType =
           analyzeWithDefault(secondArgument, null);
 
-      if (identical(name, '+') || identical(name, '=') || identical(name, '-')
-          || identical(name, '*') || identical(name, '/') || identical(name, '%')
-          || identical(name, '~/') || identical(name, '|') || identical(name, '&')
-          || identical(name, '^') || identical(name, '~')|| identical(name, '<<')
-          || identical(name, '>>') || identical(name, '[]')) {
+      if (identical(name, '+') || identical(name, '=') ||
+          identical(name, '-') || identical(name, '*') ||
+          identical(name, '/') || identical(name, '%') ||
+          identical(name, '~/') || identical(name, '|') ||
+          identical(name, '&') || identical(name, '^') ||
+          identical(name, '~')|| identical(name, '<<') ||
+          identical(name, '>>') || identical(name, '[]')) {
         return types.dynamicType;
-      } else if (identical(name, '<') || identical(name, '>') || identical(name, '<=')
-                 || identical(name, '>=') || identical(name, '==') || identical(name, '!=')
-                 || identical(name, '===') || identical(name, '!==')) {
+      } else if (identical(name, '<') || identical(name, '>') ||
+                 identical(name, '<=') || identical(name, '>=') ||
+                 identical(name, '==') || identical(name, '!=') ||
+                 identical(name, '===') || identical(name, '!==')) {
         return boolType;
-      } else if (identical(name, '||') || identical(name, '&&') || identical(name, '!')) {
+      } else if (identical(name, '||') ||
+                 identical(name, '&&') ||
+                 identical(name, '!')) {
         checkAssignable(firstArgument, boolType, firstArgumentType);
         if (!arguments.isEmpty) {
           // TODO(karlklose): check number of arguments in validator.
@@ -370,56 +466,46 @@
 
     } else if (node.isFunctionObjectInvocation) {
       fail(node.receiver, 'function object invocation unimplemented');
-
     } else {
-      FunctionType computeFunType() {
+      ElementAccess computeMethod() {
         if (node.receiver != null) {
+          // e.foo() for some expression e.
           DartType receiverType = analyze(node.receiver);
-          if (receiverType.element == compiler.dynamicClass) return null;
+          if (receiverType.element == compiler.dynamicClass) {
+            return const DynamicAccess();
+          }
           if (receiverType == null) {
-            fail(node.receiver, 'receivertype is null');
+            fail(node.receiver, 'receiverType is null');
           }
-          if (identical(receiverType.element.kind, ElementKind.GETTER)) {
-            FunctionType getterType  = receiverType;
-            receiverType = getterType.returnType;
-          }
-          ElementKind receiverKind = receiverType.element.kind;
-          if (identical(receiverKind, ElementKind.TYPEDEF)) {
+          TypeKind receiverKind = receiverType.kind;
+          if (identical(receiverKind, TypeKind.TYPEDEF)) {
             // TODO(karlklose): handle typedefs.
-            return null;
+            return const DynamicAccess();
           }
-          if (identical(receiverKind, ElementKind.TYPE_VARIABLE)) {
+          if (identical(receiverKind, TypeKind.TYPE_VARIABLE)) {
             // TODO(karlklose): handle type variables.
-            return null;
+            return const DynamicAccess();
           }
-          if (!identical(receiverKind, ElementKind.CLASS)) {
+          if (!identical(receiverKind, TypeKind.INTERFACE)) {
             fail(node.receiver, 'unexpected receiver kind: ${receiverKind}');
           }
-          ClassElement classElement = receiverType.element;
-          // TODO(karlklose): substitute type arguments.
-          DartType memberType =
-            lookupMethodType(selector, classElement, selector.source);
-          if (identical(memberType.element, compiler.dynamicClass)) return null;
-          return memberType;
+          return lookupMethod(selector, receiverType, selector.source);
         } else {
           if (Elements.isUnresolved(element)) {
-            fail(node, 'unresolved ${node.selector}');
-          } else if (identical(element.kind, ElementKind.FUNCTION)) {
-            return computeType(element);
-          } else if (element.isForeign(compiler)) {
-            return null;
-          } else if (identical(element.kind, ElementKind.VARIABLE)
-                     || identical(element.kind, ElementKind.FIELD)) {
-            // TODO(karlklose): handle object invocations.
-            return null;
+            // foo() where foo is unresolved.
+            return const DynamicAccess();
+          } else if (element.isFunction()) {
+            // foo() where foo is a method in the same class.
+            return new ResolvedAccess(element);
+          } else if (element.isVariable() || element.isField()) {
+            // foo() where foo is a field in the same class.
+            return new ResolvedAccess(element);
           } else {
             fail(node, 'unexpected element kind ${element.kind}');
           }
         }
       }
-      FunctionType funType = computeFunType();
-      analyzeArguments(node, funType);
-      return (funType != null) ? funType.returnType : types.dynamicType;
+      return analyzeInvocation(node, computeMethod());
     }
   }
 
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index f268488..8fde89a 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -39,7 +39,9 @@
     return element == other.element;
   }
   int get hashCode => element.hashCode;
-  String toString() => element.name.slowToString();
+  String toString() {
+    return element == null ? 'toplevel' : element.name.slowToString();
+  }
   bool isClass() => true;
   bool isUnknown() => false;
   bool isNull() => false;
@@ -287,20 +289,13 @@
   final ClassBaseType objectBaseType;
   final ClassBaseType typeBaseType;
 
-  static _getNativeListClass(Compiler compiler) {
-    // TODO(polux): switch to other implementations on other backends
-    JavaScriptBackend backend = compiler.backend;
-    return backend.jsArrayClass;
-  }
-
   BaseTypes(Compiler compiler) :
     intBaseType = new ClassBaseType(compiler.intClass),
     doubleBaseType = new ClassBaseType(compiler.doubleClass),
     numBaseType = new ClassBaseType(compiler.numClass),
     boolBaseType = new ClassBaseType(compiler.boolClass),
     stringBaseType = new ClassBaseType(compiler.stringClass),
-    // in the Javascript backend, lists are implemented by JsArray
-    listBaseType = new ClassBaseType(_getNativeListClass(compiler)),
+    listBaseType = new ClassBaseType(compiler.listClass),
     mapBaseType = new ClassBaseType(compiler.mapClass),
     objectBaseType = new ClassBaseType(compiler.objectClass),
     typeBaseType = new ClassBaseType(compiler.typeClass);
@@ -454,6 +449,15 @@
   /** [: readers[field] :] is the list of [: field :]'s possible readers. */
   final Map<Element, Set<FunctionElement>> readers;
 
+  /// The set of classes encountered so far.
+  final Set<ClassElement> seenClasses;
+
+  /**
+   * A map from method names to callers of methods with this name on objects
+   * of unknown inferred type.
+   */
+  final Map<SourceString, Set<FunctionElement>> dynamicCallers;
+
   /** The inferred type of elements stored in Lists. */
   ConcreteType listElementType;
 
@@ -473,7 +477,9 @@
         workQueue = new Queue<InferenceWorkItem>(),
         callers = new Map<FunctionElement, Set<FunctionElement>>(),
         readers = new Map<Element, Set<FunctionElement>>(),
-        listElementType = new ConcreteType.empty() {
+        listElementType = new ConcreteType.empty(),
+        seenClasses = new Set<ClassElement>(),
+        dynamicCallers = new Map<SourceString, Set<FunctionElement>>() {
     unknownConcreteType = new ConcreteType.unknown();
     emptyConcreteType = new ConcreteType.empty();
   }
@@ -509,7 +515,8 @@
       // resolve num for some reason.
       receiverType.element.ensureResolved(compiler);
       FunctionElement methodElement =
-          receiverType.element.lookupMember(new SourceString(method));
+          receiverType.element.lookupMember(new SourceString(method))
+              .implementation;
       ConcreteTypesEnvironment environment =
           makeEnvironment(receiverType, methodElement, argumentType);
       Map<ConcreteTypesEnvironment, ConcreteType> map =
@@ -563,10 +570,10 @@
   List<Element> getMembersByName(SourceString methodName) {
     // TODO(polux): memoize?
     var result = new List<Element>();
-    for (ClassElement cls in compiler.enqueuer.resolution.seenClasses) {
+    for (ClassElement cls in seenClasses) {
       Element elem = cls.lookupLocalMember(methodName);
       if (elem != null) {
-        result.add(elem);
+        result.add(elem.implementation);
       }
     }
     return result;
@@ -635,6 +642,20 @@
         (oldType == null) ? type : union(oldType, type);
   }
 
+  /// Augments the set of classes encountered so far.
+  void augmentSeenClasses(ClassElement cls) {
+    if (!seenClasses.contains(cls)) {
+      seenClasses.add(cls);
+      cls.forEachLocalMember((Element member) {
+        Set<FunctionElement> functions = dynamicCallers[member.name];
+        if (functions == null) return;
+        for (FunctionElement function in functions) {
+          invalidate(function);
+        }
+      });
+    }
+  }
+
   /**
    * Add [caller] to the set of [callee]'s callers.
    */
@@ -650,6 +671,20 @@
   }
 
   /**
+   * Add [caller] to the set of [callee]'s dynamic callers.
+   */
+  void addDynamicCaller(SourceString callee, FunctionElement caller) {
+    Set<FunctionElement> current = dynamicCallers[callee];
+    if (current != null) {
+      current.add(caller);
+    } else {
+      Set<FunctionElement> newSet = new Set<FunctionElement>();
+      newSet.add(caller);
+      dynamicCallers[callee] = newSet;
+    }
+  }
+
+  /**
    * Add [reader] to the set of [field]'s readers.
    */
   void addReader(Element field, FunctionElement reader) {
@@ -670,14 +705,20 @@
     Set<FunctionElement> methodCallers = callers[function];
     if (methodCallers == null) return;
     for (FunctionElement caller in methodCallers) {
-      Map<ConcreteTypesEnvironment, ConcreteType> callerInstances =
-          cache[caller];
-      if (callerInstances != null) {
-        callerInstances.forEach((environment, _) {
-          workQueue.addLast(
-              new InferenceWorkItem(caller, environment));
-        });
-      }
+      invalidate(caller);
+    }
+  }
+
+  /**
+   * Add all instances of method to the workqueue.
+   */
+  void invalidate(FunctionElement method) {
+    Map<ConcreteTypesEnvironment, ConcreteType> instances = cache[method];
+    if (instances != null) {
+      instances.forEach((environment, _) {
+        workQueue.addLast(
+            new InferenceWorkItem(method, environment));
+      });
     }
   }
 
@@ -844,7 +885,10 @@
    */
   ConcreteType getSpecialCaseReturnType(FunctionElement function,
                                         ConcreteTypesEnvironment environment) {
-    if (function == listIndex) {
+    if (function.name == const SourceString('JS')) {
+      // TODO(polux): trust the type once we handle generic types
+      return unknownConcreteType;
+    } else if (function == listIndex) {
       ConcreteType indexType = environment.lookupType(
           listIndex.functionSignature.requiredParameters.head);
       if (!indexType.baseTypes.contains(baseTypes.intBaseType)) {
@@ -875,7 +919,7 @@
   ConcreteType analyzeMethod(FunctionElement element,
                              ConcreteTypesEnvironment environment) {
     TreeElements elements =
-        compiler.enqueuer.resolution.resolvedElements[element];
+        compiler.enqueuer.resolution.resolvedElements[element.declaration];
     ConcreteType specialResult = handleSpecialMethod(element, environment);
     if (specialResult != null) return specialResult;
     FunctionExpression tree = element.parseNode(compiler);
@@ -884,8 +928,8 @@
           new TypeInferrerVisitor(elements, element, this, environment);
       return tree.accept(visitor);
     } else {
-      // TODO(polux): implement visitForeingCall and always use the
-      // implementation element instead of this hack
+      // TODO(polux): handle num#<, num#>, etc. in order to get rid of this
+      //     else branch
       return new ConcreteType.unknown();
     }
   }
@@ -893,6 +937,7 @@
   ConcreteType analyzeConstructor(FunctionElement element,
                                   ConcreteTypesEnvironment environment) {
     ClassElement enclosingClass = element.enclosingElement;
+    augmentSeenClasses(enclosingClass);
     FunctionExpression tree = compiler.parser.parse(element);
     TreeElements elements =
         compiler.enqueuer.resolution.resolvedElements[element];
@@ -926,7 +971,8 @@
       ClassElement superClass = enclosingClass.superclass;
       if (enclosingClass != compiler.objectClass) {
         FunctionElement target = superClass.lookupConstructor(
-          new Selector.callDefaultConstructor(enclosingClass.getLibrary()));
+            new Selector.callDefaultConstructor(enclosingClass.getLibrary()))
+                .implementation;
         final superClassConcreteType = singletonConcreteType(
             new ClassBaseType(enclosingClass));
         getSendReturnType(target, enclosingClass,
@@ -1005,11 +1051,15 @@
    * Dumps debugging information on the standard output.
    */
   void debug() {
-    print("callers :");
+    print("seen classes:");
+    for (ClassElement cls in seenClasses) {
+      print("  ${cls.name.slowToString()}");
+    }
+    print("callers:");
     callers.forEach((k,v) {
       print("  $k: $v");
     });
-    print("readers :");
+    print("readers:");
     readers.forEach((k,v) {
       print("  $k: $v");
     });
@@ -1025,7 +1075,7 @@
     cache.forEach((k,v) {
       print("  $k: $v");
     });
-    print("inferred expression types: ");
+    print("inferred expression types:");
     inferredTypes.forEach((k,v) {
       print("  $k: $v");
     });
@@ -1225,6 +1275,7 @@
     }
 
     if (receiverType.isUnkown()) {
+      inferrer.addDynamicCaller(name, currentMethod);
       for (Element member in inferrer.getMembersByName(name)) {
         if (!(member.isField() || member.isAbstractField())) continue;
         Element cls = member.getEnclosingClass();
@@ -1304,14 +1355,19 @@
   }
 
   ConcreteType visitLiteralInt(LiteralInt node) {
+    inferrer.augmentSeenClasses(inferrer.compiler.intClass);
+    inferrer.augmentSeenClasses(inferrer.compiler.numClass);
     return inferrer.singletonConcreteType(inferrer.baseTypes.intBaseType);
   }
 
   ConcreteType visitLiteralDouble(LiteralDouble node) {
+    inferrer.augmentSeenClasses(inferrer.compiler.doubleClass);
+    inferrer.augmentSeenClasses(inferrer.compiler.numClass);
     return inferrer.singletonConcreteType(inferrer.baseTypes.doubleBaseType);
   }
 
   ConcreteType visitLiteralBool(LiteralBool node) {
+    inferrer.augmentSeenClasses(inferrer.compiler.boolClass);
     return inferrer.singletonConcreteType(inferrer.baseTypes.boolBaseType);
   }
 
@@ -1322,6 +1378,7 @@
         && node.dartString.slowToString() == "__dynamic_for_test") {
       return inferrer.unknownConcreteType;
     }
+    inferrer.augmentSeenClasses(inferrer.compiler.stringClass);
     return inferrer.singletonConcreteType(inferrer.baseTypes.stringBaseType);
   }
 
@@ -1352,6 +1409,7 @@
       elementsType = inferrer.union(elementsType, analyze(link.head));
     }
     inferrer.augmentListElementType(elementsType);
+    inferrer.augmentSeenClasses(inferrer.compiler.listClass);
     return inferrer.singletonConcreteType(inferrer.baseTypes.listBaseType);
   }
 
@@ -1427,11 +1485,13 @@
 
   ConcreteType visitStringInterpolation(StringInterpolation node) {
     node.visitChildren(this);
+    inferrer.augmentSeenClasses(inferrer.compiler.stringClass);
     return inferrer.singletonConcreteType(inferrer.baseTypes.stringBaseType);
   }
 
   ConcreteType visitStringInterpolationPart(StringInterpolationPart node) {
     node.visitChildren(this);
+    inferrer.augmentSeenClasses(inferrer.compiler.stringClass);
     return inferrer.singletonConcreteType(inferrer.baseTypes.stringBaseType);
   }
 
@@ -1462,6 +1522,7 @@
 
   ConcreteType visitLiteralMap(LiteralMap node) {
     visitNodeList(node.entries);
+    inferrer.augmentSeenClasses(inferrer.compiler.mapClass);
     return inferrer.singletonConcreteType(inferrer.baseTypes.mapBaseType);
   }
 
@@ -1566,8 +1627,9 @@
 
       ConcreteType receiverType = analyze(node.receiver);
       if (receiverType.isUnkown()) {
-        List<Element> members =
-            inferrer.getMembersByName(node.selector.asIdentifier().source);
+        SourceString name = node.selector.asIdentifier().source;
+        inferrer.addDynamicCaller(name, currentMethod);
+        List<Element> members = inferrer.getMembersByName(name);
         for (Element member in members) {
           if (!(member.isField() || member.isAbstractField())) continue;
           Element cls = member.getEnclosingClass();
@@ -1581,7 +1643,7 @@
             Element getterOrField =
                 cls.lookupMember(node.selector.asIdentifier().source);
             if (getterOrField != null) {
-              augmentResult(cls, getterOrField);
+              augmentResult(cls, getterOrField.implementation);
             }
           }
         }
@@ -1600,6 +1662,7 @@
     ConcreteType result = inferrer.emptyConcreteType;
 
     if (receiverType.isUnkown()) {
+      inferrer.addDynamicCaller(canonicalizedMethodName, currentMethod);
       List<Element> methods =
           inferrer.getMembersByName(canonicalizedMethodName);
       for (Element element in methods) {
@@ -1621,6 +1684,7 @@
           ClassElement cls = classBaseReceiverType.element;
           FunctionElement method = cls.lookupMember(canonicalizedMethodName);
           if (method != null) {
+            method = method.implementation;
             inferrer.addCaller(method, currentMethod);
             result = inferrer.union(
                 result,
@@ -1661,11 +1725,11 @@
   }
 
   ConcreteType visitForeignSend(Send node) {
-    inferrer.fail(node, 'not implemented');
+    return inferrer.unknownConcreteType;
   }
 
   ConcreteType visitStaticSend(Send node) {
-    Element element = elements[node];
+    Element element = elements[node].implementation;
     inferrer.addCaller(element, currentMethod);
     return inferrer.getSendReturnType(element, null,
         analyzeArguments(node.arguments));
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 e4a16b0..114e8e9 100644
--- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -35,6 +35,53 @@
   bool get isEmpty => queue.isEmpty;
 }
 
+/**
+ * Placeholder for type information of final fields of classes.
+ */
+class ClassInfoForFinalFields {
+  /**
+   * Maps a final field to a map from generative constructor to the
+   * inferred type of the field in that generative constructor.
+   */
+  final Map<Element, Map<Element, Element>> typesOfFinalFields =
+      new Map<Element, Map<Element, Element>>();
+
+  /**
+   * The number of generative constructors that need to be visited
+   * before we can take any decision on the type of the fields.
+   * Given that all generative constructors must be analyzed before
+   * re-analyzing one, we know that once [constructorsToVisitCount]
+   * reaches to 0, all generative constructors have been analyzed.
+   */
+  int constructorsToVisitCount;
+
+  ClassInfoForFinalFields(this.constructorsToVisitCount);
+
+  /**
+   * Records that the generative [constructor] has inferred [type]
+   * for the final [field].
+   */
+  void recordFinalFieldType(Element constructor, Element field, Element type) {
+    Map<Element, Element> typesFor = typesOfFinalFields.putIfAbsent(
+        field, () => new Map<Element, Element>());
+    typesFor[constructor] = type;
+  }
+
+  /**
+   * Records that [constructor] has been analyzed. If not at 0,
+   * decrement [constructorsToVisitCount].
+   */ 
+  void doneAnalyzingGenerativeConstructor(Element constructor) {
+    if (constructorsToVisitCount != 0) constructorsToVisitCount--;
+  }
+
+  /**
+   * Returns whether all generative constructors of the class have
+   * been analyzed.
+   */
+  bool get isDone => constructorsToVisitCount == 0;
+}
+
 class SimpleTypesInferrer extends TypesInferrer {
   /**
    * Maps an element to its callers.
@@ -49,18 +96,19 @@
       new Map<Element, Element>();
 
   /**
-   * Maps a name to elements in the universe that have that name.
-   */
-  final Map<SourceString, Set<Element>> methodCache =
-      new Map<SourceString, Set<Element>>();
-
-  /**
    * Maps an element to the number of times this type inferrer
    * analyzed it.
    */
   final Map<Element, int> analyzeCount = new Map<Element, int>();
 
   /**
+   * Maps a class to a [ClassInfoForFinalFields] to help collect type
+   * information of final fields.
+   */
+  final Map<ClassElement, ClassInfoForFinalFields> classInfoForFinalFields =
+      new Map<ClassElement, ClassInfoForFinalFields>();
+
+  /**
    * The work list of the inferrer.
    */
   final WorkSet<Element> workSet = new WorkSet<Element>();
@@ -78,8 +126,6 @@
 
   final Compiler compiler;
 
-  // Times the computation of the call graph.
-  final Stopwatch memberWatch = new Stopwatch();
   // Times the computation of re-analysis of methods.
   final Stopwatch recomputeWatch = new Stopwatch();
   // Number of re-analysis.
@@ -153,6 +199,9 @@
    */
   getConcreteTypeOfNode(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?
@@ -202,6 +251,21 @@
         set.forEach((e) { workSet.add(e); });
       }
     }
+
+    // Build the [classInfoForFinalFields] map by iterating over all
+    // seen classes and counting the number of their generative
+    // constructors.
+    // We iterate over the seen classes and not the instantiated ones,
+    // because we also need to analyze the final fields of super
+    // classes that are not instantiated.
+    compiler.enqueuer.resolution.seenClasses.forEach((ClassElement cls) {
+      int constructorCount = 0;
+      cls.forEachMember((_, member) {
+        if (member.isGenerativeConstructor()) constructorCount++;
+      });
+      classInfoForFinalFields[cls.implementation] =
+          new ClassInfoForFinalFields(constructorCount);
+    });
   }
 
   dump() {
@@ -214,8 +278,6 @@
         interestingTypes++;
       }
     });
-    compiler.log('Type inferrer spent ${memberWatch.elapsedMilliseconds} ms '
-                 'computing a call graph.');
     compiler.log('Type inferrer re-analyzed methods $recompiles times '
                  'in ${recomputeWatch.elapsedMilliseconds} ms.');
     compiler.log('Type inferrer found $interestingTypes interesting '
@@ -228,16 +290,33 @@
   void clear() {
     callersOf.clear();
     analyzeCount.clear();
+    classInfoForFinalFields.clear();
   }
 
   bool analyze(Element element) {
-    if (element.isField()) {
-      // TODO(ngeoffray): Analyze its initializer.
+    SimpleTypeInferrerVisitor visitor =
+        new SimpleTypeInferrerVisitor(element, compiler, this);
+    Element returnType = visitor.run();
+    if (analyzeCount.containsKey(element)) {
+      analyzeCount[element]++;
+    } else {
+      analyzeCount[element] = 1;
+    }
+    if (element.isGenerativeConstructor()) {
+      // We always know the return type of a generative constructor.
+      return false;
+    } else if (element.isField()) {
+      if (element.modifiers.isFinal() || element.modifiers.isConst()) {
+        if (element.parseNode(compiler).asSendSet() != null) {
+          // If [element] is final and has an initializer, we record
+          // the inferred type.
+          return recordReturnType(element, returnType);
+        }
+      }
+      // We don't record anything for non-final fields.
       return false;
     } else {
-      SimpleTypeInferrerVisitor visitor =
-          new SimpleTypeInferrerVisitor(element, compiler, this);
-      return visitor.run();
+      return recordReturnType(element, returnType);
     }
   }
 
@@ -249,30 +328,14 @@
   bool recordReturnType(analyzedElement, returnType) {
     assert(returnType != null);
     Element existing = returnTypeOf[analyzedElement];
-    if (existing == null) {
-      // First time we analyzed [analyzedElement]. Initialize the
-      // return type.
-      assert(!analyzeCount.containsKey(analyzedElement));
-      returnTypeOf[analyzedElement] = returnType;
-      // If the return type is useful, say it has changed.
-      return returnType != compiler.dynamicClass
-          && returnType != compiler.nullClass;
-    } else if (existing == compiler.dynamicClass) {
-      // Previous analysis did not find any type.
-      returnTypeOf[analyzedElement] = returnType;
-      // If the return type is useful, say it has changed.
-      return returnType != compiler.dynamicClass
-          && returnType != compiler.nullClass;
-    } else if (existing == giveUpType) {
-      // If we already gave up on the return type, we don't change it.
-      return false;
-    } else if (existing != returnType) {
-      // The method is returning two different types. Give up for now.
-      // TODO(ngeoffray): Compute LUB.
-      returnTypeOf[analyzedElement] = giveUpType;
-      return true;
-    }
-    return false;
+    Element newType = existing == compiler.dynamicClass
+        ? returnType // Previous analysis did not find any type.
+        : computeLUB(existing, returnType);
+    returnTypeOf[analyzedElement] = newType;
+    // If the return type is useful, say it has changed.
+    return existing != newType
+        && newType != compiler.dynamicClass
+        && newType != compiler.nullClass;
   }
 
   /**
@@ -286,6 +349,7 @@
     if (returnType == null || returnType == giveUpType) {
       return compiler.dynamicClass;
     }
+    assert(returnType != null);
     return returnType;
   }
 
@@ -314,6 +378,9 @@
         return true;
       }
     });
+    if (result == null) {
+      result = compiler.dynamicClass;
+    }
     return result;
   }
 
@@ -326,8 +393,8 @@
                              ArgumentsTypes arguments) {
     if (analyzeCount.containsKey(caller)) return;
     callee = callee.implementation;
-    Set<FunctionElement> callers = callersOf.putIfAbsent(
-        callee, () => new Set<FunctionElement>());
+    Set<Element> callers = callersOf.putIfAbsent(
+        callee, () => new Set<Element>());
     callers.add(caller);
   }
 
@@ -339,8 +406,8 @@
                                Element callee) {
     if (analyzeCount.containsKey(caller)) return;
     callee = callee.implementation;
-    Set<FunctionElement> callers = callersOf.putIfAbsent(
-        callee, () => new Set<FunctionElement>());
+    Set<Element> callers = callersOf.putIfAbsent(
+        callee, () => new Set<Element>());
     callers.add(caller);
   }
 
@@ -354,8 +421,8 @@
     if (analyzeCount.containsKey(caller)) return;
     iterateOverElements(selector, (Element element) {
       assert(element.isImplementation);
-      Set<FunctionElement> callers = callersOf.putIfAbsent(
-          element, () => new Set<FunctionElement>());
+      Set<Element> callers = callersOf.putIfAbsent(
+          element, () => new Set<Element>());
       callers.add(caller);
       return true;
     });
@@ -369,8 +436,8 @@
     if (analyzeCount.containsKey(caller)) return;
     iterateOverElements(selector, (Element element) {
       assert(element.isImplementation);
-      Set<FunctionElement> callers = callersOf.putIfAbsent(
-          element, () => new Set<FunctionElement>());
+      Set<Element> callers = callersOf.putIfAbsent(
+          element, () => new Set<Element>());
       callers.add(caller);
       return true;
     });
@@ -392,39 +459,76 @@
    * [selector]. If [f] returns false, aborts the iteration.
    */
   void iterateOverElements(Selector selector, bool f(Element element)) {
-    SourceString name = selector.name;
-
-    // The following is already computed by the resolver, but it does
-    // not save it yet.
-    Set<Element> methods = methodCache[name];
-    if (methods == null) {
-      memberWatch.start();
-      methods = new Set<Element>();
-      void add(element) {
-        if (!element.isInstanceMember()) return;
-        if (element.isAbstract(compiler)) return;
-        if (!compiler.enqueuer.resolution.isProcessed(element)) return;
-        methods.add(element.implementation);
-      }
-      for (ClassElement cls in compiler.enqueuer.resolution.seenClasses) {
-        var element = cls.lookupLocalMember(name);
-        if (element != null) {
-          if (element.isAbstractField()) {
-            if (element.getter != null) add(element.getter);
-            if (element.setter != null) add(element.setter);
-          } else {
-            add(element);
-          }
-        }
-      }
-      methodCache[name] = methods;
-      memberWatch.stop();
+    Iterable<Element> elements = compiler.world.allFunctions.filter(selector);
+    for (Element e in elements) {
+      if (!f(e.implementation)) return;
     }
+  }
 
-    for (Element element in methods) {
-      if (selector.appliesUnnamed(element, compiler)) {
-        if (!f(element)) return;
-      }
+  /**
+   * Records in [classInfoForFinalFields] that [constructor] has
+   * inferred [type] for the final [field].
+   */
+  void recordFinalFieldType(Element constructor, Element field, Element type) {
+    // If the field is being set at its declaration site, it is not
+    // being tracked in the [classInfoForFinalFields] map.
+    if (constructor == field) return;
+    assert(field.modifiers.isFinal() || field.modifiers.isConst());
+    ClassElement cls = constructor.getEnclosingClass();
+    ClassInfoForFinalFields info = classInfoForFinalFields[cls.implementation];
+    info.recordFinalFieldType(constructor, field, type);
+  }
+
+  /**
+   * Records that we are done analyzing [constructor]. If all
+   * generative constructors of its enclosing class have already been
+   * analyzed, this method updates the types of final fields.
+   */
+  void doneAnalyzingGenerativeConstructor(Element constructor) {
+    ClassElement cls = constructor.getEnclosingClass();
+    ClassInfoForFinalFields info = classInfoForFinalFields[cls.implementation];
+    info.doneAnalyzingGenerativeConstructor(constructor);
+    if (info.isDone) {
+      updateFieldTypes(info);
+    }
+  }
+
+  /**
+   * Updates types of final fields listed in [info].
+   */
+  void updateFieldTypes(ClassInfoForFinalFields info) {
+    assert(info.isDone);
+    info.typesOfFinalFields.forEach((Element field,
+                                     Map<Element, Element> types) {
+      assert(field.modifiers.isFinal());
+      Element fieldType;
+      types.forEach((_, type) {
+        fieldType = computeLUB(fieldType, type);
+      });
+      returnTypeOf[field] = fieldType;
+    });
+  }
+
+  /**
+   * Returns the least upper bound between [firstType] and
+   * [secondType].
+   */
+  Element computeLUB(Element firstType, Element secondType) {
+    assert(secondType != null);
+    if (firstType == null) {
+      return secondType;
+    } else if (firstType == giveUpType) {
+      return firstType;
+    } else if (secondType == compiler.dynamicClass) {
+      return secondType;
+    } else if (firstType == compiler.dynamicClass) {
+      return firstType;
+    } else if (firstType != secondType) {
+      // TODO(ngeoffray): Actually compute the least upper bound.
+      return giveUpType;
+    } else {
+      assert(firstType == secondType);
+      return firstType;
     }
   }
 }
@@ -441,12 +545,12 @@
 }
 
 class SimpleTypeInferrerVisitor extends ResolvedVisitor {
-  final FunctionElement analyzedElement;
+  final Element analyzedElement;
   final SimpleTypesInferrer inferrer;
   final Compiler compiler;
   Element returnType;
 
-  SimpleTypeInferrerVisitor(FunctionElement element,
+  SimpleTypeInferrerVisitor(Element element,
                             Compiler compiler,
                             this.inferrer)
     : super(compiler.enqueuer.resolution.resolvedElements[element.declaration]),
@@ -455,49 +559,42 @@
     assert(elements != null);
   }
 
-  bool run() {
-    FunctionExpression node =
-        analyzedElement.implementation.parseNode(compiler);
-    bool changed;
-    if (analyzedElement.isGenerativeConstructor()) {
-      FunctionSignature signature = analyzedElement.computeSignature(compiler);
-      // TODO(ngeoffray): handle initializing formals.
-      // TODO(ngeoffray): handle initializers.
-      node.body.accept(this);
-      // We always know the return type of a generative constructor.
-      changed = false;
+  Element run() {
+    var node = analyzedElement.implementation.parseNode(compiler);
+    if (analyzedElement.isField()) {
+      returnType = visit(node);
+    } else if (analyzedElement.isGenerativeConstructor()) {
+      FunctionElement function = analyzedElement;
+      FunctionSignature signature = function.computeSignature(compiler);
+      signature.forEachParameter((element) {
+        if (element.kind == ElementKind.FIELD_PARAMETER
+            && element.modifiers.isFinal()) {
+          // We don't track argument types yet, so just set the field
+          // as dynamic.
+          inferrer.recordFinalFieldType(
+              analyzedElement, element.fieldElement, compiler.dynamicClass);
+        }
+      });
+      visit(node.initializers);
+      visit(node.body);
+      inferrer.doneAnalyzingGenerativeConstructor(analyzedElement);
+      returnType = analyzedElement.getEnclosingClass();
     } else if (analyzedElement.isNative()) {
       // Native methods do not have a body, and we currently just say
       // they return dynamic.
-      inferrer.recordReturnType(analyzedElement, compiler.dynamicClass);
-      changed = false;
+      returnType = compiler.dynamicClass;
     } else {
-      node.body.accept(this);
+      visit(node.body);
       if (returnType == null) {
         // No return in the body.
         returnType = compiler.nullClass;
       }
-      changed = inferrer.recordReturnType(analyzedElement, returnType);
     }
-    if (inferrer.analyzeCount.containsKey(analyzedElement)) {
-      inferrer.analyzeCount[analyzedElement]++;
-    } else {
-      inferrer.analyzeCount[analyzedElement] = 1;
-    }
-    return changed;
+    return returnType;
   }
 
   recordReturnType(ClassElement cls) {
-    if (returnType == null) {
-      returnType = cls;
-    } else if (returnType != inferrer.giveUpType
-               && cls == compiler.dynamicClass) {
-      returnType = cls;
-    } else if (returnType == compiler.dynamicClass) {
-      // Nothing to do. Stay dynamic.
-    } else if (leastUpperBound(cls, returnType) == compiler.dynamicClass) {
-      returnType = inferrer.giveUpType;
-    }
+    returnType = inferrer.computeLUB(returnType, cls);
   }
 
   visitNode(Node node) {
@@ -509,6 +606,10 @@
     return node.send.accept(this);
   }
 
+  visit(Node node) {
+    return node == null ? compiler.dynamicClass : node.accept(this);
+  }
+
   visitFunctionExpression(FunctionExpression node) {
     // We don't put the closure in the work queue of the
     // inferrer, because it will share information with its enclosing
@@ -560,9 +661,52 @@
   }
 
   visitSendSet(SendSet node) {
-    // TODO(ngeoffray): return the right hand side's type.
-    node.visitChildren(this);
-    return compiler.dynamicClass;
+    Element element = elements[node];
+    if (!Elements.isUnresolved(element) && element.impliesType()) {
+      node.visitChildren(this);
+      return compiler.dynamicClass;
+    }
+
+    Operator op = node.assignmentOperator;
+    if (node.isSuperCall) {
+      // [: super.foo = 42 :] or [: super.foo++ :] or [: super.foo += 1 :].
+      node.visitChildren(this);
+      return compiler.dynamicClass;
+    } else if (node.isIndex) {
+      if (const SourceString("=") == op.source) {
+        // [: foo[0] = 42 :]
+        visit(node.receiver);
+        Element returnType;
+        for (Node argument in node.arguments) {
+          returnType = argument.accept(this);
+        }
+        return returnType;
+      } else {
+        // [: foo[0] += 42 :] or [: foo[0]++ :].
+        node.visitChildren(this);
+        return compiler.dynamicClass;
+      }
+    } else if (const SourceString("=") == op.source) {
+      // [: foo = 42 :]
+      visit(node.receiver);
+      Link<Node> link = node.arguments;
+      assert(!link.isEmpty && link.tail.isEmpty);
+      Element type = link.head.accept(this);
+
+      if (!Elements.isUnresolved(element)
+          && element.isField()
+          && element.modifiers.isFinal()) {
+        inferrer.recordFinalFieldType(analyzedElement, element, type);
+      }
+      return type;
+    } else {
+      // [: foo++ :] or [: foo += 1 :].
+      assert(const SourceString("++") == op.source ||
+             const SourceString("--") == op.source ||
+             node.assignmentOperator.source.stringValue.endsWith("="));
+      node.visitChildren(this);
+      return compiler.dynamicClass;
+    }
   }
 
   visitIdentifier(Identifier node) {
@@ -709,14 +853,8 @@
   visitGetterSend(Send node) {
     Element element = elements[node];
     if (Elements.isStaticOrTopLevelField(element)) {
-      if (element.isGetter()) {
-        inferrer.registerGetterOnElement(analyzedElement, element);
-        return inferrer.returnTypeOfElement(element);
-      } else {
-        // Nothing yet.
-        // TODO: Analyze initializer of element.
-        return compiler.dynamicClass;
-      }
+      inferrer.registerGetterOnElement(analyzedElement, element);
+      return inferrer.returnTypeOfElement(element);
     } else if (Elements.isInstanceSend(node, elements)) {
       ClassElement receiverType;
       if (node.receiver == null) {
@@ -765,12 +903,9 @@
     node.condition.accept(this);
     Element firstType = node.thenExpression.accept(this);
     Element secondType = node.elseExpression.accept(this);
-    return leastUpperBound(firstType, secondType);
-  }
-
-  leastUpperBound(Element firstType, Element secondType) {
-    if (firstType == secondType) return firstType;
-    return compiler.dynamicClass;
+    Element type = inferrer.computeLUB(firstType, secondType);
+    if (type == inferrer.giveUpType) type = compiler.dynamicClass;
+    return type;
   }
 
   internalError(String reason, {Node node}) {
diff --git a/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart b/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart
new file mode 100644
index 0000000..1f970f2
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/universe/full_function_set.dart
@@ -0,0 +1,120 @@
+// 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 universe;
+
+class FullFunctionSet extends FunctionSet {
+  FullFunctionSet(Compiler compiler) : super(compiler);
+
+  FunctionSetNode newNode(SourceString name)
+      => new FullFunctionSetNode(name);
+
+  // TODO(kasperl): This interface is a little bit weird and mostly
+  // put here to illustrate how we can refine types. Returning a
+  // selector seems weird because we're only really interested in the
+  // receiver type information and the type kind.
+  Selector refine(Selector selector) {
+    SourceString name = selector.name;
+    FunctionSetNode node = nodes[name];
+    if (node == null) return null;
+    FullFunctionSetQuery query = node.query(selector, compiler);
+
+    // If the selector is already exact, then we cannot refine it
+    // further. If the query isn't exact, it means that the exact
+    // class didn't contain any mathing element.
+    if (selector.typeKind == TypedSelectorKind.EXACT) {
+      if (!query.isExact) return null;
+      assert(selector.receiverType.element == query.classes[0]);
+      return selector;
+    }
+
+    // If the query yields an exact class, we refine the selector.
+    if (query.isExact) {
+      ClassElement refinement = query.classes[0];
+      DartType type = refinement.computeType(compiler);
+      return new TypedSelector.exact(type, selector);
+    }
+
+    // Get the list of classes from the query. If the type information
+    // cannot be represented in the selector, we avoid refining it.
+    List<ClassElement> classes = query.classes;
+    if (classes == null || classes.length != 1) return selector;
+    if (classes.isEmpty) return null;
+
+    // We found one non-exact class, so we try to refine the selector
+    // to be of subclass kind. We take care to reuse the existing
+    // selector if matching class.
+    assert(classes.length == 1);
+    ClassElement refinement = query.classes[0];
+    if (selector.typeKind == TypedSelectorKind.SUBCLASS) {
+      ClassElement existing = selector.receiverType.element;
+      if (refinement == existing) return selector;
+      assert(refinement.isSubclassOf(existing));
+    }
+    DartType type = refinement.computeType(compiler);
+    return new TypedSelector.subclass(type, selector);
+  }
+}
+
+class FullFunctionSetNode extends FunctionSetNode {
+  // To cut down on the time we spend on computing type information
+  // about the function holders, we limit the number of classes and
+  // the number of steps it takes to compute them.
+  static const int MAX_CLASSES = 4;
+  static const int MAX_CLASSES_STEPS = 32;
+
+  FullFunctionSetNode(SourceString name) : super(name);
+
+  FunctionSetQuery newQuery(List<Element> functions,
+                            Selector selector,
+                            Compiler compiler) {
+    List<ClassElement> classes = computeClasses(functions, compiler);
+    bool isExact = (selector.typeKind == TypedSelectorKind.EXACT)
+        || isExactClass(classes, compiler);
+    return new FullFunctionSetQuery(functions, classes, isExact);
+  }
+
+  static List<ClassElement> computeClasses(List<Element> functions,
+                                           Compiler compiler) {
+    // TODO(kasperl): Check if any of the found classes may have a
+    // non-throwing noSuchMethod implementation in a subclass instead
+    // of always disabling the class list computation.
+    if (compiler.enabledNoSuchMethod) return null;
+    List<ClassElement> classes = <ClassElement>[];
+    int budget = MAX_CLASSES_STEPS;
+    L: for (Element element in functions) {
+      ClassElement enclosing = element.getEnclosingClass();
+      for (int i = 0; i < classes.length; i++) {
+        if (--budget <= 0) {
+          return null;
+        } else if (enclosing.isSubclassOf(classes[i])) {
+          continue L;
+        } else if (classes[i].isSubclassOf(enclosing)) {
+          classes[i] = enclosing;
+          continue L;
+        }
+      }
+      if (classes.length >= MAX_CLASSES) return null;
+      classes.add(enclosing);
+    }
+    return classes;
+  }
+
+  static bool isExactClass(List<ClassElement> classes, Compiler compiler) {
+    if (classes == null || classes.length != 1) return false;
+    ClassElement single = classes[0];
+    // Return true if the single class in our list does not have a
+    // single instantiated subclass.
+    Set<ClassElement> subtypes = compiler.world.subtypes[single];
+    return subtypes == null
+        || subtypes.every((ClassElement each) => !each.isSubclassOf(single));
+  }
+}
+
+class FullFunctionSetQuery extends FunctionSetQuery {
+  final List<ClassElement> classes;
+  final bool isExact;
+  FullFunctionSetQuery(List<Element> functions, this.classes, this.isExact)
+      : super(functions);
+}
diff --git a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
index b6c6a53..dc30ef1 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
@@ -13,16 +13,20 @@
       new Map<SourceString, FunctionSetNode>();
   FunctionSet(this.compiler);
 
+  FunctionSetNode newNode(SourceString name)
+      => new FunctionSetNode(name);
+
   void add(Element element) {
-    assert(element.isMember());
+    assert(element.isInstanceMember());
+    assert(!element.isAbstract(compiler));
     SourceString name = element.name;
-    FunctionSetNode node = nodes.putIfAbsent(
-        name, () => new FunctionSetNode(name));
+    FunctionSetNode node = nodes.putIfAbsent(name, () => newNode(name));
     node.add(element);
   }
 
   void remove(Element element) {
-    assert(element.isMember());
+    assert(element.isInstanceMember());
+    assert(!element.isAbstract(compiler));
     SourceString name = element.name;
     FunctionSetNode node = nodes[name];
     if (node != null) {
@@ -31,7 +35,8 @@
   }
 
   bool contains(Element element) {
-    assert(element.isMember());
+    assert(element.isInstanceMember());
+    assert(!element.isAbstract(compiler));
     SourceString name = element.name;
     FunctionSetNode node = nodes[name];
     return (node != null)
@@ -40,24 +45,17 @@
   }
 
   /**
-   * Returns all elements that may be invoked with the given [selector].
+   * Returns an object that allows iterating over all the functions
+   * that may be invoked with the given [selector].
    */
-  Iterable<Element> filterBySelector(Selector selector) {
+  Iterable<Element> filter(Selector selector) {
     SourceString name = selector.name;
     FunctionSetNode node = nodes[name];
     return (node != null)
-        ? node.filter(selector, compiler)
+        ? node.query(selector, compiler).functions
         : const <Element>[];
   }
 
-  /**
-   * Returns whether the set has any element matching the given
-   * [selector].
-   */
-  bool hasAnyElementMatchingSelector(Selector selector) {
-    return !filterBySelector(selector).isEmpty;
-  }
-
   void forEach(Function action) {
     nodes.forEach((SourceString name, FunctionSetNode node) {
       node.forEach(action);
@@ -65,9 +63,11 @@
   }
 }
 
+
 class FunctionSetNode {
   final SourceString name;
-  final Map<Selector, List<Element>> cache = new Map<Selector, List<Element>>();
+  final Map<Selector, FunctionSetQuery> cache =
+      new Map<Selector, FunctionSetQuery>();
 
   // Initially, we keep the elements in a list because it is more
   // compact than a hash set. Once we get enough elements, we change
@@ -124,23 +124,36 @@
     elements.forEach(action);
   }
 
-  Iterable<Element> filter(Selector selector, Compiler compiler) {
+  FunctionSetQuery query(Selector selector, Compiler compiler) {
     assert(selector.name == name);
-    List<Element> result = cache[selector];
+    FunctionSetQuery result = cache[selector];
     if (result != null) return result;
+    List<Element> functions;
     for (Element element in elements) {
       if (selector.appliesUnnamed(element, compiler)) {
-        if (result == null) {
-          // Defer the allocation of the resulting list until we are
+        if (functions == null) {
+          // Defer the allocation of the functions list until we are
           // sure we need it. This allows us to return immutable empty
           // lists when the filtering produced no results.
-          result = <Element>[];
+          functions = <Element>[];
         }
-        result.add(element);
+        functions.add(element);
       }
     }
-    if (result == null) result = const <Element>[];
-    cache[selector] = result;
+    cache[selector] = result = (functions != null)
+        ? newQuery(functions, selector, compiler)
+        : const FunctionSetQuery(const <Element>[]);
     return result;
   }
+
+  FunctionSetQuery newQuery(List<Element> functions,
+                            Selector selector,
+                            Compiler compiler) {
+    return new FunctionSetQuery(functions);
+  }
+}
+
+class FunctionSetQuery {
+  final List<Element> functions;
+  const FunctionSetQuery(this.functions);
 }
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index 8f57035..4fb6cfb 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -13,6 +13,7 @@
 import '../js/js.dart' as js;
 
 part 'function_set.dart';
+part 'full_function_set.dart';
 part 'selector_map.dart';
 
 class Universe {
@@ -414,8 +415,8 @@
     if (namedArgumentCount > 0) {
       StringBuffer result = new StringBuffer();
       for (int i = 0; i < namedArgumentCount; i++) {
-        if (i != 0) result.add(', ');
-        result.add(namedArguments[i].slowToString());
+        if (i != 0) result.write(', ');
+        result.write(namedArguments[i].slowToString());
       }
       return "[$result]";
     }
@@ -514,12 +515,15 @@
     if (typeKind == TypedSelectorKind.EXACT) {
       return hasElementIn(self, element) && appliesUntyped(element, compiler);
     } else if (typeKind == TypedSelectorKind.SUBCLASS) {
-      return (hasElementIn(self, element) || other.isSubclassOf(self))
+      return (hasElementIn(self, element)
+              || other.isSubclassOf(self)
+              || compiler.world.hasAnySubclassThatMixes(self, other))
           && appliesUntyped(element, compiler);
     } else {
       assert(typeKind == TypedSelectorKind.INTERFACE);
       if (other.implementsInterface(self)
           || other.isSubclassOf(self)
+          || compiler.world.hasAnySubclassThatMixes(self, other)
           || compiler.world.hasAnySubclassThatImplements(other, receiverType)) {
         return appliesUntyped(element, compiler);
       }
diff --git a/sdk/lib/_internal/compiler/implementation/util/link_implementation.dart b/sdk/lib/_internal/compiler/implementation/util/link_implementation.dart
index d00ec86..2f9ea84 100644
--- a/sdk/lib/_internal/compiler/implementation/util/link_implementation.dart
+++ b/sdk/lib/_internal/compiler/implementation/util/link_implementation.dart
@@ -36,19 +36,19 @@
   }
 
   void printOn(StringBuffer buffer, [separatedBy]) {
-    buffer.add(head);
+    buffer.write(head);
     if (separatedBy == null) separatedBy = '';
     for (Link link = tail; !link.isEmpty; link = link.tail) {
-      buffer.add(separatedBy);
-      buffer.add(link.head);
+      buffer.write(separatedBy);
+      buffer.write(link.head);
     }
   }
 
   String toString() {
     StringBuffer buffer = new StringBuffer();
-    buffer.add('[ ');
+    buffer.write('[ ');
     printOn(buffer, ', ');
-    buffer.add(' ]');
+    buffer.write(' ]');
     return buffer.toString();
   }
 
diff --git a/sdk/lib/_internal/compiler/implementation/util/uri_extras.dart b/sdk/lib/_internal/compiler/implementation/util/uri_extras.dart
index fed5f15..f43e826 100644
--- a/sdk/lib/_internal/compiler/implementation/util/uri_extras.dart
+++ b/sdk/lib/_internal/compiler/implementation/util/uri_extras.dart
@@ -53,12 +53,12 @@
     }
     StringBuffer sb = new StringBuffer();
     for (int i = common + 1; i < baseParts.length; i++) {
-      sb.add('../');
+      sb.write('../');
     }
     for (int i = common; i < uriParts.length - 1; i++) {
-      sb.add('${uriParts[i]}/');
+      sb.write('${uriParts[i]}/');
     }
-    sb.add('${uriParts.last}');
+    sb.write('${uriParts.last}');
     return sb.toString();
   }
   return uri.toString();
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index 82fdd8d..39f53b6 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -28,6 +28,8 @@
       "no named argument '#{argumentName}' found on method");
   static const METHOD_NOT_FOUND = const MessageKind(
       'no method named #{memberName} in class #{className}');
+  static const NOT_CALLABLE = const MessageKind(
+      "'#{elementName}' is not callable");
   static const MEMBER_NOT_STATIC = const MessageKind(
       '#{className}.#{memberName} is not static');
   static const NO_INSTANCE_AVAILABLE = const MessageKind(
@@ -378,6 +380,9 @@
   static const MISSING_FACTORY_KEYWORD = const MessageKind(
       "Did you forget a factory keyword here?");
 
+  static const DEFERRED_LIBRARY_NAME_MISMATCH = const MessageKind(
+      'Error: Library name mismatch "#{expectedName}" != "#{actualName}".');
+
   static const COMPILER_CRASHED = const MessageKind(
       "Error: The compiler crashed when compiling this element.");
 
diff --git a/sdk/lib/_internal/compiler/implementation/world.dart b/sdk/lib/_internal/compiler/implementation/world.dart
index 4230708..f3142f6 100644
--- a/sdk/lib/_internal/compiler/implementation/world.dart
+++ b/sdk/lib/_internal/compiler/implementation/world.dart
@@ -11,18 +11,16 @@
   final Map<ClassElement, Set<ClassElement>> typesImplementedBySubclasses;
   final Set<ClassElement> classesNeedingRti;
   final Map<ClassElement, Set<ClassElement>> rtiDependencies;
-  final FunctionSet userDefinedGetters;
-  final FunctionSet userDefinedSetters;
+  final FullFunctionSet allFunctions;
 
   World(Compiler compiler)
       : subtypes = new Map<ClassElement, Set<ClassElement>>(),
         mixinUses = new Map<ClassElement, Set<MixinApplicationElement>>(),
         typesImplementedBySubclasses =
             new Map<ClassElement, Set<ClassElement>>(),
-        userDefinedGetters = new FunctionSet(compiler),
-        userDefinedSetters = new FunctionSet(compiler),
         classesNeedingRti = new Set<ClassElement>(),
         rtiDependencies = new Map<ClassElement, Set<ClassElement>>(),
+        allFunctions = new FullFunctionSet(compiler),
         this.compiler = compiler;
 
   void populate() {
@@ -117,122 +115,67 @@
     return classesNeedingRti.contains(cls) || compiler.enabledRuntimeType;
   }
 
-  void recordUserDefinedGetter(Element element) {
-    assert(element.isGetter());
-    userDefinedGetters.add(element);
-  }
-
-  void recordUserDefinedSetter(Element element) {
-    assert(element.isSetter());
-    userDefinedSetters.add(element);
-  }
-
   bool hasAnyUserDefinedGetter(Selector selector) {
-    return userDefinedGetters.hasAnyElementMatchingSelector(selector);
+    return allFunctions.filter(selector).any((each) => each.isGetter());
   }
 
   bool hasAnyUserDefinedSetter(Selector selector) {
-    return userDefinedSetters.hasAnyElementMatchingSelector(selector);
+     return allFunctions.filter(selector).any((each) => each.isSetter());
   }
 
   // Returns whether a subclass of [superclass] implements [type].
   bool hasAnySubclassThatImplements(ClassElement superclass, DartType type) {
-    Set<ClassElement> subclasses= typesImplementedBySubclasses[superclass];
+    Set<ClassElement> subclasses = typesImplementedBySubclasses[superclass];
     if (subclasses == null) return false;
     return subclasses.contains(type.element);
   }
 
-  bool hasNoOverridingMember(Element element) {
-    ClassElement cls = element.getEnclosingClass();
-    Set<ClassElement> subclasses = compiler.world.subtypes[cls];
-    // TODO(ngeoffray): Implement the full thing.
-    return subclasses == null || subclasses.isEmpty;
+  // Returns whether a subclass of [superclass] mixes in [other].
+  bool hasAnySubclassThatMixes(ClassElement superclass, ClassElement other) {
+    Set<MixinApplicationElement> uses = mixinUses[other];
+    return (uses != null)
+        ? uses.any((each) => each.isSubclassOf(superclass))
+        : false;
   }
 
   void registerUsedElement(Element element) {
-    if (element.isMember()) {
-      if (element.isGetter()) {
-        // We're collecting user-defined getters to let the codegen know which
-        // field accesses might have side effects.
-        recordUserDefinedGetter(element);
-      } else if (element.isSetter()) {
-        recordUserDefinedSetter(element);
-      }
+    if (element.isInstanceMember() && !element.isAbstract(compiler)) {
+      allFunctions.add(element);
     }
   }
 
-  /**
-   * Returns a [MemberSet] that contains the possible targets of the given
-   * [selector] on a receiver with the given [type]. This includes all sub
-   * types.
-   */
-  MemberSet _memberSetFor(DartType type, Selector selector) {
-    assert(compiler != null);
-    ClassElement cls = type.element;
-    SourceString name = selector.name;
-    LibraryElement library = selector.library;
-    MemberSet result = new MemberSet(name);
-    Element element = cls.implementation.lookupSelector(selector);
-    if (element != null) result.add(element);
-
-    bool isPrivate = name.isPrivate();
-    Set<ClassElement> subtypesOfCls = subtypes[cls];
-    if (subtypesOfCls != null) {
-      for (ClassElement sub in subtypesOfCls) {
-        // Private members from a different library are not visible.
-        if (isPrivate && sub.getLibrary() != library) continue;
-        element = sub.implementation.lookupLocalMember(name);
-        if (element != null) result.add(element);
-      }
-    }
-    return result;
+  VariableElement locateSingleField(Selector selector) {
+    Element result = locateSingleElement(selector);
+    return (result != null && result.isField()) ? result : null;
   }
 
-  /**
-   * Returns the field in [type] described by the given [selector].
-   * If no such field exists, or a subclass overrides the field
-   * returns [:null:].
-   */
-  VariableElement locateSingleField(DartType type, Selector selector) {
-    MemberSet memberSet = _memberSetFor(type, selector);
-    ClassElement cls = type.element;
-    Element result = cls.implementation.lookupSelector(selector);
-    if (result == null) return null;
-    if (!result.isField()) return null;
-
-    // Verify that no subclass overrides the field.
-    if (memberSet.elements.length != 1) return null;
-    assert(memberSet.elements.contains(result));
-    return result;
+  Element locateSingleElement(Selector selector) {
+    Iterable<Element> targets = allFunctions.filter(selector);
+    if (targets.length != 1) return null;
+    Element result = targets.first;
+    ClassElement enclosing = result.getEnclosingClass();
+    DartType receiverType = selector.receiverType;
+    ClassElement receiverTypeElement = (receiverType == null)
+        ? compiler.objectClass
+        : receiverType.element;
+    // We only return the found element if it is guaranteed to be
+    // implemented on the exact receiver type. It could be found in a
+    // subclass or in an inheritance-wise unrelated class in case of
+    // subtype selectors.
+    return (receiverTypeElement.isSubclassOf(enclosing)) ? result : null;
   }
 
-  Set<ClassElement> findNoSuchMethodHolders(DartType type) {
-    Set<ClassElement> result = new Set<ClassElement>();
+  Iterable<ClassElement> locateNoSuchMethodHolders(Selector selector) {
     Selector noSuchMethodSelector = new Selector.noSuchMethod();
-    MemberSet memberSet = _memberSetFor(type, noSuchMethodSelector);
-    for (Element element in memberSet.elements) {
-      ClassElement holder = element.getEnclosingClass();
-      if (!identical(holder, compiler.objectClass) &&
-          noSuchMethodSelector.applies(element, compiler)) {
-        result.add(holder);
-      }
+    DartType receiverType = selector.receiverType;
+    if (receiverType != null) {
+      noSuchMethodSelector = new TypedSelector(
+          receiverType, selector.typeKind, noSuchMethodSelector);
     }
-    return result;
+    ClassElement objectClass = compiler.objectClass;
+    return allFunctions
+        .filter(noSuchMethodSelector)
+        .map((Element member) => member.getEnclosingClass())
+        .where((ClassElement holder) => !identical(holder, objectClass));
   }
 }
-
-/**
- * A [MemberSet] contains all the possible targets for a selector.
- */
-class MemberSet {
-  final Set<Element> elements;
-  final SourceString name;
-
-  MemberSet(SourceString this.name) : elements = new Set<Element>();
-
-  void add(Element element) {
-    elements.add(element);
-  }
-
-  bool get isEmpty => elements.isEmpty;
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
index e0305ab..a6f0179d 100644
--- a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
+++ b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -107,18 +107,19 @@
 Future copyDirectory(Path from, Path to) {
   final completer = new Completer();
   final fromDir = new Directory.fromPath(from);
-  final lister = fromDir.list(recursive: false);
+  fromDir.list(recursive: false).listen(
+      (FileSystemEntity entity) {
+        if (entity is File) {
+          final name = new Path(entity.name).filename;
+          // TODO(rnystrom): Hackish. Ignore 'hidden' files like .DS_Store.
+          if (name.startsWith('.')) return;
 
-  lister.onFile = (String path) {
-    final name = new Path(path).filename;
-    // TODO(rnystrom): Hackish. Ignore 'hidden' files like .DS_Store.
-    if (name.startsWith('.')) return;
-
-    File fromFile = new File(path);
-    File toFile = new File.fromPath(to.append(name));
-    fromFile.openInputStream().pipe(toFile.openOutputStream());
-  };
-  lister.onDone = (done) => completer.complete(true);
+          File fromFile = entity;
+          File toFile = new File.fromPath(to.append(name));
+          fromFile.openRead().pipe(toFile.openWrite());
+        }
+      },
+      onDone: () => completer.complete(true));
   return completer.future;
 }
 
@@ -175,7 +176,7 @@
    * Path to the directory containing data files for each library.
    *
    * Currently this is the serialized json version of the LibraryElement for
-   * the library. 
+   * the library.
    */
   String location;
   /**
@@ -1902,15 +1903,18 @@
     write("NETWORK:\n*\n\n");
     write("CACHE:\n");
     var toCache = new Directory.fromPath(outputDir);
-    var toCacheLister = toCache.list(recursive: true);
-    toCacheLister.onFile = (filename) {
-      if (filename.endsWith('appcache.manifest')) {
-        return;
-      }
-      Path relativeFilePath = new Path(filename).relativeTo(outputDir);
-      write("$relativeFilePath\n");
-    };
-    toCacheLister.onDone = (done) => endFile();
+    toCache.list(recursive: true).listen(
+        (FileSystemEntity entity) {
+          if (entity.isFile) {
+            var filename = entity.path;
+            if (filename.endsWith('appcache.manifest')) {
+              return;
+            }
+            Path relativeFilePath = new Path(filename).relativeTo(outputDir);
+            write("$relativeFilePath\n");
+          }
+        },
+        onDone: () => endFile());
   }
 
   /**
diff --git a/sdk/lib/_internal/dartdoc/lib/markdown.dart b/sdk/lib/_internal/dartdoc/lib/markdown.dart
index ef111fb..a7ea5cc 100644
--- a/sdk/lib/_internal/dartdoc/lib/markdown.dart
+++ b/sdk/lib/_internal/dartdoc/lib/markdown.dart
@@ -5,8 +5,6 @@
 /// Parses text in a markdown-like format and renders to HTML.
 library markdown;
 
-import 'classify.dart';
-
 // TODO(rnystrom): Use "package:" URL (#4968).
 part 'src/markdown/ast.dart';
 part 'src/markdown/block_parser.dart';
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart b/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
index c90469a..d6e8daa 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
@@ -29,8 +29,8 @@
 void setupLocation() {
   // Figure out where we are.
   final body = document.query('body');
-  currentLibrary = body.dataAttributes['library'];
-  currentType = body.dataAttributes['type'];
+  currentLibrary = body.dataset['library'];
+  currentType = body.dataset['type'];
   prefix = (currentType != null) ? '../' : '';
 }
 
@@ -71,9 +71,9 @@
 void enableShowHideInherited() {
   var showInherited = document.query('#show-inherited');
   if (showInherited == null) return;
-  showInherited.dataAttributes.putIfAbsent('show-inherited', () => 'block');
+  showInherited.dataset.putIfAbsent('show-inherited', () => 'block');
   showInherited.onClick.listen((e) {
-    String display = showInherited.dataAttributes['show-inherited'];
+    String display = showInherited.dataset['show-inherited'];
     if (display == 'block') {
       display = 'none';
       showInherited.innerHtml = 'Show inherited';
@@ -81,7 +81,7 @@
       display = 'block';
       showInherited.innerHtml = 'Hide inherited';
     }
-    showInherited.dataAttributes['show-inherited'] = display;
+    showInherited.dataset['show-inherited'] = display;
     for (var elem in document.queryAll('.inherited')) {
       elem.style.display = display;
     }
diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart
index a5be1a7..bd14f36 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart
@@ -234,9 +234,9 @@
     childLines.add('');
 
     // Escape the code.
-    final escaped = classifySource(childLines.join('\n'));
+    final escaped = escapeHtml(childLines.join('\n'));
 
-    return new Element.text('pre', escaped);
+    return new Element('pre', [new Element.text('code', escaped)]);
   }
 }
 
diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart
index 8d5a548..8ab2e7f 100644
--- a/sdk/lib/_internal/libraries.dart
+++ b/sdk/lib/_internal/libraries.dart
@@ -104,6 +104,11 @@
         category: "Client",
         dart2jsPath: "web_audio/dart2js/web_audio_dart2js.dart"),
 
+  "web_sql": const LibraryInfo(
+        "web_sql/dartium/web_sql_dartium.dart",
+        category: "Client",
+        dart2jsPath: "web_sql/dart2js/web_sql_dart2js.dart"),
+
   "_collection-dev": const LibraryInfo(
       "_collection_dev/collection_dev.dart",
       category: "Internal",
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index 8998f83..d6144af 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.dart
@@ -6,6 +6,7 @@
 
 part 'async_error.dart';
 part 'collection_sink.dart';
+part 'deferred_load.dart';
 part 'future.dart';
 part 'future_impl.dart';
 part 'stream.dart';
diff --git a/sdk/lib/async/async_sources.gypi b/sdk/lib/async/async_sources.gypi
index 549a749..d297cae 100644
--- a/sdk/lib/async/async_sources.gypi
+++ b/sdk/lib/async/async_sources.gypi
@@ -7,6 +7,7 @@
   'sources': [
     'async_error.dart',
     'collection_sink.dart',
+    'deferred_load.dart',
     'future.dart',
     'future_impl.dart',
     'stream.dart',
@@ -16,4 +17,3 @@
     'timer.dart',
   ],
 }
-
diff --git a/sdk/lib/async/deferred_load.dart b/sdk/lib/async/deferred_load.dart
new file mode 100644
index 0000000..bc99a4d
--- /dev/null
+++ b/sdk/lib/async/deferred_load.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.
+
+/**
+ * Indicates that loading of [libraryName] is deferred.
+ *
+ * Applies to library imports, when used as metadata.
+ *
+ * Example usage:
+ *
+ * [:
+ * @lazy
+ * import 'foo.dart' as foo;
+ *
+ * const lazy = const DeferredLibrary('com.example.foo');
+ *
+ * void main() {
+ *   foo.method(); // Throws a NoSuchMethodError, foo is not loaded yet.
+ *   lazy.load().then(onFooLoaded);
+ * }
+ *
+ * void onFooLoaded(_) {
+ *   foo.method();
+ * }
+ * :]
+ */
+class DeferredLibrary {
+  final String libraryName;
+  final String uri;
+
+  const DeferredLibrary(this.libraryName, {this.uri});
+
+  /**
+   * Ensure that [libraryName] has been loaded.
+   *
+   * The value of the returned future is true if this invocation of
+   * [load] caused the library to be loaded.
+   */
+  external Future<bool> load();
+}
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index af68d43..130f226 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -21,9 +21,11 @@
 const int _STREAM_EVENT_ID_SHIFT = 2;
 /// Bit set while firing and clear while not.
 const int _STREAM_FIRING = 8;
+/// Bit set while calling a pause-state or subscription-state change callback.
+const int _STREAM_CALLBACK = 16;
 /// The count of times a stream has paused is stored in the
 /// state, shifted by this amount.
-const int _STREAM_PAUSE_COUNT_SHIFT = 4;
+const int _STREAM_PAUSE_COUNT_SHIFT = 5;
 
 // States for listeners.
 
@@ -121,7 +123,7 @@
    * should be the last message sent.
    */
   void _close() {
-    if (_isClosed) throw new StateError("Sending on closed stream");
+    if (_isClosed) return;
     _state |= _STREAM_CLOSED;
     if (!_canFireEvent) {
       // You can't enqueue an event after the Done, so make it const.
@@ -146,6 +148,9 @@
   /** Whether one or more active subscribers have requested a pause. */
   bool get _isPaused => _state >= (1 << _STREAM_PAUSE_COUNT_SHIFT);
 
+  /** Whether we are currently executing a state-chance callback. */
+  bool get _isInCallback => (_state & _STREAM_CALLBACK) != 0;
+
   /** Check whether the pending event queue is non-empty */
   bool get _hasPendingEvent =>
       _pendingEvents != null && !_pendingEvents.isEmpty;
@@ -153,6 +158,19 @@
   /** Whether we are currently firing an event. */
   bool get _isFiring => (_state & _STREAM_FIRING) != 0;
 
+  /** Whether the state bits allow firing. */
+  bool get _mayFireState {
+    // The state disallows firing if:
+    // - an event is currently firing
+    // - a stat-change callback is being called
+    // - the pause-count is not zero.
+    const int mask =
+        _STREAM_FIRING |
+        _STREAM_CALLBACK |
+        ~((1 << _STREAM_PAUSE_COUNT_SHIFT) - 1);
+    return (_state & mask) == 0;
+  }
+
   int get _currentEventIdBit =>
       (_state & _STREAM_EVENT_ID ) >> _STREAM_EVENT_ID_SHIFT;
 
@@ -160,7 +178,7 @@
   bool get _hasSubscribers;
 
   /** Whether the stream can fire a new event. */
-  bool get _canFireEvent => !_isFiring && !_isPaused && !_hasPendingEvent;
+  bool get _canFireEvent => _mayFireState && !_hasPendingEvent;
 
   // State modification.
 
@@ -216,8 +234,11 @@
   void _endFiring() {
     assert(_isFiring);
     _state ^= _STREAM_FIRING;
-    if (_isPaused) _onPauseStateChange();
-    if (!_hasSubscribers) _onSubscriptionStateChange();
+    if (!_hasSubscribers) {
+      _callOnSubscriptionStateChange();
+    } else if (_isPaused) {
+      _callOnPauseStateChange();
+    }
   }
 
   /**
@@ -241,7 +262,7 @@
       resumeSignal.whenComplete(() { this._resume(listener, true); });
     }
     if (!wasPaused && !_isFiring) {
-      _onPauseStateChange();
+      _callOnPauseStateChange();
     }
   }
 
@@ -252,7 +273,7 @@
     assert(_isPaused);
     _decrementPauseCount(listener);
     if (!_isPaused) {
-      if (!_isFiring) _onPauseStateChange();
+      if (!_isFiring) _callOnPauseStateChange();
       if (_hasPendingEvent) {
         // If we can fire events now, fire any pending events right away.
         if (fromEvent && !_isFiring) {
@@ -309,6 +330,30 @@
    */
   void _forEachSubscriber(void action(_StreamSubscriptionImpl<T> subscription));
 
+  /** Calls [_onPauseStateChange] while setting callback bit. */
+  void _callOnPauseStateChange() {
+    // After calling [_close], all pauses are handled internally by the Stream.
+    if (_isClosed) return;
+    if (!_isInCallback) {
+      _state |= _STREAM_CALLBACK;
+      _onPauseStateChange();
+      _state ^= _STREAM_CALLBACK;
+    } else {
+      _onPauseStateChange();
+    }
+  }
+
+  /** Calls [_onSubscriptionStateChange] while setting callback bit. */
+  void _callOnSubscriptionStateChange() {
+    if (!_isInCallback) {
+      _state |= _STREAM_CALLBACK;
+      _onSubscriptionStateChange();
+      _state ^= _STREAM_CALLBACK;
+    } else {
+      _onSubscriptionStateChange();
+    }
+  }
+
   /**
    * Called when the first subscriber requests a pause or the last a resume.
    *
@@ -430,9 +475,20 @@
 class _SingleStreamImpl<T> extends _StreamImpl<T> {
   _StreamListener _subscriber = null;
 
-  /** Whether one or more active subscribers have requested a pause. */
+  // A single-stream is considered paused when it has no subscriber.
+  // Exception is when it's complete (which only matters for pause-state-change
+  // callbacks), where it's not considered paused.
   bool get _isPaused => (!_hasSubscribers && !_isComplete) || super._isPaused;
 
+
+  bool get _canFireEvent {
+    // A single-stream is considered paused when it has no subscriber and
+    // isn't complete, so it can't fire if there is no subscriber.
+    // It won't try to fire when completed, so no need to check that.
+    return _mayFireState && !_hasPendingEvent && _hasSubscribers;
+  }
+
+
   /** Whether there is currently a subscriber on this [Stream]. */
   bool get _hasSubscribers => _subscriber != null;
 
@@ -457,7 +513,7 @@
     }
     _subscriber = subscription;
     subscription._setSubscribed(0);
-    _onSubscriptionStateChange();
+    _callOnSubscriptionStateChange();
     if (_hasPendingEvent) {
       _schedulePendingEvents();
     }
@@ -485,10 +541,7 @@
     int subscriptionPauseCount = subscriber._setUnsubscribed();
     _updatePauseCount(-subscriptionPauseCount);
     if (!_isFiring) {
-      if (subscriptionPauseCount > 0) {
-        _onPauseStateChange();
-      }
-      _onSubscriptionStateChange();
+      _callOnSubscriptionStateChange();
     }
   }
 
@@ -607,7 +660,7 @@
     bool firstSubscriber = !_hasSubscribers;
     _InternalLinkList.add(this, listener);
     if (firstSubscriber) {
-      _onSubscriptionStateChange();
+      _callOnSubscriptionStateChange();
     }
   }
 
@@ -640,7 +693,7 @@
       bool wasPaused = _isPaused;
       _removeListener(listener);
       if (wasPaused != _isPaused) _onPauseStateChange();
-      if (!_hasSubscribers) _onSubscriptionStateChange();
+      if (!_hasSubscribers) _callOnSubscriptionStateChange();
     }
   }
 
@@ -648,7 +701,7 @@
    * Removes a listener from this stream and cancels its pauses.
    *
    * This is a low-level action that doesn't call [_onSubscriptionStateChange].
-   * or [_onPauseStateChange].
+   * or [_callOnPauseStateChange].
    */
   void _removeListener(_StreamListener listener) {
     int pauseCount = listener._setUnsubscribed();
@@ -1138,7 +1191,7 @@
 
   _SingleStreamMultiplexer(this._source);
 
-  void _onPauseStateChange() {
+  void _callOnPauseStateChange() {
     if (_isPaused) {
       if (_subscription != null) {
         _subscription.pause();
diff --git a/sdk/lib/chrome/dart2js/chrome_dart2js.dart b/sdk/lib/chrome/dart2js/chrome_dart2js.dart
index ec23fde..92b66c5 100644
--- a/sdk/lib/chrome/dart2js/chrome_dart2js.dart
+++ b/sdk/lib/chrome/dart2js/chrome_dart2js.dart
@@ -9,7 +9,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// DO NOT EDIT
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:chrome library.
 
 /// Native wrappers for the Chrome Packaged App APIs.
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index 31be011..0345f8a 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.dart
@@ -26,7 +26,7 @@
  * This implementation is a Dart version of the JavaScript
  * implementation in the V8 project.
  */
-class SplayTreeMap<K extends Comparable, V> implements Map<K, V> {
+class SplayTreeMap<K extends Comparable<K>, V> implements Map<K, V> {
 
   // The root node of the splay tree. It will contain either the last
   // element inserted, or the last element looked up.
diff --git a/sdk/lib/core/comparable.dart b/sdk/lib/core/comparable.dart
index e544201..ee92df9 100644
--- a/sdk/lib/core/comparable.dart
+++ b/sdk/lib/core/comparable.dart
@@ -22,7 +22,7 @@
 /**
  * Interface used by types that have an intrinsic ordering.
  */
-abstract class Comparable {
+abstract class Comparable<T> {
   /**
    * Compares this object to another [Comparable]
    *
@@ -31,7 +31,7 @@
    * May throw an [ArgumentError] if [other] is of a type that
    * is not comparable to [:this:].
    */
-  int compareTo(Comparable other);
+  int compareTo(T other);
 
   /**
    * Compare one comparable to another.
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index b57b630..38d179e 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -8,7 +8,7 @@
  * Deprecated class. Please use [DateTime] instead.
  */
 @deprecated
-abstract class Date implements Comparable {
+abstract class Date implements Comparable<Date> {
   // Weekday constants that are returned by [weekday] method:
   static const int MON = 1;
   static const int TUE = 2;
diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart
index 92f313f..34fcaed 100644
--- a/sdk/lib/core/errors.dart
+++ b/sdk/lib/core/errors.dart
@@ -19,8 +19,9 @@
     }
     if (object is String) {
       // TODO(ahe): Remove backslash when http://dartbug.com/4995 is fixed.
+      String string = object;
       const backslash = '\\';
-      String escaped = object
+      String escaped = string
         .replaceAll('$backslash', '$backslash$backslash')
         .replaceAll('\n', '${backslash}n')
         .replaceAll('\r', '${backslash}r')
@@ -151,49 +152,7 @@
                           [List existingArgumentNames = null])
       : this._existingArgumentNames = existingArgumentNames;
 
-  String toString() {
-    StringBuffer sb = new StringBuffer();
-    int i = 0;
-    if (_arguments != null) {
-      for (; i < _arguments.length; i++) {
-        if (i > 0) {
-          sb.add(", ");
-        }
-        sb.add(Error.safeToString(_arguments[i]));
-      }
-    }
-    if (_namedArguments != null) {
-      _namedArguments.forEach((String key, var value) {
-        if (i > 0) {
-          sb.add(", ");
-        }
-        sb.add(key);
-        sb.add(": ");
-        sb.add(Error.safeToString(value));
-        i++;
-      });
-    }
-    if (_existingArgumentNames == null) {
-      return "NoSuchMethodError : method not found: '$_memberName'\n"
-          "Receiver: ${Error.safeToString(_receiver)}\n"
-          "Arguments: [$sb]";
-    } else {
-      String actualParameters = sb.toString();
-      sb = new StringBuffer();
-      for (int i = 0; i < _existingArgumentNames.length; i++) {
-        if (i > 0) {
-          sb.add(", ");
-        }
-        sb.add(_existingArgumentNames[i]);
-      }
-      String formalParameters = sb.toString();
-      return "NoSuchMethodError: incorrect number of arguments passed to "
-          "method named '$_memberName'\n"
-          "Receiver: ${Error.safeToString(_receiver)}\n"
-          "Tried calling: $_memberName($actualParameters)\n"
-          "Found: $_memberName($formalParameters)";
-    }
-  }
+  external String toString();
 }
 
 
diff --git a/sdk/lib/core/num.dart b/sdk/lib/core/num.dart
index b5e42cb..439022f 100644
--- a/sdk/lib/core/num.dart
+++ b/sdk/lib/core/num.dart
@@ -7,7 +7,7 @@
 /**
  * All numbers in dart are instances of [num].
  */
-abstract class num implements Comparable {
+abstract class num implements Comparable<num> {
   /** Addition operator. */
   num operator +(num other);
 
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index 4e5b950..ba07bae 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -17,7 +17,7 @@
  * Unicode code point. The runes of a string are accessible through the [runes]
  * getter.
  */
-abstract class String implements Comparable, Pattern {
+abstract class String implements Comparable<String>, Pattern {
   /**
    * Allocates a new String for the specified [charCodes].
    *
diff --git a/sdk/lib/core/string_buffer.dart b/sdk/lib/core/string_buffer.dart
index cbfcd6e..07d3277 100644
--- a/sdk/lib/core/string_buffer.dart
+++ b/sdk/lib/core/string_buffer.dart
@@ -11,13 +11,16 @@
  */
 class StringBuffer implements StringSink {
 
-  /// Creates the string buffer with an initial content.
+  /** Creates the string buffer with an initial content. */
   external StringBuffer([Object content = ""]);
 
-  /// Returns the length of the buffer.
+  /**
+   * Returns the length of the content that has been accumulated so far.
+   * This is a constant-time operation.
+   */
   external int get length;
 
-  /// Returns whether the buffer is empty.
+  /** Returns whether the buffer is empty. This is a constant-time operation. */
   bool get isEmpty => length == 0;
 
   /**
diff --git a/sdk/lib/core/string_sink.dart b/sdk/lib/core/string_sink.dart
index c2eff2d..04650f7 100644
--- a/sdk/lib/core/string_sink.dart
+++ b/sdk/lib/core/string_sink.dart
@@ -7,8 +7,8 @@
 abstract class StringSink {
 
   /**
-   * Converts [obj] to a String by invoking [:toString:] and adds the result to
-   * this [StringSink].
+   * Converts [obj] to a String by invoking `toString` and adds the result to
+   * `this`.
    */
   void write(Object obj);
 
@@ -18,15 +18,15 @@
   void writeAll(Iterable objects);
 
   /**
-   * Converts [obj] to a String by invoking [:toString:] and adds the result to
-   * this [StringSink]. Then adds a new line.
+   * Converts [obj] to a String by invoking `toString` and adds the result to
+   * `this`. Then adds a new line.
    */
   void writeln(Object obj);
 
   /**
-   * Writes the [charCode] to this [StringSink].
+   * Writes the [charCode] to `this`.
    *
-   * This method is equivalent to [:write(new String.fromCharCode(charCode)):].
+   * This method is equivalent to `write(new String.fromCharCode(charCode))`.
    */
   void writeCharCode(int charCode);
 }
diff --git a/sdk/lib/crypto/crypto.dart b/sdk/lib/crypto/crypto.dart
index 590a62e..755c18b 100644
--- a/sdk/lib/crypto/crypto.dart
+++ b/sdk/lib/crypto/crypto.dart
@@ -6,148 +6,10 @@
 
 import 'dart:math';
 
+part 'crypto_base.dart';
 part 'crypto_utils.dart';
 part 'hash_utils.dart';
 part 'hmac.dart';
 part 'md5.dart';
 part 'sha1.dart';
 part 'sha256.dart';
-
-/**
- * Interface for cryptographic hash functions.
- *
- * The [add] method is used to add data to the hash. The [close] method
- * is used to extract the message digest.
- *
- * Once the [close] method has been called no more data can be added using the
- * [add] method. If [add] is called after the first call to [close] a
- * HashException is thrown.
- *
- * If multiple instances of a given Hash is needed the [newInstance]
- * method can provide a new instance.
- */
-// TODO(floitsch): make Hash implement Sink, StreamSink or similar.
-abstract class Hash {
-  /**
-   * Add a list of bytes to the hash computation.
-   */
-  add(List<int> data);
-
-  /**
-   * Finish the hash computation and extract the message digest as
-   * a list of bytes.
-   */
-  List<int> close();
-
-  /**
-   * Returns a new instance of this hash function.
-   */
-  Hash newInstance();
-
-  /**
-   * Internal block size of the hash in bytes.
-   *
-   * This is exposed for use by the HMAC class which needs to know the
-   * block size for the [Hash] it is using.
-   */
-  int get blockSize;
-}
-
-/**
- * SHA1 hash function implementation.
- */
-abstract class SHA1 implements Hash {
-  factory SHA1() => new _SHA1();
-}
-
-/**
- * SHA256 hash function implementation.
- */
-abstract class SHA256 implements Hash {
-  factory SHA256() => new _SHA256();
-}
-
-/**
- * MD5 hash function implementation.
- *
- * WARNING: MD5 has known collisions and should only be used when
- * required for backwards compatibility.
- */
-abstract class MD5 implements Hash {
-  factory MD5() => new _MD5();
-}
-
-/**
- * Hash-based Message Authentication Code support.
- *
- * The [add] method is used to add data to the message. The [digest] and
- * [close] methods are used to extract the message authentication code.
- */
-// TODO(floitsch): make Hash implement Sink, StreamSink or similar.
-abstract class HMAC {
-  /**
-   * Create an [HMAC] object from a [Hash] and a key.
-   */
-  factory HMAC(Hash hash, List<int> key) => new _HMAC(hash, key);
-
-  /**
-   * Add a list of bytes to the message.
-   */
-  add(List<int> data);
-
-  /**
-   * Perform the actual computation and extract the message digest
-   * as a list of bytes.
-   */
-  List<int> close();
-
-  /**
-   * Extract the message digest as a list of bytes without closing [this].
-   */
-  List<int> get digest;
-
-  /**
-   * Verify that the HMAC computed for the data so far matches the
-   * given message digest.
-   *
-   * This method should be used instead of memcmp-style comparisons
-   * to avoid leaking information via timing.
-   *
-   * Throws an exception if the given digest does not have the same
-   * size as the digest computed by this HMAC instance.
-   */
-  bool verify(List<int> digest);
-}
-
-/**
- * Utility methods for working with message digests.
- */
-abstract class CryptoUtils {
-  /**
-   * Convert a list of bytes (for example a message digest) into a hex
-   * string.
-   */
-  static String bytesToHex(List<int> bytes) {
-    return _CryptoUtils.bytesToHex(bytes);
-  }
-
-  /**
-   * Converts a list of bytes (for example a message digest) into a
-   * base64 encoded string optionally broken up in to lines of
-   * [lineLength] chars separated by '\r\n'.
-   */
-  static String bytesToBase64(List<int> bytes, [int lineLength]) {
-    return _CryptoUtils.bytesToBase64(bytes, lineLength);
-  }
-}
-
-/**
- * HashExceptions are thrown on invalid use of a Hash
- * object.
- */
-class HashException {
-  HashException(String this.message);
-  toString() => "HashException: $message";
-  String message;
-}
-
diff --git a/runtime/lib/crypto/crypto_vm.dart b/sdk/lib/crypto/crypto_base.dart
similarity index 63%
rename from runtime/lib/crypto/crypto_vm.dart
rename to sdk/lib/crypto/crypto_base.dart
index a542984..4231718 100644
--- a/runtime/lib/crypto/crypto_vm.dart
+++ b/sdk/lib/crypto/crypto_base.dart
@@ -1,38 +1,34 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
-// TODO(ager, iposva): Get rid of this file when the VM snapshot
-// generation can deal with normal library structure.
-
-library crypto;
-
-import 'dart:math';
+part of dart.crypto;
 
 /**
  * Interface for cryptographic hash functions.
  *
- * The [update] method is used to add data to the hash. The [digest] method
+ * The [add] method is used to add data to the hash. The [close] method
  * is used to extract the message digest.
  *
- * Once the [digest] method has been called no more data can be added using the
- * [update] method. If [update] is called after the first call to [digest] a
+ * Once the [close] method has been called no more data can be added using the
+ * [add] method. If [add] is called after the first call to [close] a
  * HashException is thrown.
  *
  * If multiple instances of a given Hash is needed the [newInstance]
  * method can provide a new instance.
  */
+// TODO(floitsch): make Hash implement Sink, StreamSink or similar.
 abstract class Hash {
   /**
    * Add a list of bytes to the hash computation.
    */
-  Hash update(List<int> data);
+  add(List<int> data);
 
   /**
    * Finish the hash computation and extract the message digest as
    * a list of bytes.
    */
-  List<int> digest();
+  List<int> close();
 
   /**
    * Returns a new instance of this hash function.
@@ -40,7 +36,10 @@
   Hash newInstance();
 
   /**
-   * Block size of the hash in bytes.
+   * Internal block size of the hash in bytes.
+   *
+   * This is exposed for use by the HMAC class which needs to know the
+   * block size for the [Hash] it is using.
    */
   int get blockSize;
 }
@@ -72,9 +71,10 @@
 /**
  * Hash-based Message Authentication Code support.
  *
- * The [update] method is used to add data to the message. The [digest] method
- * is used to extract the message authentication code.
+ * The [add] method is used to add data to the message. The [digest] and
+ * [close] methods are used to extract the message authentication code.
  */
+// TODO(floitsch): make Hash implement Sink, StreamSink or similar.
 abstract class HMAC {
   /**
    * Create an [HMAC] object from a [Hash] and a key.
@@ -84,13 +84,30 @@
   /**
    * Add a list of bytes to the message.
    */
-  HMAC update(List<int> data);
+  add(List<int> data);
 
   /**
    * Perform the actual computation and extract the message digest
    * as a list of bytes.
    */
-  List<int> digest();
+  List<int> close();
+
+  /**
+   * Extract the message digest as a list of bytes without closing [this].
+   */
+  List<int> get digest;
+
+  /**
+   * Verify that the HMAC computed for the data so far matches the
+   * given message digest.
+   *
+   * This method should be used instead of memcmp-style comparisons
+   * to avoid leaking information via timing.
+   *
+   * Throws an exception if the given digest does not have the same
+   * size as the digest computed by this HMAC instance.
+   */
+  bool verify(List<int> digest);
 }
 
 /**
diff --git a/sdk/lib/crypto/crypto_sources.gypi b/sdk/lib/crypto/crypto_sources.gypi
new file mode 100644
index 0000000..b5a934a
--- /dev/null
+++ b/sdk/lib/crypto/crypto_sources.gypi
@@ -0,0 +1,20 @@
+# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This file contains all sources for the dart:crypto library.
+#
+# TODO(ager): crypto_base.dart should be removed when the
+# VM can use the 'library' and 'part' directives for libraries.
+# At that point crypto.dart should be the only crypto library file.
+{
+  'sources': [
+    'crypto_base.dart',
+    'crypto_utils.dart',
+    'hash_utils.dart',
+    'hmac.dart',
+    'md5.dart',
+    'sha1.dart',
+    'sha256.dart',
+  ],
+}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 78346e6..7cf2fcc 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -7,6 +7,7 @@
 import 'dart:isolate';
 import 'dart:json' as json;
 import 'dart:math';
+import 'dart:web_sql';
 import 'dart:svg' as svg;
 import 'dart:web_audio' as web_audio;
 import 'dart:_js_helper' show convertDartClosureToJS, Creates, JavaScriptIndexingBehavior, JSName, Null, Returns;
@@ -16,7 +17,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// DO NOT EDIT
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:html library.
 
 /// The Dart HTML library.
@@ -1476,7 +1478,7 @@
       '#.lineDashOffset || #.webkitLineDashOffset', this, this);
 
   @DomName('CanvasRenderingContext2D.lineDashOffset')
-  void set lineDashOffset(num value) => JS('void', 
+  void set lineDashOffset(num value) => JS('void',
       'typeof #.lineDashOffset != "undefined" ? #.lineDashOffset = # : '
       '#.webkitLineDashOffset = #', this, this, value, this, value);
 }
@@ -2193,6 +2195,8 @@
 
   static const int CSS_VH = 27;
 
+  static const int CSS_VMAX = 29;
+
   static const int CSS_VMIN = 28;
 
   static const int CSS_VW = 26;
@@ -5961,77 +5965,6 @@
 
 
 @DocsEditable
-@DomName('Database')
-@SupportedBrowser(SupportedBrowser.CHROME)
-@SupportedBrowser(SupportedBrowser.SAFARI)
-@Experimental
-class Database native "*Database" {
-
-  /// Checks if this type is supported on the current platform.
-  static bool get supported => JS('bool', '!!(window.openDatabase)');
-
-  @DomName('Database.version')
-  @DocsEditable
-  final String version;
-
-  @DomName('Database.changeVersion')
-  @DocsEditable
-  void changeVersion(String oldVersion, String newVersion, [SqlTransactionCallback callback, SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native;
-
-  @DomName('Database.readTransaction')
-  @DocsEditable
-  void readTransaction(SqlTransactionCallback callback, [SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native;
-
-  @DomName('Database.transaction')
-  @DocsEditable
-  void transaction(SqlTransactionCallback callback, [SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-typedef void DatabaseCallback(database);
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
-@DomName('DatabaseSync')
-@SupportedBrowser(SupportedBrowser.CHROME)
-@SupportedBrowser(SupportedBrowser.SAFARI)
-@Experimental
-class DatabaseSync native "*DatabaseSync" {
-
-  @DomName('DatabaseSync.lastErrorMessage')
-  @DocsEditable
-  final String lastErrorMessage;
-
-  @DomName('DatabaseSync.version')
-  @DocsEditable
-  final String version;
-
-  @DomName('DatabaseSync.changeVersion')
-  @DocsEditable
-  void changeVersion(String oldVersion, String newVersion, [SqlTransactionSyncCallback callback]) native;
-
-  @DomName('DatabaseSync.readTransaction')
-  @DocsEditable
-  void readTransaction(SqlTransactionSyncCallback callback) native;
-
-  @DomName('DatabaseSync.transaction')
-  @DocsEditable
-  void transaction(SqlTransactionSyncCallback callback) native;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
 @DomName('DedicatedWorkerContext')
 class DedicatedWorkerContext extends WorkerContext native "*DedicatedWorkerContext" {
 
@@ -8502,7 +8435,7 @@
   _ElementCssClassSet(this._element);
 
   Set<String> readClasses() {
-    var s = new Set<String>();
+    var s = new LinkedHashSet<String>();
     var classname = _element.$dom_className;
 
     for (String name in classname.split(' ')) {
@@ -11163,7 +11096,7 @@
 
   @DomName('Float32Array.fromBuffer')
   @DocsEditable
-  factory Float32Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) => 
+  factory Float32Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) =>
     _TypedArrayFactoryProvider.createFloat32Array_fromBuffer(buffer, byteOffset, length);
 
   static const int BYTES_PER_ELEMENT = 4;
@@ -11379,7 +11312,7 @@
 
   @DomName('Float64Array.fromBuffer')
   @DocsEditable
-  factory Float64Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) => 
+  factory Float64Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) =>
     _TypedArrayFactoryProvider.createFloat64Array_fromBuffer(buffer, byteOffset, length);
 
   static const int BYTES_PER_ELEMENT = 8;
@@ -11580,6 +11513,21 @@
 
 
 @DocsEditable
+@DomName('FocusEvent')
+class FocusEvent extends UIEvent native "*FocusEvent" {
+
+  EventTarget get relatedTarget => _convertNativeToDart_EventTarget(this._relatedTarget);
+  @JSName('relatedTarget')
+  @DomName('FocusEvent.relatedTarget')
+  @DocsEditable
+  final dynamic _relatedTarget;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
 @DomName('FormData')
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.FIREFOX)
@@ -11708,18 +11656,113 @@
 @DomName('Geolocation')
 class Geolocation native "*Geolocation" {
 
-  @DomName('Geolocation.clearWatch')
-  @DocsEditable
-  void clearWatch(int watchId) native;
-
   @DomName('Geolocation.getCurrentPosition')
-  @DocsEditable
-  void getCurrentPosition(PositionCallback successCallback, [PositionErrorCallback errorCallback, Object options]) native;
+  Future<Geoposition> getCurrentPosition({bool enableHighAccuracy,
+      Duration timeout, Duration maximumAge}) {
+    var options = {};
+    if (enableHighAccuracy != null) {
+      options['enableHighAccuracy'] = enableHighAccuracy;
+    }
+    if (timeout != null) {
+      options['timeout'] = timeout.inMilliseconds;
+    }
+    if (maximumAge != null) {
+      options['maximumAge'] = maximumAge.inMilliseconds;
+    }
+    var completer = new Completer<Geoposition>();
+    try {
+      $dom_getCurrentPosition(
+          (position) {
+            completer.complete(_ensurePosition(position));
+          },
+          (error) {
+            completer.completeError(error);
+          },
+          options);
+    } catch (e, stacktrace) {
+      completer.completeError(e, stacktrace);
+    }
+    return completer.future;
+  }
 
   @DomName('Geolocation.watchPosition')
+  Stream<Geoposition> watchPosition({bool enableHighAccuracy,
+      Duration timeout, Duration maximumAge}) {
+
+    var options = {};
+    if (enableHighAccuracy != null) {
+      options['enableHighAccuracy'] = enableHighAccuracy;
+    }
+    if (timeout != null) {
+      options['timeout'] = timeout.inMilliseconds;
+    }
+    if (maximumAge != null) {
+      options['maximumAge'] = maximumAge.inMilliseconds;
+    }
+
+    int watchId;
+    var controller;
+    controller = new StreamController<Geoposition>(
+      onSubscriptionStateChange: () {
+        if (controller.hasSubscribers) {
+          assert(watchId == null);
+          watchId = $dom_watchPosition(
+              (position) {
+                controller.add(_ensurePosition(position));
+              },
+              (error) {
+                controller.signalError(error);
+              },
+              options);
+        } else {
+          assert(watchId != null);
+          $dom_clearWatch(watchId);
+        }
+      });
+
+    return controller.stream;
+  }
+
+  Geoposition _ensurePosition(domPosition) {
+    try {
+      // Firefox may throw on this.
+      if (domPosition is Geoposition) {
+        return domPosition;
+      }
+    } catch(e) {}
+    return new _GeopositionWrapper(domPosition);
+  }
+
+  @JSName('clearWatch')
+  @DomName('Geolocation.clearWatch')
   @DocsEditable
-  int watchPosition(PositionCallback successCallback, [PositionErrorCallback errorCallback, Object options]) native;
+  void $dom_clearWatch(int watchId) native;
+
+  @JSName('getCurrentPosition')
+  @DomName('Geolocation.getCurrentPosition')
+  @DocsEditable
+  void $dom_getCurrentPosition(_PositionCallback successCallback, [_PositionErrorCallback errorCallback, Object options]) native;
+
+  @JSName('watchPosition')
+  @DomName('Geolocation.watchPosition')
+  @DocsEditable
+  int $dom_watchPosition(_PositionCallback successCallback, [_PositionErrorCallback errorCallback, Object options]) native;
 }
+
+/**
+ * Wrapper for Firefox- it returns an object which we cannot map correctly.
+ * Basically Firefox was returning a [xpconnect wrapped nsIDOMGeoPosition] but
+ * which has further oddities.
+ */
+class _GeopositionWrapper implements Geoposition {
+  var _ptr;
+  _GeopositionWrapper(this._ptr);
+
+  Coordinates get coords => JS('Coordinates', '#.coords', _ptr);
+  int get timestamp => JS('int', '#.timestamp', _ptr);
+}
+
+
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -14130,7 +14173,7 @@
 
   @DomName('Int16Array.fromBuffer')
   @DocsEditable
-  factory Int16Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) => 
+  factory Int16Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) =>
     _TypedArrayFactoryProvider.createInt16Array_fromBuffer(buffer, byteOffset, length);
 
   static const int BYTES_PER_ELEMENT = 2;
@@ -14346,7 +14389,7 @@
 
   @DomName('Int32Array.fromBuffer')
   @DocsEditable
-  factory Int32Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) => 
+  factory Int32Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) =>
     _TypedArrayFactoryProvider.createInt32Array_fromBuffer(buffer, byteOffset, length);
 
   static const int BYTES_PER_ELEMENT = 4;
@@ -14562,7 +14605,7 @@
 
   @DomName('Int8Array.fromBuffer')
   @DocsEditable
-  factory Int8Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) => 
+  factory Int8Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) =>
     _TypedArrayFactoryProvider.createInt8Array_fromBuffer(buffer, byteOffset, length);
 
   static const int BYTES_PER_ELEMENT = 1;
@@ -14819,6 +14862,10 @@
   @DomName('JavaScriptCallFrame.scopeType')
   @DocsEditable
   int scopeType(int scopeIndex) native;
+
+  @DomName('JavaScriptCallFrame.setVariableValue')
+  @DocsEditable
+  Object setVariableValue(int scopeIndex, String variableName, Object newValue) native;
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -18389,7 +18436,7 @@
 // WARNING: Do not edit - generated code.
 
 
-typedef void PositionCallback(Geoposition position);
+typedef void _PositionCallback(Geoposition position);
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -18420,7 +18467,7 @@
 // WARNING: Do not edit - generated code.
 
 
-typedef void PositionErrorCallback(PositionError error);
+typedef void _PositionErrorCallback(PositionError error);
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -18965,17 +19012,17 @@
   }
 
   /**
-   * Checks if Real Time Communication (RTC) APIs are supported and enabled on 
+   * Checks if Real Time Communication (RTC) APIs are supported and enabled on
    * the current platform.
    */
   static bool get supported {
     // Currently in Firefox some of the RTC elements are defined but throw an
-    // error unless the user has specifically enabled them in their 
+    // error unless the user has specifically enabled them in their
     // about:config. So we have to construct an element to actually test if RTC
     // is supported at at the given time.
     try {
       var c = new RtcPeerConnection({"iceServers": [ {"url":"stun:foo.com"}]});
-      return c is RtcPeerConnection; 
+      return c is RtcPeerConnection;
     } catch (_) {}
     return false;
   }
@@ -19024,12 +19071,6 @@
   @DocsEditable
   final RtcSessionDescription localDescription;
 
-  @DomName('RTCPeerConnection.localStreams')
-  @DocsEditable
-  @Returns('_MediaStreamList')
-  @Creates('_MediaStreamList')
-  final List<MediaStream> localStreams;
-
   @DomName('RTCPeerConnection.readyState')
   @DocsEditable
   final String readyState;
@@ -19038,12 +19079,6 @@
   @DocsEditable
   final RtcSessionDescription remoteDescription;
 
-  @DomName('RTCPeerConnection.remoteStreams')
-  @DocsEditable
-  @Returns('_MediaStreamList')
-  @Creates('_MediaStreamList')
-  final List<MediaStream> remoteStreams;
-
   @DomName('RTCPeerConnection.signalingState')
   @DocsEditable
   final String signalingState;
@@ -19101,6 +19136,11 @@
   @DocsEditable
   void _createAnswer_2(RtcSessionDescriptionCallback successCallback, RtcErrorCallback failureCallback) native;
 
+  @JSName('createDTMFSender')
+  @DomName('RTCPeerConnection.createDTMFSender')
+  @DocsEditable
+  RtcdtmfSender createDtmfSender(MediaStreamTrack track) native;
+
   @DomName('RTCPeerConnection.createDataChannel')
   @DocsEditable
   RtcDataChannel createDataChannel(String label, [Map options]) {
@@ -19143,6 +19183,14 @@
   @DocsEditable
   bool dispatchEvent(Event event) native;
 
+  @DomName('RTCPeerConnection.getLocalStreams')
+  @DocsEditable
+  List<MediaStream> getLocalStreams() native;
+
+  @DomName('RTCPeerConnection.getRemoteStreams')
+  @DocsEditable
+  List<MediaStream> getRemoteStreams() native;
+
   @DomName('RTCPeerConnection.getStats')
   @DocsEditable
   void getStats(RtcStatsCallback successCallback, MediaStreamTrack selector) native;
@@ -19307,42 +19355,64 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// WARNING: Do not edit - generated code.
 
+@DocsEditable
+@DomName('RTCDTMFSender')
+class RtcdtmfSender extends EventTarget native "*RTCDTMFSender" {
 
-typedef void SqlStatementCallback(SqlTransaction transaction, SqlResultSet resultSet);
+  @JSName('canInsertDTMF')
+  @DomName('RTCDTMFSender.canInsertDTMF')
+  @DocsEditable
+  final bool canInsertDtmf;
+
+  @DomName('RTCDTMFSender.duration')
+  @DocsEditable
+  final int duration;
+
+  @DomName('RTCDTMFSender.interToneGap')
+  @DocsEditable
+  final int interToneGap;
+
+  @DomName('RTCDTMFSender.toneBuffer')
+  @DocsEditable
+  final String toneBuffer;
+
+  @DomName('RTCDTMFSender.track')
+  @DocsEditable
+  final MediaStreamTrack track;
+
+  @JSName('addEventListener')
+  @DomName('RTCDTMFSender.addEventListener')
+  @DocsEditable
+  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native;
+
+  @DomName('RTCDTMFSender.dispatchEvent')
+  @DocsEditable
+  bool dispatchEvent(Event event) native;
+
+  @JSName('insertDTMF')
+  @DomName('RTCDTMFSender.insertDTMF')
+  @DocsEditable
+  void insertDtmf(String tones, [int duration, int interToneGap]) native;
+
+  @JSName('removeEventListener')
+  @DomName('RTCDTMFSender.removeEventListener')
+  @DocsEditable
+  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native;
+}
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// WARNING: Do not edit - generated code.
 
+@DocsEditable
+@DomName('RTCDTMFToneChangeEvent')
+class RtcdtmfToneChangeEvent extends Event native "*RTCDTMFToneChangeEvent" {
 
-typedef void SqlStatementErrorCallback(SqlTransaction transaction, SqlError error);
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-typedef void SqlTransactionCallback(SqlTransaction transaction);
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-typedef void SqlTransactionErrorCallback(SqlError error);
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-typedef void SqlTransactionSyncCallback(SqlTransactionSync transaction);
+  @DomName('RTCDTMFToneChangeEvent.tone')
+  @DocsEditable
+  final String tone;
+}
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -20530,330 +20600,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
-@DocsEditable
-@DomName('SQLError')
-class SqlError native "*SQLError" {
-
-  static const int CONSTRAINT_ERR = 6;
-
-  static const int DATABASE_ERR = 1;
-
-  static const int QUOTA_ERR = 4;
-
-  static const int SYNTAX_ERR = 5;
-
-  static const int TIMEOUT_ERR = 7;
-
-  static const int TOO_LARGE_ERR = 3;
-
-  static const int UNKNOWN_ERR = 0;
-
-  static const int VERSION_ERR = 2;
-
-  @DomName('SQLError.code')
-  @DocsEditable
-  final int code;
-
-  @DomName('SQLError.message')
-  @DocsEditable
-  final String message;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
-@DomName('SQLException')
-class SqlException native "*SQLException" {
-
-  static const int CONSTRAINT_ERR = 6;
-
-  static const int DATABASE_ERR = 1;
-
-  static const int QUOTA_ERR = 4;
-
-  static const int SYNTAX_ERR = 5;
-
-  static const int TIMEOUT_ERR = 7;
-
-  static const int TOO_LARGE_ERR = 3;
-
-  static const int UNKNOWN_ERR = 0;
-
-  static const int VERSION_ERR = 2;
-
-  @DomName('SQLException.code')
-  @DocsEditable
-  final int code;
-
-  @DomName('SQLException.message')
-  @DocsEditable
-  final String message;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
-@DomName('SQLResultSet')
-class SqlResultSet native "*SQLResultSet" {
-
-  @DomName('SQLResultSet.insertId')
-  @DocsEditable
-  final int insertId;
-
-  @DomName('SQLResultSet.rows')
-  @DocsEditable
-  final SqlResultSetRowList rows;
-
-  @DomName('SQLResultSet.rowsAffected')
-  @DocsEditable
-  final int rowsAffected;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
-@DomName('SQLResultSetRowList')
-class SqlResultSetRowList implements JavaScriptIndexingBehavior, List<Map> native "*SQLResultSetRowList" {
-
-  @DomName('SQLResultSetRowList.length')
-  @DocsEditable
-  int get length => JS("int", "#.length", this);
-
-  Map operator[](int index) => JS("Map", "#[#]", this, index);
-
-  void operator[]=(int index, Map value) {
-    throw new UnsupportedError("Cannot assign element of immutable List.");
-  }
-  // -- start List<Map> mixins.
-  // Map is the element type.
-
-  // From Iterable<Map>:
-
-  Iterator<Map> get iterator {
-    // Note: NodeLists are not fixed size. And most probably length shouldn't
-    // be cached in both iterator _and_ forEach method. For now caching it
-    // for consistency.
-    return new FixedSizeListIterator<Map>(this);
-  }
-
-  dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Map)) {
-    return IterableMixinWorkaround.reduce(this, initialValue, combine);
-  }
-
-  bool contains(Map element) => IterableMixinWorkaround.contains(this, element);
-
-  void forEach(void f(Map element)) => IterableMixinWorkaround.forEach(this, f);
-
-  String join([String separator]) =>
-      IterableMixinWorkaround.joinList(this, separator);
-
-  Iterable map(f(Map element)) =>
-      IterableMixinWorkaround.mapList(this, f);
-
-  Iterable<Map> where(bool f(Map element)) =>
-      IterableMixinWorkaround.where(this, f);
-
-  Iterable expand(Iterable f(Map element)) =>
-      IterableMixinWorkaround.expand(this, f);
-
-  bool every(bool f(Map element)) => IterableMixinWorkaround.every(this, f);
-
-  bool any(bool f(Map element)) => IterableMixinWorkaround.any(this, f);
-
-  List<Map> toList() => new List<Map>.from(this);
-  Set<Map> toSet() => new Set<Map>.from(this);
-
-  bool get isEmpty => this.length == 0;
-
-  Iterable<Map> take(int n) => IterableMixinWorkaround.takeList(this, n);
-
-  Iterable<Map> takeWhile(bool test(Map value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
-  }
-
-  Iterable<Map> skip(int n) => IterableMixinWorkaround.skipList(this, n);
-
-  Iterable<Map> skipWhile(bool test(Map value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
-  }
-
-  Map firstMatching(bool test(Map value), { Map orElse() }) {
-    return IterableMixinWorkaround.firstMatching(this, test, orElse);
-  }
-
-  Map lastMatching(bool test(Map value), {Map orElse()}) {
-    return IterableMixinWorkaround.lastMatchingInList(this, test, orElse);
-  }
-
-  Map singleMatching(bool test(Map value)) {
-    return IterableMixinWorkaround.singleMatching(this, test);
-  }
-
-  Map elementAt(int index) {
-    return this[index];
-  }
-
-  // From Collection<Map>:
-
-  void add(Map value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addLast(Map value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addAll(Iterable<Map> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  // From List<Map>:
-  void set length(int value) {
-    throw new UnsupportedError("Cannot resize immutable List.");
-  }
-
-  void clear() {
-    throw new UnsupportedError("Cannot clear immutable List.");
-  }
-
-  Iterable<Map> get reversed {
-    return IterableMixinWorkaround.reversedList(this);
-  }
-
-  void sort([int compare(Map a, Map b)]) {
-    throw new UnsupportedError("Cannot sort immutable List.");
-  }
-
-  int indexOf(Map element, [int start = 0]) =>
-      Lists.indexOf(this, element, start, this.length);
-
-  int lastIndexOf(Map element, [int start]) {
-    if (start == null) start = length - 1;
-    return Lists.lastIndexOf(this, element, start);
-  }
-
-  Map get first {
-    if (this.length > 0) return this[0];
-    throw new StateError("No elements");
-  }
-
-  Map get last {
-    if (this.length > 0) return this[this.length - 1];
-    throw new StateError("No elements");
-  }
-
-  Map get single {
-    if (length == 1) return this[0];
-    if (length == 0) throw new StateError("No elements");
-    throw new StateError("More than one element");
-  }
-
-  Map min([int compare(Map a, Map b)]) =>
-      IterableMixinWorkaround.min(this, compare);
-
-  Map max([int compare(Map a, Map b)]) =>
-      IterableMixinWorkaround.max(this, compare);
-
-  Map removeAt(int pos) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  Map removeLast() {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void remove(Object object) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeAll(Iterable elements) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainAll(Iterable elements) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeMatching(bool test(Map element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainMatching(bool test(Map element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void setRange(int start, int rangeLength, List<Map> from, [int startFrom]) {
-    throw new UnsupportedError("Cannot setRange on immutable List.");
-  }
-
-  void removeRange(int start, int rangeLength) {
-    throw new UnsupportedError("Cannot removeRange on immutable List.");
-  }
-
-  void insertRange(int start, int rangeLength, [Map initialValue]) {
-    throw new UnsupportedError("Cannot insertRange on immutable List.");
-  }
-
-  List<Map> getRange(int start, int rangeLength) =>
-      Lists.getRange(this, start, rangeLength, <Map>[]);
-
-  // -- end List<Map> mixins.
-
-  @DomName('SQLResultSetRowList.item')
-  @DocsEditable
-  @Creates('=Object')
-  Map item(int index) {
-    return convertNativeToDart_Dictionary(_item_1(index));
-  }
-  @JSName('item')
-  @DomName('SQLResultSetRowList.item')
-  @DocsEditable
-  @Creates('=Object')
-  _item_1(index) native;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
-@DomName('SQLTransaction')
-@SupportedBrowser(SupportedBrowser.CHROME)
-@SupportedBrowser(SupportedBrowser.SAFARI)
-@Experimental
-class SqlTransaction native "*SQLTransaction" {
-
-  @DomName('SQLTransaction.executeSql')
-  @DocsEditable
-  void executeSql(String sqlStatement, List arguments, [SqlStatementCallback callback, SqlStatementErrorCallback errorCallback]) native;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
-@DomName('SQLTransactionSync')
-@SupportedBrowser(SupportedBrowser.CHROME)
-@SupportedBrowser(SupportedBrowser.SAFARI)
-@Experimental
-class SqlTransactionSync native "*SQLTransactionSync" {
-
-  @DomName('SQLTransactionSync.executeSql')
-  @DocsEditable
-  SqlResultSet executeSql(String sqlStatement, List arguments) native;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
 /**
  * The type used by the
  * [Window.localStorage] and [Window.sessionStorage] properties.
@@ -22765,7 +22511,7 @@
 
   @DomName('Uint16Array.fromBuffer')
   @DocsEditable
-  factory Uint16Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) => 
+  factory Uint16Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) =>
     _TypedArrayFactoryProvider.createUint16Array_fromBuffer(buffer, byteOffset, length);
 
   static const int BYTES_PER_ELEMENT = 2;
@@ -22981,7 +22727,7 @@
 
   @DomName('Uint32Array.fromBuffer')
   @DocsEditable
-  factory Uint32Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) => 
+  factory Uint32Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) =>
     _TypedArrayFactoryProvider.createUint32Array_fromBuffer(buffer, byteOffset, length);
 
   static const int BYTES_PER_ELEMENT = 4;
@@ -23197,7 +22943,7 @@
 
   @DomName('Uint8Array.fromBuffer')
   @DocsEditable
-  factory Uint8Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) => 
+  factory Uint8Array.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) =>
     _TypedArrayFactoryProvider.createUint8Array_fromBuffer(buffer, byteOffset, length);
 
   static const int BYTES_PER_ELEMENT = 1;
@@ -23413,7 +23159,7 @@
 
   @DomName('Uint8ClampedArray.fromBuffer')
   @DocsEditable
-  factory Uint8ClampedArray.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) => 
+  factory Uint8ClampedArray.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) =>
     _TypedArrayFactoryProvider.createUint8ClampedArray_fromBuffer(buffer, byteOffset, length);
 
   // Use implementation from Uint8Array.
@@ -25607,6 +25353,12 @@
   }
 
 
+  static const int DOM_DELTA_LINE = 0x01;
+
+  static const int DOM_DELTA_PAGE = 0x02;
+
+  static const int DOM_DELTA_PIXEL = 0x00;
+
   @JSName('webkitDirectionInvertedFromDevice')
   @DomName('WheelEvent.webkitDirectionInvertedFromDevice')
   @DocsEditable
@@ -25679,12 +25431,13 @@
         'deltaX is not supported');
   }
 
+  @DomName('WheelEvent.deltaMode')
   int get deltaMode {
-    if (JS('bool', '!!#.deltaMode', this)) {
-      // If not available then we're poly-filling and doing pixel scroll.
-      return 0;
+    if (JS('bool', '!!(#.deltaMode)', this)) {
+      return JS('int', '#.deltaMode', this);
     }
-    return this._deltaMode;
+    // If not available then we're poly-filling and doing pixel scroll.
+    return 0;
   }
 
   num get _deltaY => JS('num', '#.deltaY', this);
@@ -25692,7 +25445,6 @@
   num get _wheelDelta => JS('num', '#.wheelDelta', this);
   num get _wheelDeltaX => JS('num', '#.wheelDeltaX', this);
   num get _detail => JS('num', '#.detail', this);
-  int get _deltaMode => JS('int', '#.deltaMode', this);
 
   bool get _hasInitMouseScrollEvent =>
       JS('bool', '!!(#.initMouseScrollEvent)', this);
@@ -25756,7 +25508,7 @@
    * frame unwinds, causing the future to complete after all processing has
    * completed for the current event, but before any subsequent events.
    */
-  void setImmediate(TimeoutHandler callback) { 
+  void setImmediate(TimeoutHandler callback) {
     _addMicrotaskCallback(callback);
   }
   /**
@@ -25787,7 +25539,7 @@
    * If you need to later cancel this animation, use [requestAnimationFrame]
    * instead.
    *
-   * Note: The code that runs when the future completes should call 
+   * Note: The code that runs when the future completes should call
    * [animationFrame] again for the animation to continue.
    */
   Future<num> get animationFrame {
@@ -25862,7 +25614,7 @@
 
   /**
    * Called to draw an animation frame and then request the window to repaint
-   * after [callback] has finished (creating the animation). 
+   * after [callback] has finished (creating the animation).
    *
    * Use this method only if you need to later call [cancelAnimationFrame]. If
    * not, the preferred Dart idiom is to set animation frames by calling
@@ -26311,9 +26063,9 @@
   @SupportedBrowser(SupportedBrowser.CHROME)
   @SupportedBrowser(SupportedBrowser.SAFARI)
   @Experimental
-  @Creates('Database')
-  @Creates('DatabaseSync')
-  Database openDatabase(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native;
+  @Creates('SqlDatabase')
+  @Creates('SqlDatabaseSync')
+  SqlDatabase openDatabase(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native;
 
   @DomName('DOMWindow.postMessage')
   @DocsEditable
@@ -26752,14 +26504,14 @@
   @SupportedBrowser(SupportedBrowser.CHROME)
   @SupportedBrowser(SupportedBrowser.SAFARI)
   @Experimental
-  Database openDatabase(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native;
+  SqlDatabase openDatabase(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native;
 
   @DomName('WorkerContext.openDatabaseSync')
   @DocsEditable
   @SupportedBrowser(SupportedBrowser.CHROME)
   @SupportedBrowser(SupportedBrowser.SAFARI)
   @Experimental
-  DatabaseSync openDatabaseSync(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native;
+  SqlDatabaseSync openDatabaseSync(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native;
 
   @JSName('removeEventListener')
   @DomName('WorkerContext.removeEventListener')
@@ -28370,203 +28122,6 @@
 
 
 @DocsEditable
-@DomName('MediaStreamList')
-class _MediaStreamList implements JavaScriptIndexingBehavior, List<MediaStream> native "*MediaStreamList" {
-
-  @DomName('MediaStreamList.length')
-  @DocsEditable
-  int get length => JS("int", "#.length", this);
-
-  MediaStream operator[](int index) => JS("MediaStream", "#[#]", this, index);
-
-  void operator[]=(int index, MediaStream value) {
-    throw new UnsupportedError("Cannot assign element of immutable List.");
-  }
-  // -- start List<MediaStream> mixins.
-  // MediaStream is the element type.
-
-  // From Iterable<MediaStream>:
-
-  Iterator<MediaStream> get iterator {
-    // Note: NodeLists are not fixed size. And most probably length shouldn't
-    // be cached in both iterator _and_ forEach method. For now caching it
-    // for consistency.
-    return new FixedSizeListIterator<MediaStream>(this);
-  }
-
-  dynamic reduce(dynamic initialValue, dynamic combine(dynamic, MediaStream)) {
-    return IterableMixinWorkaround.reduce(this, initialValue, combine);
-  }
-
-  bool contains(MediaStream element) => IterableMixinWorkaround.contains(this, element);
-
-  void forEach(void f(MediaStream element)) => IterableMixinWorkaround.forEach(this, f);
-
-  String join([String separator]) =>
-      IterableMixinWorkaround.joinList(this, separator);
-
-  Iterable map(f(MediaStream element)) =>
-      IterableMixinWorkaround.mapList(this, f);
-
-  Iterable<MediaStream> where(bool f(MediaStream element)) =>
-      IterableMixinWorkaround.where(this, f);
-
-  Iterable expand(Iterable f(MediaStream element)) =>
-      IterableMixinWorkaround.expand(this, f);
-
-  bool every(bool f(MediaStream element)) => IterableMixinWorkaround.every(this, f);
-
-  bool any(bool f(MediaStream element)) => IterableMixinWorkaround.any(this, f);
-
-  List<MediaStream> toList() => new List<MediaStream>.from(this);
-  Set<MediaStream> toSet() => new Set<MediaStream>.from(this);
-
-  bool get isEmpty => this.length == 0;
-
-  Iterable<MediaStream> take(int n) => IterableMixinWorkaround.takeList(this, n);
-
-  Iterable<MediaStream> takeWhile(bool test(MediaStream value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
-  }
-
-  Iterable<MediaStream> skip(int n) => IterableMixinWorkaround.skipList(this, n);
-
-  Iterable<MediaStream> skipWhile(bool test(MediaStream value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
-  }
-
-  MediaStream firstMatching(bool test(MediaStream value), { MediaStream orElse() }) {
-    return IterableMixinWorkaround.firstMatching(this, test, orElse);
-  }
-
-  MediaStream lastMatching(bool test(MediaStream value), {MediaStream orElse()}) {
-    return IterableMixinWorkaround.lastMatchingInList(this, test, orElse);
-  }
-
-  MediaStream singleMatching(bool test(MediaStream value)) {
-    return IterableMixinWorkaround.singleMatching(this, test);
-  }
-
-  MediaStream elementAt(int index) {
-    return this[index];
-  }
-
-  // From Collection<MediaStream>:
-
-  void add(MediaStream value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addLast(MediaStream value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addAll(Iterable<MediaStream> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  // From List<MediaStream>:
-  void set length(int value) {
-    throw new UnsupportedError("Cannot resize immutable List.");
-  }
-
-  void clear() {
-    throw new UnsupportedError("Cannot clear immutable List.");
-  }
-
-  Iterable<MediaStream> get reversed {
-    return IterableMixinWorkaround.reversedList(this);
-  }
-
-  void sort([int compare(MediaStream a, MediaStream b)]) {
-    throw new UnsupportedError("Cannot sort immutable List.");
-  }
-
-  int indexOf(MediaStream element, [int start = 0]) =>
-      Lists.indexOf(this, element, start, this.length);
-
-  int lastIndexOf(MediaStream element, [int start]) {
-    if (start == null) start = length - 1;
-    return Lists.lastIndexOf(this, element, start);
-  }
-
-  MediaStream get first {
-    if (this.length > 0) return this[0];
-    throw new StateError("No elements");
-  }
-
-  MediaStream get last {
-    if (this.length > 0) return this[this.length - 1];
-    throw new StateError("No elements");
-  }
-
-  MediaStream get single {
-    if (length == 1) return this[0];
-    if (length == 0) throw new StateError("No elements");
-    throw new StateError("More than one element");
-  }
-
-  MediaStream min([int compare(MediaStream a, MediaStream b)]) =>
-      IterableMixinWorkaround.min(this, compare);
-
-  MediaStream max([int compare(MediaStream a, MediaStream b)]) =>
-      IterableMixinWorkaround.max(this, compare);
-
-  MediaStream removeAt(int pos) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  MediaStream removeLast() {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void remove(Object object) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeAll(Iterable elements) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainAll(Iterable elements) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeMatching(bool test(MediaStream element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainMatching(bool test(MediaStream element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void setRange(int start, int rangeLength, List<MediaStream> from, [int startFrom]) {
-    throw new UnsupportedError("Cannot setRange on immutable List.");
-  }
-
-  void removeRange(int start, int rangeLength) {
-    throw new UnsupportedError("Cannot removeRange on immutable List.");
-  }
-
-  void insertRange(int start, int rangeLength, [MediaStream initialValue]) {
-    throw new UnsupportedError("Cannot insertRange on immutable List.");
-  }
-
-  List<MediaStream> getRange(int start, int rangeLength) =>
-      Lists.getRange(this, start, rangeLength, <MediaStream>[]);
-
-  // -- end List<MediaStream> mixins.
-
-  @DomName('MediaStreamList.item')
-  @DocsEditable
-  MediaStream item(int index) native;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
 @DomName('NamedNodeMap')
 class _NamedNodeMap implements JavaScriptIndexingBehavior, List<Node> native "*NamedNodeMap" {
 
@@ -30538,9 +30093,9 @@
 
 
 /**
- * Defines the keycode values for keys that are returned by 
+ * Defines the keycode values for keys that are returned by
  * KeyboardEvent.keyCode.
- * 
+ *
  * Important note: There is substantial divergence in how different browsers
  * handle keycodes and their variants in different locales/keyboard layouts. We
  * provide these constants to help make code processing keys more readable.
@@ -30548,7 +30103,7 @@
 abstract class KeyCode {
   // These constant names were borrowed from Closure's Keycode enumeration
   // class.
-  // http://closure-library.googlecode.com/svn/docs/closure_goog_events_keycodes.js.source.html  
+  // http://closure-library.googlecode.com/svn/docs/closure_goog_events_keycodes.js.source.html
   static const int WIN_KEY_FF_LINUX = 0;
   static const int MAC_ENTER = 3;
   static const int BACKSPACE = 8;
@@ -30743,12 +30298,12 @@
         (keyCode >= A && keyCode <= Z)) {
       return true;
     }
- 
+
     // Safari sends zero key code for non-latin characters.
     if (_Device.isWebKit && keyCode == 0) {
       return true;
     }
- 
+
     return (keyCode == SPACE || keyCode == QUESTION_MARK || keyCode == NUM_PLUS
         || keyCode == NUM_MINUS || keyCode == NUM_PERIOD ||
         keyCode == NUM_DIVISION || keyCode == SEMICOLON ||
@@ -32536,7 +32091,7 @@
   final int _length;  // Cache array length for faster access.
   int _position;
   T _current;
-  
+
   FixedSizeListIterator(List<T> array)
       : _array = array,
         _position = -1,
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 017bfb3..0dc02f2 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -7,6 +7,7 @@
 import 'dart:isolate';
 import 'dart:json' as json;
 import 'dart:nativewrappers';
+import 'dart:web_sql';
 import 'dart:svg' as svg;
 import 'dart:web_audio' as web_audio;
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -2762,6 +2763,8 @@
 
   static const int CSS_VH = 27;
 
+  static const int CSS_VMAX = 29;
+
   static const int CSS_VMIN = 28;
 
   static const int CSS_VW = 26;
@@ -6746,85 +6749,6 @@
 
 
 @DocsEditable
-@DomName('Database')
-@SupportedBrowser(SupportedBrowser.CHROME)
-@SupportedBrowser(SupportedBrowser.SAFARI)
-@Experimental
-class Database extends NativeFieldWrapperClass1 {
-  Database.internal();
-
-  /// Checks if this type is supported on the current platform.
-  static bool get supported => true;
-
-  @DomName('Database.version')
-  @DocsEditable
-  String get version native "Database_version_Getter";
-
-  @DomName('Database.changeVersion')
-  @DocsEditable
-  void changeVersion(String oldVersion, String newVersion, [SqlTransactionCallback callback, SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native "Database_changeVersion_Callback";
-
-  @DomName('Database.readTransaction')
-  @DocsEditable
-  void readTransaction(SqlTransactionCallback callback, [SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native "Database_readTransaction_Callback";
-
-  @DomName('Database.transaction')
-  @DocsEditable
-  void transaction(SqlTransactionCallback callback, [SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native "Database_transaction_Callback";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-typedef void DatabaseCallback(database);
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
-@DomName('DatabaseSync')
-@SupportedBrowser(SupportedBrowser.CHROME)
-@SupportedBrowser(SupportedBrowser.SAFARI)
-@Experimental
-class DatabaseSync extends NativeFieldWrapperClass1 {
-  DatabaseSync.internal();
-
-  @DomName('DatabaseSync.lastErrorMessage')
-  @DocsEditable
-  String get lastErrorMessage native "DatabaseSync_lastErrorMessage_Getter";
-
-  @DomName('DatabaseSync.version')
-  @DocsEditable
-  String get version native "DatabaseSync_version_Getter";
-
-  @DomName('DatabaseSync.changeVersion')
-  @DocsEditable
-  void changeVersion(String oldVersion, String newVersion, [SqlTransactionSyncCallback callback]) native "DatabaseSync_changeVersion_Callback";
-
-  @DomName('DatabaseSync.readTransaction')
-  @DocsEditable
-  void readTransaction(SqlTransactionSyncCallback callback) native "DatabaseSync_readTransaction_Callback";
-
-  @DomName('DatabaseSync.transaction')
-  @DocsEditable
-  void transaction(SqlTransactionSyncCallback callback) native "DatabaseSync_transaction_Callback";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
 @DomName('DedicatedWorkerContext')
 class DedicatedWorkerContext extends WorkerContext {
   DedicatedWorkerContext.internal() : super.internal();
@@ -9263,7 +9187,7 @@
   _ElementCssClassSet(this._element);
 
   Set<String> readClasses() {
-    var s = new Set<String>();
+    var s = new LinkedHashSet<String>();
     var classname = _element.$dom_className;
 
     for (String name in classname.split(' ')) {
@@ -12402,6 +12326,23 @@
 
 
 @DocsEditable
+@DomName('FocusEvent')
+class FocusEvent extends UIEvent {
+  FocusEvent.internal() : super.internal();
+
+  @DomName('FocusEvent.relatedTarget')
+  @DocsEditable
+  EventTarget get relatedTarget native "FocusEvent_relatedTarget_Getter";
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
 @DomName('FormData')
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.FIREFOX)
@@ -12564,27 +12505,104 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// WARNING: Do not edit - generated code.
-
 
 @DocsEditable
 @DomName('Geolocation')
 class Geolocation extends NativeFieldWrapperClass1 {
+
+  @DomName('Geolocation.getCurrentPosition')
+  Future<Geoposition> getCurrentPosition({bool enableHighAccuracy,
+      Duration timeout, Duration maximumAge}) {
+    var options = {};
+    if (enableHighAccuracy != null) {
+      options['enableHighAccuracy'] = enableHighAccuracy;
+    }
+    if (timeout != null) {
+      options['timeout'] = timeout.inMilliseconds;
+    }
+    if (maximumAge != null) {
+      options['maximumAge'] = maximumAge.inMilliseconds;
+    }
+    var completer = new Completer<Geoposition>();
+    try {
+      $dom_getCurrentPosition(
+          (position) {
+            completer.complete(_ensurePosition(position));
+          },
+          (error) {
+            completer.completeError(error);
+          },
+          options);
+    } catch (e, stacktrace) {
+      completer.completeError(e, stacktrace);
+    }
+    return completer.future;
+  }
+
+  @DomName('Geolocation.watchPosition')
+  Stream<Geoposition> watchPosition({bool enableHighAccuracy,
+      Duration timeout, Duration maximumAge}) {
+
+    var options = {};
+    if (enableHighAccuracy != null) {
+      options['enableHighAccuracy'] = enableHighAccuracy;
+    }
+    if (timeout != null) {
+      options['timeout'] = timeout.inMilliseconds;
+    }
+    if (maximumAge != null) {
+      options['maximumAge'] = maximumAge.inMilliseconds;
+    }
+
+    int watchId;
+    var controller;
+    controller = new StreamController<Geoposition>(
+      onSubscriptionStateChange: () {
+        if (controller.hasSubscribers) {
+          assert(watchId == null);
+          watchId = $dom_watchPosition(
+              (position) {
+                controller.add(_ensurePosition(position));
+              },
+              (error) {
+                controller.signalError(error);
+              },
+              options);
+        } else {
+          assert(watchId != null);
+          $dom_clearWatch(watchId);
+        }
+      });
+
+    return controller.stream;
+  }
+
+  Geoposition _ensurePosition(domPosition) {
+    try {
+      // Firefox may throw on this.
+      if (domPosition is Geoposition) {
+        return domPosition;
+      }
+    } catch(e) {}
+    return new _GeopositionWrapper(domPosition);
+  }
   Geolocation.internal();
 
   @DomName('Geolocation.clearWatch')
   @DocsEditable
-  void clearWatch(int watchId) native "Geolocation_clearWatch_Callback";
+  void $dom_clearWatch(int watchId) native "Geolocation_clearWatch_Callback";
 
   @DomName('Geolocation.getCurrentPosition')
   @DocsEditable
-  void getCurrentPosition(PositionCallback successCallback, [PositionErrorCallback errorCallback, Object options]) native "Geolocation_getCurrentPosition_Callback";
+  void $dom_getCurrentPosition(_PositionCallback successCallback, [_PositionErrorCallback errorCallback, Object options]) native "Geolocation_getCurrentPosition_Callback";
 
   @DomName('Geolocation.watchPosition')
   @DocsEditable
-  int watchPosition(PositionCallback successCallback, [PositionErrorCallback errorCallback, Object options]) native "Geolocation_watchPosition_Callback";
-
+  int $dom_watchPosition(_PositionCallback successCallback, [_PositionErrorCallback errorCallback, Object options]) native "Geolocation_watchPosition_Callback";
 }
+
+
+
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -16092,6 +16110,10 @@
   @DocsEditable
   int scopeType(int scopeIndex) native "JavaScriptCallFrame_scopeType_Callback";
 
+  @DomName('JavaScriptCallFrame.setVariableValue')
+  @DocsEditable
+  Object setVariableValue(int scopeIndex, String variableName, Object newValue) native "JavaScriptCallFrame_setVariableValue_Callback";
+
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -20081,7 +20103,7 @@
 // WARNING: Do not edit - generated code.
 
 
-typedef void PositionCallback(Geoposition position);
+typedef void _PositionCallback(Geoposition position);
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -20116,7 +20138,7 @@
 // WARNING: Do not edit - generated code.
 
 
-typedef void PositionErrorCallback(PositionError error);
+typedef void _PositionErrorCallback(PositionError error);
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -20820,10 +20842,6 @@
   @DocsEditable
   RtcSessionDescription get localDescription native "RTCPeerConnection_localDescription_Getter";
 
-  @DomName('RTCPeerConnection.localStreams')
-  @DocsEditable
-  List<MediaStream> get localStreams native "RTCPeerConnection_localStreams_Getter";
-
   @DomName('RTCPeerConnection.readyState')
   @DocsEditable
   String get readyState native "RTCPeerConnection_readyState_Getter";
@@ -20832,10 +20850,6 @@
   @DocsEditable
   RtcSessionDescription get remoteDescription native "RTCPeerConnection_remoteDescription_Getter";
 
-  @DomName('RTCPeerConnection.remoteStreams')
-  @DocsEditable
-  List<MediaStream> get remoteStreams native "RTCPeerConnection_remoteStreams_Getter";
-
   @DomName('RTCPeerConnection.signalingState')
   @DocsEditable
   String get signalingState native "RTCPeerConnection_signalingState_Getter";
@@ -20860,6 +20874,10 @@
   @DocsEditable
   void createAnswer(RtcSessionDescriptionCallback successCallback, [RtcErrorCallback failureCallback, Map mediaConstraints]) native "RTCPeerConnection_createAnswer_Callback";
 
+  @DomName('RTCPeerConnection.createDTMFSender')
+  @DocsEditable
+  RtcdtmfSender createDtmfSender(MediaStreamTrack track) native "RTCPeerConnection_createDTMFSender_Callback";
+
   @DomName('RTCPeerConnection.createDataChannel')
   @DocsEditable
   RtcDataChannel createDataChannel(String label, [Map options]) native "RTCPeerConnection_createDataChannel_Callback";
@@ -20872,6 +20890,14 @@
   @DocsEditable
   bool dispatchEvent(Event event) native "RTCPeerConnection_dispatchEvent_Callback";
 
+  @DomName('RTCPeerConnection.getLocalStreams')
+  @DocsEditable
+  List<MediaStream> getLocalStreams() native "RTCPeerConnection_getLocalStreams_Callback";
+
+  @DomName('RTCPeerConnection.getRemoteStreams')
+  @DocsEditable
+  List<MediaStream> getRemoteStreams() native "RTCPeerConnection_getRemoteStreams_Callback";
+
   @DomName('RTCPeerConnection.getStats')
   @DocsEditable
   void getStats(RtcStatsCallback successCallback, MediaStreamTrack selector) native "RTCPeerConnection_getStats_Callback";
@@ -21041,7 +21067,69 @@
 // WARNING: Do not edit - generated code.
 
 
-typedef void SqlStatementCallback(SqlTransaction transaction, SqlResultSet resultSet);
+@DocsEditable
+@DomName('RTCDTMFSender')
+class RtcdtmfSender extends EventTarget {
+  RtcdtmfSender.internal() : super.internal();
+
+  @DomName('RTCDTMFSender.canInsertDTMF')
+  @DocsEditable
+  bool get canInsertDtmf native "RTCDTMFSender_canInsertDTMF_Getter";
+
+  @DomName('RTCDTMFSender.duration')
+  @DocsEditable
+  int get duration native "RTCDTMFSender_duration_Getter";
+
+  @DomName('RTCDTMFSender.interToneGap')
+  @DocsEditable
+  int get interToneGap native "RTCDTMFSender_interToneGap_Getter";
+
+  @DomName('RTCDTMFSender.toneBuffer')
+  @DocsEditable
+  String get toneBuffer native "RTCDTMFSender_toneBuffer_Getter";
+
+  @DomName('RTCDTMFSender.track')
+  @DocsEditable
+  MediaStreamTrack get track native "RTCDTMFSender_track_Getter";
+
+  @DomName('RTCDTMFSender.addEventListener')
+  @DocsEditable
+  void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native "RTCDTMFSender_addEventListener_Callback";
+
+  @DomName('RTCDTMFSender.dispatchEvent')
+  @DocsEditable
+  bool dispatchEvent(Event event) native "RTCDTMFSender_dispatchEvent_Callback";
+
+  void insertDtmf(String tones, [int duration, int interToneGap]) {
+    if (?interToneGap) {
+      _insertDTMF_1(tones, duration, interToneGap);
+      return;
+    }
+    if (?duration) {
+      _insertDTMF_2(tones, duration);
+      return;
+    }
+    _insertDTMF_3(tones);
+    return;
+  }
+
+  @DomName('RTCDTMFSender._insertDTMF_1')
+  @DocsEditable
+  void _insertDTMF_1(tones, duration, interToneGap) native "RTCDTMFSender__insertDTMF_1_Callback";
+
+  @DomName('RTCDTMFSender._insertDTMF_2')
+  @DocsEditable
+  void _insertDTMF_2(tones, duration) native "RTCDTMFSender__insertDTMF_2_Callback";
+
+  @DomName('RTCDTMFSender._insertDTMF_3')
+  @DocsEditable
+  void _insertDTMF_3(tones) native "RTCDTMFSender__insertDTMF_3_Callback";
+
+  @DomName('RTCDTMFSender.removeEventListener')
+  @DocsEditable
+  void $dom_removeEventListener(String type, EventListener listener, [bool useCapture]) native "RTCDTMFSender_removeEventListener_Callback";
+
+}
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -21049,31 +21137,16 @@
 // WARNING: Do not edit - generated code.
 
 
-typedef void SqlStatementErrorCallback(SqlTransaction transaction, SqlError error);
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
+@DocsEditable
+@DomName('RTCDTMFToneChangeEvent')
+class RtcdtmfToneChangeEvent extends Event {
+  RtcdtmfToneChangeEvent.internal() : super.internal();
 
-// WARNING: Do not edit - generated code.
+  @DomName('RTCDTMFToneChangeEvent.tone')
+  @DocsEditable
+  String get tone native "RTCDTMFToneChangeEvent_tone_Getter";
 
-
-typedef void SqlTransactionCallback(SqlTransaction transaction);
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-typedef void SqlTransactionErrorCallback(SqlError error);
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-typedef void SqlTransactionSyncCallback(SqlTransactionSync transaction);
+}
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -22480,346 +22553,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
-@DomName('SQLError')
-class SqlError extends NativeFieldWrapperClass1 {
-  SqlError.internal();
-
-  static const int CONSTRAINT_ERR = 6;
-
-  static const int DATABASE_ERR = 1;
-
-  static const int QUOTA_ERR = 4;
-
-  static const int SYNTAX_ERR = 5;
-
-  static const int TIMEOUT_ERR = 7;
-
-  static const int TOO_LARGE_ERR = 3;
-
-  static const int UNKNOWN_ERR = 0;
-
-  static const int VERSION_ERR = 2;
-
-  @DomName('SQLError.code')
-  @DocsEditable
-  int get code native "SQLError_code_Getter";
-
-  @DomName('SQLError.message')
-  @DocsEditable
-  String get message native "SQLError_message_Getter";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
-@DomName('SQLException')
-class SqlException extends NativeFieldWrapperClass1 {
-  SqlException.internal();
-
-  static const int CONSTRAINT_ERR = 6;
-
-  static const int DATABASE_ERR = 1;
-
-  static const int QUOTA_ERR = 4;
-
-  static const int SYNTAX_ERR = 5;
-
-  static const int TIMEOUT_ERR = 7;
-
-  static const int TOO_LARGE_ERR = 3;
-
-  static const int UNKNOWN_ERR = 0;
-
-  static const int VERSION_ERR = 2;
-
-  @DomName('SQLException.code')
-  @DocsEditable
-  int get code native "SQLException_code_Getter";
-
-  @DomName('SQLException.message')
-  @DocsEditable
-  String get message native "SQLException_message_Getter";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
-@DomName('SQLResultSet')
-class SqlResultSet extends NativeFieldWrapperClass1 {
-  SqlResultSet.internal();
-
-  @DomName('SQLResultSet.insertId')
-  @DocsEditable
-  int get insertId native "SQLResultSet_insertId_Getter";
-
-  @DomName('SQLResultSet.rows')
-  @DocsEditable
-  SqlResultSetRowList get rows native "SQLResultSet_rows_Getter";
-
-  @DomName('SQLResultSet.rowsAffected')
-  @DocsEditable
-  int get rowsAffected native "SQLResultSet_rowsAffected_Getter";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
-@DomName('SQLResultSetRowList')
-class SqlResultSetRowList extends NativeFieldWrapperClass1 implements List<Map> {
-  SqlResultSetRowList.internal();
-
-  @DomName('SQLResultSetRowList.length')
-  @DocsEditable
-  int get length native "SQLResultSetRowList_length_Getter";
-
-  Map operator[](int index) native "SQLResultSetRowList_item_Callback";
-
-  void operator[]=(int index, Map value) {
-    throw new UnsupportedError("Cannot assign element of immutable List.");
-  }
-  // -- start List<Map> mixins.
-  // Map is the element type.
-
-  // From Iterable<Map>:
-
-  Iterator<Map> get iterator {
-    // Note: NodeLists are not fixed size. And most probably length shouldn't
-    // be cached in both iterator _and_ forEach method. For now caching it
-    // for consistency.
-    return new FixedSizeListIterator<Map>(this);
-  }
-
-  dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Map)) {
-    return IterableMixinWorkaround.reduce(this, initialValue, combine);
-  }
-
-  bool contains(Map element) => IterableMixinWorkaround.contains(this, element);
-
-  void forEach(void f(Map element)) => IterableMixinWorkaround.forEach(this, f);
-
-  String join([String separator]) =>
-      IterableMixinWorkaround.joinList(this, separator);
-
-  Iterable map(f(Map element)) =>
-      IterableMixinWorkaround.mapList(this, f);
-
-  Iterable<Map> where(bool f(Map element)) =>
-      IterableMixinWorkaround.where(this, f);
-
-  Iterable expand(Iterable f(Map element)) =>
-      IterableMixinWorkaround.expand(this, f);
-
-  bool every(bool f(Map element)) => IterableMixinWorkaround.every(this, f);
-
-  bool any(bool f(Map element)) => IterableMixinWorkaround.any(this, f);
-
-  List<Map> toList() => new List<Map>.from(this);
-  Set<Map> toSet() => new Set<Map>.from(this);
-
-  bool get isEmpty => this.length == 0;
-
-  Iterable<Map> take(int n) => IterableMixinWorkaround.takeList(this, n);
-
-  Iterable<Map> takeWhile(bool test(Map value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
-  }
-
-  Iterable<Map> skip(int n) => IterableMixinWorkaround.skipList(this, n);
-
-  Iterable<Map> skipWhile(bool test(Map value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
-  }
-
-  Map firstMatching(bool test(Map value), { Map orElse() }) {
-    return IterableMixinWorkaround.firstMatching(this, test, orElse);
-  }
-
-  Map lastMatching(bool test(Map value), {Map orElse()}) {
-    return IterableMixinWorkaround.lastMatchingInList(this, test, orElse);
-  }
-
-  Map singleMatching(bool test(Map value)) {
-    return IterableMixinWorkaround.singleMatching(this, test);
-  }
-
-  Map elementAt(int index) {
-    return this[index];
-  }
-
-  // From Collection<Map>:
-
-  void add(Map value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addLast(Map value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addAll(Iterable<Map> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  // From List<Map>:
-  void set length(int value) {
-    throw new UnsupportedError("Cannot resize immutable List.");
-  }
-
-  void clear() {
-    throw new UnsupportedError("Cannot clear immutable List.");
-  }
-
-  Iterable<Map> get reversed {
-    return IterableMixinWorkaround.reversedList(this);
-  }
-
-  void sort([int compare(Map a, Map b)]) {
-    throw new UnsupportedError("Cannot sort immutable List.");
-  }
-
-  int indexOf(Map element, [int start = 0]) =>
-      Lists.indexOf(this, element, start, this.length);
-
-  int lastIndexOf(Map element, [int start]) {
-    if (start == null) start = length - 1;
-    return Lists.lastIndexOf(this, element, start);
-  }
-
-  Map get first {
-    if (this.length > 0) return this[0];
-    throw new StateError("No elements");
-  }
-
-  Map get last {
-    if (this.length > 0) return this[this.length - 1];
-    throw new StateError("No elements");
-  }
-
-  Map get single {
-    if (length == 1) return this[0];
-    if (length == 0) throw new StateError("No elements");
-    throw new StateError("More than one element");
-  }
-
-  Map min([int compare(Map a, Map b)]) =>
-      IterableMixinWorkaround.min(this, compare);
-
-  Map max([int compare(Map a, Map b)]) =>
-      IterableMixinWorkaround.max(this, compare);
-
-  Map removeAt(int pos) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  Map removeLast() {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void remove(Object object) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeAll(Iterable elements) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainAll(Iterable elements) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeMatching(bool test(Map element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainMatching(bool test(Map element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void setRange(int start, int rangeLength, List<Map> from, [int startFrom]) {
-    throw new UnsupportedError("Cannot setRange on immutable List.");
-  }
-
-  void removeRange(int start, int rangeLength) {
-    throw new UnsupportedError("Cannot removeRange on immutable List.");
-  }
-
-  void insertRange(int start, int rangeLength, [Map initialValue]) {
-    throw new UnsupportedError("Cannot insertRange on immutable List.");
-  }
-
-  List<Map> getRange(int start, int rangeLength) =>
-      Lists.getRange(this, start, rangeLength, <Map>[]);
-
-  // -- end List<Map> mixins.
-
-  @DomName('SQLResultSetRowList.item')
-  @DocsEditable
-  Map item(int index) native "SQLResultSetRowList_item_Callback";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
-@DomName('SQLTransaction')
-@SupportedBrowser(SupportedBrowser.CHROME)
-@SupportedBrowser(SupportedBrowser.SAFARI)
-@Experimental
-class SqlTransaction extends NativeFieldWrapperClass1 {
-  SqlTransaction.internal();
-
-  @DomName('SQLTransaction.executeSql')
-  @DocsEditable
-  void executeSql(String sqlStatement, List arguments, [SqlStatementCallback callback, SqlStatementErrorCallback errorCallback]) native "SQLTransaction_executeSql_Callback";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
-@DomName('SQLTransactionSync')
-@SupportedBrowser(SupportedBrowser.CHROME)
-@SupportedBrowser(SupportedBrowser.SAFARI)
-@Experimental
-class SqlTransactionSync extends NativeFieldWrapperClass1 {
-  SqlTransactionSync.internal();
-
-  @DomName('SQLTransactionSync.executeSql')
-  @DocsEditable
-  SqlResultSet executeSql(String sqlStatement, List arguments) native "SQLTransactionSync_executeSql_Callback";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
 
 /**
  * The type used by the
@@ -28106,6 +27839,16 @@
 
   WheelEvent.internal() : super.internal();
 
+  static const int DOM_DELTA_LINE = 0x01;
+
+  static const int DOM_DELTA_PAGE = 0x02;
+
+  static const int DOM_DELTA_PIXEL = 0x00;
+
+  @DomName('WheelEvent.deltaMode')
+  @DocsEditable
+  int get deltaMode native "WheelEvent_deltaMode_Getter";
+
   @DomName('WheelEvent.webkitDirectionInvertedFromDevice')
   @DocsEditable
   @SupportedBrowser(SupportedBrowser.CHROME)
@@ -28130,9 +27873,6 @@
   num get deltaX => $dom_wheelDeltaX;
   @DomName('WheelEvent.deltaY')
   num get deltaY => $dom_wheelDeltaY;
-  @DomName('WheelEvent.deltaMode')
-  int get deltaMode => 0;
-
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -28585,7 +28325,7 @@
   @SupportedBrowser(SupportedBrowser.CHROME)
   @SupportedBrowser(SupportedBrowser.SAFARI)
   @Experimental
-  Database openDatabase(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native "DOMWindow_openDatabase_Callback";
+  SqlDatabase openDatabase(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native "DOMWindow_openDatabase_Callback";
 
   @DomName('DOMWindow.postMessage')
   @DocsEditable
@@ -29000,14 +28740,14 @@
   @SupportedBrowser(SupportedBrowser.CHROME)
   @SupportedBrowser(SupportedBrowser.SAFARI)
   @Experimental
-  Database openDatabase(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native "WorkerContext_openDatabase_Callback";
+  SqlDatabase openDatabase(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native "WorkerContext_openDatabase_Callback";
 
   @DomName('WorkerContext.openDatabaseSync')
   @DocsEditable
   @SupportedBrowser(SupportedBrowser.CHROME)
   @SupportedBrowser(SupportedBrowser.SAFARI)
   @Experimental
-  DatabaseSync openDatabaseSync(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native "WorkerContext_openDatabaseSync_Callback";
+  SqlDatabaseSync openDatabaseSync(String name, String version, String displayName, int estimatedSize, [DatabaseCallback creationCallback]) native "WorkerContext_openDatabaseSync_Callback";
 
   @DomName('WorkerContext.removeEventListener')
   @DocsEditable
@@ -30836,207 +30576,6 @@
 
 
 @DocsEditable
-@DomName('MediaStreamList')
-class _MediaStreamList extends NativeFieldWrapperClass1 implements List<MediaStream> {
-  _MediaStreamList.internal();
-
-  @DomName('MediaStreamList.length')
-  @DocsEditable
-  int get length native "MediaStreamList_length_Getter";
-
-  MediaStream operator[](int index) native "MediaStreamList_item_Callback";
-
-  void operator[]=(int index, MediaStream value) {
-    throw new UnsupportedError("Cannot assign element of immutable List.");
-  }
-  // -- start List<MediaStream> mixins.
-  // MediaStream is the element type.
-
-  // From Iterable<MediaStream>:
-
-  Iterator<MediaStream> get iterator {
-    // Note: NodeLists are not fixed size. And most probably length shouldn't
-    // be cached in both iterator _and_ forEach method. For now caching it
-    // for consistency.
-    return new FixedSizeListIterator<MediaStream>(this);
-  }
-
-  dynamic reduce(dynamic initialValue, dynamic combine(dynamic, MediaStream)) {
-    return IterableMixinWorkaround.reduce(this, initialValue, combine);
-  }
-
-  bool contains(MediaStream element) => IterableMixinWorkaround.contains(this, element);
-
-  void forEach(void f(MediaStream element)) => IterableMixinWorkaround.forEach(this, f);
-
-  String join([String separator]) =>
-      IterableMixinWorkaround.joinList(this, separator);
-
-  Iterable map(f(MediaStream element)) =>
-      IterableMixinWorkaround.mapList(this, f);
-
-  Iterable<MediaStream> where(bool f(MediaStream element)) =>
-      IterableMixinWorkaround.where(this, f);
-
-  Iterable expand(Iterable f(MediaStream element)) =>
-      IterableMixinWorkaround.expand(this, f);
-
-  bool every(bool f(MediaStream element)) => IterableMixinWorkaround.every(this, f);
-
-  bool any(bool f(MediaStream element)) => IterableMixinWorkaround.any(this, f);
-
-  List<MediaStream> toList() => new List<MediaStream>.from(this);
-  Set<MediaStream> toSet() => new Set<MediaStream>.from(this);
-
-  bool get isEmpty => this.length == 0;
-
-  Iterable<MediaStream> take(int n) => IterableMixinWorkaround.takeList(this, n);
-
-  Iterable<MediaStream> takeWhile(bool test(MediaStream value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
-  }
-
-  Iterable<MediaStream> skip(int n) => IterableMixinWorkaround.skipList(this, n);
-
-  Iterable<MediaStream> skipWhile(bool test(MediaStream value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
-  }
-
-  MediaStream firstMatching(bool test(MediaStream value), { MediaStream orElse() }) {
-    return IterableMixinWorkaround.firstMatching(this, test, orElse);
-  }
-
-  MediaStream lastMatching(bool test(MediaStream value), {MediaStream orElse()}) {
-    return IterableMixinWorkaround.lastMatchingInList(this, test, orElse);
-  }
-
-  MediaStream singleMatching(bool test(MediaStream value)) {
-    return IterableMixinWorkaround.singleMatching(this, test);
-  }
-
-  MediaStream elementAt(int index) {
-    return this[index];
-  }
-
-  // From Collection<MediaStream>:
-
-  void add(MediaStream value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addLast(MediaStream value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addAll(Iterable<MediaStream> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  // From List<MediaStream>:
-  void set length(int value) {
-    throw new UnsupportedError("Cannot resize immutable List.");
-  }
-
-  void clear() {
-    throw new UnsupportedError("Cannot clear immutable List.");
-  }
-
-  Iterable<MediaStream> get reversed {
-    return IterableMixinWorkaround.reversedList(this);
-  }
-
-  void sort([int compare(MediaStream a, MediaStream b)]) {
-    throw new UnsupportedError("Cannot sort immutable List.");
-  }
-
-  int indexOf(MediaStream element, [int start = 0]) =>
-      Lists.indexOf(this, element, start, this.length);
-
-  int lastIndexOf(MediaStream element, [int start]) {
-    if (start == null) start = length - 1;
-    return Lists.lastIndexOf(this, element, start);
-  }
-
-  MediaStream get first {
-    if (this.length > 0) return this[0];
-    throw new StateError("No elements");
-  }
-
-  MediaStream get last {
-    if (this.length > 0) return this[this.length - 1];
-    throw new StateError("No elements");
-  }
-
-  MediaStream get single {
-    if (length == 1) return this[0];
-    if (length == 0) throw new StateError("No elements");
-    throw new StateError("More than one element");
-  }
-
-  MediaStream min([int compare(MediaStream a, MediaStream b)]) =>
-      IterableMixinWorkaround.min(this, compare);
-
-  MediaStream max([int compare(MediaStream a, MediaStream b)]) =>
-      IterableMixinWorkaround.max(this, compare);
-
-  MediaStream removeAt(int pos) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  MediaStream removeLast() {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void remove(Object object) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeAll(Iterable elements) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainAll(Iterable elements) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeMatching(bool test(MediaStream element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainMatching(bool test(MediaStream element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void setRange(int start, int rangeLength, List<MediaStream> from, [int startFrom]) {
-    throw new UnsupportedError("Cannot setRange on immutable List.");
-  }
-
-  void removeRange(int start, int rangeLength) {
-    throw new UnsupportedError("Cannot removeRange on immutable List.");
-  }
-
-  void insertRange(int start, int rangeLength, [MediaStream initialValue]) {
-    throw new UnsupportedError("Cannot insertRange on immutable List.");
-  }
-
-  List<MediaStream> getRange(int start, int rangeLength) =>
-      Lists.getRange(this, start, rangeLength, <MediaStream>[]);
-
-  // -- end List<MediaStream> mixins.
-
-  @DomName('MediaStreamList.item')
-  @DocsEditable
-  MediaStream item(int index) native "MediaStreamList_item_Callback";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
 @DomName('NamedNodeMap')
 class _NamedNodeMap extends NativeFieldWrapperClass1 implements List<Node> {
   _NamedNodeMap.internal();
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index 76547dd..9180c8a 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -9,7 +9,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// DO NOT EDIT
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:svg library.
 
 
diff --git a/sdk/lib/io/chunked_stream.dart b/sdk/lib/io/chunked_stream.dart
deleted file mode 100644
index 07fd9b4..0000000
--- a/sdk/lib/io/chunked_stream.dart
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.io;
-
-class _ChunkedInputStream implements ChunkedInputStream {
-  _ChunkedInputStream(InputStream this._input, int this._chunkSize)
-      : _bufferList = new _BufferList() {
-    _input.onClosed = _onClosed;
-  }
-
-  List<int> read() {
-    if (_closed) return null;
-    var result = _bufferList.readBytes(_chunkSize);
-    if (result == null) {
-      _readData();
-      result = _bufferList.readBytes(_chunkSize);
-    }
-    if (result == null && _inputClosed) {
-      if (_bufferList.length == 0) {
-        result = null;
-      } else {
-        result = _bufferList.readBytes(_bufferList.length);
-      }
-    }
-    _checkInstallDataHandler();
-    return result;
-  }
-
-  int get chunkSize => _chunkSize;
-
-  void set chunkSize(int chunkSize) {
-    _chunkSize = chunkSize;
-    _checkInstallDataHandler();
-    _checkScheduleCallback();
-  }
-
-  bool get closed => _closed;
-
-  void set onData(void callback()) {
-    _clientDataHandler = callback;
-    _checkInstallDataHandler();
-  }
-
-  void set onClosed(void callback()) {
-    _clientCloseHandler = callback;
-  }
-
-  void set onError(void callback(e)) {
-    _input.onError = callback;
-  }
-
-  void _onData() {
-    _readData();
-    if (_bufferList.length >= _chunkSize && _clientDataHandler != null) {
-      _clientDataHandler();
-    }
-    _checkScheduleCallback();
-    _checkInstallDataHandler();
-  }
-
-  void _readData() {
-    List<int> data = _input.read();
-    if (data != null) {
-      _bufferList.add(data);
-    }
-  }
-
-  void _onClosed() {
-    _inputClosed = true;
-    if (_bufferList.length == 0 && _clientCloseHandler != null) {
-      _clientCloseHandler();
-      _closed = true;
-    } else {
-      _checkScheduleCallback();
-    }
-  }
-
-  void _checkInstallDataHandler() {
-    if (_clientDataHandler == null) {
-      _input.onData = null;
-    } else {
-      if (_bufferList.length < _chunkSize && !_inputClosed) {
-        _input.onData = _onData;
-      } else {
-        _input.onData = null;
-      }
-    }
-  }
-
-  void _checkScheduleCallback() {
-    // TODO(sgjesse): Find a better way of scheduling callbacks from
-    // the event loop.
-    void issueDataCallback() {
-      _scheduledDataCallback = null;
-      if (_clientDataHandler != null) {
-        _clientDataHandler();
-        _checkScheduleCallback();
-      }
-    }
-
-    void issueCloseCallback() {
-      _scheduledCloseCallback = null;
-      if (!_closed) {
-        if (_clientCloseHandler != null) _clientCloseHandler();
-        _closed = true;
-      }
-    }
-
-    // Schedule data callback if enough data in buffer.
-    if ((_bufferList.length >= _chunkSize ||
-         (_bufferList.length > 0 && _inputClosed)) &&
-        _clientDataHandler != null &&
-        _scheduledDataCallback == null) {
-      _scheduledDataCallback = Timer.run(issueDataCallback);
-    }
-
-    // Schedule close callback if no more data and input is closed.
-    if (_bufferList.length == 0 &&
-        _inputClosed &&
-        !_closed &&
-        _scheduledCloseCallback == null) {
-      if (_scheduledDataCallback != null) {
-        _scheduledDataCallback.cancel();
-      }
-      _scheduledCloseCallback = Timer.run(issueCloseCallback);
-    }
-  }
-
-  InputStream _input;
-  _BufferList _bufferList;
-  int _chunkSize;
-  bool _inputClosed = false;  // Is the underlying input stream closed?
-  bool _closed = false;  // Has the close handler been called?.
-  Timer _scheduledDataCallback;
-  Timer _scheduledCloseCallback;
-  Function _clientDataHandler;
-  Function _clientCloseHandler;
-}
diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart
index 60717b8..fd70674 100644
--- a/sdk/lib/io/directory.dart
+++ b/sdk/lib/io/directory.dart
@@ -7,7 +7,7 @@
 /**
  * [Directory] objects are used for working with directories.
  */
-abstract class Directory {
+abstract class Directory extends FileSystemEntity {
   /**
    * Creates a directory object. The path is either an absolute path,
    * or it is a relative path which is interpreted relative to the directory
@@ -65,8 +65,8 @@
 
   /**
    * Creates a temporary directory with a name based on the current
-   * path.  This name and path is used as a template, and additional
-   * characters are appended to it by the call to make a unique
+   * path.  The path is used as a template, and additional
+   * characters are appended to it to make a unique temporary
    * directory name.  If the path is the empty string, a default
    * system temp directory and name are used for the template.
    *
@@ -77,15 +77,15 @@
 
   /**
    * Synchronously creates a temporary directory with a name based on the
-   * current path. This name and path is used as a template, and additional
-   * characters are appended to it by the call to make a unique directory name.
+   * current path. The path is used as a template, and additional
+   * characters are appended to it to make a unique temporary directory name.
    * If the path is the empty string, a default system temp directory and name
    * are used for the template. Returns the newly created temporary directory.
    */
   Directory createTempSync();
 
   /**
-   * Deletes the directory with this name.
+   * Deletes this directory.
    *
    * If [recursive] is false, the directory must be empty.
    *
@@ -99,7 +99,7 @@
   Future<Directory> delete({recursive: false});
 
   /**
-   * Synchronously deletes the directory with this name.
+   * Synchronously deletes this directory.
    *
    * If [recursive] is false, the directory must be empty.
    *
@@ -111,17 +111,17 @@
   void deleteSync({recursive: false});
 
   /**
-   * Rename this directory. Returns a [:Future<Directory>:] that completes
+   * Renames this directory. Returns a [:Future<Directory>:] that completes
    * with a [Directory] instance for the renamed directory.
    *
    * If newPath identifies an existing directory, that directory is
-   * replaced. If newPath identifies an existing file the operation
+   * replaced. If newPath identifies an existing file, the operation
    * fails and the future completes with an exception.
    */
   Future<Directory> rename(String newPath);
 
   /**
-   * Synchronously rename this directory. Returns a [Directory]
+   * Synchronously renames this directory. Returns a [Directory]
    * instance for the renamed directory.
    *
    * If newPath identifies an existing directory, that directory is
@@ -131,20 +131,22 @@
   Directory renameSync(String newPath);
 
   /**
-   * List the sub-directories and files of this
-   * [Directory]. Optionally recurse into sub-directories. Returns a
-   * [DirectoryLister] object representing the active listing
-   * operation. Handlers for files and directories should be
-   * registered on this DirectoryLister object.
+   * Lists the sub-directories and files of this [Directory].
+   * Optionally recurses into sub-directories.
+   *
+   * The result is a stream of [FileSystemEntity] objects
+   * for the directories and files.
    */
-  DirectoryLister list({bool recursive: false});
+  Stream<FileSystemEntity> list({bool recursive: false});
 
   /**
-   * List the sub-directories and files of this
-   * [Directory]. Optionally recurse into sub-directories. Returns a
-   * List containing Directory and File objects.
+   * Lists the sub-directories and files of this [Directory].
+   * Optionally recurses into sub-directories.
+   *
+   * Returns a [List] containing [FileSystemEntity] objects for the
+   * directories and files.
    */
-  List listSync({bool recursive: false});
+  List<FileSystemEntity> listSync({bool recursive: false});
 
   /**
    * Returns a human readable string for this Directory instance.
@@ -158,49 +160,6 @@
 }
 
 
-/**
- * A [DirectoryLister] represents an actively running listing operation.
- *
- * A [DirectoryLister] is obtained from a [Directory] object by calling
- * the [:Directory.list:] method.
- *
- *     Directory dir = new Directory('path/to/my/dir');
- *     DirectoryLister lister = dir.list();
- *
- * For each file and directory, the file or directory handler is
- * called. When all directories have been listed the done handler is
- * called. If the listing operation is recursive, the error handler is
- * called if a subdirectory cannot be opened for listing.
- */
-abstract class DirectoryLister {
-  /**
-   * Sets the directory handler that is called for all directories
-   * during listing. The directory handler is called with the full
-   * path of the directory.
-   */
-  void set onDir(void onDir(String dir));
-
-  /**
-   * Sets the handler that is called for all files during listing. The
-   * file handler is called with the full path of the file.
-   */
-  void set onFile(void onFile(String file));
-
-  /**
-   * Set the handler that is called when a listing is done. The
-   * handler is called with an indication of whether or not the
-   * listing operation completed.
-   */
-  void set onDone(void onDone(bool completed));
-
-  /**
-   * Sets the handler that is called if there is an error while
-   * listing directories.
-   */
-  void set onError(void onError(e));
-}
-
-
 class DirectoryIOException implements Exception {
   const DirectoryIOException([String this.message = "",
                               String this.path = "",
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index 59911ed..5963d83 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -226,8 +226,65 @@
     return new Directory(newPath);
   }
 
-  DirectoryLister list({bool recursive: false}) {
-    return new _DirectoryLister(_path, recursive);
+  Stream<FileSystemEntity> list({bool recursive: false}) {
+    const int LIST_FILE = 0;
+    const int LIST_DIRECTORY = 1;
+    const int LIST_ERROR = 2;
+    const int LIST_DONE = 3;
+
+    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>();
+
+    List request = [ _Directory.LIST_REQUEST, path, recursive ];
+    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.signalError(new DirectoryIOException("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_ERROR:
+          var errorType =
+              message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE];
+          if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) {
+            controller.signalError(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.signalError(
+                new DirectoryIOException("Directory listing failed",
+                                         errorPath,
+                                         err));
+          } else {
+            controller.signalError(new DirectoryIOException("Internal error"));
+          }
+          break;
+        case LIST_DONE:
+          responsePort.close();
+          controller.close();
+          break;
+      }
+    });
+
+    return controller.stream;
   }
 
   List listSync({bool recursive: false}) {
@@ -268,93 +325,3 @@
   final String _path;
   SendPort _directoryService;
 }
-
-class _DirectoryLister implements DirectoryLister {
-  _DirectoryLister(String path, bool recursive) {
-    const int LIST_DIRECTORY = 0;
-    const int LIST_FILE = 1;
-    const int LIST_ERROR = 2;
-    const int LIST_DONE = 3;
-
-    final int RESPONSE_TYPE = 0;
-    final int RESPONSE_PATH = 1;
-    final int RESPONSE_COMPLETE = 1;
-    final int RESPONSE_ERROR = 2;
-
-    List request = new List.fixedLength(3);
-    request[0] = _Directory.LIST_REQUEST;
-    request[1] = path;
-    request[2] = recursive;
-    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();
-        _reportError(new DirectoryIOException("Internal error"));
-        return;
-      }
-      switch (message[RESPONSE_TYPE]) {
-        case LIST_DIRECTORY:
-          if (_onDir != null) _onDir(message[RESPONSE_PATH]);
-          break;
-        case LIST_FILE:
-          if (_onFile != null) _onFile(message[RESPONSE_PATH]);
-          break;
-        case LIST_ERROR:
-          var errorType =
-              message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE];
-          if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) {
-            _reportError(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;
-            _reportError(new DirectoryIOException("Directory listing failed",
-                                                  errorPath,
-                                                  err));
-          } else {
-            _reportError(new DirectoryIOException("Internal error"));
-          }
-          break;
-        case LIST_DONE:
-          responsePort.close();
-          if (_onDone != null) _onDone(message[RESPONSE_COMPLETE]);
-          break;
-      }
-    });
-  }
-
-  void set onDir(void onDir(String dir)) {
-    _onDir = onDir;
-  }
-
-  void set onFile(void onFile(String file)) {
-    _onFile = onFile;
-  }
-
-  void set onDone(void onDone(bool completed)) {
-    _onDone = onDone;
-  }
-
-  void set onError(void onError(e)) {
-    _onError = onError;
-  }
-
-  void _reportError(e) {
-    if (_onError != null) {
-      _onError(e);
-    } else {
-      throw e;
-    }
-  }
-
-  Function _onDir;
-  Function _onFile;
-  Function _onDone;
-  Function _onError;
-}
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index 53a348c..ff956c8 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -19,11 +19,14 @@
 /**
  * [File] objects are references to files.
  *
- * To operate on the underlying file data you need to either get
- * streams using [openInputStream] and [openOutputStream] or open the
- * file for random access operations using [open].
+ * To operate on the underlying file data there are two options:
+ *
+ *  * Use streaming: read the contents of the file from the [Stream]
+ *    this.[openRead]() and write to the file by writing to the [IOSink]
+ *    this.[openWrite]().
+ *  * Open the file for random access operations using [open].
  */
-abstract class File {
+abstract class File extends FileSystemEntity {
   /**
    * Create a File object.
    */
@@ -35,8 +38,8 @@
   factory File.fromPath(Path path) => new _File.fromPath(path);
 
   /**
-   * Check if the file exists. Does not block and returns a
-   * [:Future<bool>:].
+   * Check if the file exists. Returns a
+   * [:Future<bool>:] that completes when the answer is known.
    */
   Future<bool> exists();
 
@@ -49,7 +52,7 @@
    * Create the file. Returns a [:Future<File>:] that completes with
    * the file when it has been created.
    *
-   * Existing files are left untouched by create. Calling create on an
+   * Existing files are left untouched by [create]. Calling [create] on an
    * existing file might fail if there are restrictive permissions on
    * the file.
    */
@@ -57,8 +60,8 @@
 
   /**
    * Synchronously create the file. Existing files are left untouched
-   * by create. Calling create on an existing file might fail if there
-   * are restrictive permissions on the file.
+   * by [createSync]. Calling [createSync] on an existing file might fail
+   * if there are restrictive permissions on the file.
    */
   void createSync();
 
@@ -74,14 +77,14 @@
   void deleteSync();
 
   /**
-   * Get a Directory object for the directory containing this
+   * Get a [Directory] object for the directory containing this
    * file. Returns a [:Future<Directory>:] that completes with the
    * directory.
    */
   Future<Directory> directory();
 
   /**
-   * Synchronously get a Directory object for the directory containing
+   * Synchronously get a [Directory] object for the directory containing
    * this file.
    */
   Directory directorySync();
@@ -113,27 +116,27 @@
   /**
    * Open the file for random access operations. Returns a
    * [:Future<RandomAccessFile>:] that completes with the opened
-   * random access file. RandomAccessFiles must be closed using the
-   * [close] method.
+   * random access file. [RandomAccessFile]s must be closed using the
+   * [RandomAccessFile.close] method.
    *
    * Files can be opened in three modes:
    *
-   * FileMode.READ: open the file for reading.
+   * [FileMode.READ]: open the file for reading.
    *
-   * FileMode.WRITE: open the file for both reading and writing and
+   * [FileMode.WRITE]: open the file for both reading and writing and
    * truncate the file to length zero. If the file does not exist the
    * file is created.
    *
-   * FileMode.APPEND: same as FileMode.WRITE except that the file is
+   * [FileMode.APPEND]: same as [FileMode.WRITE] except that the file is
    * not truncated.
    */
   Future<RandomAccessFile> open([FileMode mode = FileMode.READ]);
 
   /**
    * Synchronously open the file for random access operations. The
-   * result is a RandomAccessFile on which random access operations
-   * can be performed. Opened RandomAccessFiles must be closed using
-   * the [close] method.
+   * result is a [RandomAccessFile] on which random access operations
+   * can be performed. Opened [RandomAccessFile]s must be closed using
+   * the [RandomAccessFile.close] method.
    *
    * See [open] for information on the [mode] argument.
    */
@@ -151,26 +154,28 @@
   String fullPathSync();
 
   /**
-   * Create a new independent input stream for the file. The file
-   * input stream must be closed when no longer used to free up system
-   * resources.
+   * Create a new independent [Stream](../dart_async/Stream.html) for the
+   * contents of this file.
+   *
+   * In order to make sure that system resources are freed, the stream
+   * must be read to completion or the subscription on the stream must
+   * be cancelled.
    */
-  InputStream openInputStream();
+  Stream<List<int>> openRead();
+
 
   /**
-   * Creates a new independent output stream for the file. The file
-   * output stream must be closed when no longer used to free up
+   * Creates a new independent [IOSink] for the file. The
+   * [IOSink] must be closed when no longer used, to free
    * system resources.
    *
-   * An output stream can be opened in two modes:
+   * An [IOSink] for a file can be opened in two modes:
    *
-   * FileMode.WRITE: create the stream and truncate the underlying
-   * file to length zero.
-   *
-   * FileMode.APPEND: create the stream and set the position to the end of
-   * the underlying file.
+   * * [FileMode.WRITE]: truncates the file to length zero.
+   * * [FileMode.APPEND]: sets the initial write position to the end
+   *   of the file.
    */
-  OutputStream openOutputStream([FileMode mode = FileMode.WRITE]);
+  IOSink<File> openWrite([FileMode mode = FileMode.WRITE]);
 
   /**
    * Read the entire file contents as a list of bytes. Returns a
@@ -186,7 +191,7 @@
 
   /**
    * Read the entire file contents as a string using the given
-   * [encoding].
+   * [Encoding].
    *
    * Returns a [:Future<String>:] that completes with the string once
    * the file contents has been read.
@@ -195,13 +200,13 @@
 
   /**
    * Synchronously read the entire file contents as a string using the
-   * given [encoding].
+   * given [Encoding].
    */
   String readAsStringSync([Encoding encoding = Encoding.UTF_8]);
 
   /**
-   * Read the entire file contents as lines of text using the give
-   * [encoding].
+   * Read the entire file contents as lines of text using the given
+   * [Encoding].
    *
    * Returns a [:Future<List<String>>:] that completes with the lines
    * once the file contents has been read.
@@ -210,7 +215,7 @@
 
   /**
    * Synchronously read the entire file contents as lines of text
-   * using the given [encoding].
+   * using the given [Encoding].
    */
   List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8]);
 
@@ -223,18 +228,18 @@
    *
    * By default [writeAsBytes] creates the file for writing and truncates the
    * file if it already exists. In order to append the bytes to an existing
-   * file pass [:FileMode.APPEND:] as the optional mode parameter.
+   * file, pass [FileMode.APPEND] as the optional mode parameter.
    */
   Future<File> writeAsBytes(List<int> bytes, [FileMode mode = FileMode.WRITE]);
 
   /**
    * Synchronously write a list of bytes to a file.
    *
-   * Opens the file, writes the list of bytes to it and closses the file.
+   * Opens the file, writes the list of bytes to it and closes the file.
    *
    * By default [writeAsBytesSync] creates the file for writing and truncates
    * the file if it already exists. In order to append the bytes to an existing
-   * file pass [:FileMode.APPEND:] as the optional mode parameter.
+   * file, pass [FileMode.APPEND] as the optional mode parameter.
    */
   void writeAsBytesSync(List<int> bytes, [FileMode mode = FileMode.WRITE]);
 
@@ -247,7 +252,7 @@
    *
    * By default [writeAsString] creates the file for writing and truncates the
    * file if it already exists. In order to append the bytes to an existing
-   * file pass [:FileMode.APPEND:] as the optional mode parameter.
+   * file, pass [FileMode.APPEND] as the optional mode parameter.
    */
   Future<File> writeAsString(String contents,
                              {FileMode mode: FileMode.WRITE,
@@ -261,7 +266,7 @@
    *
    * By default [writeAsStringSync] creates the file for writing and
    * truncates the file if it already exists. In order to append the bytes
-   * to an existing file pass [:FileMode.APPEND:] as the optional mode
+   * to an existing file, pass [FileMode.APPEND] as the optional mode
    * parameter.
    */
   void writeAsStringSync(String contents,
@@ -282,79 +287,85 @@
  */
 abstract class RandomAccessFile {
   /**
-   * Close the file. Returns a [:Future<RandomAccessFile>:] that
+   * Closes the file. Returns a [:Future<RandomAccessFile>:] that
    * completes with this RandomAccessFile when it has been closed.
    */
   Future<RandomAccessFile> close();
 
   /**
-   * Synchronously close the file.
+   * Synchronously closes the file.
    */
   void closeSync();
 
   /**
-   * Read a byte from the file. Returns a [:Future<int>:] that
-   * completes with the byte or -1 if end of file has been reached.
+   * Reads a byte from the file. Returns a [:Future<int>:] that
+   * completes with the byte, or with -1 if end-of-file has been reached.
    */
   Future<int> readByte();
 
   /**
-   * Synchronously read a single byte from the file. If end of file
+   * Synchronously reads a single byte from the file. If end-of-file
    * has been reached -1 is returned.
    */
   int readByteSync();
 
   /**
-   * Reads from a file and returns the result as a list of bytes.
+   * Reads [bytes] bytes from a file and returns the result as a list of bytes.
    */
   Future<List<int>> read(int bytes);
 
   /**
-   * Synchronously reads from a file and returns the result in a
+   * Synchronously reads a maximum of [bytes] bytes from a file
+   * and returns the result in a
    * list of bytes.
    */
   List<int> readSync(int bytes);
 
   /**
-   * Read a List<int> from the file. Returns a [:Future<int>:] that
-   * completes with an indication of how much was read.
+   * Reads into an existing List<int> from the file. A maximum of [bytes] bytes
+   * is read into [buffer], starting at position [offset] in the buffer.
+   * Returns a [:Future<int>:] that completes with the number of bytes read.
    */
   Future<int> readList(List<int> buffer, int offset, int bytes);
 
   /**
-   * Synchronously read a List<int> from the file. Returns the number
-   * of bytes read.
+   * Synchronously reads from a file into [buffer].  A maximum of [bytes] bytes
+   * is read into [buffer], starting at position [offset] in the buffer.
+   * Returns the number of bytes read.
    */
   int readListSync(List<int> buffer, int offset, int bytes);
 
   /**
-   * Write a single byte to the file. Returns a
+   * Writes a single byte to the file. Returns a
    * [:Future<RandomAccessFile>:] that completes with this
    * RandomAccessFile when the write completes.
    */
   Future<RandomAccessFile> writeByte(int value);
 
   /**
-   * Synchronously write a single byte to the file. Returns the
+   * Synchronously writes a single byte to the file. Returns the
    * number of bytes successfully written.
    */
   int writeByteSync(int value);
 
   /**
-   * Write a List<int> to the file. Returns a
+   * Writes from a List<int> to the file. [bytes] bytes are written from
+   * [buffer], starting at position [offset] in the buffer. Returns a
    * [:Future<RandomAccessFile>:] that completes with this
    * RandomAccessFile when the write completes.
    */
   Future<RandomAccessFile> writeList(List<int> buffer, int offset, int bytes);
 
   /**
-   * Synchronously write a List<int> to the file. Returns the number
+   * Synchronously writes a List<int> to the file.
+   * [bytes] bytes are written from
+   * [buffer], starting at position [offset] in the buffer. Returns the number
    * of bytes successfully written.
    */
   int writeListSync(List<int> buffer, int offset, int bytes);
 
   /**
-   * Write a string to the file using the given [encoding]. Returns a
+   * Writes a string to the file using the given [Encoding]. Returns a
    * [:Future<RandomAccessFile>:] that completes with this
    * RandomAccessFile when the write completes.
    */
@@ -362,78 +373,78 @@
                                        [Encoding encoding = Encoding.UTF_8]);
 
   /**
-   * Synchronously write a single string to the file using the given
-   * [encoding]. Returns the number of characters successfully
+   * Synchronously writes a single string to the file using the given
+   * [Encoding]. Returns the number of characters successfully
    * written.
    */
   int writeStringSync(String string,
                       [Encoding encoding = Encoding.UTF_8]);
 
   /**
-   * Get the current byte position in the file. Returns a
+   * Gets the current byte position in the file. Returns a
    * [:Future<int>:] that completes with the position.
    */
   Future<int> position();
 
   /**
-   * Synchronously get the current byte position in the file.
+   * Synchronously gets the current byte position in the file.
    */
   int positionSync();
 
   /**
-   * Set the byte position in the file. Returns a
+   * Sets the byte position in the file. Returns a
    * [:Future<RandomAccessFile>:] that completes with this
    * RandomAccessFile when the position has been set.
    */
   Future<RandomAccessFile> setPosition(int position);
 
   /**
-   * Synchronously set the byte position in the file.
+   * Synchronously sets the byte position in the file.
    */
   void setPositionSync(int position);
 
   /**
-   * Truncate (or extend) the file to [length] bytes. Returns a
+   * Truncates (or extends) the file to [length] bytes. Returns a
    * [:Future<RandomAccessFile>:] that completes with this
    * RandomAccessFile when the truncation has been performed.
    */
   Future<RandomAccessFile> truncate(int length);
 
   /**
-   * Synchronously truncate (or extend) the file to [length] bytes.
+   * Synchronously truncates (or extends) the file to [length] bytes.
    */
   void truncateSync(int length);
 
   /**
-   * Get the length of the file. Returns a [:Future<int>:] that
+   * Gets the length of the file. Returns a [:Future<int>:] that
    * completes with the length in bytes.
    */
   Future<int> length();
 
   /**
-   * Synchronously get the length of the file.
+   * Synchronously gets the length of the file.
    */
   int lengthSync();
 
   /**
-   * Flush the contents of the file to disk. Returns a
+   * Flushes the contents of the file to disk. Returns a
    * [:Future<RandomAccessFile>:] that completes with this
    * RandomAccessFile when the flush operation completes.
    */
   Future<RandomAccessFile> flush();
 
   /**
-   * Synchronously flush the contents of the file to disk.
+   * Synchronously flushes the contents of the file to disk.
    */
   void flushSync();
 
   /**
-   * Returns a human readable string for this File instance.
+   * Returns a human-readable string for this RandomAccessFile instance.
    */
   String toString();
 
   /**
-   * Get the name of the file.
+   * Gets the name of the file underlying this RandomAccessFile.
    */
   String get name;
 }
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index f6cade2..ce60209 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -4,293 +4,202 @@
 
 part of dart.io;
 
-class _FileInputStream extends _BaseDataInputStream implements InputStream {
-  _FileInputStream(String name)
-      : _data = const [],
-        _position = 0,
-        _filePosition = 0 {
-    var file = new File(name);
-    var future = file.open(FileMode.READ);
-    future.then(_setupOpenedFile)
-          .catchError((e) {
-            _reportError(e.error);
-          });
+
+class _FileStream extends Stream<List<int>> {
+  // Stream controller.
+  StreamController<List<int>> _controller;
+
+  // Read the file in blocks of size 64k.
+  final int _blockSize = 64 * 1024;
+
+  // Information about the underlying file.
+  String _name;
+  RandomAccessFile _openedFile;
+  int _position;
+
+  // Has the stream been paused or unsubscribed?
+  bool _paused = false;
+  bool _unsubscribed = false;
+
+  // Is there a read currently in progress?
+  bool _readInProgress = false;
+
+  // Block read but not yet send because stream is paused.
+  List<int> _currentBlock;
+
+  _FileStream(String this._name) : _position = 0 {
+    _setupController();
   }
 
-  _FileInputStream.fromStdio(int fd)
-      : _data = const [],
-        _position = 0,
-        _filePosition = 0 {
-    assert(fd == 0);
-    _setupOpenedFile(_File._openStdioSync(fd));
+  _FileStream.forStdin() : _position = 0 {
+    _setupController();
   }
 
-  void _setupOpenedFile(RandomAccessFile openedFile) {
-    _openedFile = openedFile;
-    if (_streamMarkedClosed) {
-      // This input stream has already been closed.
-      _fileLength = 0;
-      _closeFile();
-      return;
+  StreamSubscription<List<int>> listen(void onData(List<int> event),
+                                       {void onError(AsyncError error),
+                                        void onDone(),
+                                        bool unsubscribeOnError}) {
+    return _controller.stream.listen(onData,
+                                     onError: onError,
+                                     onDone: onDone,
+                                     unsubscribeOnError: unsubscribeOnError);
+  }
+
+  void _setupController() {
+    _controller = new StreamController<List<int>>(
+        onSubscriptionStateChange: _onSubscriptionStateChange,
+        onPauseStateChange: _onPauseStateChange);
+  }
+
+  Future _closeFile() {
+    Future closeFuture;
+    if (_openedFile != null) {
+      Future closeFuture = _openedFile.close();
+      _openedFile = null;
+      return closeFuture;
+    } else {
+      return new Future.immediate(null);
     }
-    var futureOpen = _openedFile.length();
-    futureOpen
-      .then((len) {
-        _fileLength = len;
-        _fillBuffer();
+  }
+
+  void _readBlock() {
+    // Don't start a new read if one is already in progress.
+    if (_readInProgress) return;
+    _readInProgress = true;
+    _openedFile.length()
+      .then((length) {
+        if (_position >= length) {
+          _readInProgress = false;
+          if (!_unsubscribed) {
+            _closeFile().then((_) { _controller.close(); });
+            _unsubscribed = true;
+          }
+          return null;
+        } else {
+          return _openedFile.read(_blockSize);
+        }
+      })
+      .then((block) {
+        _readInProgress = false;
+        if (block == null || _unsubscribed) {
+          return;
+        }
+        _position += block.length;
+        if (_paused) {
+          _currentBlock = block;
+        } else {
+          _controller.add(block);
+          _readBlock();
+        }
       })
       .catchError((e) {
-        _reportError(e.error);
+        if (!_unsubscribed) {
+          _controller.signalError(e);
+          _closeFile().then((_) { _controller.close(); });
+          _unsubscribed = true;
+        }
       });
   }
 
-  void _closeFile() {
-    if (_openedFile == null) {
-      _streamMarkedClosed = true;
-      return;
+  void _start() {
+    Future<RandomAccessFile> openFuture;
+    if (_name != null) {
+      openFuture = new File(_name).open(FileMode.READ);
+    } else {
+      openFuture = new Future.immediate(_File._openStdioSync(0));
     }
-    if (available() == 0) _cancelScheduledDataCallback();
-    if (!_openedFile.closed) {
-      _openedFile.close().then((ignore) {
-        _streamMarkedClosed = true;
-        _checkScheduleCallbacks();
+    openFuture
+      .then((RandomAccessFile opened) {
+        _openedFile = opened;
+        _readBlock();
+      })
+      .catchError((e) {
+        _controller.signalError(e);
+        _controller.close();
       });
-    }
   }
 
-  void _fillBuffer() {
-    Expect.equals(_position, _data.length);
-    if (_openedFile == null) return;  // Called before the file is opened.
-    int size = min(_bufferLength, _fileLength - _filePosition);
-    if (size == 0) {
+  void _resume() {
+    _paused = false;
+    if (_currentBlock != null) {
+      _controller.add(_currentBlock);
+      _currentBlock = null;
+    }
+    // Resume reading unless we are already done.
+    if (_openedFile != null) _readBlock();
+  }
+
+  void _onSubscriptionStateChange() {
+    if (_controller.hasSubscribers) {
+      _start();
+    } else {
+      _unsubscribed = true;
       _closeFile();
-      return;
     }
-    // If there is currently a _fillBuffer call waiting on read,
-    // let it fill the buffer instead of us.
-    if (_activeFillBufferCall) return;
-    _activeFillBufferCall = true;
-    var future = _openedFile.read(size);
-    future.then((data) {
-      _data = data;
-      _position = 0;
-      _filePosition += _data.length;
-      _activeFillBufferCall = false;
-
-      if (_fileLength == _filePosition) {
-        _closeFile();
-      }
-      _checkScheduleCallbacks();
-    }).catchError((e) {
-      _activeFillBufferCall = false;
-      _reportError(e.error);
-    });
   }
 
-  int available() {
-    return closed ? 0 : _data.length - _position;
-  }
-
-  void pipe(OutputStream output, {bool close: true}) {
-    _pipe(this, output, close: close);
-  }
-
-  void _finishRead() {
-    if (_position == _data.length && !_streamMarkedClosed) {
-      _fillBuffer();
+  void _onPauseStateChange() {
+    if (_controller.isPaused) {
+      _paused = true;
     } else {
-      _checkScheduleCallbacks();
+      _resume();
     }
   }
-
-  List<int> _read(int bytesToRead) {
-    List<int> result;
-    if (_position == 0 && bytesToRead == _data.length) {
-      result = _data;
-      _data = const [];
-    } else {
-      result = new Uint8List(bytesToRead);
-      result.setRange(0, bytesToRead, _data, _position);
-      _position += bytesToRead;
-    }
-    _finishRead();
-    return result;
-  }
-
-  int _readInto(List<int> buffer, int offset, int len) {
-    buffer.setRange(offset, len, _data, _position);
-    _position += len;
-    _finishRead();
-    return len;
-  }
-
-  void _close() {
-    _data = const [];
-    _position = 0;
-    _filePosition = 0;
-    _fileLength = 0;
-    _closeFile();
-  }
-
-  static const int _bufferLength = 64 * 1024;
-
-  RandomAccessFile _openedFile;
-  List<int> _data;
-  int _position;
-  int _filePosition;
-  int _fileLength;
-  bool _activeFillBufferCall = false;
 }
 
+class _FileStreamConsumer extends StreamConsumer<List<int>, File> {
+  File _file;
+  Future<RandomAccessFile> _openFuture;
+  StreamSubscription _subscription;
 
-class _PendingOperation {
-  const _PendingOperation(this._id);
-  static const _PendingOperation CLOSE = const _PendingOperation(0);
-  static const _PendingOperation FLUSH = const _PendingOperation(1);
-  final int _id;
-}
-
-
-class _FileOutputStream extends _BaseOutputStream implements OutputStream {
-  _FileOutputStream(String name, FileMode mode) {
-    _pendingOperations = new List();
-    var f = new File(name);
-    var openFuture = f.open(mode);
-    openFuture.then((openedFile) {
-      _file = openedFile;
-      _processPendingOperations();
-    }).catchError((e) {
-      _reportError(e.error);
-    });
+  _FileStreamConsumer(File this._file, FileMode mode) {
+    _openFuture = _file.open(mode);
   }
 
-  _FileOutputStream.fromStdio(int fd) {
+  _FileStreamConsumer.fromStdio(int fd) {
     assert(1 <= fd && fd <= 2);
-    _file = _File._openStdioSync(fd);
+    _openFuture = new Future.immediate(_File._openStdioSync(fd));
   }
 
-  bool write(List<int> buffer, [bool copyBuffer = false]) {
-    var data = buffer;
-    if (copyBuffer) {
-      var length = buffer.length;
-      data = new Uint8List(length);
-      data.setRange(0, length, buffer, 0);
-    }
-    if (_file == null) {
-      _pendingOperations.add(data);
-    } else {
-      _write(data, 0, data.length);
-    }
-    return false;
-  }
-
-  bool writeFrom(List<int> buffer, [int offset = 0, int len]) {
-    // A copy is required by the interface.
-    var length = buffer.length - offset;
-    if (len != null) {
-      if (len > length) throw new RangeError.value(len);
-      length = len;
-    }
-    var copy = new Uint8List(length);
-    copy.setRange(0, length, buffer, offset);
-    return write(copy);
-  }
-
-
-  void flush() {
-    if (_file == null) {
-      _pendingOperations.add(_PendingOperation.FLUSH);
-    } else {
-      _file.flush().then((ignored) => null);
-    }
-  }
-
-
-  void close() {
-    _streamMarkedClosed = true;
-    if (_file == null) {
-      _pendingOperations.add(_PendingOperation.CLOSE);
-    } else if (!_closeCallbackScheduled) {
-      _file.close().then((ignore) {
-        if (_onClosed != null) _onClosed();
+  Future<File> consume(Stream<List<int>> stream) {
+    Completer<File> completer = new Completer<File>();
+    _openFuture
+      .then((openedFile) {
+        _subscription = stream.listen(
+          (d) {
+            _subscription.pause();
+            openedFile.writeList(d, 0, d.length)
+              .then((_) => _subscription.resume())
+              .catchError((e) {
+                openedFile.close();
+                completer.completeError(e);
+              });
+          },
+          onDone: () {
+            // Wait for the file to close (and therefore flush) before
+            // completing the future.
+            openedFile.close()
+              .then((_) {
+                completer.complete(_file);
+              })
+              .catchError((e) {
+                completer.completeError(e);
+              });
+          },
+          onError: (e) {
+            openedFile.close();
+            completer.completeError(e);
+          },
+          unsubscribeOnError: true);
+      })
+      .catchError((e) {
+        completer.completeError(e);
       });
-      _closeCallbackScheduled = true;
-    }
+    return completer.future;
   }
-
-  void set onNoPendingWrites(void callback()) {
-    _onNoPendingWrites = callback;
-    if ((_pendingOperations == null || _pendingOperations.length == 0) &&
-        outstandingWrites == 0 &&
-        !_streamMarkedClosed &&
-        _onNoPendingWrites != null) {
-      Timer.run(() {
-        if (_onNoPendingWrites != null) {
-          _onNoPendingWrites();
-        }
-      });
-    }
-  }
-
-  void set onClosed(void callback()) {
-    _onClosed = callback;
-  }
-
-  void _processPendingOperations() {
-    _pendingOperations.forEach((buffer) {
-      if (buffer is _PendingOperation) {
-        if (identical(buffer, _PendingOperation.CLOSE)) {
-          close();
-        } else {
-          assert(identical(buffer, _PendingOperation.FLUSH));
-          flush();
-        }
-      } else {
-        write(buffer);
-      }
-    });
-    _pendingOperations = null;
-  }
-
-  void _write(List<int> buffer, int offset, int len) {
-    outstandingWrites++;
-    var writeListFuture = _file.writeList(buffer, offset, len);
-    writeListFuture.then((ignore) {
-        outstandingWrites--;
-        if (outstandingWrites == 0 &&
-            !_streamMarkedClosed &&
-            _onNoPendingWrites != null) {
-          _onNoPendingWrites();
-        }
-    }).catchError((e) {
-      outstandingWrites--;
-      _reportError(e.error);
-    });
-  }
-
-  bool get closed => _streamMarkedClosed;
-
-  RandomAccessFile _file;
-
-  // When this is set to true the stream is marked closed. When a
-  // stream is marked closed no more data can be written.
-  bool _streamMarkedClosed = false;
-
-  // When this is set to true, the close callback has been scheduled and the
-  // stream will be fully closed once it's called.
-  bool _closeCallbackScheduled = false;
-
-  // Number of writes that have not yet completed.
-  int outstandingWrites = 0;
-
-  // List of pending writes that were issued before the underlying
-  // file was successfully opened.
-  List _pendingOperations;
-
-  Function _onNoPendingWrites;
-  Function _onClosed;
 }
 
+
 const int _EXISTS_REQUEST = 0;
 const int _CREATE_REQUEST = 1;
 const int _DELETE_REQUEST = 2;
@@ -555,36 +464,35 @@
     return result;
   }
 
-  InputStream openInputStream() {
-    return new _FileInputStream(_name);
+  Stream<List<int>> openRead() {
+    return new _FileStream(_name);
   }
 
-  OutputStream openOutputStream([FileMode mode = FileMode.WRITE]) {
+  IOSink<File> openWrite([FileMode mode = FileMode.WRITE]) {
     if (mode != FileMode.WRITE &&
         mode != FileMode.APPEND) {
       throw new FileIOException(
           "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND");
     }
-    return new _FileOutputStream(_name, mode);
+    var consumer = new _FileStreamConsumer(this, mode);
+    return new IOSink<File>(consumer);
   }
 
   Future<List<int>> readAsBytes() {
     _ensureFileService();
     Completer<List<int>> completer = new Completer<List<int>>();
     var chunks = new _BufferList();
-    var stream = openInputStream();
-    stream.onClosed = () {
-      var result = chunks.readBytes(chunks.length);
-      if (result == null) result = <int>[];
-      completer.complete(result);
-    };
-    stream.onData = () {
-      var chunk = stream.read();
-      chunks.add(chunk);
-    };
-    stream.onError = (e) {
-      completer.completeError(e);
-    };
+    openRead().listen(
+      (d) => chunks.add(d),
+      onDone: () {
+        var result = chunks.readBytes(chunks.length);
+        if (result == null) result = <int>[];
+        completer.complete(result);
+      },
+      onError: (e) {
+        completer.completeError(e);
+      },
+      unsubscribeOnError: true);
     return completer.future;
   }
 
@@ -603,67 +511,54 @@
   Future<String> readAsString([Encoding encoding = Encoding.UTF_8]) {
     _ensureFileService();
     return readAsBytes().then((bytes) {
-      if (bytes.length == 0) return "";
-      var decoder = _StringDecoders.decoder(encoding);
-      decoder.write(bytes);
-      return decoder.decoded();
+      return _decodeString(bytes, encoding);
     });
   }
 
   String readAsStringSync([Encoding encoding = Encoding.UTF_8]) {
-    var decoder = _StringDecoders.decoder(encoding);
     List<int> bytes = readAsBytesSync();
-    if (bytes.length == 0) return "";
-    decoder.write(bytes);
-    return decoder.decoded();
+    return _decodeString(bytes, encoding);
   }
 
-  List<String> _getDecodedLines(_StringDecoder decoder) {
-    List<String> result = [];
-    var line = decoder.decodedLine;
-    while (line != null) {
-      result.add(line);
-      line = decoder.decodedLine;
-    }
-    // If there is more data with no terminating line break we treat
-    // it as the last line.
-    var data = decoder.decoded();
-    if (data != null) {
-      result.add(data);
-    }
-    return result;
+  static List<String> _decodeLines(List<int> bytes, Encoding encoding) {
+    if (bytes.length == 0) return [];
+    var list = [];
+    var controller = new StreamController();
+    controller.stream
+      .transform(new StringDecoder(encoding))
+      .transform(new LineTransformer())
+      .listen((line) => list.add(line));
+    controller.add(bytes);
+    controller.close();
+    return list;
   }
 
   Future<List<String>> readAsLines([Encoding encoding = Encoding.UTF_8]) {
     _ensureFileService();
     Completer<List<String>> completer = new Completer<List<String>>();
     return readAsBytes().then((bytes) {
-      var decoder = _StringDecoders.decoder(encoding);
-      decoder.write(bytes);
-      return _getDecodedLines(decoder);
+      return _decodeLines(bytes, encoding);
     });
   }
 
   List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8]) {
-    var decoder = _StringDecoders.decoder(encoding);
-    List<int> bytes = readAsBytesSync();
-    decoder.write(bytes);
-    return _getDecodedLines(decoder);
+    return _decodeLines(readAsBytesSync(), encoding);
   }
 
   Future<File> writeAsBytes(List<int> bytes,
                             [FileMode mode = FileMode.WRITE]) {
     Completer<File> completer = new Completer<File>();
     try {
-      var stream = openOutputStream(mode);
-      stream.write(bytes);
+      var stream = openWrite(mode);
+      stream.add(bytes);
       stream.close();
-      stream.onClosed = () {
-        completer.complete(this);
-      };
-      stream.onError = (e) {
-        completer.completeError(e);
-      };
+      stream.done
+        .then((_) {
+          completer.complete(this);
+        })
+        .catchError((e) {
+          completer.completeError(e);
+        });
     } catch (e) {
       Timer.run(() => completer.completeError(e));
       return completer.future;
@@ -681,8 +576,7 @@
                              {FileMode mode: FileMode.WRITE,
                               Encoding encoding: Encoding.UTF_8}) {
     try {
-      var data = _StringEncoders.encoder(encoding).encodeString(contents);
-      return writeAsBytes(data, mode);
+      return writeAsBytes(_encodeString(contents, encoding), mode);
     } catch (e) {
       var completer = new Completer();
       Timer.run(() => completer.completeError(e));
@@ -693,8 +587,7 @@
   void writeAsStringSync(String contents,
                          {FileMode mode: FileMode.WRITE,
                           Encoding encoding: Encoding.UTF_8}) {
-    var data = _StringEncoders.encoder(encoding).encodeString(contents);
-    writeAsBytesSync(data, mode);
+    writeAsBytesSync(_encodeString(contents, encoding), mode);
   }
 
   String get name => _name;
@@ -987,7 +880,7 @@
       });
       return completer.future;
     }
-    var data = _StringEncoders.encoder(encoding).encodeString(string);
+    var data = _encodeString(string, encoding);
     return writeList(data, 0, data.length);
   }
 
@@ -996,7 +889,7 @@
       throw new FileIOException(
           "Invalid encoding in writeStringSync: $encoding");
     }
-    var data = _StringEncoders.encoder(encoding).encodeString(string);
+    var data = _encodeString(string, encoding);
     return writeListSync(data, 0, data.length);
   }
 
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
new file mode 100644
index 0000000..103f2be
--- /dev/null
+++ b/sdk/lib/io/file_system_entity.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.io;
+
+/**
+ * A [FileSystemEntity] is a common super class for [File] and
+ * [Directory] objects.
+ *
+ * [FileSystemEntity] objects are returned from directory listing
+ * operations. To determine if a FileSystemEntity is a [File] or a
+ * [Directory], perform a type check:
+ *
+ *     if (entity is File) (entity as File).readAsStringSync();
+ */
+abstract class FileSystemEntity {
+}
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index 2862036..9c5a6fb 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -57,54 +57,56 @@
 /**
  * HTTP server.
  */
-abstract class HttpServer {
-  factory HttpServer() => new _HttpServer();
-
+abstract class HttpServer implements Stream<HttpRequest> {
+  // TODO(ajohnsen): Document with example, once the stream API is final.
+  // TODO(ajohnsen): Add HttpServer.secure.
   /**
    * Start listening for HTTP requests on the specified [host] and
    * [port]. If a [port] of 0 is specified the server will choose an
    * ephemeral port. The optional argument [backlog] can be used to
-   * specify the listen backlog for the underlying OS listen.
-   * The optional arguments [certificate_name] and [requestClientCertificate]
-   * are used by the HttpsServer class, which shares the same interface.
-   * See [addRequestHandler] and [defaultRequestHandler] for
-   * information on how incoming HTTP requests are handled.
+   * specify the listen backlog for the underlying OS listen
+   * setup.
    */
-  void listen(String host,
-              int port,
-              {int backlog: 128,
-               String certificate_name,
-               bool requestClientCertificate: false});
+  static Future<HttpServer> bind([String address = "127.0.0.1",
+                                  int port = 0,
+                                  int backlog = 0])
+      => _HttpServer.bind(address, port, backlog);
 
   /**
-   * Attach the HTTP server to an existing [:ServerSocket:]. If the
+   * Start listening for HTTPS requests on the specified [host] and
+   * [port]. If a [port] of 0 is specified the server will choose an
+   * ephemeral port. The optional argument [backlog] can be used to
+   * specify the listen backlog for the underlying OS listen
+   * setup.
+   *
+   * The certificate with Distinguished Name [certificate_name] is looked
+   * up in the certificate database, and is used as the server certificate.
+   * if [requestClientCertificate] is true, the server will request clients
+   * to authenticate with a client certificate.
+   */
+
+  static Future<HttpServer> bindSecure(String address,
+                                       int port,
+                                       {int backlog: 0,
+                                        String certificateName,
+                                        bool requestClientCertificate: false})
+      => _HttpServer.bindSecure(address,
+                                port,
+                                backlog,
+                                certificateName,
+                                requestClientCertificate);
+
+  /**
+   * Attach the HTTP server to an existing [:ServerSocket:]. When the
    * [HttpServer] is closed, the [HttpServer] will just detach itself,
-   * and not close [serverSocket].
+   * close current connections but not close [serverSocket].
    */
-  void listenOn(ServerSocket serverSocket);
+  factory HttpServer.listenOn(ServerSocket serverSocket)
+      => new _HttpServer.listenOn(serverSocket);
 
   /**
-   * Adds a request handler to the list of request handlers. The
-   * function [matcher] is called with the request and must return
-   * [:true:] if the [handler] should handle the request. The first
-   * handler for which [matcher] returns [:true:] will be handed the
-   * request.
-   */
-  addRequestHandler(bool matcher(HttpRequest request),
-                    void handler(HttpRequest request, HttpResponse response));
-
-  /**
-   * Sets the default request handler. This request handler will be
-   * called if none of the request handlers registered by
-   * [addRequestHandler] matches the current request. If no default
-   * request handler is set the server will just respond with status
-   * code [:NOT_FOUND:] (404).
-   */
-  void set defaultRequestHandler(
-      void handler(HttpRequest request, HttpResponse response));
-
-  /**
-   * Stop server listening.
+   * Stop server listening. This will make the [Stream] close with a done
+   * event.
    */
   void close();
 
@@ -116,11 +118,6 @@
   int get port;
 
   /**
-   * Sets the error handler that is called when a connection error occurs.
-   */
-  void set onError(void callback(e));
-
-  /**
    * Set the timeout, in seconds, for sessions of this HTTP server. Default
    * is 20 minutes.
    */
@@ -128,21 +125,13 @@
 
   /**
    * Returns a [:HttpConnectionsInfo:] object with an overview of the
-   * current connection handled by the server.
+   * current connections handled by the server.
    */
   HttpConnectionsInfo connectionsInfo();
 }
 
 
 /**
- * HTTPS server.
- */
-abstract class HttpsServer implements HttpServer {
-  factory HttpsServer() => new _HttpServer.httpsServer();
-}
-
-
-/**
  * Overview information of the [:HttpServer:] socket connections.
  */
 class HttpConnectionsInfo {
@@ -445,18 +434,13 @@
   String toString();
 }
 
-abstract class HttpSession {
+abstract class HttpSession implements Map {
   /**
    * Get the id for the current session.
    */
   String get id;
 
   /**
-   * Access the user-data associated with the session.
-   */
-  dynamic data;
-
-  /**
    * Destroy the session. This will terminate the session and any further
    * connections with this id will be given a new id and session.
    */
@@ -466,6 +450,11 @@
    * Set a callback that will be called when the session is timed out.
    */
   void set onTimeout(void callback());
+
+  /**
+   * Is true if the session have not been sent to the client yet.
+   */
+  bool get isNew;
 }
 
 
@@ -590,9 +579,11 @@
 
 
 /**
- * Http request delivered to the HTTP server callback.
+ * Http request delivered to the HTTP server callback. The [HttpRequest] is a
+ * [Stream] of the body content of the request. Listen to the body to handle the
+ * data and be notified once the entire body is received.
  */
-abstract class HttpRequest {
+abstract class HttpRequest implements Stream<List<int>> {
   /**
    * Returns the content length of the request body. If the size of
    * the request body is not known in advance this -1.
@@ -600,11 +591,6 @@
   int get contentLength;
 
   /**
-   * Returns the persistent connection state signaled by the client.
-   */
-  bool get persistentConnection;
-
-  /**
    * Returns the method for the request.
    */
   String get method;
@@ -612,17 +598,7 @@
   /**
    * Returns the URI for the request.
    */
-  String get uri;
-
-  /**
-   * Returns the path part of the URI.
-   */
-  String get path;
-
-  /**
-   * Returns the query string.
-   */
-  String get queryString;
+  Uri get uri;
 
   /**
    * Returns the parsed query string.
@@ -640,6 +616,11 @@
   List<Cookie> get cookies;
 
   /**
+   * Returns the persistent connection state signaled by the client.
+   */
+  bool get persistentConnection;
+
+  /**
    * Returns the client certificate of the client making the request.
    * Returns null if the connection is not a secure TLS or SSL connection,
    * or if the server does not request a client certificate, or if the client
@@ -648,19 +629,12 @@
   X509Certificate get certificate;
 
   /**
-   * Returns, or initialize, a session for the given request. If the session is
-   * being initialized by this call, [init] will be called with the
-   * newly create session. Here the [:HttpSession.data:] field can be set, if
-   * needed.
+   * Get the session for the given request. If the session is
+   * being initialized by this call, [:isNew:] will be true for the returned
+   * session.
    * See [:HttpServer.sessionTimeout:] on how to change default timeout.
    */
-  HttpSession session([init(HttpSession session)]);
-
-  /**
-   * Returns the input stream for the request. This is used to read
-   * the request data.
-   */
-  InputStream get inputStream;
+  HttpSession get session;
 
   /**
    * Returns the HTTP protocol version used in the request. This will
@@ -673,13 +647,20 @@
    * isn't available.
    */
   HttpConnectionInfo get connectionInfo;
+
+  /**
+   * Get the [HttpResponse] object, used for sending back the response to the
+   * client.
+   */
+  HttpResponse get response;
 }
 
 
 /**
  * HTTP response to be send back to the client.
  */
-abstract class HttpResponse {
+abstract class HttpResponse implements IOSink<HttpResponse> {
+  // TODO(ajohnsen): Add documentation of how to pipe a file to the response.
   /**
    * Gets and sets the content length of the response. If the size of
    * the response is not known in advance set the content length to
@@ -719,17 +700,6 @@
   List<Cookie> get cookies;
 
   /**
-   * Returns the output stream for the response. This is used to write
-   * the response data. When all response data has been written close
-   * the stream to indicate the end of the response.
-   *
-   * When this is accessed for the first time the response header is
-   * send. Calling any methods that will change the header after
-   * having retrieved the output stream will throw an exception.
-   */
-  OutputStream get outputStream;
-
-  /**
    * Detach the underlying socket from the HTTP server. When the
    * socket is detached the HTTP server will no longer perform any
    * operations on it.
@@ -737,7 +707,7 @@
    * This is normally used when a HTTP upgrade request is received
    * and the communication should continue with a different protocol.
    */
-  DetachedSocket detachSocket();
+  Future<Socket> detachSocket();
 
   /**
    * Get information about the client connection. Returns [null] if the socket
@@ -753,7 +723,7 @@
  * try to reuse opened sockets for several requests to support HTTP 1.1
  * persistent connections. This means that sockets will be kept open for some
  * time after a requests have completed, unless HTTP procedures indicate that it
- * must be closed as part of completing the request. Use [:HttpClient.shutdown:]
+ * must be closed as part of completing the request. Use [:HttpClient.close:]
  * to force close the idle sockets.
  */
 abstract class HttpClient {
@@ -763,50 +733,51 @@
   factory HttpClient() => new _HttpClient();
 
   /**
-   * Opens a HTTP connection. The returned [HttpClientConnection] is
-   * used to register callbacks for asynchronous events on the HTTP
-   * connection. The "Host" header for the request will be set to the
-   * value [host]:[port]. This can be overridden through the
-   * HttpClientRequest interface before the request is sent. NOTE if
-   * [host] is an IP address this will still be set in the "Host"
+   * Opens a HTTP connection. The returned [HttpClientRequest] is used to
+   * fill in the content of the request before sending it. The "Host" header for
+   * the request will be set to the value [host]:[port]. This can be overridden
+   * through the [HttpClientRequest] interface before the request is sent.
+   * NOTE if [host] is an IP address this will still be set in the "Host"
    * header.
    */
-  HttpClientConnection open(String method, String host, int port, String path);
+  Future<HttpClientRequest> open(String method,
+                                 String host,
+                                 int port,
+                                 String path);
 
   /**
-   * Opens a HTTP connection. The returned [HttpClientConnection] is
-   * used to register callbacks for asynchronous events on the HTTP
-   * connection. The "Host" header for the request will be set based
-   * the host and port specified in [url]. This can be overridden
-   * through the HttpClientRequest interface before the request is
-   * sent. NOTE if the host is specified as an IP address this will
-   * still be set in the "Host" header.
+   * Opens a HTTP connection. The returned [HttpClientRequest] is used to
+   * fill in the content of the request before sending it. The "Host" header for
+   * the request will be set to the value [host]:[port]. This can be overridden
+   * through the [HttpClientRequest] interface before the request is sent.
+   * NOTE if [host] is an IP address this will still be set in the "Host"
+   * header.
    */
-  HttpClientConnection openUrl(String method, Uri url);
+  Future<HttpClientRequest> openUrl(String method, Uri url);
 
   /**
    * Opens a HTTP connection using the GET method. See [open] for
    * details. Using this method to open a HTTP connection will set the
    * content length to 0.
    */
-  HttpClientConnection get(String host, int port, String path);
+  Future<HttpClientRequest> get(String host, int port, String path);
 
   /**
    * Opens a HTTP connection using the GET method. See [openUrl] for
    * details. Using this method to open a HTTP connection will set the
    * content length to 0.
    */
-  HttpClientConnection getUrl(Uri url);
+  Future<HttpClientRequest> getUrl(Uri url);
 
   /**
    * Opens a HTTP connection using the POST method. See [open] for details.
    */
-  HttpClientConnection post(String host, int port, String path);
+  Future<HttpClientRequest> post(String host, int port, String path);
 
   /**
    * Opens a HTTP connection using the POST method. See [openUrl] for details.
    */
-  HttpClientConnection postUrl(Uri url);
+  Future<HttpClientRequest> postUrl(Uri url);
 
   /**
    * Sets the function to be called when a site is requesting
@@ -881,109 +852,23 @@
    * trying to establish a new connection after calling [shutdown]
    * will throw an exception.
    */
-  void shutdown({bool force: false});
-}
-
-
-/**
- * A [HttpClientConnection] is returned by all [HttpClient] methods
- * that initiate a connection to an HTTP server. The handlers will be
- * called as the connection state progresses.
- *
- * The setting of all handlers is optional. If [onRequest] is not set
- * the request will be send without any additional headers and an
- * empty body. If [onResponse] is not set the response will be read
- * and discarded.
- */
-abstract class HttpClientConnection {
-  /**
-   * Sets the handler that is called when the connection is established.
-   */
-  void set onRequest(void callback(HttpClientRequest request));
-
-  /**
-   * Sets callback to be called when the request has been send and
-   * the response is ready for processing. The callback is called when
-   * all headers of the response are received and data is ready to be
-   * received.
-   */
-  void set onResponse(void callback(HttpClientResponse response));
-
-  /**
-   * Sets the handler that gets called if an error occurs while
-   * connecting or processing the HTTP request.
-   */
-  void set onError(void callback(e));
-
-  /**
-   * Set this property to [:true:] if this connection should
-   * automatically follow redirects. The default is
-   * [:true:].
-   *
-   * Automatic redirect will only happen for "GET" and "HEAD" requests
-   * and only for the status codes [:HttpStatus.MOVED_PERMANENTLY:]
-   * (301), [:HttpStatus.FOUND:] (302),
-   * [:HttpStatus.MOVED_TEMPORARILY:] (302, alias for
-   * [:HttpStatus.FOUND:]), [:HttpStatus.SEE_OTHER:] (303) and
-   * [:HttpStatus.TEMPORARY_REDIRECT:] (307). For
-   * [:HttpStatus.SEE_OTHER:] (303) autmatic redirect will also happen
-   * for "POST" requests with the method changed to "GET" when
-   * following the redirect.
-   *
-   * All headers added to the request will be added to the redirection
-   * request(s). However, any body send with the request will not be
-   * part of the redirection request(s).
-   */
-  bool followRedirects;
-
-  /**
-   * Set this property to the maximum number of redirects to follow
-   * when [followRedirects] is [:true:]. If this number is exceeded the
-   * [onError] callback will be called with a [RedirectLimitExceeded]
-   * exception. The default value is 5.
-   */
-  int maxRedirects;
-
-  /**
-   * Returns the series of redirects this connection has been through.
-   */
-  List<RedirectInfo> get redirects;
-
-  /**
-   * Redirect this connection to a new URL. The default value for
-   * [method] is the method for the current request. The default value
-   * for [url] is the value of the [:HttpHeaders.LOCATION:] header of
-   * the current response. All body data must have been read from the
-   * current response before calling [redirect].
-   *
-   * All headers added to the request will be added to the redirection
-   * request(s). However, any body send with the request will not be
-   * part of the redirection request(s).
-   */
-  void redirect([String method, Uri url]);
-
-  /**
-   * Detach the underlying socket from the HTTP client. When the
-   * socket is detached the HTTP client will no longer perform any
-   * operations on it.
-   *
-   * This is normally used when a HTTP upgrade is negotiated and the
-   * communication should continue with a different protocol.
-   */
-  DetachedSocket detachSocket();
-
-  /**
-   * Get information about the client connection. Returns [null] if the socket
-   * isn't available.
-   */
-  HttpConnectionInfo get connectionInfo;
+  void close({bool force: false});
 }
 
 
 /**
  * HTTP request for a client connection.
+ *
+ * The request is an [IOSink], used to write the request data. When
+ * all request data has been written, close the stream to indicate the end of
+ * the request.
+ *
+ * When this is accessed for the first time the request header is
+ * send. Calling any methods that will change the header after
+ * having retrieved the output stream will throw an exception.
  */
-abstract class HttpClientRequest {
+abstract class HttpClientRequest
+    implements IOSink<HttpClientRequest> {
   /**
    * Gets and sets the content length of the request. If the size of
    * the request is not known in advance set content length to -1,
@@ -1008,22 +893,60 @@
   bool persistentConnection;
 
   /**
-   * Returns the output stream for the request. This is used to write
-   * the request data. When all request data has been written close
-   * the stream to indicate the end of the request.
-   *
-   * When this is accessed for the first time the request header is
-   * send. Calling any methods that will change the header after
-   * having retrieved the output stream will throw an exception.
+   * A [HttpClientResponse] future that will complete once the response is
+   * available. If an error occours before the response is available, this
+   * future will complete with an error.
    */
-  OutputStream get outputStream;
+  Future<HttpClientResponse> get response;
+
+  /**
+   * Close the request for input. Returns the value of [response].
+   */
+  Future<HttpClientResponse> close();
+
+  /**
+   * Set this property to [:true:] if this request should
+   * automatically follow redirects. The default is [:true:].
+   *
+   * Automatic redirect will only happen for "GET" and "HEAD" requests
+   * and only for the status codes [:HttpHeaders.MOVED_PERMANENTLY:]
+   * (301), [:HttpStatus.FOUND:] (302),
+   * [:HttpStatus.MOVED_TEMPORARILY:] (302, alias for
+   * [:HttpStatus.FOUND:]), [:HttpStatus.SEE_OTHER:] (303) and
+   * [:HttpStatus.TEMPORARY_REDIRECT:] (307). For
+   * [:HttpStatus.SEE_OTHER:] (303) autmatic redirect will also happen
+   * for "POST" requests with the method changed to "GET" when
+   * following the redirect.
+   *
+   * All headers added to the request will be added to the redirection
+   * request(s). However, any body send with the request will not be
+   * part of the redirection request(s).
+   */
+  bool followRedirects;
+
+  /**
+   * Set this property to the maximum number of redirects to follow
+   * when [followRedirects] is [:true:]. If this number is exceeded the
+   * [onError] callback will be called with a [RedirectLimitExceeded]
+   * exception. The default value is 5.
+   */
+  int maxRedirects;
+
+  /**
+   * Get information about the client connection. Returns [null] if the socket
+   * isn't available.
+   */
+  HttpConnectionInfo get connectionInfo;
 }
 
 
 /**
- * HTTP response for a client connection.
+ * HTTP response for a client connection. The [HttpClientResponse] is a
+ * [Stream] of the body content of the response. Listen to the body to handle
+ * the data and be notified once the entire body is received.
+
  */
-abstract class HttpClientResponse {
+abstract class HttpClientResponse implements Stream<List<int>> {
   /**
    * Returns the status code.
    */
@@ -1054,11 +977,49 @@
   bool get isRedirect;
 
   /**
+   * Returns the series of redirects this connection has been through. The
+   * list will be empty if no redirects was followed. [redirects] will be
+   * updated both in the case of an automatic and a manual redirect.
+   */
+  List<RedirectInfo> get redirects;
+
+  /**
+   * Redirect this connection to a new URL. The default value for
+   * [method] is the method for the current request. The default value
+   * for [url] is the value of the [:HttpHeaders.LOCATION:] header of
+   * the current response. All body data must have been read from the
+   * current response before calling [redirect].
+   *
+   * All headers added to the request will be added to the redirection
+   * request(s). However, any body send with the request will not be
+   * part of the redirection request(s).
+   *
+   * If [followLoops] is set to [true], redirect will follow the redirect,
+   * even if was already visited. Default value is [false].
+   *
+   * [redirect] will ignore [maxRedirects] and always perform the redirect.
+   */
+  Future<HttpClientResponse> redirect([String method,
+                                       Uri url,
+                                       bool followLoops]);
+
+
+  /**
    * Returns the response headers.
    */
   HttpHeaders get headers;
 
   /**
+   * Detach the underlying socket from the HTTP client. When the
+   * socket is detached the HTTP client will no longer perform any
+   * operations on it.
+   *
+   * This is normally used when a HTTP upgrade is negotiated and the
+   * communication should continue with a different protocol.
+   */
+  Future<Socket> detachSocket();
+
+  /**
    * Cookies set by the server (from the Set-Cookie header).
    */
   List<Cookie> get cookies;
@@ -1070,10 +1031,10 @@
   X509Certificate get certificate;
 
   /**
-   * Returns the input stream for the response. This is used to read
-   * the response data.
+   * Get information about the client connection. Returns [null] if the socket
+   * isn't available.
    */
-  InputStream get inputStream;
+  HttpConnectionInfo get connectionInfo;
 }
 
 
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart
index 928334d..949ace3 100644
--- a/sdk/lib/io/http_headers.dart
+++ b/sdk/lib/io/http_headers.dart
@@ -1,11 +1,12 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.io;
 
 class _HttpHeaders implements HttpHeaders {
-  _HttpHeaders() : _headers = new Map<String, List<String>>();
+  _HttpHeaders(String this.protocolVersion)
+      : _headers = new Map<String, List<String>>();
 
   List<String> operator[](String name) {
     name = name.toLowerCase();
@@ -67,6 +68,29 @@
     _noFoldingHeaders.add(name);
   }
 
+  bool get persistentConnection {
+    List<String> connection = this[HttpHeaders.CONNECTION];
+    if (protocolVersion == "1.1") {
+      if (connection == null) return true;
+      return !connection.any((value) => value.toLowerCase() == "close");
+    } else {
+      if (connection == null) return false;
+      return connection.any((value) => value.toLowerCase() == "keep-alive");
+    }
+  }
+
+  void set persistentConnection(bool persistentConnection) {
+    _checkMutable();
+    // Determine the value of the "Connection" header.
+    remove(HttpHeaders.CONNECTION, "close");
+    remove(HttpHeaders.CONNECTION, "keep-alive");
+    if (protocolVersion == "1.1" && !persistentConnection) {
+      add(HttpHeaders.CONNECTION, "close");
+    } else if (protocolVersion == "1.0" && persistentConnection) {
+      add(HttpHeaders.CONNECTION, "keep-alive");
+    }
+  }
+
   int get contentLength => _contentLength;
 
   void set contentLength(int contentLength) {
@@ -223,27 +247,31 @@
         throw new HttpException("Unexpected type for header named $name");
       }
     } else if (lowerCaseName == "host") {
-      int pos = value.indexOf(":");
-      if (pos == -1) {
-        _host = value;
-        _port = HttpClient.DEFAULT_HTTP_PORT;
-      } else {
-        if (pos > 0) {
-          _host = value.substring(0, pos);
-        } else {
-          _host = null;
-        }
-        if (pos + 1 == value.length) {
+      if (value is String) {
+        int pos = (value as String).indexOf(":");
+        if (pos == -1) {
+          _host = value;
           _port = HttpClient.DEFAULT_HTTP_PORT;
         } else {
-          try {
-            _port = int.parse(value.substring(pos + 1));
-          } on FormatException catch (e) {
-            _port = null;
+          if (pos > 0) {
+            _host = (value as String).substring(0, pos);
+          } else {
+            _host = null;
+          }
+          if (pos + 1 == value.length) {
+            _port = HttpClient.DEFAULT_HTTP_PORT;
+          } else {
+            try {
+              _port = int.parse(value.substring(pos + 1));
+            } on FormatException catch (e) {
+              _port = null;
+            }
           }
         }
+        _set("host", value);
+      } else {
+        throw new HttpException("Unexpected type for header named $name");
       }
-      _set("host", value);
     } else if (lowerCaseName == "content-type") {
       _set("content-type", value);
     } else {
@@ -290,7 +318,7 @@
     return true;
   }
 
-  void _finalize(String protocolVersion) {
+  void _finalize() {
     // If the content length is not known make sure chunked transfer
     // encoding is used for HTTP 1.1.
     if (contentLength < 0 && protocolVersion == "1.1") {
@@ -306,7 +334,7 @@
     _mutable = false;
   }
 
-  _write(_HttpConnectionBase connection) {
+  _write(IOSink sink) {
     final COLONSP = const [_CharCode.COLON, _CharCode.SP];
     final COMMASP = const [_CharCode.COMMA, _CharCode.SP];
     final CRLF = const [_CharCode.CR, _CharCode.LF];
@@ -316,7 +344,7 @@
     var bufferPos = 0;
 
     void writeBuffer() {
-      connection._writeFrom(buffer, 0, bufferPos);
+      sink.add(buffer.getRange(0, bufferPos));
       bufferPos = 0;
     }
 
@@ -381,12 +409,78 @@
     return sb.toString();
   }
 
+  List<Cookie> _parseCookies() {
+    // Parse a Cookie header value according to the rules in RFC 6265.
+    var cookies = new List<Cookie>();
+    void parseCookieString(String s) {
+      int index = 0;
+
+      bool done() => index == s.length;
+
+      void skipWS() {
+        while (!done()) {
+         if (s[index] != " " && s[index] != "\t") return;
+         index++;
+        }
+      }
+
+      String parseName() {
+        int start = index;
+        while (!done()) {
+          if (s[index] == " " || s[index] == "\t" || s[index] == "=") break;
+          index++;
+        }
+        return s.substring(start, index).toLowerCase();
+      }
+
+      String parseValue() {
+        int start = index;
+        while (!done()) {
+          if (s[index] == " " || s[index] == "\t" || s[index] == ";") break;
+          index++;
+        }
+        return s.substring(start, index).toLowerCase();
+      }
+
+      void expect(String expected) {
+        if (done()) {
+          throw new HttpException("Failed to parse header value [$s]");
+        }
+        if (s[index] != expected) {
+          throw new HttpException("Failed to parse header value [$s]");
+        }
+        index++;
+      }
+
+      while (!done()) {
+        skipWS();
+        if (done()) return;
+        String name = parseName();
+        skipWS();
+        expect("=");
+        skipWS();
+        String value = parseValue();
+        cookies.add(new _Cookie(name, value));
+        skipWS();
+        if (done()) return;
+        expect(";");
+      }
+    }
+    List<String> values = this["cookie"];
+    if (values != null) {
+      values.forEach((headerValue) => parseCookieString(headerValue));
+    }
+    return cookies;
+  }
+
+
   bool _mutable = true;  // Are the headers currently mutable?
   Map<String, List<String>> _headers;
   List<String> _noFoldingHeaders;
 
   int _contentLength = -1;
   bool _chunkedTransferEncoding = false;
+  final String protocolVersion;
   String _host;
   int _port;
 }
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 4a8d266a..8bc8a98 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -4,344 +4,94 @@
 
 part of dart.io;
 
-// The close queue handles graceful closing of HTTP connections. When
-// a connection is added to the queue it will enter a wait state
-// waiting for all data written and possibly socket shutdown from
-// peer.
-class _CloseQueue {
-  _CloseQueue() : _q = new Set<_HttpConnectionBase>();
+class _HttpIncoming
+    extends Stream<List<int>> implements StreamSink<List<int>> {
+  final int _transferLength;
+  final Completer _dataCompleter = new Completer();
+  Stream<List<int>> _stream;
 
-  void add(_HttpConnectionBase connection) {
-    void closeIfDone() {
-      // When either the client has closed or all data has been
-      // written to the client we close the underlying socket
-      // completely.
-      if (connection._isWriteClosed || connection._isReadClosed) {
-        _q.remove(connection);
-        connection._socket.close();
-        if (connection.onClosed != null) connection.onClosed();
-      }
-    }
+  bool fullBodyRead = false;
 
-    // If the connection is already fully closed don't insert it into
-    // the queue.
-    if (connection._isFullyClosed) {
-      connection._socket.close();
-      if (connection.onClosed != null) connection.onClosed();
-      return;
-    }
+  // Common properties.
+  final _HttpHeaders headers;
+  bool upgraded = false;
 
-    connection._state |= _HttpConnectionBase.CLOSING;
-    _q.add(connection);
+  // ClientResponse properties.
+  int statusCode;
+  String reasonPhrase;
 
-    // If the output stream is not closed for writing, close it now and
-    // wait for callback when closed.
-    if (!connection._isWriteClosed) {
-      connection._socket.outputStream.close();
-      connection._socket.outputStream.onClosed = () {
-        connection._state |= _HttpConnectionBase.WRITE_CLOSED;
-        closeIfDone();
-      };
-    } else {
-      connection._socket.outputStream.onClosed = () { assert(false); };
-    }
+  // Request properties.
+  String method;
+  Uri uri;
 
-    // If the request is not already fully read wait for the socket to close.
-    // As the _isReadClosed state from the HTTP request processing indicate
-    // that the response has been parsed this does not necesarily mean tha
-    // the socket is closed.
-    if (!connection._isReadClosed) {
-      connection._socket.onClosed = () {
-        connection._state |= _HttpConnectionBase.READ_CLOSED;
-        closeIfDone();
-      };
-    }
+  // The transfer length if the length of the message body as it
+  // appears in the message (RFC 2616 section 4.4). This can be -1 if
+  // the length of the massage body is not known due to transfer
+  // codings.
+  int get transferLength => _transferLength;
 
-    // Ignore any data on a socket in the close queue.
-    connection._socket.onData = connection._socket.read;
-
-    // If an error occurs immediately close the socket.
-    connection._socket.onError = (e) {
-      connection._state |= _HttpConnectionBase.READ_CLOSED;
-      connection._state |= _HttpConnectionBase.WRITE_CLOSED;
-      closeIfDone();
-    };
+  _HttpIncoming(_HttpHeaders this.headers,
+                int this._transferLength,
+                Stream<List<int>> this._stream) {
   }
 
-  void shutdown() {
-    _q.forEach((_HttpConnectionBase connection) {
-      connection._socket.close();
-    });
+  StreamSubscription<List<int>> listen(void onData(List<int> event),
+                                       {void onError(AsyncError error),
+                                        void onDone(),
+                                        bool unsubscribeOnError}) {
+    return _stream.listen(onData,
+                          onError: onError,
+                          onDone: onDone,
+                          unsubscribeOnError: unsubscribeOnError);
   }
 
-  final Set<_HttpConnectionBase> _q;
+  // Is completed once all data have been received.
+  Future get dataDone => _dataCompleter.future;
+
+  void close() {
+    fullBodyRead = true;
+    _dataCompleter.complete();
+  }
 }
 
-
-class _HttpRequestResponseBase {
-  static const int START = 0;
-  static const int HEADER_SENT = 1;
-  static const int DONE = 2;
-  static const int UPGRADED = 3;
-
-  _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection)
-      : _state = START, _headResponse = false;
-
-  int get contentLength => _headers.contentLength;
-  HttpHeaders get headers => _headers;
-
-  bool get persistentConnection {
-    List<String> connection = headers[HttpHeaders.CONNECTION];
-    if (_protocolVersion == "1.1") {
-      if (connection == null) return true;
-      return !headers[HttpHeaders.CONNECTION].any(
-          (value) => value.toLowerCase() == "close");
-    } else {
-      if (connection == null) return false;
-      return headers[HttpHeaders.CONNECTION].any(
-          (value) => value.toLowerCase() == "keep-alive");
-    }
-  }
-
-  X509Certificate get certificate {
-    var socket = _httpConnection._socket as SecureSocket;
-    return socket == null ? socket : socket.peerCertificate;
-  }
-
-  void set persistentConnection(bool persistentConnection) {
-    if (_outputStream != null) throw new HttpException("Header already sent");
-
-    // Determine the value of the "Connection" header.
-    headers.remove(HttpHeaders.CONNECTION, "close");
-    headers.remove(HttpHeaders.CONNECTION, "keep-alive");
-    if (_protocolVersion == "1.1" && !persistentConnection) {
-      headers.add(HttpHeaders.CONNECTION, "close");
-    } else if (_protocolVersion == "1.0" && persistentConnection) {
-      headers.add(HttpHeaders.CONNECTION, "keep-alive");
-    }
-  }
-
-
-  bool _write(List<int> data, bool copyBuffer) {
-    if (_headResponse) return true;
-    _ensureHeadersSent();
-    bool allWritten = true;
-    if (data.length > 0) {
-      if (_headers.chunkedTransferEncoding) {
-        // Write chunk size if transfer encoding is chunked.
-        _writeHexString(data.length);
-        _writeCRLF();
-        _httpConnection._write(data, copyBuffer);
-        allWritten = _writeCRLF();
-      } else {
-        _updateContentLength(data.length);
-        allWritten = _httpConnection._write(data, copyBuffer);
-      }
-    }
-    return allWritten;
-  }
-
-  bool _writeList(List<int> data, int offset, int count) {
-    if (_headResponse) return true;
-    _ensureHeadersSent();
-    bool allWritten = true;
-    if (count > 0) {
-      if (_headers.chunkedTransferEncoding) {
-        // Write chunk size if transfer encoding is chunked.
-        _writeHexString(count);
-        _writeCRLF();
-        _httpConnection._writeFrom(data, offset, count);
-        allWritten = _writeCRLF();
-      } else {
-        _updateContentLength(count);
-        allWritten = _httpConnection._writeFrom(data, offset, count);
-      }
-    }
-    return allWritten;
-  }
-
-  bool _writeDone() {
-    bool allWritten = true;
-    if (_headers.chunkedTransferEncoding) {
-      // Terminate the content if transfer encoding is chunked.
-      allWritten = _httpConnection._write(_Const.END_CHUNKED);
-    } else {
-      if (!_headResponse && _bodyBytesWritten < _headers.contentLength) {
-        throw new HttpException("Sending less than specified content length");
-      }
-      assert(_headResponse || _bodyBytesWritten == _headers.contentLength);
-    }
-    return allWritten;
-  }
-
-  bool _writeHeaders() {
-    _headers._write(_httpConnection);
-    // Terminate header.
-    return _writeCRLF();
-  }
-
-  bool _writeHexString(int x) {
-    final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34,
-                                 0x35, 0x36, 0x37, 0x38, 0x39,
-                                 0x41, 0x42, 0x43, 0x44, 0x45, 0x46];
-    List<int> hex = new Uint8List(10);
-    int index = hex.length;
-    while (x > 0) {
-      index--;
-      hex[index] = hexDigits[x % 16];
-      x = x >> 4;
-    }
-    return _httpConnection._writeFrom(hex, index, hex.length - index);
-  }
-
-  bool _writeCRLF() {
-    final CRLF = const [_CharCode.CR, _CharCode.LF];
-    return _httpConnection._write(CRLF);
-  }
-
-  bool _writeSP() {
-    final SP = const [_CharCode.SP];
-    return _httpConnection._write(SP);
-  }
-
-  void _ensureHeadersSent() {
-    // Ensure that headers are written.
-    if (_state == START) {
-      _writeHeader();
-    }
-  }
-
-  void _updateContentLength(int bytes) {
-    if (_bodyBytesWritten + bytes > _headers.contentLength) {
-      throw new HttpException("Writing more than specified content length");
-    }
-    _bodyBytesWritten += bytes;
-  }
-
-  HttpConnectionInfo get connectionInfo => _httpConnection.connectionInfo;
-
-  bool get _done => _state == DONE;
-
-  int _state;
-  bool _headResponse;
-
-  _HttpConnectionBase _httpConnection;
-  _HttpHeaders _headers;
+class _HttpInboundMessage extends Stream<List<int>> {
+  final _HttpIncoming _incoming;
   List<Cookie> _cookies;
-  String _protocolVersion = "1.1";
 
-  // Number of body bytes written. This is only actual body data not
-  // including headers or chunk information of using chinked transfer
-  // encoding.
-  int _bodyBytesWritten = 0;
-}
-
-
-// Parsed HTTP request providing information on the HTTP headers.
-class _HttpRequest extends _HttpRequestResponseBase implements HttpRequest {
-  _HttpRequest(_HttpConnection connection) : super(connection);
-
-  String get method => _method;
-  String get uri => _uri;
-  String get path => _path;
-  String get queryString => _queryString;
-  Map get queryParameters => _queryParameters;
+  _HttpInboundMessage(_HttpIncoming this._incoming);
 
   List<Cookie> get cookies {
     if (_cookies != null) return _cookies;
-
-    // Parse a Cookie header value according to the rules in RFC 6265.
-   void _parseCookieString(String s) {
-      int index = 0;
-
-      bool done() => index == s.length;
-
-      void skipWS() {
-        while (!done()) {
-         if (s[index] != " " && s[index] != "\t") return;
-         index++;
-        }
-      }
-
-      String parseName() {
-        int start = index;
-        while (!done()) {
-          if (s[index] == " " || s[index] == "\t" || s[index] == "=") break;
-          index++;
-        }
-        return s.substring(start, index).toLowerCase();
-      }
-
-      String parseValue() {
-        int start = index;
-        while (!done()) {
-          if (s[index] == " " || s[index] == "\t" || s[index] == ";") break;
-          index++;
-        }
-        return s.substring(start, index).toLowerCase();
-      }
-
-      void expect(String expected) {
-        if (done()) {
-          throw new HttpException("Failed to parse header value [$s]");
-        }
-        if (s[index] != expected) {
-          throw new HttpException("Failed to parse header value [$s]");
-        }
-        index++;
-      }
-
-      while (!done()) {
-        skipWS();
-        if (done()) return;
-        String name = parseName();
-        skipWS();
-        expect("=");
-        skipWS();
-        String value = parseValue();
-        _cookies.add(new _Cookie(name, value));
-        skipWS();
-        if (done()) return;
-        expect(";");
-      }
-    }
-
-    _cookies = new List<Cookie>();
-    List<String> headerValues = headers["cookie"];
-    if (headerValues != null) {
-      headerValues.forEach((headerValue) => _parseCookieString(headerValue));
-    }
-    return _cookies;
+    return _cookies = headers._parseCookies();
   }
 
-  InputStream get inputStream {
-    if (_inputStream == null) {
-      _inputStream = new _HttpInputStream(this);
-    }
-    return _inputStream;
-  }
+  HttpHeaders get headers => _incoming.headers;
+  String get protocolVersion => headers.protocolVersion;
+  int get contentLength => headers.contentLength;
+  bool get persistentConnection => headers.persistentConnection;
+}
 
-  String get protocolVersion => _protocolVersion;
 
-  HttpSession session([init(HttpSession session)]) {
-    if (_session != null) {
-      // It's already mapped, use it.
-      return _session;
-    }
-    // Create session, store it in connection, and return.
-    var sessionManager = _httpConnection._server._sessionManager;
-    return _session = sessionManager.createSession(init);
-  }
+class _HttpRequest extends _HttpInboundMessage implements HttpRequest {
+  final HttpResponse response;
 
-  void _onRequestReceived(String method,
-                          String uri,
-                          String version,
-                          _HttpHeaders headers) {
-    _method = method;
-    _uri = uri;
-    _parseRequestUri(uri);
-    _headers = headers;
-    if (_httpConnection._server._sessionManagerInstance != null) {
+  // Lazy initialized parsed query parameters.
+  Map<String, String> _queryParameters;
+
+  final _HttpServer _httpServer;
+
+  final _HttpConnection _httpConnection;
+
+  HttpSession _session;
+
+  _HttpRequest(_HttpResponse this.response,
+               _HttpIncoming _incoming,
+               _HttpServer this._httpServer,
+               _HttpConnection this._httpConnection)
+      : super(_incoming) {
+    response.headers.persistentConnection = headers.persistentConnection;
+
+    if (_httpServer._sessionManagerInstance != null) {
       // Map to session if exists.
       var sessionId = cookies.reduce(null, (last, cookie) {
         if (last != null) return last;
@@ -349,175 +99,382 @@
             cookie.value : null;
       });
       if (sessionId != null) {
-        var sessionManager = _httpConnection._server._sessionManager;
-        _session = sessionManager.getSession(sessionId);
+        _session = _httpServer._sessionManager.getSession(sessionId);
         if (_session != null) {
           _session._markSeen();
         }
       }
     }
-
-    // Prepare for receiving data.
-    _buffer = new _BufferList();
   }
 
-  void _onDataReceived(List<int> data) {
-    _buffer.add(data);
-    if (_inputStream != null) _inputStream._dataReceived();
+  StreamSubscription<List<int>> listen(void onData(List<int> event),
+                                       {void onError(AsyncError error),
+                                        void onDone(),
+                                        bool unsubscribeOnError}) {
+    return _incoming.listen(onData,
+                            onError: onError,
+                            onDone: onDone,
+                            unsubscribeOnError: unsubscribeOnError);
   }
 
-  void _onDataEnd() {
-    if (_inputStream != null) {
-      _inputStream._closeReceived();
-    } else {
-      inputStream._streamMarkedClosed = true;
+  Map<String, String> get queryParameters {
+    if (_queryParameters == null) {
+      _queryParameters = _HttpUtils.splitQueryString(uri.query);
     }
+    return _queryParameters;
   }
 
-  // Escaped characters in uri are expected to have been parsed.
-  void _parseRequestUri(String uri) {
-    int position;
-    position = uri.indexOf("?", 0);
-    if (position == -1) {
-      _path = _HttpUtils.decodeUrlEncodedString(_uri);
-      _queryString = null;
-      _queryParameters = new Map();
-    } else {
-      _path = _HttpUtils.decodeUrlEncodedString(_uri.substring(0, position));
-      _queryString = _uri.substring(position + 1);
-      _queryParameters = _HttpUtils.splitQueryString(_queryString);
+  Uri get uri => _incoming.uri;
+
+  String get method => _incoming.method;
+
+  HttpSession get session {
+    if (_session != null) {
+      // It's already mapped, use it.
+      return _session;
     }
+    // Create session, store it in connection, and return.
+    return _session = _httpServer._sessionManager.createSession();
   }
 
-  // Delegate functions for the HttpInputStream implementation.
-  int _streamAvailable() {
-    return _buffer.length;
-  }
+  HttpConnectionInfo get connectionInfo => _httpConnection.connectionInfo;
 
-  List<int> _streamRead(int bytesToRead) {
-    return _buffer.readBytes(bytesToRead);
+  X509Certificate get certificate {
+    Socket socket = _httpConnection._socket;
+    if (socket is SecureSocket) return socket.peerCertificate;
+    return null;
   }
-
-  int _streamReadInto(List<int> buffer, int offset, int len) {
-    List<int> data = _buffer.readBytes(len);
-    buffer.setRange(offset, data.length, data);
-    return data.length;
-  }
-
-  void _streamSetErrorHandler(callback(e)) {
-    _streamErrorHandler = callback;
-  }
-
-  String _method;
-  String _uri;
-  String _path;
-  String _queryString;
-  Map<String, String> _queryParameters;
-  _HttpInputStream _inputStream;
-  _BufferList _buffer;
-  Function _streamErrorHandler;
-  _HttpSession _session;
 }
 
 
-// HTTP response object for sending a HTTP response.
-class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse {
-  _HttpResponse(_HttpConnection httpConnection)
-      : super(httpConnection),
-        _statusCode = HttpStatus.OK {
-    _headers = new _HttpHeaders();
-  }
+class _HttpClientResponse
+    extends _HttpInboundMessage implements HttpClientResponse {
+  List<RedirectInfo> get redirects => _httpRequest._responseRedirects;
 
-  void set contentLength(int contentLength) {
-    if (_state >= _HttpRequestResponseBase.HEADER_SENT) {
-      throw new HttpException("Header already sent");
+  // The HttpClient this response belongs to.
+  final _HttpClient _httpClient;
+
+  // The HttpClientRequest of this response.
+  final _HttpClientRequest _httpRequest;
+
+  List<Cookie> _cookies;
+
+  _HttpClientResponse(_HttpIncoming _incoming,
+                      _HttpClientRequest this._httpRequest,
+                      _HttpClient this._httpClient)
+      : super(_incoming);
+
+  int get statusCode => _incoming.statusCode;
+  String get reasonPhrase => _incoming.reasonPhrase;
+
+  List<Cookie> get cookies {
+    if (_cookies != null) return _cookies;
+    _cookies = new List<Cookie>();
+    List<String> values = headers["set-cookie"];
+    if (values != null) {
+      values.forEach((value) {
+        _cookies.add(new Cookie.fromSetCookieValue(value));
+      });
     }
-    _headers.contentLength = contentLength;
+    return _cookies;
   }
 
-  int get statusCode => _statusCode;
-  void set statusCode(int statusCode) {
-    if (_outputStream != null) throw new HttpException("Header already sent");
-    _statusCode = statusCode;
+  bool get isRedirect {
+    if (_httpRequest.method == "GET" || _httpRequest.method == "HEAD") {
+      return statusCode == HttpStatus.MOVED_PERMANENTLY ||
+             statusCode == HttpStatus.FOUND ||
+             statusCode == HttpStatus.SEE_OTHER ||
+             statusCode == HttpStatus.TEMPORARY_REDIRECT;
+    } else if (_httpRequest.method == "POST") {
+      return statusCode == HttpStatus.SEE_OTHER;
+    }
+    return false;
   }
 
-  String get reasonPhrase => _findReasonPhrase(_statusCode);
-  void set reasonPhrase(String reasonPhrase) {
-    if (_outputStream != null) throw new HttpException("Header already sent");
-    _reasonPhrase = reasonPhrase;
+  Future<HttpClientResponse> redirect([String method,
+                                       Uri url,
+                                       bool followLoops]) {
+    if (method == null) {
+      // Set method as defined by RFC 2616 section 10.3.4.
+      if (statusCode == HttpStatus.SEE_OTHER && _httpRequest.method == "POST") {
+        method = "GET";
+      } else {
+        method = _httpRequest.method;
+      }
+    }
+    if (url == null) {
+      String location = headers.value(HttpHeaders.LOCATION);
+      if (location == null) {
+        throw new StateError("Response has no Location header for redirect");
+      }
+      url = Uri.parse(location);
+    }
+    if (followLoops != true) {
+      for (var redirect in redirects) {
+        if (redirect.location == url) {
+          return new Future.immediateError(
+              new RedirectLoopException(redirects));
+        }
+      }
+    }
+    return _httpClient._openUrlFromRequest(method, url, _httpRequest)
+        .then((request) {
+          request._responseRedirects.addAll(this.redirects);
+          request._responseRedirects.add(new _RedirectInfo(statusCode,
+                                                           method,
+                                                           url));
+          return request.close();
+        });
   }
 
+  StreamSubscription<List<int>> listen(void onData(List<int> event),
+                                       {void onError(AsyncError error),
+                                        void onDone(),
+                                        bool unsubscribeOnError}) {
+    return _incoming.listen(onData,
+                            onError: onError,
+                            onDone: onDone,
+                            unsubscribeOnError: unsubscribeOnError);
+  }
+
+  Future<Socket> detachSocket() {
+    _httpClient._connectionClosed(_httpRequest._httpClientConnection);
+    return _httpRequest._httpClientConnection.detachSocket();
+  }
+
+  HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo;
+
+  bool get _shouldAuthenticate {
+    // Only try to authenticate if there is a challenge in the response.
+    List<String> challenge = headers[HttpHeaders.WWW_AUTHENTICATE];
+    return statusCode == HttpStatus.UNAUTHORIZED &&
+        challenge != null && challenge.length == 1;
+  }
+
+  Future<HttpClientResponse> _authenticate() {
+    Future<HttpClientResponse> retryWithCredentials(_Credentials cr) {
+      if (cr != null) {
+        // TODO(sgjesse): Support digest.
+        if (cr.scheme == _AuthenticationScheme.BASIC) {
+          // Drain body and retry.
+          return reduce(null, (x, y) {}).then((_) {
+              return _httpClient._openUrlFromRequest(_httpRequest.method,
+                                                     _httpRequest.uri,
+                                                     _httpRequest)
+                  .then((request) => request.close());
+            });
+        }
+      }
+
+      // Fall through to here to perform normal response handling if
+      // there is no sensible authorization handling.
+      return new Future.immediate(this);
+    }
+
+    List<String> challenge = headers[HttpHeaders.WWW_AUTHENTICATE];
+    assert(challenge != null || challenge.length == 1);
+    _HeaderValue header =
+        new _HeaderValue.fromString(challenge[0], parameterSeparator: ",");
+    _AuthenticationScheme scheme =
+        new _AuthenticationScheme.fromString(header.value);
+    String realm = header.parameters["realm"];
+
+    // See if any credentials are available.
+    _Credentials cr = _httpClient._findCredentials(_httpRequest.uri, scheme);
+
+    if (cr != null && !cr.used) {
+      // If credentials found prepare for retrying the request.
+      return retryWithCredentials(cr);
+    }
+
+    // Ask for more credentials if none found or the one found has
+    // already been used. If it has already been used it must now be
+    // invalid and is removed.
+    if (cr != null) {
+      _httpClient._removeCredentials(cr);
+      cr = null;
+    }
+    if (_httpClient._authenticate != null) {
+      Future authComplete = _httpClient._authenticate(_httpRequest.uri,
+                                                      scheme.toString(),
+                                                      realm);
+      return authComplete.then((credsAvailable) {
+        if (credsAvailable) {
+          cr = _httpClient._findCredentials(_httpRequest.uri, scheme);
+          return retryWithCredentials(cr);
+        } else {
+          // No credentials available, complete with original response.
+          return this;
+        }
+      });
+    }
+    // No credentials were found and the callback was not set.
+    return new Future.immediate(this);
+  }
+}
+
+
+class _HttpOutboundMessage<T> extends IOSink {
+  // Used to mark when the body should be written. This is used for HEAD
+  // requests and in error handling.
+  bool _ignoreBody = false;
+
+  _HttpOutboundMessage(String protocolVersion, _HttpOutgoing outgoing)
+      : super(outgoing),
+        _outgoing = outgoing,
+        headers = new _HttpHeaders(protocolVersion);
+
+  int get contentLength => headers.contentLength;
+  void set contentLength(int contentLength) {
+    headers.contentLength = contentLength;
+  }
+
+  bool get persistentConnection => headers.persistentConnection;
+  bool set persistentConnection(bool p) {
+    headers.persistentConnection = p;
+  }
+
+  Future<T> consume(Stream<List<int>> stream) {
+    _writeHeaders();
+    if (_ignoreBody) return new Future.immediate(this);
+    if (_chunked) {
+      // Transform when chunked.
+      stream = stream.transform(new _ChunkedTransformer());
+    }
+    return super.consume(stream).then((_) => this);
+  }
+
+  void add(List<int> data) {
+    _writeHeaders();
+    if (_ignoreBody) return;
+    if (_chunked) {
+      _ChunkedTransformer._addChunk(data, super.add);
+    } else {
+      super.add(data);
+    }
+  }
+
+  void close() {
+    if (!_headersWritten && !_ignoreBody && headers.chunkedTransferEncoding) {
+      // If no body was written, _ignoreBody is false (it's not a HEAD
+      // request) and the content-length is unspecified, set contentLength to 0.
+      headers.contentLength = 0;
+    }
+    _writeHeaders();
+    if (!_ignoreBody) {
+      if (_chunked) {
+        _ChunkedTransformer._addChunk([], super.add);
+      }
+    }
+    super.close();
+  }
+
+  void _writeHeaders() {
+    if (_headersWritten) return;
+    bool _tmpIgnoreBody = _ignoreBody;
+    _ignoreBody = false;
+    _headersWritten = true;
+    _writeHeader();
+    _ignoreBody = _tmpIgnoreBody;
+    if (_ignoreBody) {
+      super.close();
+      return;
+    }
+    _chunked = headers.chunkedTransferEncoding;
+    if (!_chunked) {
+      _outgoing.setTransferLength(headers.contentLength);
+    }
+  }
+
+  void _writeHeader();  // TODO(ajohnsen): Better name.
+
+  final _HttpHeaders headers;
+
+  final _HttpOutgoing _outgoing;
+  bool _headersWritten = false;
+  bool _chunked = false;
+}
+
+
+class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
+    implements HttpResponse {
+  int statusCode = 200;
+  String _reasonPhrase;
+  List<Cookie> _cookies;
+  _HttpRequest _httpRequest;
+
+  _HttpResponse(String protocolVersion,
+                _HttpOutgoing _outgoing)
+      : super(protocolVersion, _outgoing);
+
   List<Cookie> get cookies {
     if (_cookies == null) _cookies = new List<Cookie>();
     return _cookies;
   }
 
-  OutputStream get outputStream {
-    if (_state >= _HttpRequestResponseBase.DONE) {
-      throw new HttpException("Response closed");
+  String get reasonPhrase => _findReasonPhrase(statusCode);
+  void set reasonPhrase(String reasonPhrase) {
+    if (_headersWritten) throw new StateError("Header already sent");
+    _reasonPhrase = reasonPhrase;
+  }
+
+  Future<Socket> detachSocket() {
+    if (_headersWritten) throw new StateError("Headers already sent");
+    _writeHeaders();
+    var future = _httpRequest._httpConnection.detachSocket();
+    // Close connection so the socket is 'free'.
+    close();
+    return future;
+  }
+
+  HttpConnectionInfo get connectionInfo => _httpRequest.connectionInfo;
+
+  void _writeHeader() {
+    writeSP() => add([_CharCode.SP]);
+    writeCRLF() => add([_CharCode.CR, _CharCode.LF]);
+
+    // Write status line.
+    if (headers.protocolVersion == "1.1") {
+      add(_Const.HTTP11);
+    } else {
+      add(_Const.HTTP10);
     }
-    if (_outputStream == null) {
-      _outputStream = new _HttpOutputStream(this);
+    writeSP();
+    addString(statusCode.toString());
+    writeSP();
+    addString(reasonPhrase);
+    writeCRLF();
+
+    var session = _httpRequest._session;
+    if (session != null && !session._destroyed) {
+      // Mark as not new.
+      session._isNew = false;
+      // Make sure we only send the current session id.
+      bool found = false;
+      for (int i = 0; i < cookies.length; i++) {
+        if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) {
+          cookies[i].value = session.id;
+          cookies[i].httpOnly = true;
+          found = true;
+          break;
+        }
+      }
+      if (!found) {
+        cookies.add(new Cookie(_DART_SESSION_ID, session.id)..httpOnly = true);
+      }
     }
-    return _outputStream;
-  }
-
-  DetachedSocket detachSocket() {
-    if (_state >= _HttpRequestResponseBase.DONE) {
-      throw new HttpException("Response closed");
+    // Add all the cookies set to the headers.
+    if (_cookies != null) {
+      _cookies.forEach((cookie) {
+        headers.add("set-cookie", cookie);
+      });
     }
-    // Ensure that headers are written.
-    if (_state == _HttpRequestResponseBase.START) {
-      _writeHeader();
-    }
-    _state = _HttpRequestResponseBase.UPGRADED;
-    // Ensure that any trailing data is written.
-    _writeDone();
-    // Indicate to the connection that the response handling is done.
-    return _httpConnection._detachSocket();
-  }
 
-  // Delegate functions for the HttpOutputStream implementation.
-  bool _streamWrite(List<int> buffer, bool copyBuffer) {
-    if (_done) throw new HttpException("Response closed");
-    return _write(buffer, copyBuffer);
-  }
+    headers._finalize();
 
-  bool _streamWriteFrom(List<int> buffer, int offset, int len) {
-    if (_done) throw new HttpException("Response closed");
-    return _writeList(buffer, offset, len);
-  }
-
-  void _streamFlush() {
-    _httpConnection._flush();
-  }
-
-  void _streamClose() {
-    _ensureHeadersSent();
-    _state = _HttpRequestResponseBase.DONE;
-    // Stop tracking no pending write events.
-    _httpConnection._onNoPendingWrites = null;
-    // Ensure that any trailing data is written.
-    _writeDone();
-    // Indicate to the connection that the response handling is done.
-    _httpConnection._responseClosed();
-    if (_streamClosedHandler != null) {
-      Timer.run(_streamClosedHandler);
-    }
-  }
-
-  void _streamSetNoPendingWriteHandler(callback()) {
-    if (_state != _HttpRequestResponseBase.DONE) {
-      _httpConnection._onNoPendingWrites = callback;
-    }
-  }
-
-  void _streamSetClosedHandler(callback()) {
-    _streamClosedHandler = callback;
-  }
-
-  void _streamSetErrorHandler(callback(e)) {
-    _streamErrorHandler = callback;
+    // Write headers.
+    headers._write(this);
+    writeCRLF();
   }
 
   String _findReasonPhrase(int statusCode) {
@@ -574,547 +531,871 @@
       default: return "Status $statusCode";
     }
   }
+}
 
-  bool _writeHeader() {
-    List<int> data;
 
-    // Write status line.
-    if (_protocolVersion == "1.1") {
-      _httpConnection._write(_Const.HTTP11);
-    } else {
-      _httpConnection._write(_Const.HTTP10);
+class _HttpClientRequest extends _HttpOutboundMessage<HttpClientRequest>
+    implements HttpClientRequest {
+  final String method;
+  final Uri uri;
+  final List<Cookie> cookies = new List<Cookie>();
+
+  // The HttpClient this request belongs to.
+  final _HttpClient _httpClient;
+  final _HttpClientConnection _httpClientConnection;
+
+  final Completer<HttpClientResponse> _responseCompleter
+      = new Completer<HttpClientResponse>();
+
+  final bool _usingProxy;
+
+  // TODO(ajohnsen): Get default value from client?
+  bool _followRedirects = true;
+
+  int _maxRedirects = 5;
+
+  List<RedirectInfo> _responseRedirects = [];
+
+  _HttpClientRequest(_HttpOutgoing outgoing,
+                     Uri this.uri,
+                     String this.method,
+                     bool this._usingProxy,
+                     _HttpClient this._httpClient,
+                     _HttpClientConnection this._httpClientConnection)
+      : super("1.1", outgoing) {
+    // GET and HEAD have 'content-length: 0' by default.
+    if (method == "GET" || method == "HEAD") {
+      contentLength = 0;
     }
-    _writeSP();
-    data = _statusCode.toString().charCodes;
-    _httpConnection._write(data);
-    _writeSP();
-    data = reasonPhrase.charCodes;
-    _httpConnection._write(data);
-    _writeCRLF();
+  }
 
-    var session = _httpConnection._request._session;
-    if (session != null && !session._destroyed) {
-      // Make sure we only send the current session id.
-      bool found = false;
-      for (int i = 0; i < cookies.length; i++) {
-        if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) {
-          cookies[i].value = session.id;
-          cookies[i].httpOnly = true;
-          found = true;
-          break;
+  Future<HttpClientResponse> get response => _responseCompleter.future;
+
+  Future<HttpClientResponse> close() {
+    super.close();
+    return response;
+  }
+
+  int get maxRedirects => _maxRedirects;
+  void set maxRedirects(int maxRedirects) {
+    if (_headersWritten) throw new StateError("Request already sent");
+    _maxRedirects = maxRedirects;
+  }
+
+  bool get followRedirects => _followRedirects;
+  void set followRedirects(bool followRedirects) {
+    if (_headersWritten) throw new StateError("Request already sent");
+    _followRedirects = followRedirects;
+  }
+
+  HttpConnectionInfo get connectionInfo => _httpClientConnection.connectionInfo;
+
+  void _onIncoming(_HttpIncoming incoming) {
+    var response = new _HttpClientResponse(incoming,
+                                           this,
+                                          _httpClient);
+    Future<HttpClientResponse> future;
+    if (followRedirects && response.isRedirect) {
+      if (response.redirects.length < maxRedirects) {
+        // Redirect and drain response.
+        future = response.reduce(null, (x, y) {})
+          .then((_) => response.redirect());
+      } else {
+        // End with exception, too many redirects.
+        future = response.reduce(null, (x, y) {})
+            .then((_) => new Future.immediateError(
+                new RedirectLimitExceededException(response.redirects)));
+      }
+    } else if (response._shouldAuthenticate) {
+      future = response._authenticate();
+    } else {
+      future = new Future<HttpClientResponse>.immediate(response);
+    }
+    future.then(
+        (v) => _responseCompleter.complete(v),
+        onError: (e) {
+          _responseCompleter.completeError(e);
+        });
+  }
+
+  void _onError(AsyncError error) {
+    _responseCompleter.completeError(error);
+  }
+
+  void _writeHeader() {
+    writeSP() => add([_CharCode.SP]);
+    writeCRLF() => add([_CharCode.CR, _CharCode.LF]);
+
+    addString(method);
+    writeSP();
+    // Send the path for direct connections and the whole URL for
+    // proxy connections.
+    if (!_usingProxy) {
+      String path = uri.path;
+      if (path.length == 0) path = "/";
+      if (uri.query != "") {
+        if (uri.fragment != "") {
+          path = "${path}?${uri.query}#${uri.fragment}";
+        } else {
+          path = "${path}?${uri.query}";
         }
       }
-      if (!found) {
-        cookies.add(new Cookie(_DART_SESSION_ID, session.id)..httpOnly = true);
+      addString(path);
+    } else {
+      addString(uri.toString());
+    }
+    writeSP();
+    add(_Const.HTTP11);
+    writeCRLF();
+
+    // Add the cookies to the headers.
+    if (!cookies.isEmpty) {
+      StringBuffer sb = new StringBuffer();
+      for (int i = 0; i < cookies.length; i++) {
+        if (i > 0) sb.add("; ");
+        sb.add(cookies[i].name);
+        sb.add("=");
+        sb.add(cookies[i].value);
       }
+      headers.add("cookie", sb.toString());
     }
-    // Add all the cookies set to the headers.
-    if (_cookies != null) {
-      _cookies.forEach((cookie) {
-        _headers.add("set-cookie", cookie);
-      });
-    }
+
+    headers._finalize();
 
     // Write headers.
-    _headers._finalize(_protocolVersion);
-    bool allWritten = _writeHeaders();
-    _state = _HttpRequestResponseBase.HEADER_SENT;
-    return allWritten;
+    headers._write(this);
+    writeCRLF();
   }
-
-  int _statusCode;  // Response status code.
-  String _reasonPhrase;  // Response reason phrase.
-  _HttpOutputStream _outputStream;
-  Function _streamClosedHandler;
-  Function _streamErrorHandler;
 }
 
 
-class _HttpInputStream extends _BaseDataInputStream implements InputStream {
-  _HttpInputStream(_HttpRequestResponseBase this._requestOrResponse) {
-    _checkScheduleCallbacks();
+// Transformer that transforms data to HTTP Chunked Encoding.
+class _ChunkedTransformer implements StreamTransformer<List<int>, List<int>> {
+  final StreamController<List<int>> _controller
+      = new StreamController<List<int>>();
+
+  Stream<List<int>> bind(Stream<List<int>> stream) {
+    var subscription = stream.listen(
+        (data) {
+          if (data.length == 0) return;  // Avoid close on 0-bytes payload.
+          _addChunk(data, _controller.add);
+       },
+       onDone: () {
+          _addChunk([], _controller.add);
+          _controller.close();
+       });
+    return _controller.stream;
   }
 
-  int available() {
-    return _requestOrResponse._streamAvailable();
+  static void _addChunk(List<int> data, void add(List<int> data)) {
+    add(_chunkHeader(data.length));
+    if (data.length > 0) add(data);
+    add(_chunkFooter);
   }
 
-  void pipe(OutputStream output, {bool close: true}) {
-    _pipe(this, output, close: close);
+  static List<int> _chunkHeader(int length) {
+    const hexDigits = const [0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+                             0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46];
+    var header = [];
+    if (length == 0) {
+      header.add(hexDigits[length]);
+    } else {
+      while (length > 0) {
+        header.insertRange(0, 1, hexDigits[length % 16]);
+        length = length >> 4;
+      }
+    }
+    header.add(_CharCode.CR);
+    header.add(_CharCode.LF);
+    return header;
   }
 
-  List<int> _read(int bytesToRead) {
-    List<int> result = _requestOrResponse._streamRead(bytesToRead);
-    _checkScheduleCallbacks();
-    return result;
-  }
-
-  void set onError(void callback(e)) {
-    _requestOrResponse._streamSetErrorHandler(callback);
-  }
-
-  int _readInto(List<int> buffer, int offset, int len) {
-    int result = _requestOrResponse._streamReadInto(buffer, offset, len);
-    _checkScheduleCallbacks();
-    return result;
-  }
-
-  void _close() {
-    // TODO(sgjesse): Handle this.
-  }
-
-  void _dataReceived() {
-    super._dataReceived();
-  }
-
-  _HttpRequestResponseBase _requestOrResponse;
+  // Footer is just a CRLF.
+  static List<int> get _chunkFooter => const [_CharCode.CR, _CharCode.LF];
 }
 
 
-class _HttpOutputStream extends _BaseOutputStream implements OutputStream {
-  _HttpOutputStream(_HttpRequestResponseBase this._requestOrResponse);
+// Transformer that invokes [_onDone] when completed.
+class _DoneTransformer implements StreamTransformer<List<int>, List<int>> {
+  final StreamController<List<int>> _controller
+      = new StreamController<List<int>>();
+  final Function _onDone;
 
-  bool write(List<int> buffer, [bool copyBuffer = true]) {
-    return _requestOrResponse._streamWrite(buffer, copyBuffer);
+  _DoneTransformer(this._onDone);
+
+  Stream<List<int>> bind(Stream<List<int>> stream) {
+    var subscription = stream.listen(
+        _controller.add,
+        onError: _controller.signalError,
+        onDone: () {
+          _onDone();
+          _controller.close();
+        });
+    return _controller.stream;
+  }
+}
+
+// Transformer that validates the data written.
+class _DataValidatorTransformer
+    implements StreamTransformer<List<int>, List<int>> {
+  final StreamController<List<int>> _controller
+      = new StreamController<List<int>>();
+  int _bytesWritten = 0;
+  Completer _completer = new Completer();
+
+  int expectedTransferLength;
+
+  _DataValidatorTransformer();
+
+  Future get validatorFuture => _completer.future;
+
+  Stream<List<int>> bind(Stream<List<int>> stream) {
+    var subscription;
+    subscription = stream.listen(
+        (data) {
+          if (expectedTransferLength != null) {
+            _bytesWritten += data.length;
+            if (_bytesWritten > expectedTransferLength) {
+              _controller.close();
+              subscription.cancel();
+              if (_completer != null) {
+                _completer.completeError(new HttpException(
+                    "Content size exceeds specified contentLength. "
+                    "$_bytesWritten bytes written while expected "
+                    "$expectedTransferLength."));
+                _completer = null;
+              }
+              return;
+            }
+          }
+          _controller.add(data);
+        },
+        onError: (error) {
+          _controller.close();
+          if (_completer != null) {
+            _completer.completeError(error);
+            _completer = null;
+          }
+        },
+        onDone: () {
+          _controller.close();
+          if (expectedTransferLength != null) {
+            if (_bytesWritten < expectedTransferLength) {
+              if (_completer != null) {
+                _completer.completeError(new HttpException(
+                    "Content size below specified contentLength. "
+                    " $_bytesWritten bytes written while expected "
+                    "$expectedTransferLength."));
+                _completer = null;
+                return;
+              }
+            }
+          }
+          if (_completer != null) {
+            _completer.complete(this);
+            _completer = null;
+          }
+        },
+        unsubscribeOnError: true);
+    return _controller.stream;
+  }
+}
+
+// Extends StreamConsumer as this is an internal type, only used to pipe to.
+class _HttpOutgoing implements StreamConsumer<List<int>, dynamic> {
+  final Completer _dataCompleter = new Completer();
+  final Completer _streamCompleter = new Completer();
+  final _DataValidatorTransformer _validator = new _DataValidatorTransformer();
+
+  // Future that completes when all data is written.
+  Future get dataDone => _dataCompleter.future;
+
+  // Future that completes with the Stream, once the _HttpClientConnection is
+  // bound to one.
+  Future<Stream<List<int>>> get stream => _streamCompleter.future;
+
+  void setTransferLength(int transferLength) {
+    _validator.expectedTransferLength = transferLength;
   }
 
-  bool writeFrom(List<int> buffer, [int offset = 0, int len]) {
-    if (offset < 0 || offset >= buffer.length) throw new ArgumentError();
-    len = len != null ? len : buffer.length - offset;
-    if (len < 0) throw new ArgumentError();
-    return _requestOrResponse._streamWriteFrom(buffer, offset, len);
+  Future consume(Stream<List<int>> stream) {
+    stream = stream.transform(_validator);
+    _streamCompleter.complete(stream);
+    _validator.validatorFuture.catchError((e) {
+      _dataCompleter.completeError(e);
+    });
+    return _validator.validatorFuture.then((v) {
+      _dataCompleter.complete();
+      return v;
+    });
+  }
+}
+
+
+class _HttpClientConnection {
+  final String key;
+  final Socket _socket;
+  final _HttpParser _httpParser;
+  StreamSubscription _subscription;
+  final _HttpClient _httpClient;
+
+  Completer<_HttpIncoming> _nextResponseCompleter;
+  Future _writeDoneFuture;
+
+  _HttpClientConnection(String this.key,
+                        Socket this._socket,
+                        _HttpClient this._httpClient)
+      : _httpParser = new _HttpParser.responseParser() {
+    _socket.pipe(_httpParser);
+    _socket.done.catchError((e) { destroy(); });
+
+    // Set up handlers on the parser here, so we are sure to get 'onDone' from
+    // the parser.
+    _subscription = _httpParser.listen(
+        (incoming) {
+          // Only handle one incoming response at the time. Keep the
+          // stream paused until the response have been processed.
+          _subscription.pause();
+          // We assume the response is not here, until we have send the request.
+          assert(_nextResponseCompleter != null);
+          _nextResponseCompleter.complete(incoming);
+        },
+        onError: (error) {
+          if (_nextResponseCompleter != null) {
+            _nextResponseCompleter.completeError(error);
+          }
+        },
+        onDone: () {
+          close();
+        });
   }
 
-  void flush() {
-    _requestOrResponse._streamFlush();
+  Future<_HttpIncoming> sendRequest(_HttpOutgoing outgoing) {
+    return outgoing.stream
+      .then((stream) {
+        // Close socket if output data is invalid.
+        outgoing.dataDone.catchError((e) {
+          close();
+        });
+        // Sending request, set up response completer.
+        _nextResponseCompleter = new Completer();
+        _writeDoneFuture = _socket.addStream(stream);
+        // Listen for response.
+        return _nextResponseCompleter.future
+            .whenComplete(() {
+               _nextResponseCompleter = null;
+             })
+            .then((incoming) {
+              incoming.dataDone.then((_) {
+                if (!incoming.headers.persistentConnection) {
+                  close();
+                } else {
+                  // Wait for the socket to be done with writing, before we
+                  // continue.
+                  _writeDoneFuture.then((_) {
+                    _subscription.resume();
+                    // Return connection, now we are done.
+                    _httpClient._returnConnection(this);
+                  });
+                }
+              });
+              // TODO(ajohnsen): Can there be an error on dataDone?
+              return incoming;
+            })
+            // If we see a state error, we failed to get the 'first' element.
+            // Transform the error to a HttpParserException, for consistency.
+            .catchError((error) {
+              throw new HttpParserException(
+                  "Connection closed before data was received");
+            }, test: (error) => error is StateError)
+            .catchError((error) {
+              // We are done with the socket.
+              destroy();
+              throw error;
+            });
+        });
   }
 
-  void close() {
-    _requestOrResponse._streamClose();
+  Future<Socket> detachSocket() {
+    return _writeDoneFuture.then((_) =>
+        new _DetachedSocket(_socket, _httpParser.detachIncoming()));
   }
 
-  bool get closed => _requestOrResponse._done;
-
   void destroy() {
-    throw "Not implemented";
-  }
-
-  void set onNoPendingWrites(void callback()) {
-    _requestOrResponse._streamSetNoPendingWriteHandler(callback);
-  }
-
-  void set onClosed(void callback()) {
-    _requestOrResponse._streamSetClosedHandler(callback);
-  }
-
-  void set onError(void callback(e)) {
-    _requestOrResponse._streamSetErrorHandler(callback);
-  }
-
-  _HttpRequestResponseBase _requestOrResponse;
-}
-
-
-abstract class _HttpConnectionBase {
-  static const int IDLE = 0;
-  static const int ACTIVE = 1;
-  static const int CLOSING = 2;
-  static const int REQUEST_DONE = 4;
-  static const int RESPONSE_DONE = 8;
-  static const int ALL_DONE = REQUEST_DONE | RESPONSE_DONE;
-  static const int READ_CLOSED = 16;
-  static const int WRITE_CLOSED = 32;
-  static const int FULLY_CLOSED = READ_CLOSED | WRITE_CLOSED;
-
-  _HttpConnectionBase() : hashCode = _nextHashCode {
-    _nextHashCode = (_nextHashCode + 1) & 0xFFFFFFF;
-  }
-
-  bool get _isIdle => (_state & ACTIVE) == 0;
-  bool get _isActive => (_state & ACTIVE) == ACTIVE;
-  bool get _isClosing => (_state & CLOSING) == CLOSING;
-  bool get _isRequestDone => (_state & REQUEST_DONE) == REQUEST_DONE;
-  bool get _isResponseDone => (_state & RESPONSE_DONE) == RESPONSE_DONE;
-  bool get _isAllDone => (_state & ALL_DONE) == ALL_DONE;
-  bool get _isReadClosed => (_state & READ_CLOSED) == READ_CLOSED;
-  bool get _isWriteClosed => (_state & WRITE_CLOSED) == WRITE_CLOSED;
-  bool get _isFullyClosed => (_state & FULLY_CLOSED) == FULLY_CLOSED;
-
-  void _connectionEstablished(Socket socket) {
-    _socket = socket;
-    // Register handlers for socket events. All socket events are
-    // passed to the HTTP parser.
-    _socket.onData = () {
-      List<int> buffer = _socket.read();
-      if (buffer != null) {
-        _httpParser.streamData(buffer);
-      }
-    };
-    _socket.onClosed = _httpParser.streamDone;
-    _socket.onError = _httpParser.streamError;
-    _socket.outputStream.onError = _httpParser.streamError;
-  }
-
-  bool _write(List<int> data, [bool copyBuffer = false]);
-  bool _writeFrom(List<int> buffer, [int offset, int len]);
-  bool _flush();
-  bool _close();
-  bool _destroy();
-  DetachedSocket _detachSocket();
-
-  HttpConnectionInfo get connectionInfo {
-    if (_socket == null) return null;
-    try {
-      _HttpConnectionInfo info = new _HttpConnectionInfo();
-      info.remoteHost = _socket.remoteHost;
-      info.remotePort = _socket.remotePort;
-      info.localPort = _socket.port;
-      return info;
-    } catch (e) { }
-    return null;
-  }
-
-  void set _onNoPendingWrites(void callback()) {
-    _socket.outputStream.onNoPendingWrites = callback;
-  }
-
-  int _state = IDLE;
-
-  Socket _socket;
-  _HttpParser _httpParser;
-
-  // Callbacks.
-  Function onDetach;
-  Function onClosed;
-
-  // Hash code for HTTP connection. Currently this is just a counter.
-  final int hashCode;
-  static int _nextHashCode = 0;
-}
-
-
-// HTTP server connection over a socket.
-class _HttpConnection extends _HttpConnectionBase {
-  _HttpConnection(HttpServer this._server) {
-    _httpParser = new _HttpParser.requestParser();
-    // Register HTTP parser callbacks.
-    _httpParser.requestStart = _onRequestReceived;
-    _httpParser.dataReceived = _onDataReceived;
-    _httpParser.dataEnd = _onDataEnd;
-    _httpParser.error = _onError;
-    _httpParser.closed = _onClosed;
-    _httpParser.responseStart = (statusCode, reasonPhrase, version) {
-      assert(false);
-    };
-  }
-
-  void _bufferData(List<int> data, [bool copyBuffer = false]) {
-    if (_buffer == null) _buffer = new _BufferList();
-    if (copyBuffer) data = data.getRange(0, data.length);
-    _buffer.add(data);
-  }
-
-  void _writeBufferedResponse() {
-    if (_buffer != null) {
-      while (!_buffer.isEmpty) {
-        var data = _buffer.first;
-        _socket.outputStream.write(data, false);
-        _buffer.removeBytes(data.length);
-      }
-      _buffer = null;
-    }
-  }
-
-  bool _write(List<int> data, [bool copyBuffer = false]) {
-    if (_isRequestDone || !_hasBody || _httpParser.upgrade) {
-      return _socket.outputStream.write(data, copyBuffer);
-    } else {
-      _bufferData(data, copyBuffer);
-      return false;
-    }
-  }
-
-  bool _writeFrom(List<int> data, [int offset, int len]) {
-    if (_isRequestDone || !_hasBody || _httpParser.upgrade) {
-      return _socket.outputStream.writeFrom(data, offset, len);
-    } else {
-      if (offset == null) offset = 0;
-      if (len == null) len = buffer.length - offset;
-      _bufferData(data.getRange(offset, len), false);
-      return false;
-    }
-  }
-
-  bool _flush() {
-    _socket.outputStream.flush();
-  }
-
-  bool _close() {
-    _socket.outputStream.close();
-  }
-
-  bool _destroy() {
-    _socket.close();
-  }
-
-  void _onClosed() {
-    _state |= _HttpConnectionBase.READ_CLOSED;
-    _checkDone();
-  }
-
-  DetachedSocket _detachSocket() {
-    _socket.onData = null;
-    _socket.onClosed = null;
-    _socket.onError = null;
-    _socket.outputStream.onNoPendingWrites = null;
-    _writeBufferedResponse();
-    Socket socket = _socket;
-    _socket = null;
-    if (onDetach != null) onDetach();
-    return new _DetachedSocket(socket, _httpParser.readUnparsedData());
-  }
-
-  void _onError(e) {
-    // Don't report errors for a request parser when HTTP parser is in
-    // idle state. Clients can close the connection and cause a
-    // connection reset by peer error which is OK.
-    _onClosed();
-    if (_state == _HttpConnectionBase.IDLE) return;
-
-    // Propagate the error to the streams.
-    if (_request != null &&
-        !_isRequestDone &&
-        _request._streamErrorHandler != null) {
-      _request._streamErrorHandler(e);
-    } else if (_response != null &&
-        !_isResponseDone &&
-        _response._streamErrorHandler != null) {
-      _response._streamErrorHandler(e);
-    } else {
-      onError(e);
-    }
-    if (_socket != null) _socket.close();
-  }
-
-  void _onRequestReceived(String method,
-                          String uri,
-                          String version,
-                          _HttpHeaders headers,
-                          bool hasBody) {
-    _state = _HttpConnectionBase.ACTIVE;
-    // Create new request and response objects for this request.
-    _request = new _HttpRequest(this);
-    _response = new _HttpResponse(this);
-    _request._onRequestReceived(method, uri, version, headers);
-    _request._protocolVersion = version;
-    _response._protocolVersion = version;
-    _response._headResponse = method == "HEAD";
-    _response.persistentConnection = _httpParser.persistentConnection;
-    _hasBody = hasBody;
-    if (onRequestReceived != null) {
-      onRequestReceived(_request, _response);
-    }
-    _checkDone();
-  }
-
-  void _onDataReceived(List<int> data) {
-    _request._onDataReceived(data);
-    _checkDone();
-  }
-
-  void _checkDone() {
-    if (_isReadClosed) {
-      // If the client closes the conversation is ended.
-      _server._closeQueue.add(this);
-    } else if (_isAllDone) {
-      // If we are done writing the response, and the connection is
-      // not persistent, we must close. Also if using HTTP 1.0 and the
-      // content length was not known we must close to indicate end of
-      // body.
-      bool close =
-          !_response.persistentConnection ||
-          (_response._protocolVersion == "1.0" && _response.contentLength < 0);
-      _request = null;
-      _response = null;
-      if (close) {
-        _httpParser.cancel();
-        _server._closeQueue.add(this);
-      } else {
-        _state = _HttpConnectionBase.IDLE;
-      }
-    } else if (_isResponseDone && _hasBody) {
-      // If the response is closed before the request is fully read
-      // close this connection. If there is buffered output
-      // (e.g. error response for invalid request where the server did
-      // not care to read the request body) this is send.
-      assert(!_isRequestDone);
-      _writeBufferedResponse();
-      _httpParser.cancel();
-      _server._closeQueue.add(this);
-    }
-  }
-
-  void _onDataEnd(bool close) {
-    // Start sending queued response if any.
-    _state |= _HttpConnectionBase.REQUEST_DONE;
-    _writeBufferedResponse();
-    _request._onDataEnd();
-    _checkDone();
-  }
-
-  void _responseClosed() {
-    _state |= _HttpConnectionBase.RESPONSE_DONE;
-  }
-
-  HttpServer _server;
-  HttpRequest _request;
-  HttpResponse _response;
-  bool _hasBody = false;
-
-  // Buffer for data written before full response has been processed.
-  _BufferList _buffer;
-
-  // Callbacks.
-  Function onRequestReceived;
-  Function onError;
-}
-
-
-class _RequestHandlerRegistration {
-  _RequestHandlerRegistration(Function this._matcher, Function this._handler);
-  Function _matcher;
-  Function _handler;
-}
-
-// HTTP server waiting for socket connections. The connections are
-// managed by the server and as requests are received the request.
-// HTTPS connections are also supported, if the _HttpServer.httpsServer
-// constructor is used and a certificate name is provided in listen,
-// or a SecureServerSocket is provided to listenOn.
-class _HttpServer implements HttpServer, HttpsServer {
-  _HttpServer() : this._internal(isSecure: false);
-
-  _HttpServer.httpsServer() : this._internal(isSecure: true);
-
-  _HttpServer._internal({ bool isSecure: false })
-      : _secure = isSecure,
-        _connections = new Set<_HttpConnection>(),
-        _handlers = new List<_RequestHandlerRegistration>(),
-        _closeQueue = new _CloseQueue();
-
-  void listen(String host,
-              int port,
-              {int backlog: 128,
-               String certificate_name,
-               bool requestClientCertificate: false}) {
-    if (_secure) {
-      listenOn(new SecureServerSocket(
-          host,
-          port,
-          backlog,
-          certificate_name,
-          requestClientCertificate: requestClientCertificate));
-    } else {
-      listenOn(new ServerSocket(host, port, backlog));
-    }
-    _closeServer = true;
-  }
-
-  void listenOn(ServerSocket serverSocket) {
-    if (_secure && serverSocket is! SecureServerSocket) {
-        throw new HttpException(
-            'HttpsServer.listenOn was called with non-secure server socket');
-    } else if (!_secure && serverSocket is SecureServerSocket) {
-        throw new HttpException(
-            'HttpServer.listenOn was called with a secure server socket');
-    }
-    void onConnection(Socket socket) {
-      // Accept the client connection.
-      _HttpConnection connection = new _HttpConnection(this);
-      connection._connectionEstablished(socket);
-      _connections.add(connection);
-      connection.onRequestReceived = _handleRequest;
-      connection.onClosed = () => _connections.remove(connection);
-      connection.onDetach = () => _connections.remove(connection);
-      connection.onError = (e) {
-        _connections.remove(connection);
-        if (_onError != null) {
-          _onError(e);
-        } else {
-          throw(e);
-        }
-      };
-    }
-    serverSocket.onConnection = onConnection;
-    _server = serverSocket;
-    _closeServer = false;
-  }
-
-  addRequestHandler(bool matcher(HttpRequest request),
-                    void handler(HttpRequest request, HttpResponse response)) {
-    _handlers.add(new _RequestHandlerRegistration(matcher, handler));
-  }
-
-  void set defaultRequestHandler(
-      void handler(HttpRequest request, HttpResponse response)) {
-    _defaultHandler = handler;
+    _socket.destroy();
+    _httpClient._connectionClosed(this);
   }
 
   void close() {
-    _closeQueue.shutdown();
+    var future = _writeDoneFuture;
+    if (future == null) future = new Future.immediate(null);
+    _httpClient._connectionClosed(this);
+    future.then((_) {
+      _socket.close();
+      // TODO(ajohnsen): Add timeout.
+      // Delay destroy until socket is actually done writing.
+      _socket.done.then((_) => _socket.destroy(),
+                        onError: (_) => _socket.destroy());
+    });
+  }
+
+  HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket);
+}
+
+class _ConnnectionInfo {
+  _ConnnectionInfo(_HttpClientConnection this.connection, _Proxy this.proxy);
+  final _HttpClientConnection connection;
+  final _Proxy proxy;
+}
+
+
+class _HttpClient implements HttpClient {
+  // TODO(ajohnsen): Use eviction timeout.
+  static const int DEFAULT_EVICTION_TIMEOUT = 60000;
+  bool _closing = false;
+
+  final Map<String, Queue<_HttpClientConnection>> _idleConnections
+      = new Map<String, Queue<_HttpClientConnection>>();
+  final Set<_HttpClientConnection> _activeConnections
+      = new Set<_HttpClientConnection>();
+  final List<_Credentials> _credentials = [];
+  Function _authenticate;
+  Function _findProxy;
+
+  Future<HttpClientRequest> open(String method,
+                                 String host,
+                                 int port,
+                                 String path) {
+    // TODO(sgjesse): The path set here can contain both query and
+    // fragment. They should be cracked and set correctly.
+    return _openUrl(method, new Uri.fromComponents(
+        scheme: "http", domain: host, port: port, path: path));
+  }
+
+  Future<HttpClientRequest> openUrl(String method, Uri url) {
+    return _openUrl(method, url);
+  }
+
+  Future<HttpClientRequest> get(String host,
+                                int port,
+                                String path) {
+    return open("get", host, port, path);
+  }
+
+  Future<HttpClientRequest> getUrl(Uri url) {
+    return _openUrl("get", url);
+  }
+
+  Future<HttpClientRequest> post(String host,
+                                 int port,
+                                 String path) {
+    return open("post", host, port, path);
+  }
+
+  Future<HttpClientRequest> postUrl(Uri url) {
+    return _openUrl("post", url);
+  }
+
+  void close({bool force: false}) {
+    _closing = true;
+    // Create flattened copy of _idleConnections, as 'destory' will manipulate
+    // it.
+    var idle = _idleConnections.values.reduce(
+        [],
+        (l, e) {
+          l.addAll(e);
+          return l;
+        });
+    idle.forEach((e) {
+      e.close();
+    });
+    assert(_idleConnections.isEmpty);
+    if (force) {
+      for (var connection in _activeConnections.toList()) {
+        connection.destroy();
+      }
+      assert(_activeConnections.isEmpty);
+      _activeConnections.clear();
+    }
+  }
+
+  set authenticate(Future<bool> f(Uri url, String scheme, String realm)) {
+    _authenticate = f;
+  }
+
+  void addCredentials(Uri url, String realm, HttpClientCredentials cr) {
+    _credentials.add(new _Credentials(url, realm, cr));
+  }
+
+  set findProxy(String f(Uri uri)) => _findProxy = f;
+
+  Future<HttpClientRequest> _openUrl(String method, Uri uri) {
+    if (method == null) {
+      throw new ArgumentError(method);
+    }
+    if (uri.domain.isEmpty || (uri.scheme != "http" && uri.scheme != "https")) {
+      throw new ArgumentError("Unsupported scheme '${uri.scheme}' in $uri");
+    }
+
+    bool isSecure = (uri.scheme == "https");
+    int port = uri.port;
+    if (port == 0) {
+      port = isSecure ?
+          HttpClient.DEFAULT_HTTPS_PORT :
+          HttpClient.DEFAULT_HTTP_PORT;
+    }
+    // Check to see if a proxy server should be used for this connection.
+    var proxyConf = const _ProxyConfiguration.direct();
+    if (_findProxy != null) {
+      // TODO(sgjesse): Keep a map of these as normally only a few
+      // configuration strings will be used.
+      try {
+        proxyConf = new _ProxyConfiguration(_findProxy(uri));
+      } catch (error, stackTrace) {
+        return new Future.immediateError(error, stackTrace);
+      }
+    }
+    return _getConnection(uri.domain, port, proxyConf, isSecure).then((info) {
+          // Create new internal outgoing connection.
+          var outgoing = new _HttpOutgoing();
+          // Create new request object, wrapping the outgoing connection.
+          var request = new _HttpClientRequest(outgoing,
+                                               uri,
+                                               method.toUpperCase(),
+                                               !info.proxy.isDirect,
+                                               this,
+                                               info.connection);
+          request.headers.host = uri.domain;
+          request.headers.port = port;
+          if (uri.userInfo != null && !uri.userInfo.isEmpty) {
+            // If the URL contains user information use that for basic
+            // authorization
+            String auth =
+                CryptoUtils.bytesToBase64(_encodeString(uri.userInfo));
+            request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
+          } else {
+            // Look for credentials.
+            _Credentials cr = _findCredentials(uri);
+            if (cr != null) {
+              cr.authorize(request);
+            }
+          }
+          // Start sending the request (lazy, delayed until the user provides
+          // data).
+          info.connection._httpParser.responseToMethod = method;
+          info.connection.sendRequest(outgoing)
+              .then((incoming) {
+                // The full request have been sent and a response is received
+                // containing status-code, headers and etc.
+                request._onIncoming(incoming);
+              })
+              .catchError((error) {
+                // An error occoured before the http-header was parsed. This
+                // could be either a socket-error or parser-error.
+                request._onError(error);
+              });
+          // Return the request to the user. Immediate socket errors are not
+          // handled, thus forwarded to the user.
+          return request;
+        });
+  }
+
+  Future<HttpClientRequest> _openUrlFromRequest(String method,
+                                                Uri uri,
+                                                _HttpClientRequest previous) {
+    return openUrl(method, uri).then((request) {
+          // Only follow redirects if initial request did.
+          request.followRedirects = previous.followRedirects;
+          // Allow same number of redirects.
+          request.maxRedirects = previous.maxRedirects;
+          // Copy headers
+          for (var header in previous.headers._headers.keys) {
+            if (request.headers[header] == null) {
+              request.headers.set(header, previous.headers[header]);
+            }
+          }
+          request.headers.chunkedTransferEncoding = false;
+          request.contentLength = 0;
+          return request;
+        });
+  }
+
+  // Return a live connection to the idle pool.
+  void _returnConnection(_HttpClientConnection connection) {
+    _activeConnections.remove(connection);
+    if (_closing) {
+      connection.close();
+      return;
+    }
+    // TODO(ajohnsen): Listen for socket close events.
+    if (!_idleConnections.containsKey(connection.key)) {
+      _idleConnections[connection.key] = new Queue();
+    }
+    _idleConnections[connection.key].addLast(connection);
+  }
+
+  // Remove a closed connnection from the active set.
+  void _connectionClosed(_HttpClientConnection connection) {
+    _activeConnections.remove(connection);
+    if (_idleConnections.containsKey(connection.key)) {
+      _idleConnections[connection.key].remove(connection);
+      if (_idleConnections[connection.key].isEmpty) {
+        _idleConnections.remove(connection.key);
+      }
+    }
+  }
+
+  // Get a new _HttpClientConnection, either from the idle pool or created from
+  // a new Socket.
+  Future<_ConnnectionInfo> _getConnection(String uriHost,
+                                          int uriPort,
+                                          _ProxyConfiguration proxyConf,
+                                          bool isSecure) {
+    Iterator<_Proxy> proxies = proxyConf.proxies.iterator;
+
+    Future<_ConnnectionInfo> connect(error) {
+      if (!proxies.moveNext()) return new Future.immediateError(error);
+      _Proxy proxy = proxies.current;
+      String host = proxy.isDirect ? uriHost: proxy.host;
+      int port = proxy.isDirect ? uriPort: proxy.port;
+      String key = isSecure ? "ssh:$host:$port" : "$host:$port";
+      if (_idleConnections.containsKey(key)) {
+        var connection = _idleConnections[key].removeFirst();
+        if (_idleConnections[key].isEmpty) {
+          _idleConnections.remove(key);
+        }
+        _activeConnections.add(connection);
+        return new Future.immediate(new _ConnnectionInfo(connection, proxy));
+      }
+      return (isSecure && proxy.isDirect
+                  ? SecureSocket.connect(host,
+                                         port,
+                                         sendClientCertificate: true)
+                  : Socket.connect(host, port))
+        .then((socket) {
+          var connection = new _HttpClientConnection(key, socket, this);
+          _activeConnections.add(connection);
+          return new _ConnnectionInfo(connection, proxy);
+        }, onError: (error) {
+          // Continue with next proxy.
+          return connect(error.error);
+        });
+    }
+    return connect(new HttpException("No proxies given"));
+  }
+
+  _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
+    // Look for credentials.
+    _Credentials cr =
+        _credentials.reduce(null, (_Credentials prev, _Credentials value) {
+          if (value.applies(url, scheme)) {
+            if (prev == null) return value;
+            return value.uri.path.length > prev.uri.path.length ? value : prev;
+          } else {
+            return prev;
+          }
+        });
+    return cr;
+  }
+
+  void _removeCredentials(_Credentials cr) {
+    int index = _credentials.indexOf(cr);
+    if (index != -1) {
+      _credentials.removeAt(index);
+    }
+  }
+}
+
+
+class _HttpConnection {
+  static const _ACTIVE = 0;
+  static const _IDLE = 1;
+  static const _CLOSING = 2;
+  static const _DETACHED = 3;
+
+  int _state = _IDLE;
+
+  final Socket _socket;
+  final _HttpServer _httpServer;
+  final _HttpParser _httpParser;
+  StreamSubscription _subscription;
+
+  Future _writeDoneFuture;
+
+  _HttpConnection(Socket this._socket, _HttpServer this._httpServer)
+      : _httpParser = new _HttpParser.requestParser() {
+    _socket.pipe(_httpParser);
+    _socket.done.catchError((e) => destroy());
+    _subscription = _httpParser.listen(
+        (incoming) {
+          // Only handle one incoming request at the time. Keep the
+          // stream paused until the request has been send.
+          _subscription.pause();
+          _state = _ACTIVE;
+          var outgoing = new _HttpOutgoing();
+          _writeDoneFuture = outgoing.stream.then(_socket.addStream);
+          var response = new _HttpResponse(
+              incoming.headers.protocolVersion,
+              outgoing);
+          var request = new _HttpRequest(response, incoming, _httpServer, this);
+          response._ignoreBody = request.method == "HEAD";
+          response._httpRequest = request;
+          outgoing.dataDone.then((_) {
+            if (_state == _DETACHED) return;
+            if (response.headers.persistentConnection &&
+                incoming.fullBodyRead) {
+              // Wait for the socket to be done with writing, before we
+              // continue.
+              _writeDoneFuture.then((_) {
+                _state = _IDLE;
+                // Resume the subscription for incoming requests as the
+                // request is now processed.
+                _subscription.resume();
+              });
+            } else {
+              // Close socket, keep-alive not used or body sent before received
+              // data was handled.
+              close();
+            }
+          }).catchError((e) {
+            close();
+          });
+          _httpServer._handleRequest(request);
+        },
+        onDone: () {
+          close();
+        },
+        onError: (error) {
+          _httpServer._handleError(error);
+          destroy();
+        });
+  }
+
+  void destroy() {
+    if (_state == _CLOSING || _state == _DETACHED) return;
+    _state = _CLOSING;
+    _socket.destroy();
+    _httpServer._connectionClosed(this);
+  }
+
+  void close() {
+    if (_state == _CLOSING || _state == _DETACHED) return;
+    _state = _CLOSING;
+    var future = _writeDoneFuture;
+    if (future == null) future = new Future.immediate(null);
+    _httpServer._connectionClosed(this);
+    future.then((_) {
+      _socket.close();
+      // TODO(ajohnsen): Add timeout.
+      // Delay destroy until socket is actually done writing.
+      _socket.done.then((_) => _socket.destroy(),
+                        onError: (_) => _socket.destroy());
+    });
+  }
+
+  Future<Socket> detachSocket() {
+    _state = _DETACHED;
+    // Remove connection from server.
+    _httpServer._connectionClosed(this);
+
+    _HttpDetachedIncoming detachedIncoming = _httpParser.detachIncoming();
+
+    return _writeDoneFuture.then((_) {
+      return new _DetachedSocket(_socket, detachedIncoming);
+    });
+  }
+
+  HttpConnectionInfo get connectionInfo => _HttpConnectionInfo.create(_socket);
+
+  bool get _isActive => _state == _ACTIVE;
+  bool get _isIdle => _state == _IDLE;
+  bool get _isClosing => _state == _CLOSING;
+  bool get _isDetached => _state == _DETACHED;
+}
+
+
+// HTTP server waiting for socket connections.
+class _HttpServer extends Stream<HttpRequest> implements HttpServer {
+
+  static Future<HttpServer> bind(String host, int port, int backlog) {
+    return ServerSocket.bind(host, port, backlog).then((socket) {
+      return new _HttpServer._(socket, true);
+    });
+  }
+
+  static Future<HttpServer> bindSecure(String host,
+                                       int port,
+                                       int backlog,
+                                       String certificate_name,
+                                       bool requestClientCertificate) {
+    return SecureServerSocket.bind(
+        host,
+        port,
+        backlog,
+        certificate_name,
+        requestClientCertificate: requestClientCertificate)
+        .then((socket) {
+          return new _HttpServer._(socket, true);
+        });
+  }
+
+  _HttpServer._(this._serverSocket, this._closeServer);
+
+  _HttpServer.listenOn(ServerSocket this._serverSocket)
+      : _closeServer = false;
+
+  StreamSubscription<HttpRequest> listen(void onData(HttpRequest event),
+                                         {void onError(AsyncError error),
+                                         void onDone(),
+                                         bool unsubscribeOnError}) {
+    _serverSocket.listen(
+        (Socket socket) {
+          // Accept the client connection.
+          _HttpConnection connection = new _HttpConnection(socket, this);
+          _connections.add(connection);
+        },
+        onError: _controller.signalError,
+        onDone: _controller.close);
+    return _controller.stream.listen(onData,
+                                     onError: onError,
+                                     onDone: onDone,
+                                     unsubscribeOnError: unsubscribeOnError);
+  }
+
+  void close() {
+    closed = true;
+    if (_serverSocket != null && _closeServer) {
+      _serverSocket.close();
+    }
     if (_sessionManagerInstance != null) {
       _sessionManagerInstance.close();
       _sessionManagerInstance = null;
     }
-    if (_server != null && _closeServer) {
-      _server.close();
-    }
-    _server = null;
-    for (_HttpConnection connection in _connections) {
-      connection._destroy();
+    for (_HttpConnection connection in _connections.toList()) {
+      connection.destroy();
     }
     _connections.clear();
   }
 
   int get port {
-    if (_server == null) {
-      throw new HttpException("The HttpServer is not listening on a port.");
-    }
-    return _server.port;
-  }
-
-  void set onError(void callback(e)) {
-    _onError = callback;
+    if (closed) throw new HttpException("HttpServer is not bound to a socket");
+    return _serverSocket.port;
   }
 
   set sessionTimeout(int timeout) {
     _sessionManager.sessionTimeout = timeout;
   }
 
-  void _handleRequest(HttpRequest request, HttpResponse response) {
-    for (int i = 0; i < _handlers.length; i++) {
-      if (_handlers[i]._matcher(request)) {
-        Function handler = _handlers[i]._handler;
-        try {
-          handler(request, response);
-        } catch (e) {
-          if (_onError != null) {
-            _onError(e);
-          } else {
-            throw e;
-          }
-        }
-        return;
-      }
-    }
+  void _handleRequest(HttpRequest request) {
+    _controller.add(request);
+  }
 
-    if (_defaultHandler != null) {
-      _defaultHandler(request, response);
-    } else {
-      response.statusCode = HttpStatus.NOT_FOUND;
-      response.contentLength = 0;
-      response.outputStream.close();
-    }
+  void _handleError(AsyncError error) {
+    if (!closed) _controller.signalError(error);
+  }
+
+  void _connectionClosed(_HttpConnection connection) {
+    _connections.remove(connection);
   }
 
   _HttpSessionManager get _sessionManager {
@@ -1134,671 +1415,31 @@
       } else if (conn._isIdle) {
         result.idle++;
       } else {
-        assert(result._isClosing);
+        assert(conn._isClosing);
         result.closing++;
       }
     });
     return result;
   }
 
-  ServerSocket _server;  // The server listen socket.
-  bool _closeServer = false;
-  bool _secure;
-  Set<_HttpConnection> _connections;  // Set of currently connected clients.
-  List<_RequestHandlerRegistration> _handlers;
-  Object _defaultHandler;
-  Function _onError;
-  _CloseQueue _closeQueue;
   _HttpSessionManager _sessionManagerInstance;
+
+  // Indicated if the http server has been closed.
+  bool closed = false;
+
+  // The server listen socket.
+  final ServerSocket _serverSocket;
+  final bool _closeServer;
+
+  // Set of currently connected clients.
+  final Set<_HttpConnection> _connections = new Set<_HttpConnection>();
+  final StreamController<HttpRequest> _controller
+      = new StreamController<HttpRequest>();
+
+  // TODO(ajohnsen): Use close queue?
 }
 
 
-class _HttpClientRequest
-    extends _HttpRequestResponseBase implements HttpClientRequest {
-  _HttpClientRequest(String this._method,
-                     Uri this._uri,
-                     _HttpClientConnection connection)
-      : super(connection) {
-    _headers = new _HttpHeaders();
-    _connection = connection;
-    // Default GET and HEAD requests to have no content.
-    if (_method == "GET" || _method == "HEAD") {
-      contentLength = 0;
-    }
-  }
-
-  void set contentLength(int contentLength) {
-    if (_state >= _HttpRequestResponseBase.HEADER_SENT) {
-      throw new HttpException("Header already sent");
-    }
-    _headers.contentLength = contentLength;
-  }
-
-  List<Cookie> get cookies {
-    if (_cookies == null) _cookies = new List<Cookie>();
-    return _cookies;
-  }
-
-  OutputStream get outputStream {
-    if (_done) throw new HttpException("Request closed");
-    if (_outputStream == null) {
-      _outputStream = new _HttpOutputStream(this);
-    }
-    return _outputStream;
-  }
-
-  // Delegate functions for the HttpOutputStream implementation.
-  bool _streamWrite(List<int> buffer, bool copyBuffer) {
-    if (_done) throw new HttpException("Request closed");
-    _emptyBody = _emptyBody && buffer.length == 0;
-    return _write(buffer, copyBuffer);
-  }
-
-  bool _streamWriteFrom(List<int> buffer, int offset, int len) {
-    if (_done) throw new HttpException("Request closed");
-    _emptyBody = _emptyBody && buffer.length == 0;
-    return _writeList(buffer, offset, len);
-  }
-
-  void _streamFlush() {
-    _httpConnection._flush();
-  }
-
-  void _streamClose() {
-    _ensureHeadersSent();
-    _state = _HttpRequestResponseBase.DONE;
-    // Stop tracking no pending write events.
-    _httpConnection._onNoPendingWrites = null;
-    // Ensure that any trailing data is written.
-    _writeDone();
-    _connection._requestClosed();
-    if (_streamClosedHandler != null) {
-      Timer.run(_streamClosedHandler);
-    }
-  }
-
-  void _streamSetNoPendingWriteHandler(callback()) {
-    if (_state != _HttpRequestResponseBase.DONE) {
-      _httpConnection._onNoPendingWrites = callback;
-    }
-  }
-
-  void _streamSetClosedHandler(callback()) {
-    _streamClosedHandler = callback;
-  }
-
-  void _streamSetErrorHandler(callback(e)) {
-    _streamErrorHandler = callback;
-  }
-
-  void _writeHeader() {
-    List<int> data;
-
-    // Write request line.
-    data = _method.toString().charCodes;
-    _httpConnection._write(data);
-    _writeSP();
-    // Send the path for direct connections and the whole URL for
-    // proxy connections.
-    if (!_connection._usingProxy) {
-      String path = _uri.path;
-      if (path.length == 0) path = "/";
-      if (_uri.query != "") {
-        if (_uri.fragment != "") {
-          path = "${path}?${_uri.query}#${_uri.fragment}";
-        } else {
-          path = "${path}?${_uri.query}";
-        }
-      }
-      data = path.charCodes;
-    } else {
-      data = _uri.toString().charCodes;
-    }
-    _httpConnection._write(data);
-    _writeSP();
-    _httpConnection._write(_Const.HTTP11);
-    _writeCRLF();
-
-    // Add the cookies to the headers.
-    if (_cookies != null) {
-      StringBuffer sb = new StringBuffer();
-      for (int i = 0; i < _cookies.length; i++) {
-        if (i > 0) sb.add("; ");
-        sb.add(_cookies[i].name);
-        sb.add("=");
-        sb.add(_cookies[i].value);
-      }
-      _headers.add("cookie", sb.toString());
-    }
-
-    // Write headers.
-    _headers._finalize("1.1");
-    _writeHeaders();
-    _state = _HttpRequestResponseBase.HEADER_SENT;
-  }
-
-  String _method;
-  Uri _uri;
-  _HttpClientConnection _connection;
-  _HttpOutputStream _outputStream;
-  Function _streamClosedHandler;
-  Function _streamErrorHandler;
-  bool _emptyBody = true;
-}
-
-class _HttpClientResponse
-    extends _HttpRequestResponseBase
-    implements HttpClientResponse {
-  _HttpClientResponse(_HttpClientConnection connection)
-      : super(connection) {
-    _connection = connection;
-  }
-
-  int get statusCode => _statusCode;
-  String get reasonPhrase => _reasonPhrase;
-
-  bool get isRedirect {
-    var method = _connection._request._method;
-    if (method == "GET" || method == "HEAD") {
-      return statusCode == HttpStatus.MOVED_PERMANENTLY ||
-             statusCode == HttpStatus.FOUND ||
-             statusCode == HttpStatus.SEE_OTHER ||
-             statusCode == HttpStatus.TEMPORARY_REDIRECT;
-    } else if (method == "POST") {
-      return statusCode == HttpStatus.SEE_OTHER;
-    }
-    return false;
-  }
-
-  List<Cookie> get cookies {
-    if (_cookies != null) return _cookies;
-    _cookies = new List<Cookie>();
-    List<String> values = _headers["set-cookie"];
-    if (values != null) {
-      values.forEach((value) {
-        _cookies.add(new Cookie.fromSetCookieValue(value));
-      });
-    }
-    return _cookies;
-  }
-
-  InputStream get inputStream {
-    if (_inputStream == null) {
-      _inputStream = new _HttpInputStream(this);
-    }
-    return _inputStream;
-  }
-
-  void _onResponseReceived(int statusCode,
-                           String reasonPhrase,
-                           String version,
-                           _HttpHeaders headers,
-                           bool hasBody) {
-    _statusCode = statusCode;
-    _reasonPhrase = reasonPhrase;
-    _headers = headers;
-
-    // Prepare for receiving data.
-    _buffer = new _BufferList();
-    if (isRedirect && _connection.followRedirects) {
-      if (_connection._redirects == null ||
-          _connection._redirects.length < _connection.maxRedirects) {
-        // Check the location header.
-        List<String> location = headers[HttpHeaders.LOCATION];
-        if (location == null || location.length > 1) {
-           throw new RedirectException("Invalid redirect",
-                                       _connection._redirects);
-        }
-        // Check for redirect loop
-        if (_connection._redirects != null) {
-          Uri redirectUrl = Uri.parse(location[0]);
-          for (int i = 0; i < _connection._redirects.length; i++) {
-            if (_connection._redirects[i].location.toString() ==
-                redirectUrl.toString()) {
-              throw new RedirectLoopException(_connection._redirects);
-            }
-          }
-        }
-        if (!persistentConnection) {
-          throw new RedirectException(
-              "Non-persistent connections are currently not supported for "
-              "redirects", _connection._redirects);
-        }
-        // Drain body and redirect.
-        inputStream.onData = inputStream.read;
-        if (_statusCode == HttpStatus.SEE_OTHER &&
-            _connection._method == "POST") {
-          _connection.redirect("GET");
-        } else {
-          _connection.redirect();
-        }
-      } else {
-        throw new RedirectLimitExceededException(_connection._redirects);
-      }
-    } else if (statusCode == HttpStatus.UNAUTHORIZED) {
-      _handleUnauthorized();
-    } else if (_connection._onResponse != null) {
-      _connection._onResponse(this);
-    }
-  }
-
-  void _handleUnauthorized() {
-
-    void retryRequest(_Credentials cr) {
-      if (cr != null) {
-        // Drain body and retry.
-        // TODO(sgjesse): Support digest.
-        if (cr.scheme == _AuthenticationScheme.BASIC) {
-          inputStream.onData = inputStream.read;
-          _connection._retry();
-          return;
-        }
-      }
-
-      // Fall through to here to perform normal response handling if
-      // there is no sensible authorization handling.
-      if (_connection._onResponse != null) {
-        _connection._onResponse(this);
-      }
-    }
-
-    // Only try to authenticate if there is a challenge in the response.
-    List<String> challenge = _headers[HttpHeaders.WWW_AUTHENTICATE];
-    if (challenge != null && challenge.length == 1) {
-      _HeaderValue header =
-          new _HeaderValue.fromString(challenge[0], parameterSeparator: ",");
-      _AuthenticationScheme scheme =
-          new _AuthenticationScheme.fromString(header.value);
-      String realm = header.parameters["realm"];
-
-      // See if any credentials are available.
-      _Credentials cr =
-          _connection._client._findCredentials(
-              _connection._request._uri, scheme);
-
-      // Ask for more credentials if none found or the one found has
-      // already been used. If it has already been used it must now be
-      // invalid and is removed.
-      if (cr == null || cr.used) {
-        if (cr != null) {
-          _connection._client._removeCredentials(cr);
-        }
-        cr = null;
-        if (_connection._client._authenticate != null) {
-          Future authComplete =
-              _connection._client._authenticate(
-                  _connection._request._uri, scheme.toString(), realm);
-          authComplete.then((credsAvailable) {
-            if (credsAvailable) {
-              cr = _connection._client._findCredentials(
-                  _connection._request._uri, scheme);
-              retryRequest(cr);
-            } else {
-              if (_connection._onResponse != null) {
-                _connection._onResponse(this);
-              }
-            }
-          });
-          return;
-        }
-      } else {
-        // If credentials found prepare for retrying the request.
-        retryRequest(cr);
-        return;
-      }
-    }
-
-    // Fall through to here to perform normal response handling if
-    // there is no sensible authorization handling.
-    if (_connection._onResponse != null) {
-      _connection._onResponse(this);
-    }
-  }
-
-  void _onDataReceived(List<int> data) {
-    _buffer.add(data);
-    if (_inputStream != null) _inputStream._dataReceived();
-  }
-
-  void _onDataEnd() {
-    if (_inputStream != null) {
-      _inputStream._closeReceived();
-    } else {
-      inputStream._streamMarkedClosed = true;
-    }
-  }
-
-  // Delegate functions for the HttpInputStream implementation.
-  int _streamAvailable() {
-    return _buffer.length;
-  }
-
-  List<int> _streamRead(int bytesToRead) {
-    return _buffer.readBytes(bytesToRead);
-  }
-
-  int _streamReadInto(List<int> buffer, int offset, int len) {
-    List<int> data = _buffer.readBytes(len);
-    buffer.setRange(offset, data.length, data);
-    return data.length;
-  }
-
-  void _streamSetErrorHandler(callback(e)) {
-    _streamErrorHandler = callback;
-  }
-
-  int _statusCode;
-  String _reasonPhrase;
-
-  _HttpClientConnection _connection;
-  _HttpInputStream _inputStream;
-  _BufferList _buffer;
-
-  Function _streamErrorHandler;
-}
-
-
-class _HttpClientConnection
-    extends _HttpConnectionBase implements HttpClientConnection {
-
-  _HttpClientConnection(_HttpClient this._client) {
-    _httpParser = new _HttpParser.responseParser();
-  }
-
-  bool _write(List<int> data, [bool copyBuffer = false]) {
-    return _socket.outputStream.write(data, copyBuffer);
-  }
-
-  bool _writeFrom(List<int> data, [int offset, int len]) {
-    return _socket.outputStream.writeFrom(data, offset, len);
-  }
-
-  bool _flush() {
-    _socket.outputStream.flush();
-  }
-
-  bool _close() {
-    _socket.outputStream.close();
-  }
-
-  bool _destroy() {
-    _socket.close();
-  }
-
-  DetachedSocket _detachSocket() {
-    _socket.onData = null;
-    _socket.onClosed = null;
-    _socket.onError = null;
-    _socket.outputStream.onNoPendingWrites = null;
-    Socket socket = _socket;
-    _socket = null;
-    if (onDetach != null) onDetach();
-    return new _DetachedSocket(socket, _httpParser.readUnparsedData());
-  }
-
-  void _connectionEstablished(_SocketConnection socketConn) {
-    super._connectionEstablished(socketConn._socket);
-    _socketConn = socketConn;
-    // Register HTTP parser callbacks.
-    _httpParser.responseStart = _onResponseReceived;
-    _httpParser.dataReceived = _onDataReceived;
-    _httpParser.dataEnd = _onDataEnd;
-    _httpParser.error = _onError;
-    _httpParser.closed = _onClosed;
-    _httpParser.requestStart = (method, uri, version) { assert(false); };
-    _state = _HttpConnectionBase.ACTIVE;
-  }
-
-  void _checkSocketDone() {
-    if (_isAllDone) {
-      // If we are done writing the response, and either the server
-      // has closed or the connection is not persistent, we must
-      // close.
-      if (_isReadClosed || !_response.persistentConnection) {
-        this.onClosed = () {
-          _client._closedSocketConnection(_socketConn);
-        };
-        _client._closeQueue.add(this);
-      } else if (_socket != null) {
-        _client._returnSocketConnection(_socketConn);
-        _socket = null;
-        _socketConn = null;
-        assert(_pendingRedirect == null || _pendingRetry == null);
-        if (_pendingRedirect != null) {
-          _doRedirect(_pendingRedirect);
-          _pendingRedirect = null;
-        } else if (_pendingRetry != null) {
-          _doRetry(_pendingRetry);
-          _pendingRetry = null;
-        }
-      }
-    }
-  }
-
-  void _requestClosed() {
-    _state |= _HttpConnectionBase.REQUEST_DONE;
-    _checkSocketDone();
-  }
-
-  HttpClientRequest open(String method, Uri uri) {
-    _method = method;
-    // Tell the HTTP parser the method it is expecting a response to.
-    _httpParser.responseToMethod = method;
-    // If the connection already have a request this is a retry of a
-    // request. In this case the request object is reused to ensure
-    // that the same headers are send.
-    if (_request != null) {
-      _request._method = method;
-      _request._uri = uri;
-      _request._headers._mutable = true;
-      _request._state = _HttpRequestResponseBase.START;
-    } else {
-      _request = new _HttpClientRequest(method, uri, this);
-    }
-    _response = new _HttpClientResponse(this);
-    return _request;
-  }
-
-  DetachedSocket detachSocket() {
-    return _detachSocket();
-  }
-
-  void _onClosed() {
-    _state |= _HttpConnectionBase.READ_CLOSED;
-    _checkSocketDone();
-  }
-
-  void _onError(e) {
-    // Cancel any pending data in the HTTP parser.
-    _httpParser.cancel();
-    if (_socketConn != null) {
-      _client._closeSocketConnection(_socketConn);
-    }
-
-    // If it looks as if we got a bad connection from the connection
-    // pool and the request can be retried do a retry.
-    if (_socketConn != null && _socketConn._fromPool && _request._emptyBody) {
-      String method = _request._method;
-      Uri uri = _request._uri;
-      _socketConn = null;
-
-      // Retry the URL using the same connection instance.
-      _httpParser.restart();
-      _client._openUrl(method, uri, this);
-    } else {
-      // Report the error.
-      if (_response != null && _response._streamErrorHandler != null) {
-         _response._streamErrorHandler(e);
-      } else if (_onErrorCallback != null) {
-        _onErrorCallback(e);
-      } else {
-        throw e;
-      }
-    }
-  }
-
-  void _onResponseReceived(int statusCode,
-                           String reasonPhrase,
-                           String version,
-                           _HttpHeaders headers,
-                           bool hasBody) {
-    _response._onResponseReceived(
-        statusCode, reasonPhrase, version, headers, hasBody);
-  }
-
-  void _onDataReceived(List<int> data) {
-    _response._onDataReceived(data);
-  }
-
-  void _onDataEnd(bool close) {
-    _state |= _HttpConnectionBase.RESPONSE_DONE;
-    _response._onDataEnd();
-    _checkSocketDone();
-  }
-
-  void _onClientShutdown() {
-    if (!_isResponseDone) {
-      _onError(new HttpException("Client shutdown"));
-    }
-  }
-
-  void set onRequest(void handler(HttpClientRequest request)) {
-    _onRequest = handler;
-  }
-
-  void set onResponse(void handler(HttpClientResponse response)) {
-    _onResponse = handler;
-  }
-
-  void set onError(void callback(e)) {
-    _onErrorCallback = callback;
-  }
-
-  void _doRetry(_RedirectInfo retry) {
-    assert(_socketConn == null);
-
-    // Retry the URL using the same connection instance.
-    _state = _HttpConnectionBase.IDLE;
-    _client._openUrl(retry.method, retry.location, this);
-  }
-
-  void _retry() {
-    var retry = new _RedirectInfo(_response.statusCode, _method, _request._uri);
-    // The actual retry is postponed until both response and request
-    // are done.
-    if (_isAllDone) {
-      _doRetry(retry);
-    } else {
-      // Prepare for retry.
-      assert(_pendingRedirect == null);
-      _pendingRetry = retry;
-    }
-  }
-
-  void _doRedirect(_RedirectInfo redirect) {
-    assert(_socketConn == null);
-
-    if (_redirects == null) {
-      _redirects = new List<_RedirectInfo>();
-    }
-    _redirects.add(redirect);
-    _doRetry(redirect);
-  }
-
-  void redirect([String method, Uri url]) {
-    if (method == null) method = _method;
-    if (url == null) {
-      url = Uri.parse(_response.headers.value(HttpHeaders.LOCATION));
-    }
-    // Always set the content length to 0 for redirects.
-    var mutable = _request._headers._mutable;
-    _request._headers._mutable = true;
-    _request._headers.contentLength = 0;
-    _request._headers._mutable = mutable;
-    _request._bodyBytesWritten = 0;
-    var redirect = new _RedirectInfo(_response.statusCode, method, url);
-    // The actual redirect is postponed until both response and
-    // request are done.
-    assert(_pendingRetry == null);
-    _pendingRedirect = redirect;
-  }
-
-  List<RedirectInfo> get redirects => _redirects;
-
-  Function _onRequest;
-  Function _onResponse;
-  Function _onErrorCallback;
-
-  _HttpClient _client;
-  _SocketConnection _socketConn;
-  HttpClientRequest _request;
-  HttpClientResponse _response;
-  String _method;
-  bool _usingProxy;
-
-  // Redirect handling
-  bool followRedirects = true;
-  int maxRedirects = 5;
-  List<_RedirectInfo> _redirects;
-  _RedirectInfo _pendingRedirect;
-  _RedirectInfo _pendingRetry;
-
-  // Callbacks.
-  var requestReceived;
-}
-
-
-// Class for holding keep-alive sockets in the cache for the HTTP
-// client together with the connection information.
-class _SocketConnection {
-  _SocketConnection(String this._host,
-                    int this._port,
-                    Socket this._socket);
-
-  void _markReturned() {
-    // Any activity on the socket while waiting in the pool will
-    // invalidate the connection os that it is not reused.
-    _socket.onData = _invalidate;
-    _socket.onClosed = _invalidate;
-    _socket.onError = (_) => _invalidate();
-    _returnTime = new DateTime.now();
-    _httpClientConnection = null;
-  }
-
-  void _markRetrieved() {
-    _socket.onData = null;
-    _socket.onClosed = null;
-    _socket.onError = null;
-    _httpClientConnection = null;
-  }
-
-  void _close() {
-    _socket.onData = null;
-    _socket.onClosed = null;
-    _socket.onError = null;
-    _httpClientConnection = null;
-    _socket.close();
-  }
-
-  Duration _idleTime(DateTime now) => now.difference(_returnTime);
-
-  bool get _fromPool => _returnTime != null;
-
-  void _invalidate() {
-    _valid = false;
-    _close();
-  }
-
-  int get hashCode => _socket.hashCode;
-
-  String _host;
-  int _port;
-  Socket _socket;
-  DateTime _returnTime;
-  bool _valid = true;
-  HttpClientConnection _httpClientConnection;
-}
-
 class _ProxyConfiguration {
   static const String PROXY_PREFIX = "PROXY ";
   static const String DIRECT_PREFIX = "DIRECT";
@@ -1844,6 +1485,7 @@
   final List<_Proxy> proxies;
 }
 
+
 class _Proxy {
   const _Proxy(this.host, this.port) : isDirect = false;
   const _Proxy.direct() : host = null, port = null, isDirect = true;
@@ -1853,376 +1495,59 @@
   final bool isDirect;
 }
 
-class _HttpClient implements HttpClient {
-  static const int DEFAULT_EVICTION_TIMEOUT = 60000;
-
-  _HttpClient() : _openSockets = new Map(),
-                  _activeSockets = new Set(),
-                  _closeQueue = new _CloseQueue(),
-                  credentials = new List<_Credentials>(),
-                  _shutdown = false;
-
-  HttpClientConnection open(
-      String method, String host, int port, String path) {
-    // TODO(sgjesse): The path set here can contain both query and
-    // fragment. They should be cracked and set correctly.
-    return _open(method, new Uri.fromComponents(
-        scheme: "http", domain: host, port: port, path: path));
-  }
-
-  HttpClientConnection _open(String method,
-                             Uri uri,
-                             [_HttpClientConnection connection]) {
-    if (_shutdown) throw new HttpException("HttpClient shutdown");
-    if (method == null || uri.domain.isEmpty) {
-      throw new ArgumentError(null);
-    }
-    return _prepareHttpClientConnection(method, uri, connection);
-  }
-
-  HttpClientConnection openUrl(String method, Uri url) {
-    return _openUrl(method, url);
-  }
-
-  HttpClientConnection _openUrl(String method,
-                                Uri url,
-                                [_HttpClientConnection connection]) {
-    if (url.scheme != "http" && url.scheme != "https") {
-      throw new HttpException("Unsupported URL scheme ${url.scheme}");
-    }
-    return _open(method, url, connection);
-  }
-
-  HttpClientConnection get(String host, int port, String path) {
-    return open("GET", host, port, path);
-  }
-
-  HttpClientConnection getUrl(Uri url) => _openUrl("GET", url);
-
-  HttpClientConnection post(String host, int port, String path) {
-    return open("POST", host, port, path);
-  }
-
-  HttpClientConnection postUrl(Uri url) => _openUrl("POST", url);
-
-  set authenticate(Future<bool> f(Uri url, String scheme, String realm)) {
-    _authenticate = f;
-  }
-
-  void addCredentials(
-      Uri url, String realm, HttpClientCredentials cr) {
-    credentials.add(new _Credentials(url, realm, cr));
-  }
-
-  set sendClientCertificate(bool send) => _sendClientCertificate = send;
-
-  set clientCertificate(String nickname) => _clientCertificate = nickname;
-
-  set findProxy(String f(Uri uri)) => _findProxy = f;
-
-  void shutdown({bool force: false}) {
-    if (force) _closeQueue.shutdown();
-    new Map.from(_openSockets).forEach(
-        (String key, Queue<_SocketConnection> connections) {
-      while (!connections.isEmpty) {
-        _SocketConnection socketConn = connections.removeFirst();
-        socketConn._socket.close();
-      }
-    });
-    if (force) {
-      _activeSockets.toList().forEach((_SocketConnection socketConn) {
-        socketConn._httpClientConnection._onClientShutdown();
-        socketConn._close();
-      });
-    }
-    if (_evictionTimer != null) _cancelEvictionTimer();
-    _shutdown = true;
-  }
-
-  void _cancelEvictionTimer() {
-    _evictionTimer.cancel();
-    _evictionTimer = null;
-  }
-
-  String _connectionKey(String host, int port) {
-    return "$host:$port";
-  }
-
-  HttpClientConnection _prepareHttpClientConnection(
-      String method,
-      Uri url,
-      [_HttpClientConnection connection]) {
-
-    void _establishConnection(String host,
-                              int port,
-                              _ProxyConfiguration proxyConfiguration,
-                              int proxyIndex,
-                              bool reusedConnection,
-                              bool secure) {
-
-      void _connectionOpened(_SocketConnection socketConn,
-                             _HttpClientConnection connection,
-                             bool usingProxy) {
-        socketConn._httpClientConnection = connection;
-        connection._usingProxy = usingProxy;
-        connection._connectionEstablished(socketConn);
-        HttpClientRequest request = connection.open(method, url);
-        request.headers.host = host;
-        request.headers.port = port;
-        if (url.userInfo != null && !url.userInfo.isEmpty) {
-          // If the URL contains user information use that for basic
-          // authorization
-          _UTF8Encoder encoder = new _UTF8Encoder();
-          String auth =
-              CryptoUtils.bytesToBase64(encoder.encodeString(url.userInfo));
-          request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
-        } else {
-          // Look for credentials.
-          _Credentials cr = _findCredentials(url);
-          if (cr != null) {
-            cr.authorize(request);
-          }
-        }
-        // A reused connection is indicating either redirect or retry
-        // where the onRequest callback should not be issued again.
-        if (connection._onRequest != null && !reusedConnection) {
-          connection._onRequest(request);
-        } else {
-          request.outputStream.close();
-        }
-      }
-
-      assert(proxyIndex < proxyConfiguration.proxies.length);
-
-      // Determine the actual host to connect to.
-      String connectHost;
-      int connectPort;
-      _Proxy proxy = proxyConfiguration.proxies[proxyIndex];
-      if (proxy.isDirect) {
-        connectHost = host;
-        connectPort = port;
-      } else {
-        connectHost = proxy.host;
-        connectPort = proxy.port;
-      }
-
-      // If there are active connections for this key get the first one
-      // otherwise create a new one.
-      String key = _connectionKey(connectHost, connectPort);
-      Queue socketConnections = _openSockets[key];
-      // Remove active connections that are not valid any more or of
-      // the wrong type (HTTP or HTTPS).
-      if (socketConnections != null) {
-        while (!socketConnections.isEmpty) {
-          if (socketConnections.first._valid) {
-            // If socket has the same properties, exit loop with found socket.
-            var socket = socketConnections.first._socket;
-            if (!secure && socket is! SecureSocket) break;
-            if (secure && socket is SecureSocket &&
-                 _sendClientCertificate == socket.sendClientCertificate &&
-                 _clientCertificate == socket.certificateName) break;
-          }
-          socketConnections.removeFirst()._close();
-        }
-      }
-      if (socketConnections == null || socketConnections.isEmpty) {
-        Socket socket = secure ?
-            new SecureSocket(connectHost,
-                             connectPort,
-                             sendClientCertificate: _sendClientCertificate,
-                             certificateName: _clientCertificate) :
-            new Socket(connectHost, connectPort);
-        // Until the connection is established handle connection errors
-        // here as the HttpClientConnection object is not yet associated
-        // with the socket.
-        socket.onError = (e) {
-          proxyIndex++;
-          if (proxyIndex < proxyConfiguration.proxies.length) {
-            // Try the next proxy in the list.
-            _establishConnection(
-                host, port, proxyConfiguration, proxyIndex, false, secure);
-          } else {
-            // Report the error through the HttpClientConnection object to
-            // the client.
-            connection._onError(e);
-          }
-        };
-        socket.onConnect = () {
-          // When the connection is established, clear the error
-          // callback as it will now be handled by the
-          // HttpClientConnection object which will be associated with
-          // the connected socket.
-          socket.onError = null;
-          _SocketConnection socketConn =
-              new _SocketConnection(connectHost, connectPort, socket);
-          _activeSockets.add(socketConn);
-          _connectionOpened(socketConn, connection, !proxy.isDirect);
-        };
-      } else {
-        _SocketConnection socketConn = socketConnections.removeFirst();
-        socketConn._markRetrieved();
-        _activeSockets.add(socketConn);
-        Timer.run(() =>
-                  _connectionOpened(socketConn, connection, !proxy.isDirect));
-
-        // Get rid of eviction timer if there are no more active connections.
-        if (socketConnections.isEmpty) _openSockets.remove(key);
-        if (_openSockets.isEmpty) _cancelEvictionTimer();
-      }
-    }
-
-    // Find out if we want a secure socket.
-    bool is_secure = (url.scheme == "https");
-
-    // Find the TCP host and port.
-    String host = url.domain;
-    int port = url.port;
-    if (port == 0) {
-      port = is_secure ?
-          HttpClient.DEFAULT_HTTPS_PORT :
-          HttpClient.DEFAULT_HTTP_PORT;
-    }
-    // Create a new connection object if we are not re-using an existing one.
-    var reusedConnection = false;
-    if (connection == null) {
-      connection = new _HttpClientConnection(this);
-    } else {
-      reusedConnection = true;
-    }
-    connection.onDetach = () => _activeSockets.remove(connection._socketConn);
-
-    // Check to see if a proxy server should be used for this connection.
-    _ProxyConfiguration proxyConfiguration = const _ProxyConfiguration.direct();
-    if (_findProxy != null) {
-      // TODO(sgjesse): Keep a map of these as normally only a few
-      // configuration strings will be used.
-      proxyConfiguration = new _ProxyConfiguration(_findProxy(url));
-    }
-
-    // Establish the connection starting with the first proxy configured.
-    _establishConnection(host,
-                         port,
-                         proxyConfiguration,
-                         0,
-                         reusedConnection,
-                         is_secure);
-
-    return connection;
-  }
-
-  void _returnSocketConnection(_SocketConnection socketConn) {
-    // If the HTTP client is being shutdown don't return the connection.
-    if (_shutdown) {
-      socketConn._close();
-      return;
-    };
-
-    // Mark socket as returned to unregister from the old connection.
-    socketConn._markReturned();
-
-    String key = _connectionKey(socketConn._host, socketConn._port);
-
-    // Get or create the connection list for this key.
-    Queue sockets = _openSockets[key];
-    if (sockets == null) {
-      sockets = new Queue();
-      _openSockets[key] = sockets;
-    }
-
-    // If there is currently no eviction timer start one.
-    if (_evictionTimer == null) {
-      void _handleEviction(Timer timer) {
-        DateTime now = new DateTime.now();
-        List<String> emptyKeys = new List<String>();
-        _openSockets.forEach(
-            (String key, Queue<_SocketConnection> connections) {
-              // As returned connections are added at the head of the
-              // list remove from the tail.
-              while (!connections.isEmpty) {
-                _SocketConnection socketConn = connections.last;
-                if (socketConn._idleTime(now).inMilliseconds >
-                    DEFAULT_EVICTION_TIMEOUT) {
-                  connections.removeLast();
-                  socketConn._socket.close();
-                  if (connections.isEmpty) emptyKeys.add(key);
-                } else {
-                  break;
-                }
-              }
-            });
-
-        // Remove the keys for which here are no more open connections.
-        emptyKeys.forEach((String key) => _openSockets.remove(key));
-
-        // If all connections where evicted cancel the eviction timer.
-        if (_openSockets.isEmpty) _cancelEvictionTimer();
-      }
-      _evictionTimer = new Timer.repeating(const Duration(seconds: 10),
-                                           _handleEviction);
-    }
-
-    // Return connection.
-    _activeSockets.remove(socketConn);
-    sockets.addFirst(socketConn);
-  }
-
-  void _closeSocketConnection(_SocketConnection socketConn) {
-    socketConn._close();
-    _activeSockets.remove(socketConn);
-  }
-
-  void _closedSocketConnection(_SocketConnection socketConn) {
-    _activeSockets.remove(socketConn);
-  }
-
-  _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
-    // Look for credentials.
-    _Credentials cr =
-        credentials.reduce(null, (_Credentials prev, _Credentials value) {
-          if (value.applies(url, scheme)) {
-            if (prev == null) return value;
-            return value.uri.path.length > prev.uri.path.length ? value : prev;
-          } else {
-            return prev;
-          }
-        });
-    return cr;
-  }
-
-  void _removeCredentials(_Credentials cr) {
-    int index = credentials.indexOf(cr);
-    if (index != -1) {
-      credentials.removeAt(index);
-    }
-  }
-
-  Function _onOpen;
-  Map<String, Queue<_SocketConnection>> _openSockets;
-  Set<_SocketConnection> _activeSockets;
-  _CloseQueue _closeQueue;
-  List<_Credentials> credentials;
-  Timer _evictionTimer;
-  Function _findProxy;
-  Function _authenticate;
-  bool _sendClientCertificate = false;
-  String _clientCertificate;
-  bool _shutdown;  // Has this HTTP client been shutdown?
-}
-
 
 class _HttpConnectionInfo implements HttpConnectionInfo {
+  static _HttpConnectionInfo create(Socket socket) {
+    if (socket == null) return null;
+    try {
+      _HttpConnectionInfo info = new _HttpConnectionInfo._();
+      info.remoteHost = socket.remoteHost;
+      info.remotePort = socket.remotePort;
+      info.localPort = socket.port;
+      return info;
+    } catch (e) { }
+    return null;
+  }
+
+  _HttpConnectionInfo._();
+
   String remoteHost;
   int remotePort;
   int localPort;
 }
 
 
-class _DetachedSocket implements DetachedSocket {
-  _DetachedSocket(this._socket, this._unparsedData);
-  Socket get socket => _socket;
-  List<int> get unparsedData => _unparsedData;
-  Socket _socket;
-  List<int> _unparsedData;
+class _DetachedSocket implements Socket {
+  final Stream<List<int>> _incoming;
+  final Socket _socket;
+
+  _DetachedSocket(this._socket, this._incoming);
+
+  StreamSubscription<List<int>> listen(void onData(List<int> event),
+                                       {void onError(AsyncError error),
+                                        void onDone(),
+                                        bool unsubscribeOnError}) {
+    return _incoming.listen(onData,
+                            onError: onError,
+                            onDone: onDone,
+                            unsubscribeOnError: unsubscribeOnError);
+  }
+
+  Future<Socket> consume(Stream<List<int>> stream) {
+    return _socket.consume(stream);
+  }
+
+  Future<Socket> addStream(Stream<List<int>> stream) {
+    return _socket.addStream(stream);
+  }
+
+  void addString(String string, [Encoding encoding = Encoding.UTF_8]) {
+    return _socket.addString(string, encoding);
+  }
+
+  void destroy() => _socket.destroy();
+  void add(List<int> data) => _socket.add(data);
+  Future<Socket> close() => _socket.close();
 }
 
 
@@ -2272,7 +1597,7 @@
   bool used = false;
   Uri uri;
   String realm;
-  HttpClientCredentials credentials;
+  _HttpClientCredentials credentials;
 
   // Digest specific fields.
   String nonce;
@@ -2283,11 +1608,13 @@
 
 abstract class _HttpClientCredentials implements HttpClientCredentials {
   _AuthenticationScheme get scheme;
-  void authorize(HttpClientRequest request);
+  void authorize(_Credentials credentials, HttpClientRequest request);
 }
 
 
-class _HttpClientBasicCredentials implements HttpClientBasicCredentials {
+class _HttpClientBasicCredentials
+    extends _HttpClientCredentials
+    implements HttpClientBasicCredentials {
   _HttpClientBasicCredentials(this.username,
                               this.password);
 
@@ -2300,10 +1627,8 @@
     // Proxy-Authenticate headers, see
     // http://tools.ietf.org/html/draft-reschke-basicauth-enc-06. For
     // now always use UTF-8 encoding.
-    _UTF8Encoder encoder = new _UTF8Encoder();
     String auth =
-        CryptoUtils.bytesToBase64(encoder.encodeString(
-            "$username:$password"));
+        CryptoUtils.bytesToBase64(_encodeString("$username:$password"));
     request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
   }
 
@@ -2312,7 +1637,9 @@
 }
 
 
-class _HttpClientDigestCredentials implements HttpClientDigestCredentials {
+class _HttpClientDigestCredentials
+    extends _HttpClientCredentials
+    implements HttpClientDigestCredentials {
   _HttpClientDigestCredentials(this.username,
                                this.password);
 
@@ -2328,7 +1655,6 @@
 }
 
 
-
 class _RedirectInfo implements RedirectInfo {
   const _RedirectInfo(int this.statusCode,
                       String this.method,
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index c0a2819..7dc258e 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -74,11 +74,9 @@
   static const int BODY = 24;
   static const int CLOSED = 25;
   static const int UPGRADED = 26;
-  static const int CANCELED = 27;
-  static const int FAILURE = 28;
+  static const int FAILURE = 27;
 
   static const int FIRST_BODY_STATE = CHUNK_SIZE_STARTING_CR;
-  static const int FIRST_PARSE_STOP_STATE = CLOSED;
 }
 
 // HTTP version of the request or response being parsed.
@@ -95,22 +93,87 @@
   static const int RESPONSE = 0;
 }
 
+class _HttpDetachedIncoming extends Stream<List<int>> {
+  StreamController<List<int>> controller;
+  final StreamSubscription subscription;
+
+  List<int> carryOverData;
+  bool paused;
+
+  Completer resumeCompleter;
+
+  _HttpDetachedIncoming(StreamSubscription this.subscription,
+                        List<int> this.carryOverData,
+                        Completer oldResumeCompleter) {
+    controller = new StreamController<List<int>>(
+        onSubscriptionStateChange: onSubscriptionStateChange,
+        onPauseStateChange: onPauseStateChange);
+    pause();
+    if (oldResumeCompleter != null) oldResumeCompleter.complete();
+    subscription.resume();
+    subscription.onData(controller.add);
+    subscription.onDone(controller.close);
+    subscription.onError(controller.signalError);
+  }
+
+  StreamSubscription<List<int>> listen(void onData(List<int> event),
+                                       {void onError(AsyncError error),
+                                        void onDone(),
+                                        bool unsubscribeOnError}) {
+    return controller.stream.listen(
+        onData,
+        onError: onError,
+        onDone: onDone,
+        unsubscribeOnError: unsubscribeOnError);
+  }
+
+  void resume() {
+    paused = false;
+    if (carryOverData != null) {
+      var data = carryOverData;
+      carryOverData = null;
+      controller.add(data);
+      // If the consumer pauses again after the carry-over data, we'll not
+      // continue our subscriber until the next resume.
+      if (paused) return;
+    }
+    if (resumeCompleter != null) {
+      resumeCompleter.complete();
+      resumeCompleter = null;
+    }
+  }
+
+  void pause() {
+    paused = true;
+    if (resumeCompleter == null) {
+      resumeCompleter = new Completer();
+      subscription.pause(resumeCompleter.future);
+    }
+  }
+
+  void onPauseStateChange() {
+    if (controller.isPaused) {
+      pause();
+    } else {
+      resume();
+    }
+  }
+
+  void onSubscriptionStateChange() {
+    if (controller.hasSubscribers) {
+      resume();
+    } else {
+      subscription.cancel();
+    }
+  }
+}
+
 
 /**
- * HTTP parser which parses the HTTP stream as data is supplied
- * through the [:streamData:] and [:streamDone:] methods. As the
- * data is parsed the following callbacks are called:
+ * HTTP parser which parses the data stream given to [consume].
  *
- *   [:requestStart:]
- *   [:responseStart:]
- *   [:dataReceived:]
- *   [:dataEnd:]
- *   [:closed:]
- *   [:error:]
- *
- * If an HTTP parser error occours it is possible to get an exception
- * thrown from the [:streamData:] and [:streamDone:] methods if
- * the error callback is not set.
+ * If an HTTP parser error occours, the parser will signal an error to either
+ * the current _HttpIncoming or the _parser itself.
  *
  * The connection upgrades (e.g. switching from HTTP/1.1 to the
  * WebSocket protocol) is handled in a special way. If connection
@@ -126,14 +189,51 @@
  * and should be handled according to whatever protocol is being
  * upgraded to.
  */
-class _HttpParser {
-  _HttpParser.requestParser() {
-    _requestParser = true;
+class _HttpParser
+    extends Stream<_HttpIncoming>
+    implements StreamConsumer<List<int>, _HttpParser> {
+
+  factory _HttpParser.requestParser() {
+    return new _HttpParser._(true);
+  }
+
+  factory _HttpParser.responseParser() {
+    return new _HttpParser._(false);
+  }
+
+  _HttpParser._(this._requestParser) {
+    _controller = new StreamController<_HttpIncoming>(
+          onSubscriptionStateChange: _updateParsePauseState,
+          onPauseStateChange: _updateParsePauseState);
     _reset();
   }
-  _HttpParser.responseParser() {
-    _requestParser = false;
-    _reset();
+
+
+  StreamSubscription<_HttpIncoming> listen(void onData(List<int> event),
+                                           {void onError(AsyncError error),
+                                            void onDone(),
+                                            bool unsubscribeOnError}) {
+    return _controller.stream.listen(onData,
+                                     onError: onError,
+                                     onDone: onDone,
+                                     unsubscribeOnError: unsubscribeOnError);
+  }
+
+  Future<_HttpParser> consume(Stream<List<int>> stream) {
+    // Listen to the stream and handle data accordingly. When a
+    // _HttpIncoming is created, _dataPause, _dataResume, _dataDone is
+    // given to provide a way of controlling the parser.
+    // TODO(ajohnsen): Remove _dataPause, _dataResume and _dataDone and clean up
+    // how the _HttpIncoming signals the parser.
+    var completer = new Completer();
+    _socketSubscription = stream.listen(
+        _onData,
+        onError: _onError,
+        onDone: () {
+          _onDone();
+          completer.complete(this);
+        });
+    return completer.future;
   }
 
   // From RFC 2616.
@@ -146,22 +246,23 @@
   // Status-Line     = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
   // message-header  = field-name ":" [ field-value ]
   void _parse() {
+    assert(!_parserCalled);
+    _parserCalled = true;
     try {
       if (_state == _State.CLOSED) {
         throw new HttpParserException("Data on closed connection");
       }
-      if (_state == _State.UPGRADED) {
-        throw new HttpParserException("Data on upgraded connection");
-      }
       if (_state == _State.FAILURE) {
         throw new HttpParserException("Data on failed connection");
       }
-      if (_state == _State.CANCELED) {
-        throw new HttpParserException("Data on canceled connection");
-      }
       while (_buffer != null &&
-             _index < _lastIndex &&
-             _state <= _State.FIRST_PARSE_STOP_STATE) {
+             _index < _buffer.length &&
+             _state != _State.FAILURE &&
+             _state != _State.UPGRADED) {
+        if (_paused) {
+          _parserCalled = false;
+          return;
+        }
         int byte = _buffer[_index++];
         switch (_state) {
           case _State.START:
@@ -328,15 +429,20 @@
           case _State.RESPONSE_LINE_ENDING:
             _expect(byte, _CharCode.LF);
             _messageType == _MessageType.RESPONSE;
-             _statusCode = int.parse(
-                 new String.fromCharCodes(_method_or_status_code));
+            _statusCode = int.parse(
+                new String.fromCharCodes(_method_or_status_code));
             if (_statusCode < 100 || _statusCode > 599) {
               throw new HttpParserException("Invalid response status code");
+            } else {
+              // Check whether this response will never have a body.
+              _noMessageBody = _statusCode <= 199 || _statusCode == 204 ||
+                  _statusCode == 304;
             }
             _state = _State.HEADER_START;
             break;
 
           case _State.HEADER_START:
+            _headers = new _HttpHeaders(version);
             if (byte == _CharCode.CR) {
               _state = _State.HEADER_ENDING;
             } else {
@@ -386,27 +492,19 @@
             } else {
               String headerField = new String.fromCharCodes(_headerField);
               String headerValue = new String.fromCharCodes(_headerValue);
-              bool reportHeader = true;
-              if (headerField == "connection") {
-                List<String> tokens = _tokenizeFieldValue(headerValue);
-                for (int i = 0; i < tokens.length; i++) {
-                  String token = tokens[i].toLowerCase();
-                  if (token == "keep-alive") {
-                    _persistentConnection = true;
-                  } else if (token == "close") {
-                    _persistentConnection = false;
-                  } else if (token == "upgrade") {
-                    _connectionUpgrade = true;
-                  }
-                  _headers.add(headerField, token);
-
-                }
-                reportHeader = false;
-              } else if (headerField == "transfer-encoding" &&
+              if (headerField == "transfer-encoding" &&
                          headerValue.toLowerCase() == "chunked") {
                 _chunked = true;
               }
-              if (reportHeader) {
+              if (headerField == "connection") {
+                List<String> tokens = _tokenizeFieldValue(headerValue);
+                for (int i = 0; i < tokens.length; i++) {
+                  if (tokens[i].toLowerCase() == "upgrade") {
+                    _connectionUpgrade = true;
+                  }
+                  _headers.add(headerField, tokens[i]);
+                }
+              } else {
                 _headers.add(headerField, headerValue);
               }
               _headerField.clear();
@@ -426,62 +524,62 @@
             _expect(byte, _CharCode.LF);
             _headers._mutable = false;
 
-            _contentLength = _headers.contentLength;
+            _transferLength = _headers.contentLength;
             // Ignore the Content-Length header if Transfer-Encoding
             // is chunked (RFC 2616 section 4.4)
-            if (_chunked) _contentLength = -1;
+            if (_chunked) _transferLength = -1;
 
             // If a request message has neither Content-Length nor
             // Transfer-Encoding the message must not have a body (RFC
             // 2616 section 4.3).
             if (_messageType == _MessageType.REQUEST &&
-                _contentLength < 0 &&
+                _transferLength < 0 &&
                 _chunked == false) {
-              _contentLength = 0;
+              _transferLength = 0;
             }
             if (_connectionUpgrade) {
               _state = _State.UPGRADED;
+              _transferLength = 0;
             }
-            var noBody;
+            _createIncoming(_transferLength);
             if (_requestParser) {
-              noBody = _contentLength == 0;
-              requestStart(new String.fromCharCodes(_method_or_status_code),
-                           new String.fromCharCodes(_uri_or_reason_phrase),
-                           version,
-                           _headers,
-                           !noBody);
+              _incoming.method =
+                  new String.fromCharCodes(_method_or_status_code);
+              _incoming.uri =
+                  Uri.parse(
+                      new String.fromCharCodes(_uri_or_reason_phrase));
             } else {
-              // Check whether this response will never have a body.
-              noBody = _contentLength == 0 ||
-                       _statusCode <= 199 ||
-                       _statusCode == HttpStatus.NO_CONTENT ||
-                       _statusCode == HttpStatus.NOT_MODIFIED ||
-                       _responseToMethod == "HEAD";
-              responseStart(_statusCode,
-                            new String.fromCharCodes(_uri_or_reason_phrase),
-                            version,
-                            _headers,
-                            !noBody);
+              _incoming.statusCode = _statusCode;
+              _incoming.reasonPhrase =
+                  new String.fromCharCodes(_uri_or_reason_phrase);
             }
             _method_or_status_code.clear();
             _uri_or_reason_phrase.clear();
-            if (_state == _State.CANCELED) continue;
-            if (!_connectionUpgrade) {
-              if (noBody) {
-                _bodyEnd();
-                _reset();
-              } else if (_chunked) {
-                _state = _State.CHUNK_SIZE;
-                _remainingContent = 0;
-              } else if (_contentLength > 0) {
-                _remainingContent = _contentLength;
-                _state = _State.BODY;
-              } else {
-                // Neither chunked nor content length. End of body
-                // indicated by close.
-                _state = _State.BODY;
-              }
+            if (_connectionUpgrade) {
+              _incoming.upgraded = true;
+              _controller.add(_incoming);
+              break;
             }
+            if (_chunked) {
+              _state = _State.CHUNK_SIZE;
+              _remainingContent = 0;
+            } else if (_transferLength == 0 ||
+                         (_messageType == _MessageType.RESPONSE &&
+                          (_noMessageBody || _responseToMethod == "HEAD"))) {
+              _reset();
+              var tmp = _incoming;
+              _closeIncoming();
+              _controller.add(tmp);
+              break;
+            } else if (_transferLength > 0) {
+              _remainingContent = _transferLength;
+              _state = _State.BODY;
+            } else {
+              // Neither chunked nor content length. End of body
+              // indicated by close.
+              _state = _State.BODY;
+            }
+            _controller.add(_incoming);
             break;
 
           case _State.CHUNK_SIZE_STARTING_CR:
@@ -527,15 +625,14 @@
 
           case _State.CHUNKED_BODY_DONE_LF:
             _expect(byte, _CharCode.LF);
-            _bodyEnd();
-            if (_state == _State.CANCELED) continue;
             _reset();
+            _closeIncoming();
             break;
 
           case _State.BODY:
             // The body is not handled one byte at a time but in blocks.
             _index--;
-            int dataAvailable = _lastIndex - _index;
+            int dataAvailable = _buffer.length - _index;
             List<int> data;
             if (_remainingContent == null ||
                 dataAvailable <= _remainingContent) {
@@ -546,17 +643,15 @@
               data.setRange(0, _remainingContent, _buffer, _index);
             }
 
-            dataReceived(data);
-            if (_state == _State.CANCELED) continue;
+            _bodyController.add(data);
             if (_remainingContent != null) {
               _remainingContent -= data.length;
             }
             _index += data.length;
             if (_remainingContent == 0) {
               if (!_chunked) {
-                _bodyEnd();
-                if (_state == _State.CANCELED) continue;
                 _reset();
+                _closeIncoming();
               } else {
                 _state = _State.CHUNK_SIZE_STARTING_CR;
               }
@@ -574,36 +669,62 @@
             break;
         }
       }
-    } catch (e) {
+    } catch (e, s) {
       _state = _State.FAILURE;
-      error(e);
+      error(new AsyncError(e, s));
     }
 
-    // If all data is parsed or not needed due to failure there is no
-    // need to hold on to the buffer.
-    if (_state != _State.UPGRADED) _releaseBuffer();
+    _parserCalled = false;
+    if (_buffer != null && _index == _buffer.length) {
+      // If all data is parsed release the buffer and resume receiving
+      // data.
+      _releaseBuffer();
+      if (_state != _State.UPGRADED && _state != _State.FAILURE) {
+        _socketSubscription.resume();
+      }
+    }
   }
 
-  void streamData(List<int> buffer) {
+  void _onData(List<int> buffer) {
+    _socketSubscription.pause();
     assert(_buffer == null);
     _buffer = buffer;
     _index = 0;
-    _lastIndex = buffer.length;
     _parse();
   }
 
-  void streamDone() {
-    String type() => _requestParser ? "request" : "response";
+  void _onDone() {
+    // onDone cancles the subscription.
+    _socketSubscription = null;
+    if (_state == _State.CLOSED || _state == _State.FAILURE) return;
 
+    if (_incoming != null) {
+      if (_state != _State.UPGRADED &&
+          !(_state == _State.START && !_requestParser) &&
+          !(_state == _State.BODY && !_chunked && _transferLength == -1)) {
+        _bodyController.signalError(
+            new AsyncError(
+                new HttpParserException(
+                    "Connection closed while receiving data")));
+      }
+      _closeIncoming();
+      _controller.close();
+      return;
+    }
     // If the connection is idle the HTTP stream is closed.
     if (_state == _State.START) {
-      if (_requestParser) {
-        closed();
-      } else {
+      if (!_requestParser) {
         error(
-            new HttpParserException(
-                "Connection closed before full ${type()} header was received"));
+            new AsyncError(
+                new HttpParserException(
+                    "Connection closed before full header was received")));
       }
+      _controller.close();
+      return;
+    }
+
+    if (_state == _State.UPGRADED) {
+      _controller.close();
       return;
     }
 
@@ -612,27 +733,29 @@
       // Report the error through the error callback if any. Otherwise
       // throw the error.
       error(
-          new HttpParserException(
-                "Connection closed before full ${type()} header was received"));
+          new AsyncError(
+              new HttpParserException(
+                  "Connection closed before full header was received")));
+      _controller.close();
       return;
     }
 
-    if (!_chunked && _contentLength == -1) {
-      dataEnd(true);
+    if (!_chunked && _transferLength == -1) {
       _state = _State.CLOSED;
-      closed();
     } else {
       _state = _State.FAILURE;
       // Report the error through the error callback if any. Otherwise
       // throw the error.
       error(
-          new HttpParserException(
-                "Connection closed before full ${type()} body was received"));
+          new AsyncError(
+              new HttpParserException(
+                  "Connection closed before full body was received")));
     }
+    _controller.close();
   }
 
-  void streamError(e) {
-    error(e);
+  void _onError(e) {
+    _controller.signalError(e);
   }
 
   String get version {
@@ -645,34 +768,31 @@
     return null;
   }
 
-  void cancel() {
-    _state = _State.CANCELED;
-  }
-
-  void restart() {
-    _reset();
-  }
-
   int get messageType => _messageType;
-  int get contentLength => _contentLength;
+  int get transferLength => _transferLength;
   bool get upgrade => _connectionUpgrade && _state == _State.UPGRADED;
   bool get persistentConnection => _persistentConnection;
 
   void set responseToMethod(String method) { _responseToMethod = method; }
 
+  _HttpDetachedIncoming detachIncoming() {
+    var completer = _pauseCompleter;
+    _pauseCompleter = null;
+    return new _HttpDetachedIncoming(_socketSubscription,
+                                     readUnparsedData(),
+                                     completer);
+  }
+
   List<int> readUnparsedData() {
-    if (_buffer == null) return [];
-    if (_index == _lastIndex) return [];
-    var result = _buffer.getRange(_index, _lastIndex - _index);
+    if (_buffer == null) return null;
+    if (_index == _buffer.length) return null;
+    var result = _buffer.getRange(_index, _buffer.length - _index);
     _releaseBuffer();
     return result;
   }
 
-  void _bodyEnd() {
-    dataEnd(_messageType == _MessageType.RESPONSE && !_persistentConnection);
-  }
-
   _reset() {
+    if (_state == _State.UPGRADED) return;
     _state = _State.START;
     _messageType = _MessageType.UNDETERMINED;
     _headerField = new List();
@@ -681,21 +801,21 @@
     _uri_or_reason_phrase = new List();
 
     _httpVersion = _HttpVersion.UNDETERMINED;
-    _contentLength = -1;
+    _transferLength = -1;
     _persistentConnection = false;
     _connectionUpgrade = false;
     _chunked = false;
 
+    _noMessageBody = false;
     _responseToMethod = null;
     _remainingContent = null;
 
-    _headers = new _HttpHeaders();
+    _headers = null;
   }
 
   _releaseBuffer() {
     _buffer = null;
     _index = null;
-    _lastIndex = null;
   }
 
   bool _isTokenChar(int byte) {
@@ -744,12 +864,69 @@
     }
   }
 
+  void _createIncoming(int transferLength) {
+    assert(_incoming == null);
+    assert(_bodyController == null);
+    _bodyController = new StreamController<List<int>>(
+        onSubscriptionStateChange: _updateParsePauseState,
+        onPauseStateChange: _updateParsePauseState);
+    _incoming = new _HttpIncoming(
+        _headers, transferLength, _bodyController.stream);
+    _pauseParsing();  // Needed to handle detaching - don't start on the body!
+  }
+
+  void _closeIncoming() {
+    assert(_incoming != null);
+    var tmp = _incoming;
+    _incoming = null;
+    tmp.close();
+    if (_bodyController != null) {
+      _bodyController.close();
+      _bodyController = null;
+    }
+    _updateParsePauseState();
+  }
+
+  void _continueParsing() {
+    _paused = false;
+    if (!_parserCalled && _buffer != null) _parse();
+  }
+
+  void _pauseParsing() {
+    _paused = true;
+  }
+
+  void _updateParsePauseState() {
+    if (_bodyController != null) {
+      if (_bodyController.hasSubscribers && !_bodyController.isPaused) {
+        _continueParsing();
+      } else {
+        _pauseParsing();
+      }
+    } else {
+      if (_controller.hasSubscribers && !_controller.isPaused) {
+        _continueParsing();
+      } else {
+        _pauseParsing();
+      }
+    }
+  }
+
+  void error(error) {
+    if (_socketSubscription != null) _socketSubscription.cancel();
+    _state = _State.FAILURE;
+    _controller.signalError(error);
+    _controller.close();
+  }
+
+  // State.
+  bool _parserCalled = false;
+
   // The data that is currently being parsed.
   List<int> _buffer;
   int _index;
-  int _lastIndex;
 
-  bool _requestParser;
+  final bool _requestParser;
   int _state;
   int _httpVersionIndex;
   int _messageType;
@@ -760,23 +937,24 @@
   List _headerValue;
 
   int _httpVersion;
-  int _contentLength;
+  int _transferLength;
   bool _persistentConnection;
   bool _connectionUpgrade;
   bool _chunked;
 
+  bool _noMessageBody;
   String _responseToMethod;  // Indicates the method used for the request.
   int _remainingContent;
 
-  _HttpHeaders _headers = new _HttpHeaders();
+  _HttpHeaders _headers;
 
-  // Callbacks.
-  Function requestStart;
-  Function responseStart;
-  Function dataReceived;
-  Function dataEnd;
-  Function error;
-  Function closed;
+  // The current incoming connection.
+  _HttpIncoming _incoming;
+  StreamSubscription _socketSubscription;
+  bool _paused = false;
+  Completer _pauseCompleter;
+  StreamController<_HttpIncoming> _controller;
+  StreamController<List<int>> _bodyController;
 }
 
 
diff --git a/sdk/lib/io/http_session.dart b/sdk/lib/io/http_session.dart
index 99bf13c..4cde1be 100644
--- a/sdk/lib/io/http_session.dart
+++ b/sdk/lib/io/http_session.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -9,6 +9,18 @@
 // A _HttpSession is a node in a double-linked list, with _next and _prev being
 // the previous and next pointers.
 class _HttpSession implements HttpSession {
+  // Destroyed marked. Used by the http connection to see if a session is valid.
+  bool _destroyed = false;
+  bool _isNew = true;
+  DateTime _lastSeen;
+  Function _timeoutCallback;
+  _HttpSessionManager _sessionManager;
+  // Pointers in timeout queue.
+  _HttpSession _prev;
+  _HttpSession _next;
+
+  final Map _data = new Map();
+
   _HttpSession(_HttpSessionManager this._sessionManager, String this.id)
     : _lastSeen = new DateTime.now();
 
@@ -25,24 +37,29 @@
     _sessionManager._bumpToEnd(this);
   }
 
-  dynamic data;
-
   DateTime get lastSeen => _lastSeen;
 
+  bool get isNew => _isNew;
+
   final String id;
 
   void set onTimeout(void callback()) {
     _timeoutCallback = callback;
   }
 
-  // Destroyed marked. Used by the http connection to see if a session is valid.
-  bool _destroyed = false;
-  DateTime _lastSeen;
-  Function _timeoutCallback;
-  _HttpSessionManager _sessionManager;
-  // Pointers in timeout queue.
-  _HttpSession _prev;
-  _HttpSession _next;
+  // Map implementation:
+  bool containsValue(value) => _data.containsValue(value);
+  bool containsKey(key) => _data.containsKey(key);
+  operator [](key) => _data[key];
+  void operator []=(key, value) { _data[key] = value; }
+  putIfAbsent(key, ifAbsent) => _data.putIfAbsent(key, ifAbsent);
+  remove(key) => _data.remove(key);
+  void clear() => _data.clear();
+  void forEach(void f(key, value)) => _data.forEach(f);
+  Iterable get keys => _data.keys;
+  Iterable get values => _data.values;
+  int get length => _data.length;
+  bool get isEmpty => _data.isEmpty;
 }
 
 // Private class used to manage all the active sessions. The sessions are stored
@@ -63,7 +80,7 @@
     return _sessions[id];
   }
 
-  _HttpSession createSession(init(HttpSession session)) {
+  _HttpSession createSession() {
     var id = createSessionId();
     // TODO(ajohnsen): Consider adding a limit and throwing an exception.
     // Should be very unlikely however.
@@ -71,7 +88,6 @@
       id = createSessionId();
     }
     var session = _sessions[id] = new _HttpSession(this, id);
-    if (init != null) init(session);
     _addToTimeoutQueue(session);
     return session;
   }
diff --git a/sdk/lib/io/input_stream.dart b/sdk/lib/io/input_stream.dart
deleted file mode 100644
index 8db5e19..0000000
--- a/sdk/lib/io/input_stream.dart
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.io;
-
-/**
- * Basic input stream which supplies binary data.
- *
- * Input streams are used to read data sequentially from some data
- * source. All input streams are non-blocking. They each have a number
- * of read calls which will always return without any IO related
- * blocking. If the requested data is not available a read call will
- * return `null`. All input streams have one or more handlers which
- * will trigger when data is available.
- *
- * The following example shows a data handler in an ordinary input
- * stream which will be called when some data is available and a call
- * to read will not return `null`.
- *
- *     InputStream input = ...
- *     input.onData = () {
- *       var data = input.read();
- *       ...
- *     };
- *
- * If for some reason the data from an input stream cannot be handled
- * by the application immediately setting the data handler to `null`
- * will avoid further callbacks until it is set to a function
- * again. While the data handler is not active system flow control
- * will be used to avoid buffering more data than needed.
- *
- * Always set up appropriate handlers when using input streams.
- *
- */
-abstract class InputStream {
-  /**
-   * Reads data from the stream. Returns a system allocated buffer
-   * with up to [len] bytes. If no value is passed for [len] all
-   * available data will be returned. If no data is available null will
-   * be returned.
-   */
-  List<int> read([int len]);
-
-  /**
-   * Reads up to [len] bytes into buffer [buffer] starting at offset
-   * [offset]. Returns the number of bytes actually read which might
-   * be zero. If [offset] is not specified 0 is used. If [len] is not
-   * specified the length of [buffer] is used.
-   */
-  int readInto(List<int> buffer, [int offset, int len]);
-
-  /**
-   * Returns the number of bytes available for immediate reading.
-   */
-  int available();
-
-  /**
-   * Pipe the content of this input stream directly to the output
-   * stream [output]. The default behavior is to close the output when
-   * all the data from the input stream have been written. Specifying
-   * `false` for the optional argument [close] keeps the output
-   * stream open after writing all data from the input stream.
-   */
-  void pipe(OutputStream output, {bool close: true});
-
-  /**
-   * Close the underlying communication channel to avoid getting any
-   * more data. In normal situations, where all data is read from the
-   * stream until the close handler is called, calling [close] is not
-   * required. When [close] is used the close handler will still be
-   * called.
-   */
-  void close();
-
-  /**
-   * Returns whether the stream is closed. There will be no more data
-   * to read.
-   */
-  bool get closed;
-
-  /**
-   * Sets the handler that gets called when data is available.
-   */
-  void set onData(void callback());
-
-  /**
-   * Sets the handler that gets called when there will be no more data
-   * available in the stream.
-   */
-  void set onClosed(void callback());
-
-  /**
-   * Sets the handler that gets called when the underlying
-   * communication channel gets into some kind of error situation.
-   */
-  void set onError(void callback(e));
-}
-
-
-/**
- * String encodings.
- */
-class Encoding {
-  static const Encoding UTF_8 = const Encoding._internal("UTF-8");
-  static const Encoding ISO_8859_1 = const Encoding._internal("ISO-8859-1");
-  static const Encoding ASCII = const Encoding._internal("ASCII");
-  /**
-   * SYSTEM encoding is the current code page on Windows and UTF-8 on
-   * Linux and Mac.
-   */
-  static const Encoding SYSTEM = const Encoding._internal("SYSTEM");
-  const Encoding._internal(String this.name);
-  final String name;
-}
-
-
-/**
- * A string input stream wraps a basic input stream and supplies
- * string data. This data can be read either as string chunks or as
- * lines separated by line termination character sequences.
- */
-abstract class StringInputStream {
-  /**
-   * Decodes a binary input stream into characters using the specified
-   * encoding.
-   */
-  factory StringInputStream(InputStream input,
-                            [Encoding encoding = Encoding.UTF_8]) {
-    return new _StringInputStream(input, encoding);
-  }
-
-  /**
-   * Reads up to [len] characters from the stream. if [len] is not
-   * specified reads as many characters as is available from the
-   * stream. If no data is available null will be returned.
-   */
-  String read([int len]);
-
-  /**
-   * Reads the next line from the stream. The line ending characters
-   * will not be part of the returned string. If a full line is not
-   * available null will be returned.
-   */
-  String readLine();
-
-  /**
-   * Returns the number of characters available for immediate
-   * reading. Note that this includes all characters that will be in
-   * the String returned from [read] this includes line breaking
-   * characters. If [readLine] is used for reading one can observe
-   * less characters being returned as the line breaking characters
-   * are discarded.
-   */
-  int available();
-
-  /**
-   * Returns whether the stream has been closed. There might still be
-   * more data to read.
-   */
-  bool get closed;
-
-  /**
-   * Returns the encoding used to decode the binary data into characters.
-   */
-  Encoding get encoding;
-
-  /**
-   * Sets the handler that gets called when data is available. The two
-   * handlers [onData] and [onLine] are mutually exclusive
-   * and setting one will remove the other.
-   */
-  void set onData(void callback());
-
-  /**
-   * Sets the handler that gets called when a line is available. The
-   * two handlers [onData] and [onLine] are mutually
-   * exclusive and setting one will remove the other.
-   */
-  void set onLine(void callback());
-
-  /**
-   * Sets the handler that gets called when there will be no more data
-   * available in the stream.
-   */
-  void set onClosed(void callback());
-
-  /**
-   * Sets the handler that gets called when the underlying
-   * communication channel gets into some kind of error situation.
-   */
-  void set onError(void callback(e));
-}
-
-
-/**
- * A chunked input stream wraps a basic input stream and supplies
- * binary data in configurable chunk sizes.
- */
-abstract class ChunkedInputStream {
-  /**
-   * Adds buffering to an input stream and provide the ability to read
-   * the data in known size chunks.
-   */
-  factory ChunkedInputStream(InputStream input, [int chunkSize = 0]) {
-    return new _ChunkedInputStream(input, chunkSize);
-  }
-
-  /**
-   * Reads [chunkSize] bytes from the stream. If [chunkSize] bytes are
-   * not currently available null is returned. When the stream is
-   * closed the last call can return with less than [chunkSize] bytes.
-   */
-  List<int> read();
-
-  /**
-   * Returns whether the stream has been closed. There might still be
-   * more data to read.
-   */
-  bool get closed;
-
-  /**
-   * Returns the chunk size used by this stream.
-   */
-  int get chunkSize;
-
-  /**
-   * Sets the chunk size used by this stream.
-   */
-  void set chunkSize(int chunkSize);
-
-  /**
-   * Sets the handler that gets called when at least [chunkSize] bytes
-   * of data is available or the underlying stream has been closed and
-   * there is still unread data.
-   */
-  void set onData(void callback());
-
-  /**
-   * Sets the handler that gets called when there will be no more data
-   * available in the stream.
-   */
-  void set onClosed(void callback());
-
-  /**
-   * Sets the handler that gets called when the underlying
-   * communication channel gets into some kind of error situation.
-   */
-  void set onError(void callback(e));
-}
-
-
-class StreamException implements Exception {
-  const StreamException([String this.message = ""]);
-  const StreamException.streamClosed() : message = "Stream closed";
-  String toString() => "StreamException: $message";
-  final String message;
-}
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index a9fa17a..b7d2843 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -25,34 +25,29 @@
 
 part 'base64.dart';
 part 'buffer_list.dart';
-part 'chunked_stream.dart';
 part 'common.dart';
 part 'directory.dart';
 part 'directory_impl.dart';
 part 'eventhandler.dart';
 part 'file.dart';
 part 'file_impl.dart';
+part 'file_system_entity.dart';
 part 'http.dart';
 part 'http_headers.dart';
 part 'http_impl.dart';
 part 'http_parser.dart';
 part 'http_session.dart';
 part 'http_utils.dart';
-part 'input_stream.dart';
-part 'list_stream.dart';
-part 'list_stream_impl.dart';
+part 'io_stream_consumer.dart';
 part 'mime_multipart_parser.dart';
-part 'output_stream.dart';
 part 'path.dart';
 part 'path_impl.dart';
 part 'platform.dart';
 part 'platform_impl.dart';
 part 'process.dart';
 part 'socket.dart';
-part 'socket_stream_impl.dart';
 part 'stdio.dart';
-part 'stream_util.dart';
-part 'string_stream.dart';
+part 'string_transformer.dart';
 part 'timer_impl.dart';
 part 'secure_socket.dart';
 part 'secure_server_socket.dart';
diff --git a/sdk/lib/io/io_stream_consumer.dart b/sdk/lib/io/io_stream_consumer.dart
new file mode 100644
index 0000000..51b59ab
--- /dev/null
+++ b/sdk/lib/io/io_stream_consumer.dart
@@ -0,0 +1,160 @@
+// 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.io;
+
+/**
+ * Helper class to wrap a [StreamConsumer<List<int>, T>] and provide utility
+ * functions for writing to the StreamConsumer directly. The [IOSink]
+ * buffers the input given by [add] and [addString] and will delay a [consume]
+ * or [addStream] until the buffer is flushed.
+ *
+ * When the [IOSink] is bound to a stream (through either [comsume]
+ * or [addStream]) any call to the [IOSink] will throw a
+ * [StateError].
+ */
+class IOSink<T> implements StreamConsumer<List<int>, T> {
+  final StreamConsumer<List<int>, T> _target;
+
+  StreamController<List<int>> _controllerInstance;
+  Future<T> _pipeFuture;
+  StreamSubscription<List<int>> _bindSubscription;
+  bool _paused = true;
+
+  IOSink(StreamConsumer<List<int>, T> target) : _target = target;
+
+  /**
+   * Provide functionality for piping to the [IOSink].
+   */
+  Future<T> consume(Stream<List<int>> stream) {
+    if (_isBound) {
+      throw new StateError("IOSink is already bound to a stream");
+    }
+    return _fillFromStream(stream);
+  }
+
+  /**
+   * Like [consume], but will not close the target when done.
+   */
+  Future<T> addStream(Stream<List<int>> stream) {
+    if (_isBound) {
+      throw new StateError("IOSink is already bound to a stream");
+    }
+    return _fillFromStream(stream, unbind: true);
+  }
+
+  /**
+   * Write a list of bytes to the target.
+   */
+  void add(List<int> data) {
+    if (_isBound) {
+      throw new StateError("IOSink is already bound to a stream");
+    }
+    _controller.add(data);
+  }
+
+  /**
+   * Write a String to the target.
+   */
+  void addString(String string, [Encoding encoding = Encoding.UTF_8]) {
+    add(_encodeString(string, encoding));
+  }
+
+  /**
+   * Close the target.
+   */
+  void close() {
+    if (_isBound) {
+      throw new StateError("IOSink is already bound to a stream");
+    }
+    _controller.close();
+  }
+
+  /**
+   * Get future that will complete when all data has been written to
+   * the IOSink and it has been closed.
+   */
+  Future<T> get done {
+    _controller;
+    return _pipeFuture.then((_) => this);
+  }
+
+  StreamController<List<int>> get _controller {
+    if (_controllerInstance == null) {
+      _controllerInstance = new StreamController<List<int>>(
+          onPauseStateChange: _onPauseStateChange,
+          onSubscriptionStateChange: _onSubscriptionStateChange);
+      _pipeFuture = _controller.stream.pipe(_target);
+    }
+    return _controllerInstance;
+  }
+
+  bool get _isBound => _bindSubscription != null;
+
+  void _onPauseStateChange() {
+    _paused = _controller.isPaused;
+    if (_controller.isPaused) {
+      _pause();
+    } else {
+      _resume();
+    }
+  }
+
+  void _pause() {
+    if (_bindSubscription != null) {
+      try {
+        // The subscription can be canceled at this point.
+        _bindSubscription.pause();
+      } catch (e) {
+      }
+    }
+  }
+
+  void _resume() {
+    if (_bindSubscription != null) {
+      try {
+        // The subscription can be canceled at this point.
+        _bindSubscription.resume();
+      } catch (e) {
+      }
+    }
+  }
+
+  void _onSubscriptionStateChange() {
+    if (_controller.hasSubscribers) {
+      _paused = false;
+      _resume();
+    } else {
+      if (_bindSubscription != null) {
+        _bindSubscription.cancel();
+        _bindSubscription = null;
+      }
+    }
+  }
+
+  Future<T> _fillFromStream(Stream<List<int>> stream, {unbind: false}) {
+    _controller;
+    Completer<T> unbindCompleter;
+    if (unbind) {
+      unbindCompleter = new Completer<T>();
+    }
+    _bindSubscription = stream.listen(
+        _controller.add,
+        onDone: () {
+          _bindSubscription = null;
+          if (unbind) {
+            unbindCompleter.complete(null);
+          } else {
+            _controller.close();
+          }
+        },
+        onError: _controller.signalError);
+    if (_paused) _pause();
+    if (unbind) {
+      return unbindCompleter.future;
+    } else {
+      return _pipeFuture;
+    }
+  }
+}
diff --git a/sdk/lib/io/iolib_sources.gypi b/sdk/lib/io/iolib_sources.gypi
index b4ac1bb..b695556 100644
--- a/sdk/lib/io/iolib_sources.gypi
+++ b/sdk/lib/io/iolib_sources.gypi
@@ -6,34 +6,29 @@
   'sources': [
     'base64.dart',
     'buffer_list.dart',
-    'chunked_stream.dart',
     'common.dart',
     'directory.dart',
     'directory_impl.dart',
     'eventhandler.dart',
     'file.dart',
     'file_impl.dart',
+    'file_system_entity.dart',
     'http.dart',
     'http_headers.dart',
     'http_impl.dart',
     'http_parser.dart',
     'http_session.dart',
     'http_utils.dart',
-    'input_stream.dart',
-    'list_stream.dart',
-    'list_stream_impl.dart',
+    'io_stream_consumer.dart',
     'mime_multipart_parser.dart',
-    'output_stream.dart',
     'path.dart',
     'path_impl.dart',
     'platform.dart',
     'platform_impl.dart',
     'process.dart',
     'socket.dart',
-    'socket_stream_impl.dart',
     'stdio.dart',
-    'stream_util.dart',
-    'string_stream.dart',
+    'string_transformer.dart',
     'timer_impl.dart',
     'secure_socket.dart',
     'secure_server_socket.dart',
diff --git a/sdk/lib/io/list_stream.dart b/sdk/lib/io/list_stream.dart
deleted file mode 100644
index a56476d..0000000
--- a/sdk/lib/io/list_stream.dart
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.io;
-
-/**
- * [ListInputStream] makes it possible to use the [InputStream]
- * interface to stream over data that is received in chunks as lists
- * of integers.
- *
- * When a new list of integers is received it can be written to the
- * [ListInputStream] using the [write] method. The [markEndOfStream]
- * method must be called when the last data has been written to the
- * [ListInputStream].
- */
-abstract class ListInputStream implements InputStream {
-  /**
-   * Create an empty [ListInputStream] to which data can be written
-   * using the [write] method.
-   */
-  factory ListInputStream() =>  new _ListInputStream();
-
-  /**
-   * Write more data to be streamed over to the [ListInputStream].
-   */
-  void write(List<int> data);
-
-  /**
-   * Notify the [ListInputStream] that no more data will be written to
-   * it.
-   */
-  void markEndOfStream();
-}
-
-
-/**
- * [ListOutputStream] makes it possible to use the [OutputStream]
- * interface to write data to a [List] of integers.
- */
-abstract class ListOutputStream implements OutputStream {
-  /**
-   * Create a [ListOutputStream].
-   */
-  factory ListOutputStream() => new _ListOutputStream();
-
-  /**
-   * Reads all available data from the stream. If no data is available `null`
-   * will be returned.
-   */
-  List<int> read();
-
-  /**
-   * Sets the handler that gets called when data is available.
-   */
-  void set onData(void callback());
-}
diff --git a/sdk/lib/io/list_stream_impl.dart b/sdk/lib/io/list_stream_impl.dart
deleted file mode 100644
index e593384..0000000
--- a/sdk/lib/io/list_stream_impl.dart
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.io;
-
-/**
- * Default implementation of [ListInputStream].
- */
-class _ListInputStream extends _BaseDataInputStream implements ListInputStream {
-  _ListInputStream() : _bufferList = new _BufferList();
-
-  void write(List<int> data) {
-    if (_streamMarkedClosed) {
-      throw new StreamException.streamClosed();
-    }
-    _bufferList.add(data);
-    _checkScheduleCallbacks();
-  }
-
-  void markEndOfStream() {
-    _streamMarkedClosed = true;
-    _checkScheduleCallbacks();
-  }
-
-  int available() => _bufferList.length;
-
-  List<int> _read(int bytesToRead) {
-    return _bufferList.readBytes(bytesToRead);
-  }
-
-  int _readInto(List<int> buffer, int offset, int bytesToRead) {
-    List<int> tmp = _bufferList.readBytes(bytesToRead);
-    buffer.setRange(offset, bytesToRead, tmp, 0);
-    return bytesToRead;
-  }
-
-  void _close() {
-    _streamMarkedClosed = true;
-    _bufferList.clear();
-  }
-
-  _BufferList _bufferList;
-}
-
-
-class _ListOutputStream extends _BaseOutputStream implements ListOutputStream {
-  _ListOutputStream() : _bufferList = new _BufferList();
-
-  List<int> read() => _bufferList.readBytes(_bufferList.length);
-
-  bool write(List<int> buffer, [bool copyBuffer = true]) {
-    if (_streamMarkedClosed) throw new StreamException.streamClosed();
-    if (copyBuffer) {
-      _bufferList.add(buffer.getRange(0, buffer.length));
-    } else {
-      _bufferList.add(buffer);
-    }
-    _checkScheduleCallbacks();
-    return true;
-  }
-
-  bool writeFrom(List<int> buffer, [int offset = 0, int len]) {
-    return write(
-        buffer.getRange(offset, (len == null) ? buffer.length - offset : len),
-        false);
-  }
-
-  void flush() {
-    // Nothing to do on a list output stream.
-  }
-
-  void close() {
-    if (_streamMarkedClosed) throw new StreamException.streamClosed();
-    _streamMarkedClosed = true;
-    _checkScheduleCallbacks();
-  }
-
-  void destroy() {
-    close();
-  }
-
-  void set onData(void callback()) {
-    _clientDataHandler = callback;
-    _checkScheduleCallbacks();
-  }
-
-  void set onNoPendingWrites(void callback()) {
-    _clientNoPendingWriteHandler = callback;
-    _checkScheduleCallbacks();
-  }
-
-  void set onClosed(void callback()) {
-    _clientCloseHandler = callback;
-  }
-
-  void set onError(void callback(e)) {
-    // No errors emitted.
-  }
-
-  void _checkScheduleCallbacks() {
-    void issueDataCallback() {
-      _scheduledDataCallback = null;
-      if (_clientDataHandler != null) {
-        _clientDataHandler();
-        _checkScheduleCallbacks();
-      }
-    }
-
-    void issueNoPendingWriteCallback() {
-      _scheduledNoPendingWriteCallback = null;
-      if (_clientNoPendingWriteHandler != null &&
-          !_streamMarkedClosed) {
-        _clientNoPendingWriteHandler();
-        _checkScheduleCallbacks();
-      }
-    }
-
-    void issueCloseCallback() {
-      _scheduledCloseCallback = null;
-      if (_clientCloseHandler != null) _clientCloseHandler();
-    }
-
-    // Schedule no pending callback if there is a callback set as this
-    // output stream does not wait for any transmission. Schedule
-    // close callback once when the stream is closed. Only schedule a
-    // new callback if the previous one has actually been called.
-    if (_closeCallbackCalled) return;
-
-    if (!_streamMarkedClosed) {
-      if (!_bufferList.isEmpty &&
-          _clientDataHandler != null &&
-          _scheduledDataCallback == null) {
-        _scheduledDataCallback = Timer.run(issueDataCallback);
-      }
-
-      if (_clientNoPendingWriteHandler != null &&
-          _scheduledNoPendingWriteCallback == null &&
-          _scheduledDataCallback == null) {
-        _scheduledNoPendingWriteCallback =
-          Timer.run(issueNoPendingWriteCallback);
-      }
-
-    } else if (_clientCloseHandler != null) {
-      _scheduledCloseCallback = Timer.run(issueCloseCallback);
-      _closeCallbackCalled = true;
-    }
-  }
-
-  bool get closed => _streamMarkedClosed;
-
-  _BufferList _bufferList;
-  bool _streamMarkedClosed = false;
-  bool _closeCallbackCalled = false;
-  Timer _scheduledDataCallback;
-  Timer _scheduledNoPendingWriteCallback;
-  Timer _scheduledCloseCallback;
-  Function _clientDataHandler;
-  Function _clientNoPendingWriteHandler;
-  Function _clientCloseHandler;
-}
diff --git a/sdk/lib/io/output_stream.dart b/sdk/lib/io/output_stream.dart
deleted file mode 100644
index ecccced..0000000
--- a/sdk/lib/io/output_stream.dart
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.io;
-
-/**
- * Output streams are used to write data sequentially to a data
- * destination e.g. a connected socket or an open file.
- *
- * An output stream provides internal buffering of the data written
- * through all calls to [write] and [writeFrom] if data cannot be
- * written immediately to the communication channel. The callback set
- * through [onNoPendingWrites] can be used to to keep the rate of
- * writing in sync with the rate the system can actually write data to
- * the underlying communication channel.
- */
-abstract class OutputStream {
-  /**
-   * Writes the content of [buffer] to the stream. If [copyBuffer] is
-   * false ownership of the specified buffer is passed to the system
-   * and the caller should not change it afterwards. The default value
-   * for [copyBuffer] is true.
-   *
-   * Returns true if the data could be written to the underlying
-   * communication channel immediately. Otherwise the data is buffered
-   * by the output stream and will be sent as soon as possible.
-   */
-  bool write(List<int> buffer, [bool copyBuffer]);
-
-  /**
-   * Writes [len] bytes from buffer [buffer] starting at offset
-   * [offset] to the output stream. If [offset] is not specified the
-   * default is 0. If [len] is not specified the default is the length
-   * of the buffer minus [offset] (i.e. writing from offset to the end
-   * of the buffer). The system will copy the data to be written so
-   * the caller can safely change [buffer] afterwards.
-   *
-   * Returns true if the data could be written to the underlying
-   * communication channel immediately. Otherwise the data is buffered
-   * by the output stream and will be sent as soon as possible.
-   */
-  bool writeFrom(List<int> buffer, [int offset, int len]);
-
-  /**
-   * Write a string to the stream using the given [encoding].The
-   * default encoding is UTF-8 - [:Encoding.UTF_8:].
-   *
-   * Returns true if the data could be written to the underlying
-   * communication channel immediately. Otherwise the data is buffered
-   * by the output stream and will be sent as soon as possible.
-   */
-  bool writeString(String string, [Encoding encoding]);
-
-  /**
-   * Flushes data from any internal buffers as soon as possible. Note
-   * that the actual meaning of calling [flush] will depend on the
-   * actual type of the underlying communication channel.
-   */
-  void flush();
-
-  /**
-   * Signal that no more data will be written to the output stream. When all
-   * buffered data has been written out to the communication channel, the
-   * channel will be closed and the [onClosed] callback will be called.
-   */
-  void close();
-
-  /**
-   * Close the communication channel immediately ignoring any buffered
-   * data.
-   */
-  void destroy();
-
-  /**
-   * Returns whether the stream has been closed by calling close(). If true, no
-   * more data may be written to the output stream, but there still may be
-   * buffered data that has not been written to the communication channel. The
-   * onClosed handler will only be called once all data has been written out.
-   */
-  bool get closed;
-
-  /**
-   * Sets the handler that gets called when the internal OS buffers
-   * have been flushed. This callback can be used to keep the rate of
-   * writing in sync with the rate the system can write data to the
-   * underlying communication channel.
-   */
-  void set onNoPendingWrites(void callback());
-
-  /**
-   * Sets the handler that gets called when the underlying communication channel
-   * has been closed and all the buffered data has been sent.
-   */
-  void set onClosed(void callback());
-
-  /**
-   * Sets the handler that gets called when the underlying
-   * communication channel gets into some kind of error situation.
-   */
-  void set onError(void callback(e));
-}
-
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index e146c61..deb3c83 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -84,7 +84,7 @@
    * Throws an [UnsupportedError] if the process is
    * non-interactive.
    */
-  InputStream get stdout;
+  Stream<List<int>> get stdout;
 
   /**
    * Returns an input stream of the process stderr.
@@ -92,7 +92,7 @@
    * Throws an [UnsupportedError] if the process is
    * non-interactive.
    */
-  InputStream get stderr;
+  Stream<List<int>> get stderr;
 
   /**
    * Returns an output stream to the process stdin.
@@ -100,7 +100,7 @@
    * Throws an [UnsupportedError] if the process is
    * non-interactive.
    */
-  OutputStream get stdin;
+  IOSink<Process> get stdin;
 
   /**
    * Sets an exit handler which gets invoked when the process
@@ -109,7 +109,7 @@
    * Throws an [UnsupportedError] if the process is
    * non-interactive.
    */
-  void set onExit(void callback(int exitCode));
+  Future<int> exitCode;
 
   /**
    * On Windows, [kill] kills the process, ignoring the [signal]
diff --git a/sdk/lib/io/secure_server_socket.dart b/sdk/lib/io/secure_server_socket.dart
index 7c8d78f..7a9b34d 100644
--- a/sdk/lib/io/secure_server_socket.dart
+++ b/sdk/lib/io/secure_server_socket.dart
@@ -4,16 +4,135 @@
 
 part of dart.io;
 
-abstract class SecureServerSocket implements ServerSocket {
+/**
+ * The [SecureServerSocket] is a server socket, providing a stream of high-level
+ * [Socket]s.
+ *
+ * See [SecureSocket] for more info.
+ */
+class SecureServerSocket extends Stream<SecureSocket> implements ServerSocket {
+  final RawSecureServerSocket _socket;
+
+  SecureServerSocket._(RawSecureServerSocket this._socket);
+
   /**
-   * Constructs a new secure server socket, binds it to a given address
-   * and port, and listens on it.  Incoming client connections are
-   * promoted to secure connections, using the server certificate given by
-   * certificate_name.  The bindAddress must be given as a numeric address,
-   * not a host name.  The certificate name is the distinguished name (DN) of
-   * the certificate, such as "CN=localhost" or "CN=myserver.mydomain.com".
-   * The certificate is looked up in the NSS certificate database set by
-   * SecureSocket.setCertificateDatabase.
+   * Returns a future for a [SecureServerSocket]. When the future
+   * completes the server socket is bound to the given [address] and
+   * [port] and has started listening on it.
+   *
+   * If [port] has the value [:0:] (the default) an ephemeral port will
+   * be chosen by the system. The actual port used can be retrieved
+   * using the [port] getter.
+   *
+   * If [backlog] has the value of [:0:] a reasonable value will be
+   * chosen by the system.
+   *
+   * Incoming client connections are promoted to secure connections, using
+   * the server certificate given by [certificateName].
+   *
+   * [address] must be given as a numeric address, not a host name.
+   *
+   * [certificateName] is the nickname or the distinguished name (DN) of
+   * the certificate in the certificate database. It is looked up in the
+   * NSS certificate database set by SecureSocket.setCertificateDatabase.
+   * If [certificateName] contains "CN=", it is assumed to be a distinguished
+   * name.  Otherwise, it is looked up as a nickname.
+   *
+   * To request or require that clients authenticate by providing an SSL (TLS)
+   * client certificate, set the optional parameter [requestClientCertificate]
+   * or [requireClientCertificate] to true.  Requiring a certificate implies
+   * requesting a certificate, so one doesn't need to set both to true.
+   * To check whether a client certificate was received, check
+   * SecureSocket.peerCertificate after connecting.  If no certificate
+   * was received, the result will be null.
+   */
+  static Future<SecureServerSocket> bind(
+      String address,
+      int port,
+      int backlog,
+      String certificateName,
+      {bool requestClientCertificate: false,
+       bool requireClientCertificate: false}) {
+    return RawSecureServerSocket.bind(
+        address,
+        port,
+        backlog,
+        certificateName,
+        requestClientCertificate: requestClientCertificate,
+        requireClientCertificate: requireClientCertificate).then(
+            (serverSocket) => new SecureServerSocket._(serverSocket));
+  }
+
+  StreamSubscription<SecureSocket> listen(void onData(SecureSocket socket),
+                                          {void onError(AsyncError error),
+                                           void onDone(),
+                                           bool unsubscribeOnError}) {
+    return _socket.map((rawSocket) => new SecureSocket._(rawSocket))
+                  .listen(onData,
+                          onError: onError,
+                          onDone: onDone,
+                          unsubscribeOnError: unsubscribeOnError);
+  }
+
+  /**
+   * Returns the port used by this socket.
+   */
+  int get port => _socket.port;
+
+  /**
+   * Closes the socket.
+   */
+  void close() => _socket.close();
+}
+
+
+/**
+ * The RawSecureServerSocket is a server socket, providing a stream of low-level
+ * [RawSecureSocket]s.
+ *
+ * See [RawSecureSocket] for more info.
+ */
+class RawSecureServerSocket extends Stream<RawSecureSocket> {
+  RawServerSocket _socket;
+  StreamController<RawSecureSocket> _controller;
+  StreamSubscription<RawSocket> _subscription;
+  final String certificateName;
+  final bool requestClientCertificate;
+  final bool requireClientCertificate;
+  bool _closed = false;
+
+  RawSecureServerSocket._(RawServerSocket serverSocket,
+                          String this.certificateName,
+                          bool this.requestClientCertificate,
+                          bool this.requireClientCertificate) {
+    _socket = serverSocket;
+    _controller = new StreamController<RawSecureSocket>(
+        onPauseStateChange: _onPauseStateChange,
+        onSubscriptionStateChange: _onSubscriptionStateChange);
+  }
+
+  /**
+   * Returns a future for a [RawSecureServerSocket]. When the future
+   * completes the server socket is bound to the given [address] and
+   * [port] and has started listening on it.
+   *
+   * If [port] has the value [:0:] (the default) an ephemeral port will
+   * be chosen by the system. The actual port used can be retrieved
+   * using the [port] getter.
+   *
+   * If [backlog] has the value of [:0:] a reasonable value will be
+   * chosen by the system.
+   *
+   * Incoming client connections are promoted to secure connections,
+   * using the server certificate given by [certificateName].
+   *
+   * [address] must be given as a numeric address, not a host name.
+   *
+   * [certificateName] is the nickname or the distinguished name (DN) of
+   * the certificate in the certificate database. It is looked up in the
+   * NSS certificate database set by SecureSocket.setCertificateDatabase.
+   * If [certificateName] contains "CN=", it is assumed to be a distinguished
+   * name.  Otherwise, it is looked up as a nickname.
    *
    * To request or require that clients authenticate by providing an SSL (TLS)
    * client certificate, set the optional parameters requestClientCertificate or
@@ -22,79 +141,95 @@
    * check SecureSocket.peerCertificate after connecting.  If no certificate
    * was received, the result will be null.
    */
-  factory SecureServerSocket(String bindAddress,
-                             int port,
-                             int backlog,
-                             String certificate_name,
-                             {bool requestClientCertificate: false,
-                              bool requireClientCertificate: false}) {
-    return new _SecureServerSocket(bindAddress,
-                                   port,
-                                   backlog,
-                                   certificate_name,
-                                   requestClientCertificate,
-                                   requireClientCertificate);
-  }
-}
-
-
-class _SecureServerSocket implements SecureServerSocket {
-
-  _SecureServerSocket(String bindAddress,
-                      int port,
-                      int backlog,
-                      String this.certificate_name,
-                      bool this.requestClientCertificate,
-                      bool this.requireClientCertificate) {
-    socket = new ServerSocket(bindAddress, port, backlog);
-    socket.onConnection = this._onConnectionHandler;
+  static Future<RawSecureServerSocket> bind(
+      String address,
+      int port,
+      int backlog,
+      String certificateName,
+      {bool requestClientCertificate: false,
+       bool requireClientCertificate: false}) {
+    return RawServerSocket.bind(address, port, backlog)
+        .then((serverSocket) => new RawSecureServerSocket._(
+            serverSocket,
+            certificateName,
+            requestClientCertificate,
+            requireClientCertificate));
   }
 
-  void set onConnection(void callback(Socket connection)) {
-    _onConnectionCallback = callback;
-  }
-
-  void set onError(void callback(e)) {
-    socket.onError = callback;
+  StreamSubscription<RawSecureSocket> listen(void onData(RawSecureSocket s),
+                                             {void onError(AsyncError error),
+                                              void onDone(),
+                                              bool unsubscribeOnError}) {
+    return _controller.stream.listen(onData,
+                                     onError: onError,
+                                     onDone: onDone,
+                                     unsubscribeOnError: unsubscribeOnError);
   }
 
   /**
    * Returns the port used by this socket.
    */
-  int get port => socket.port;
+  int get port => _socket.port;
 
   /**
    * Closes the socket.
    */
   void close() {
-    socket.close();
+    _closed = true;
+    _socket.close();
   }
 
-  void _onConnectionHandler(Socket connection) {
-    if (_onConnectionCallback == null) {
-      connection.close();
-      throw new SocketIOException(
-          "SecureServerSocket with no onConnection callback connected to");
-    }
-    if (certificate_name == null) {
-      connection.close();
-      throw new SocketIOException(
-          "SecureServerSocket with server certificate not set connected to");
-    }
-    var secure_connection = new _SecureSocket(
+  void _onData(RawSocket connection) {
+    _RawSecureSocket.connect(
         connection.remoteHost,
         connection.remotePort,
-        certificate_name,
+        certificateName,
         is_server: true,
         socket: connection,
         requestClientCertificate: requestClientCertificate,
-        requireClientCertificate: requireClientCertificate);
-    _onConnectionCallback(secure_connection);
+        requireClientCertificate: requireClientCertificate)
+    .then((RawSecureSocket secureConnection) {
+      if (_closed) {
+        secureConnection.close();
+      } else {
+        _controller.add(secureConnection);
+      }
+    }).catchError((e) {
+      if (_closed) {
+        throw e;
+      } else {
+        _controller.signalError(e);
+        close();
+      }
+    });
   }
 
-  ServerSocket socket;
-  var _onConnectionCallback;
-  final String certificate_name;
-  final bool requestClientCertificate;
-  final bool requireClientCertificate;
+  void _onError(e) {
+    _controller.signalError(e);
+    close();
+  }
+
+  void _onDone() {
+    _controller.close();
+  }
+
+  void _onPauseStateChange() {
+    if (_controller.isPaused) {
+      _subscription.pause();
+    } else {
+      _subscription.resume();
+    }
+  }
+
+  void _onSubscriptionStateChange() {
+    if (_controller.hasSubscribers) {
+      _subscription = _socket.listen(_onData,
+                                     onDone: _onDone,
+                                     onError: _onError);
+    } else {
+      close();
+    }
+  }
 }
+
+
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 6dc1d6d..333edd1 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -1,54 +1,63 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.io;
 
 /**
- * SecureSocket provides a secure (SSL or TLS) client connection to a server.
- * The certificate provided by the server is checked
- * using the certificate database (optionally) provided in initialize().
+ * A high-level class for communicating securely over a TCP socket, using
+ * TLS and SSL. The [SecureSocket] exposes both a [Stream] and an
+ * [IOSink] interface, making it ideal for using together with
+ * other [Stream]s.
  */
 abstract class SecureSocket implements Socket {
+  external factory SecureSocket._(RawSecureSocket rawSocket);
+
   /**
    * Constructs a new secure client socket and connect it to the given
-   * host on the given port. The returned socket is not yet connected
-   * but ready for registration of callbacks.  If sendClientCertificate is
-   * set to true, the socket will send a client certificate if one is
-   * requested by the server.  If clientCertificate is the nickname of
-   * a certificate in the certificate database, that certificate will be sent.
-   * If clientCertificate is null, which is the usual use case, an
+   * [host] on port [port]. The returned Future will complete with a
+   * [SecureSocket] that is connected and ready for subscription.
+   *
+   * If [sendClientCertificate] is set to true, the socket will send a client
+   * certificate if one is requested by the server.
+   *
+   * If [certificateName] is the nickname of a certificate in the certificate
+   * database, that certificate will be sent.
+   *
+   * If [certificateName] is null, which is the usual use case, an
    * appropriate certificate will be searched for in the database and
    * sent automatically, based on what the server says it will accept.
+   *
+   * [onBadCertificate] is an optional handler for unverifiable certificates.
+   * The handler receives the [X509Certificate], and can inspect it and
+   * decide (or let the user decide) whether to accept
+   * the connection or not.  The handler should return true
+   * to continue the [SecureSocket] connection.
    */
-  factory SecureSocket(String host,
-                       int port,
-                       {bool sendClientCertificate: false,
-                        String certificateName}) {
-    return new _SecureSocket(host,
-                             port,
-                             certificateName,
-                             is_server: false,
-                             sendClientCertificate: sendClientCertificate);
+  static Future<SecureSocket> connect(
+      String host,
+      int port,
+      {bool sendClientCertificate: false,
+       String certificateName,
+       bool onBadCertificate(X509Certificate certificate)}) {
+    return RawSecureSocket.connect(host,
+                                   port,
+                                   sendClientCertificate: sendClientCertificate,
+                                   certificateName: certificateName,
+                                   onBadCertificate: onBadCertificate)
+        .then((rawSocket) => new SecureSocket._(rawSocket));
   }
 
   /**
-   * Install a handler for unverifiable certificates.  The handler can inspect
-   * the certificate, and decide (or let the user decide) whether to accept
-   * the connection or not.  The callback should return true
-   * to continue the SecureSocket connection.
-   */
-  void set onBadCertificate(bool callback(X509Certificate certificate));
-
-  /**
-   * Get the peerCertificate for a connected secure socket.  For a server
-   * socket, this will return the client certificate, or null, if no
-   * client certificate was received.  For a client socket, this
-   * will return the server's certificate.
+   * Get the peer certificate for a connected SecureSocket.  If this
+   * SecureSocket is the server end of a secure socket connection,
+   * [peerCertificate] will return the client certificate, or null, if no
+   * client certificate was received.  If it is the client end,
+   * [peerCertificate] will return the server's certificate.
    */
   X509Certificate get peerCertificate;
 
-   /**
+  /**
    * Initializes the NSS library.  If [initialize] is not called, the library
    * is automatically initialized as if [initialize] were called with no
    * arguments.
@@ -88,6 +97,64 @@
 
 
 /**
+ * RawSecureSocket provides a secure (SSL or TLS) network connection.
+ * Client connections to a server are provided by calling
+ * RawSecureSocket.connect.  A secure server, created with
+ * RawSecureServerSocket, also returns RawSecureSocket objects representing
+ * the server end of a secure connection.
+ * The certificate provided by the server is checked
+ * using the certificate database provided in SecureSocket.initialize, and/or
+ * the default built-in root certificates.
+ */
+abstract class RawSecureSocket implements RawSocket {
+  /**
+   * Constructs a new secure client socket and connect it to the given
+   * host on the given port. The returned Future is completed with the
+   * RawSecureSocket when it is connected and ready for subscription.
+   *
+   * The certificate provided by the server is checked using the certificate
+   * database provided in [SecureSocket.initialize], and/or the default built-in
+   * root certificates. If [sendClientCertificate] is
+   * set to true, the socket will send a client certificate if one is
+   * requested by the server. If [certificateName] is the nickname of
+   * a certificate in the certificate database, that certificate will be sent.
+   * If [certificateName] is null, which is the usual use case, an
+   * appropriate certificate will be searched for in the database and
+   * sent automatically, based on what the server says it will accept.
+   *
+   * [onBadCertificate] is an optional handler for unverifiable certificates.
+   * The handler receives the [X509Certificate], and can inspect it and
+   * decide (or let the user decide) whether to accept
+   * the connection or not.  The handler should return true
+   * to continue the [RawSecureSocket] connection.
+   */
+  static Future<RawSecureSocket> connect(
+      String host,
+      int port,
+      {bool sendClientCertificate: false,
+       String certificateName,
+       bool onBadCertificate(X509Certificate certificate)}) {
+    return  _RawSecureSocket.connect(
+        host,
+        port,
+        certificateName,
+        is_server: false,
+        sendClientCertificate: sendClientCertificate,
+        onBadCertificate: onBadCertificate);
+  }
+
+  /**
+   * Get the peer certificate for a connected RawSecureSocket.  If this
+   * RawSecureSocket is the server end of a secure socket connection,
+   * [peerCertificate] will return the client certificate, or null, if no
+   * client certificate was received.  If it is the client end,
+   * [peerCertificate] will return the server's certificate.
+   */
+  X509Certificate get peerCertificate;
+}
+
+
+/**
  * X509Certificate represents an SSL certificate, with accessors to
  * get the fields of the certificate.
  */
@@ -103,7 +170,8 @@
 }
 
 
-class _SecureSocket implements SecureSocket {
+class _RawSecureSocket extends Stream<RawSocketEvent>
+                       implements RawSecureSocket {
   // Status states
   static final int NOT_CONNECTED = 200;
   static final int HANDSHAKE = 201;
@@ -118,187 +186,234 @@
   static final int WRITE_ENCRYPTED = 3;
   static final int NUM_BUFFERS = 4;
 
-  _SecureSocket(String this.host,
-                int requestedPort,
-                String this.certificateName,
-                {bool this.is_server,
-                 Socket this.socket,
-                 bool this.requestClientCertificate: false,
-                 bool this.requireClientCertificate: false,
-                 bool this.sendClientCertificate: false})
-      : secureFilter = new _SecureFilter() {
-    // Throw an ArgumentError if any field is invalid.
+  RawSocket _socket;
+  final Completer<_RawSecureSocket> _handshakeComplete =
+      new Completer<_RawSecureSocket>();
+  StreamController<RawSocketEvent> _controller;
+  Stream<RawSocketEvent> _stream;
+  StreamSubscription<RawSocketEvent> _socketSubscription;
+  final String host;
+  final bool is_server;
+  final String certificateName;
+  final bool requestClientCertificate;
+  final bool requireClientCertificate;
+  final bool sendClientCertificate;
+  final Function onBadCertificate;
+
+  var _status = NOT_CONNECTED;
+  bool _writeEventsEnabled = true;
+  bool _readEventsEnabled = true;
+  bool _socketClosedRead = false;  // The network socket is closed for reading.
+  bool _socketClosedWrite = false;  // The network socket is closed for writing.
+  bool _closedRead = false;  // The secure socket has fired an onClosed event.
+  bool _closedWrite = false;  // The secure socket has been closed for writing.
+  bool _filterReadEmpty = true;  // There is no buffered data to read.
+  bool _filterWriteEmpty = true;  // There is no buffered data to be written.
+  bool _connectPending = false;
+  _SecureFilter _secureFilter = new _SecureFilter();
+
+  static Future<_RawSecureSocket> connect(
+      String host,
+      int requestedPort,
+      String certificateName,
+      {bool is_server,
+       RawSocket socket,
+       bool requestClientCertificate: false,
+       bool requireClientCertificate: false,
+       bool sendClientCertificate: false,
+       bool onBadCertificate(X509Certificate certificate)}){
+     return new _RawSecureSocket(host,
+                                 requestedPort,
+                                 certificateName,
+                                 is_server,
+                                 socket,
+                                 requestClientCertificate,
+                                 requireClientCertificate,
+                                 sendClientCertificate,
+                                 onBadCertificate)
+         ._handshakeComplete.future;
+  }
+
+  _RawSecureSocket(
+      String this.host,
+      int requestedPort,
+      String this.certificateName,
+      bool this.is_server,
+      RawSocket socket,
+      bool this.requestClientCertificate,
+      bool this.requireClientCertificate,
+      bool this.sendClientCertificate,
+      bool this.onBadCertificate(X509Certificate certificate)) {
+    _controller = new StreamController<RawSocketEvent>(
+        onPauseStateChange: _onPauseStateChange,
+        onSubscriptionStateChange: _onSubscriptionStateChange);
+    _stream = _controller.stream;
+    // Throw an ArgumentError if any field is invalid.  After this, all
+    // errors will be reported through the future or the stream.
     _verifyFields();
-    if (socket == null) {
-      socket = new Socket(host, requestedPort);
-    }
-    socket.onConnect = _secureConnectHandler;
-    socket.onData = _secureDataHandler;
-    socket.onClosed = _secureCloseHandler;
-    socket.onError = _secureErrorHandler;
-    secureFilter.init();
-    secureFilter.registerHandshakeCompleteCallback(
+    _secureFilter.init();
+    _secureFilter.registerHandshakeCompleteCallback(
         _secureHandshakeCompleteHandler);
+    if (onBadCertificate != null) {
+      _secureFilter.registerBadCertificateCallback(onBadCertificate);
+    }
+    var futureSocket;
+    if (socket == null) {
+      futureSocket = RawSocket.connect(host, requestedPort);
+    } else {
+      futureSocket = new Future.immediate(socket);
+    }
+    futureSocket.then((rawSocket) {
+      rawSocket.writeEventsEnabled = false;
+      _socket = rawSocket;
+      _socketSubscription = _socket.listen(_eventDispatcher,
+                                           onError: _errorHandler,
+                                           onDone: _doneHandler);
+      _connectPending = true;
+      _secureFilter.connect(host,
+                            port,
+                            is_server,
+                            certificateName,
+                            requestClientCertificate ||
+                                requireClientCertificate,
+                            requireClientCertificate,
+                            sendClientCertificate);
+      _status = HANDSHAKE;
+      _secureHandshake();
+    })
+    .catchError((error) {
+      _handshakeComplete.completeError(error);
+      close();
+    });
+  }
+
+  StreamSubscription listen(void onData(RawSocketEvent data),
+                            {void onError(AsyncError error),
+                             void onDone(),
+                             bool unsubscribeOnError}) {
+    if (_writeEventsEnabled) {
+      _writeEventsEnabled = false;
+      _controller.add(RawSocketEvent.WRITE);
+    }
+    return _stream.listen(onData,
+                          onError: onError,
+                          onDone: onDone,
+                          unsubscribeOnError: unsubscribeOnError);
   }
 
   void _verifyFields() {
-    if (host is! String) throw new ArgumentError(
-        "SecureSocket constructor: host is not a String");
     assert(is_server is bool);
-    assert(socket == null || socket is Socket);
-    if (certificateName != null && certificateName is! String) {
+    assert(_socket == null || _socket is RawSocket);
+    if (host is! String) {
       throw new ArgumentError(
-          "SecureSocket constructor: certificateName is not null or a String");
+          "RawSecureSocket constructor: host is not a String");
+    }
+    if (certificateName != null && certificateName is! String) {
+      throw new ArgumentError("certificateName is not null or a String");
     }
     if (certificateName == null && is_server) {
-      throw new ArgumentError(
-          "SecureSocket constructor: certificateName is null on a server");
+      throw new ArgumentError("certificateName is null on a server");
     }
     if (requestClientCertificate is! bool) {
-      throw new ArgumentError(
-          "SecureSocket constructor: requestClientCertificate is not a bool");
+      throw new ArgumentError("requestClientCertificate is not a bool");
     }
     if (requireClientCertificate is! bool) {
-      throw new ArgumentError(
-          "SecureSocket constructor: requireClientCertificate is not a bool");
+      throw new ArgumentError("requireClientCertificate is not a bool");
     }
     if (sendClientCertificate is! bool) {
-      throw new ArgumentError(
-          "SecureSocket constructor: sendClientCertificate is not a bool");
+      throw new ArgumentError("sendClientCertificate is not a bool");
     }
-  }
-
-  int get port => socket.port;
-
-  String get remoteHost => socket.remoteHost;
-
-  int get remotePort => socket.remotePort;
-
-  void set onClosed(void callback()) {
-    if (_inputStream != null && callback != null) {
-      throw new StreamException(
-           "Cannot set close handler when input stream is used");
+    if (onBadCertificate != null && onBadCertificate is! Function) {
+      throw new ArgumentError("onBadCertificate is not null or a Function");
     }
-    _onClosed = callback;
-  }
+   }
 
-  void set _onClosed(void callback()) {
-    _socketCloseHandler = callback;
-  }
+  int get port => _socket.port;
 
-  void set onConnect(void callback()) {
-    if (_status == CONNECTED || _status == CLOSED) {
-      throw new StreamException(
-          "Cannot set connect handler when already connected");
-    }
-    _onConnect = callback;
-  }
+  String get remoteHost => _socket.remoteHost;
 
-  void set _onConnect(void callback()) {
-    _socketConnectHandler = callback;
-  }
-
-  void set onData(void callback()) {
-    if (_inputStream != null && callback != null) {
-      throw new StreamException(
-          "Cannot set data handler when input stream is used");
-    }
-    _onData = callback;
-  }
-
-  void set _onData(void callback()) {
-    _socketDataHandler = callback;
-  }
-
-  void set onError(void callback(e)) {
-    _socketErrorHandler = callback;
-  }
-
-  void set onWrite(void callback()) {
-    if (_outputStream != null && callback != null) {
-      throw new StreamException(
-          "Cannot set write handler when output stream is used");
-    }
-    _onWrite = callback;
-  }
-
-  void set _onWrite(void callback()) {
-    _socketWriteHandler = callback;
-    // Reset the one-shot onWrite handler.
-    socket.onWrite = _secureWriteHandler;
-  }
-
-  void set onBadCertificate(bool callback(X509Certificate certificate)) {
-    if (callback is! Function && callback != null) {
-      throw new SocketIOException(
-          "Callback provided to onBadCertificate is not a function or null");
-    }
-    secureFilter.registerBadCertificateCallback(callback);
-  }
-
-  InputStream get inputStream {
-    if (_inputStream == null) {
-      if (_socketDataHandler != null || _socketCloseHandler != null) {
-        throw new StreamException(
-            "Cannot get input stream when socket handlers are used");
-      }
-      _inputStream = new _SocketInputStream(this);
-    }
-    return _inputStream;
-  }
-
-  OutputStream get outputStream {
-    if (_outputStream == null) {
-      if (_socketWriteHandler != null) {
-        throw new StreamException(
-            "Cannot get output stream when socket write handler is used");
-      }
-      _outputStream = new _SocketOutputStream(this);
-    }
-    return _outputStream;
-  }
+  int get remotePort => _socket.remotePort;
 
   int available() {
-    throw new UnimplementedError("SecureSocket.available not implemented yet");
+    if (_status != CONNECTED) return 0;
+    _readEncryptedData();
+    return _secureFilter.buffers[READ_PLAINTEXT].length;
   }
 
-  void close([bool halfClose = false]) {
-    if (_status == CLOSED) return;
-    if (halfClose) {
+  void close() {
+    _closedWrite = true;
+    _closedRead = true;
+    if (_socket != null) {
+      _socket.close();
+    }
+    _socketClosedWrite = true;
+    _socketClosedRead = true;
+    if (_secureFilter != null) {
+      _secureFilter.destroy();
+      _secureFilter = null;
+    }
+    if (_socketSubscription != null) {
+      _socketSubscription.cancel();
+    }
+    _controller.close();
+    _status = CLOSED;
+  }
+
+  void shutdown(SocketDirection direction) {
+    if (direction == SocketDirection.BOTH) {
+      close();
+    } else if (direction == SocketDirection.SEND) {
       _closedWrite = true;
       _writeEncryptedData();
       if (_filterWriteEmpty) {
-        socket.close(true);
+        _socket.shutdown(SocketDirection.SEND);
         _socketClosedWrite = true;
         if (_closedRead) {
-          close(false);
+          close();
         }
       }
-    } else {
-      _closedWrite = true;
+    } else if (direction == SocketDirection.RECEIVE) {
       _closedRead = true;
-      socket.close(false);
-      _socketClosedWrite = true;
       _socketClosedRead = true;
-      secureFilter.destroy();
-      secureFilter = null;
-      if (scheduledDataEvent != null) {
-        scheduledDataEvent.cancel();
+      _socket.shutdown(SocketDirection.RECEIVE);
+      if (_socketClosedWrite) {
+        close();
       }
-      _status = CLOSED;
     }
   }
 
-  void _closeWrite() => close(true);
+  bool get writeEventsEnabled => _writeEventsEnabled;
+
+  void set writeEventsEnabled(bool value) {
+    if (value &&
+        _secureFilter != null &&
+        _secureFilter.buffers[WRITE_PLAINTEXT].free > 0) {
+      new Timer(0, (_) => _controller.add(RawSocketEvent.WRITE));
+    } else {
+      _writeEventsEnabled = value;
+    }
+  }
+
+  bool get readEventsEnabled => _readEventsEnabled;
+
+  void set readEventsEnabled(bool value) {
+    _readEventsEnabled = value;
+    if (_socketClosedRead) {
+      if (value) {
+        // We have no underlying socket to set off read events.
+        new Timer(0, (_) => _readHandler());
+      }
+    }
+  }
 
   List<int> read([int len]) {
     if (_closedRead) {
       throw new SocketIOException("Reading from a closed socket");
     }
     if (_status != CONNECTED) {
-      return new List<int>(0);
+      return null;
     }
-    var buffer = secureFilter.buffers[READ_PLAINTEXT];
+    var buffer = _secureFilter.buffers[READ_PLAINTEXT];
     _readEncryptedData();
     int toRead = buffer.length;
     if (len != null) {
@@ -313,50 +428,41 @@
     List<int> result = (toRead == 0) ? null :
         buffer.data.getRange(buffer.start, toRead);
     buffer.advanceStart(toRead);
-    _setHandlersAfterRead();
-    return result;
-  }
 
-  int readList(List<int> data, int offset, int bytes) {
-    if (_closedRead) {
-      throw new SocketIOException("Reading from a closed socket");
-    }
-    if (offset < 0 || bytes < 0 || offset + bytes > data.length) {
-      throw new ArgumentError(
-          "Invalid offset or bytes in SecureSocket.readList");
-    }
-    if (_status != CONNECTED && _status != CLOSED) {
-      return 0;
+    // Set up a read event if the filter still has data.
+    if (!_filterReadEmpty) {
+      new Timer(0, (_) => _readHandler());
     }
 
-    int bytesRead = 0;
-    var buffer = secureFilter.buffers[READ_PLAINTEXT];
-    // TODO(whesse): Currently this fails if the if is turned into a while loop.
-    // Fix it so that it can loop and read more than one buffer's worth of data.
-    if (bytes > bytesRead) {
-      _readEncryptedData();
-      if (buffer.length > 0) {
-        int toRead = min(bytes - bytesRead, buffer.length);
-        data.setRange(offset, toRead, buffer.data, buffer.start);
-        buffer.advanceStart(toRead);
-        bytesRead += toRead;
-        offset += toRead;
+    if (_socketClosedRead) {  // An onClose event is pending.
+      // _closedRead is false, since we are in a read  call.
+      if (!_filterReadEmpty) {
+        // _filterReadEmpty may be out of date since read empties
+        // the plaintext buffer after calling _readEncryptedData.
+        // TODO(whesse): Fix this as part of fixing read.
+        _readEncryptedData();
+      }
+      if (_filterReadEmpty) {
+        // This can't be an else clause: the value of _filterReadEmpty changes.
+        // This must be asynchronous, because we are in a read call.
+        new Timer(0, (_) => _closeHandler());
       }
     }
 
-    _setHandlersAfterRead();
-    return bytesRead;
+    return result;
   }
 
   // Write the data to the socket, and flush it as much as possible
   // until it would block.  If the write would block, _writeEncryptedData sets
   // up handlers to flush the pipeline when possible.
-  int writeList(List<int> data, int offset, int bytes) {
+  int write(List<int> data, [int offset, int bytes]) {
     if (_closedWrite) {
-      throw new SocketIOException("Writing to a closed socket");
+      _controller.signalError(new AsyncError(new SocketIOException(
+          "Writing to a closed socket")));
+      return 0;
     }
     if (_status != CONNECTED) return 0;
-    var buffer = secureFilter.buffers[WRITE_PLAINTEXT];
+    var buffer = _secureFilter.buffers[WRITE_PLAINTEXT];
     if (bytes > buffer.free) {
       bytes = buffer.free;
     }
@@ -368,162 +474,182 @@
     return bytes;
   }
 
-  X509Certificate get peerCertificate => secureFilter.peerCertificate;
+  X509Certificate get peerCertificate => _secureFilter.peerCertificate;
 
-  void _secureConnectHandler() {
-    _connectPending = true;
-    secureFilter.connect(host,
-                         port,
-                         is_server,
-                         certificateName,
-                         requestClientCertificate || requireClientCertificate,
-                         requireClientCertificate,
-                         sendClientCertificate);
-    _status = HANDSHAKE;
-    _secureHandshake();
-  }
-
-  void _secureWriteHandler() {
+  void _writeHandler() {
+    if (_status == CLOSED) return;
     _writeEncryptedData();
     if (_filterWriteEmpty && _closedWrite && !_socketClosedWrite) {
-      close(true);
+      // Close _socket for write, by calling shutdown(), to avoid cloning the
+      // socket closing code in shutdown().
+      shutdown(SocketDirection.SEND);
     }
     if (_status == HANDSHAKE) {
-      _secureHandshake();
-    } else if (_status == CONNECTED &&
-               _socketWriteHandler != null &&
-               secureFilter.buffers[WRITE_PLAINTEXT].free > 0) {
-      // We must be able to set onWrite from the onWrite callback.
-      var handler = _socketWriteHandler;
-      // Reset the one-shot handler.
-      _socketWriteHandler = null;
-      handler();
-    }
-  }
-
-  void _secureDataHandler() {
-    if (_status == HANDSHAKE) {
       try {
         _secureHandshake();
-      } catch (e) { _reportError(e, "SecureSocket error"); }
-    } else {
+      } catch (e) { _reportError(e, "RawSecureSocket error"); }
+    } else if (_status == CONNECTED &&
+               _writeEventsEnabled &&
+               _secureFilter.buffers[WRITE_PLAINTEXT].free > 0) {
+      // Reset the one-shot handler.
+      _writeEventsEnabled = false;
+      _controller.add(RawSocketEvent.WRITE);
+    }
+  }
+
+  void _eventDispatcher(RawSocketEvent event) {
+    if (event == RawSocketEvent.READ) {
+      _readHandler();
+    } else if (event == RawSocketEvent.WRITE) {
+      _writeHandler();
+    } else if (event == RawSocketEvent.READ_CLOSED) {
+      _closeHandler();
+    }
+  }
+
+  void _readHandler() {
+    if (_status == CLOSED) {
+      return;
+    } else if (_status == HANDSHAKE) {
       try {
-        _writeEncryptedData();  // TODO(whesse): Removing this causes a failure.
+        _secureHandshake();
+        if (_status != HANDSHAKE) _readHandler();
+      } catch (e) { _reportError(e, "RawSecureSocket error"); }
+    } else {
+      if (_status != CONNECTED) {
+        // Cannot happen.
+        throw new SocketIOException("Internal SocketIO Error");
+      }
+      try {
         _readEncryptedData();
-      } catch (e) { _reportError(e, "SecureSocket error"); }
+      } catch (e) { _reportError(e, "RawSecureSocket error"); }
       if (!_filterReadEmpty) {
-        // Call the onData event.
-        if (scheduledDataEvent != null) {
-          scheduledDataEvent.cancel();
-          scheduledDataEvent = null;
-        }
-        if (_socketDataHandler != null) {
-          _socketDataHandler();
+        if (_readEventsEnabled) {
+          if (_secureFilter.buffers[READ_PLAINTEXT].length > 0) {
+            _controller.add(RawSocketEvent.READ);
+          }
+          if (_socketClosedRead) {
+            // Keep firing read events until we are paused or buffer is empty.
+            new Timer(0, (_) => _readHandler());
+          }
         }
       } else if (_socketClosedRead) {
-        _secureCloseHandler();
+        _closeHandler();
       }
     }
   }
 
-  void _secureErrorHandler(e) {
-    _reportError(e, 'Error on underlying Socket');
+  void _doneHandler() {
+    if (_filterReadEmpty) {
+      close();
+    }
+  }
+
+  void _errorHandler(e) {
+    _reportError(e, 'Error on underlying RawSocket');
   }
 
   void _reportError(error, String message) {
     // TODO(whesse): Call _reportError from all internal functions that throw.
     var e;
-    if (error is SocketIOException) {
+    if (error is AsyncError) {
+      e = error;
+    } else if (error is SocketIOException) {
       e = new SocketIOException('$message (${error.message})', error.osError);
     } else if (error is OSError) {
       e = new SocketIOException(message, error);
     } else {
       e = new SocketIOException('$message (${error.toString()})', null);
     }
-    close(false);
-    bool reported = false;
-    if (_socketErrorHandler != null) {
-      reported = true;
-      _socketErrorHandler(e);
+    if (_connectPending) {
+      _handshakeComplete.completeError(e);
+    } else {
+      _controller.signalError(e);
     }
-    if (_inputStream != null) {
-      reported = reported || _inputStream._onSocketError(e);
-    }
-    if (_outputStream != null) {
-      reported = reported || _outputStream._onSocketError(e);
-    }
-    if (!reported) throw e;
+    close();
   }
 
-  void _secureCloseHandler() {
-    if (_closedRead) return;
-    _socketClosedRead = true;
-    if (_filterReadEmpty) {
-      _closedRead = true;
-      if (scheduledDataEvent != null) {
-        scheduledDataEvent.cancel();
+  void _closeHandler() {
+    if  (_status == CONNECTED) {
+      if (_closedRead) return;
+      _socketClosedRead = true;
+      if (_filterReadEmpty) {
+        _closedRead = true;
+        _controller.add(RawSocketEvent.READ_CLOSED);
+        if (_socketClosedWrite) {
+          close();
+        }
       }
-      if (_socketCloseHandler != null) {
-        _socketCloseHandler();
-      }
-      if (_socketClosedWrite) {
-        close(false);
-      }
+    } else if (_status == HANDSHAKE) {
+      _reportError(
+          new SocketIOException('Connection terminated during handshake'),
+          'handshake error');
     }
   }
 
   void _secureHandshake() {
     _readEncryptedData();
-    secureFilter.handshake();
+    _secureFilter.handshake();
     _writeEncryptedData();
-    if (secureFilter.buffers[WRITE_ENCRYPTED].length > 0) {
-      socket.onWrite = _secureWriteHandler;
-    }
   }
 
   void _secureHandshakeCompleteHandler() {
     _status = CONNECTED;
-    if (_connectPending && _socketConnectHandler != null) {
+    if (_connectPending) {
       _connectPending = false;
-      _socketConnectHandler();
-    }
-    if (_socketWriteHandler != null) {
-      socket.onWrite = _secureWriteHandler;
+      // If we complete the future synchronously, user code will run here,
+      // and modify the state of the RawSecureSocket.  For example, it
+      // could close the socket, and set _filter to null.
+      new Timer(0, (_) => _handshakeComplete.complete(this));
     }
   }
 
-  // True if the underlying socket is closed, the filter has been emptied of
-  // all data, and the close event has been fired.
-  get _closed => _socketClosed;
+  void _onPauseStateChange() {
+    if (!_socketClosedRead || !_socketClosedWrite) {
+      if (_controller.isPaused) {
+        _socketSubscription.pause();
+      } else {
+        _socketSubscription.resume();
+      }
+    }
+  }
+
+  void _onSubscriptionStateChange() {
+    if (_controller.hasSubscribers) {
+      // TODO(ajohnsen): Do something here?
+    }
+  }
 
   void _readEncryptedData() {
     // Read from the socket, and push it through the filter as far as
     // possible.
-    var encrypted = secureFilter.buffers[READ_ENCRYPTED];
-    var plaintext = secureFilter.buffers[READ_PLAINTEXT];
+    var encrypted = _secureFilter.buffers[READ_ENCRYPTED];
+    var plaintext = _secureFilter.buffers[READ_PLAINTEXT];
     bool progress = true;
     while (progress) {
       progress = false;
       // Do not try to read plaintext from the filter while handshaking.
       if ((_status == CONNECTED) && plaintext.free > 0) {
-        int bytes = secureFilter.processBuffer(READ_PLAINTEXT);
+        int bytes = _secureFilter.processBuffer(READ_PLAINTEXT);
         if (bytes > 0) {
           plaintext.length += bytes;
           progress = true;
         }
       }
       if (encrypted.length > 0) {
-        int bytes = secureFilter.processBuffer(READ_ENCRYPTED);
+        int bytes = _secureFilter.processBuffer(READ_ENCRYPTED);
         if (bytes > 0) {
           encrypted.advanceStart(bytes);
           progress = true;
         }
       }
-      if (!_socketClosedRead) {
-        int bytes = socket.readList(encrypted.data,
-                                    encrypted.start + encrypted.length,
-                                    encrypted.free);
-        if (bytes > 0) {
+      if (!_socketClosedRead && encrypted.free > 0) {
+        List<int> data = _socket.read(encrypted.free);
+        if (data != null) {
+          int bytes = data.length;
+          encrypted.data.setRange(encrypted.start + encrypted.length,
+                                  bytes,
+                                  data);
           encrypted.length += bytes;
           progress = true;
         }
@@ -538,29 +664,29 @@
 
   void _writeEncryptedData() {
     if (_socketClosedWrite) return;
-    var encrypted = secureFilter.buffers[WRITE_ENCRYPTED];
-    var plaintext = secureFilter.buffers[WRITE_PLAINTEXT];
+    var encrypted = _secureFilter.buffers[WRITE_ENCRYPTED];
+    var plaintext = _secureFilter.buffers[WRITE_PLAINTEXT];
     while (true) {
       if (encrypted.length > 0) {
         // Write from the filter to the socket.
-        int bytes = socket.writeList(encrypted.data,
-                                     encrypted.start,
-                                     encrypted.length);
-        if (bytes == 0) {
+        int bytes = _socket.write(encrypted.data,
+                                  encrypted.start,
+                                  encrypted.length);
+        encrypted.advanceStart(bytes);
+        if (encrypted.length > 0) {
           // The socket has blocked while we have data to write.
           // We must be notified when it becomes unblocked.
-          socket.onWrite = _secureWriteHandler;
+          _socket.writeEventsEnabled = true;
           _filterWriteEmpty = false;
           break;
         }
-        encrypted.advanceStart(bytes);
       } else {
-        var plaintext = secureFilter.buffers[WRITE_PLAINTEXT];
+        var plaintext = _secureFilter.buffers[WRITE_PLAINTEXT];
         if (plaintext.length > 0) {
-           int plaintext_bytes = secureFilter.processBuffer(WRITE_PLAINTEXT);
+           int plaintext_bytes = _secureFilter.processBuffer(WRITE_PLAINTEXT);
            plaintext.advanceStart(plaintext_bytes);
         }
-        int bytes = secureFilter.processBuffer(WRITE_ENCRYPTED);
+        int bytes = _secureFilter.processBuffer(WRITE_ENCRYPTED);
         if (bytes <= 0) {
           // We know the WRITE_ENCRYPTED buffer is empty, and the
           // filter wrote zero bytes to it, so the filter must be empty.
@@ -574,69 +700,6 @@
       }
     }
   }
-
-  /* After a read, the onData handler is enabled to fire again.
-   * We may also have a close event waiting for the SecureFilter to empty.
-   */
-  void _setHandlersAfterRead() {
-    // If the filter is empty, then we are guaranteed an event when it
-    // becomes unblocked.  Cancel any _secureDataHandler call.
-    // Otherwise, schedule a _secureDataHandler call since there may data
-    // available, and this read call enables the data event.
-    if (_filterReadEmpty) {
-      if (scheduledDataEvent != null) {
-        scheduledDataEvent.cancel();
-        scheduledDataEvent = null;
-      }
-    } else if (scheduledDataEvent == null) {
-      scheduledDataEvent = Timer.run(_secureDataHandler);
-    }
-
-    if (_socketClosedRead) {  // An onClose event is pending.
-      // _closedRead is false, since we are in a read or readList call.
-      if (!_filterReadEmpty) {
-        // _filterReadEmpty may be out of date since read and readList empty
-        // the plaintext buffer after calling _readEncryptedData.
-        // TODO(whesse): Fix this as part of fixing read and readList.
-        _readEncryptedData();
-      }
-      if (_filterReadEmpty) {
-        // This can't be an else clause: the value of _filterReadEmpty changes.
-        // This must be asynchronous, because we are in a read or readList call.
-        Timer.run(_secureCloseHandler);
-      }
-    }
-  }
-
-  bool get _socketClosed => _closedRead;
-
-  // _SecureSocket cannot extend _Socket and use _Socket's factory constructor.
-  Socket socket;
-  final String host;
-  final bool is_server;
-  final String certificateName;
-  final bool requestClientCertificate;
-  final bool requireClientCertificate;
-  final bool sendClientCertificate;
-
-  var _status = NOT_CONNECTED;
-  bool _socketClosedRead = false;  // The network socket is closed for reading.
-  bool _socketClosedWrite = false;  // The network socket is closed for writing.
-  bool _closedRead = false;  // The secure socket has fired an onClosed event.
-  bool _closedWrite = false;  // The secure socket has been closed for writing.
-  bool _filterReadEmpty = true;  // There is no buffered data to read.
-  bool _filterWriteEmpty = true;  // There is no buffered data to be written.
-  _SocketInputStream _inputStream;
-  _SocketOutputStream _outputStream;
-  bool _connectPending = false;
-  Function _socketConnectHandler;
-  Function _socketWriteHandler;
-  Function _socketDataHandler;
-  Function _socketErrorHandler;
-  Function _socketCloseHandler;
-  Timer scheduledDataEvent;
-
-  _SecureFilter secureFilter;
 }
 
 
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index 84b5e75..b0c04b4 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -1,26 +1,31 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.io;
 
-abstract class ServerSocket {
+/**
+ * The RawServerSocket is a server socket, providing a stream of low-level
+ * [RawSocket]s.
+ *
+ * See [RawSocket] for more info.
+ */
+abstract class RawServerSocket implements Stream<RawSocket> {
   /**
-   * Constructs a new server socket, binds it to a given address and port,
-   * and listens on it.
+   * Returns a future for a [:RawServerSocket:]. When the future
+   * completes the server socket is bound to the given [address] and
+   * [port] and has started listening on it.
+   *
+   * If [port] has the value [:0:] (the default) an ephemeral port will
+   * be chosen by the system. The actual port used can be retrieved
+   * using the [:port:] getter.
+   *
+   * If [backlog] has the value of [:0:] a reasonable value will be
+   * chosen by the system.
    */
-  external factory ServerSocket(String bindAddress, int port, int backlog);
-
-  /**
-   * The connection handler gets called when there is a new incoming
-   * connection on the socket.
-   */
-  void set onConnection(void callback(Socket connection));
-
-  /**
-   * The error handler gets called when a socket error occurs.
-   */
-  void set onError(void callback(e));
+  external static Future<RawServerSocket> bind([String address = "127.0.0.1",
+                                               int port = 0,
+                                               int backlog = 0]);
 
   /**
    * Returns the port used by this socket.
@@ -34,13 +39,79 @@
 }
 
 
-abstract class Socket {
+/**
+ * The [ServerSocket] is server socket, providing a stream of high-level
+ * [Socket]s.
+ *
+ * See [Socket] for more info.
+ */
+abstract class ServerSocket implements Stream<Socket> {
   /**
-   * Constructs a new socket and initiate connecting it to the given
-   * host on the given port. The returned socket is not yet connected
-   * but ready for registration of callbacks.
+   * Returns a future for a [:ServerSocket:]. When the future
+   * completes the server socket is bound to the given [address] and
+   * [port] and has started listening on it.
+   *
+   * If [port] has the value [:0:] (the default) an ephemeral port will
+   * be chosen by the system. The actual port used can be retrieved
+   * using the [port] getter.
+   *
+   * If [backlog] has the value of [:0:] a reasonable value will be
+   * chosen by the system.
    */
-  external factory Socket(String host, int port);
+  external static Future<ServerSocket> bind([String address = "127.0.0.1",
+                                             int port = 0,
+                                             int backlog = 0]);
+
+  /**
+   * Returns the port used by this socket.
+   */
+  int get port;
+
+  /**
+   * Closes the socket.
+   */
+  void close();
+}
+
+/**
+ * The [SocketDirection] is used as a parameter to [Socket.close] and
+ * [RawSocket.close] to close a socket in the specified direction(s).
+ */
+class SocketDirection {
+  static const SocketDirection RECEIVE = const SocketDirection._(0);
+  static const SocketDirection SEND = const SocketDirection._(1);
+  static const SocketDirection BOTH = const SocketDirection._(2);
+  const SocketDirection._(this._value);
+  final _value;
+}
+
+/**
+ * Events for the [RawSocket].
+ */
+class RawSocketEvent {
+  static const RawSocketEvent READ = const RawSocketEvent._(0);
+  static const RawSocketEvent WRITE = const RawSocketEvent._(1);
+  static const RawSocketEvent READ_CLOSED = const RawSocketEvent._(2);
+  const RawSocketEvent._(this._value);
+  final int _value;
+  String toString() {
+    return ['RawSocketEvent:READ',
+            'RawSocketEvent:WRITE',
+            'RawSocketEvent:READ_CLOSED'][_value];
+  }
+}
+
+/**
+ * The [RawSocket] is a low-level interface to a socket, exposing the raw
+ * events signaled by the system. It's a [Stream] of [RawSocketEvent]s.
+ */
+abstract class RawSocket implements Stream<RawSocketEvent> {
+  /**
+   * Creats a new socket connection to the host and port and returns a [Future]
+   * that will complete with either a [RawSocket] once connected or an error
+   * if the host-lookup or connection failed.
+   */
+  external static Future<RawSocket> connect(String host, int port);
 
   /**
    * Returns the number of received and non-read bytes in the socket that
@@ -58,61 +129,12 @@
   List<int> read([int len]);
 
   /**
-   * Reads up to [count] bytes of data from the socket and stores them into
-   * buffer after buffer offset [offset]. The number of successfully read
-   * bytes is returned. This function is non-blocking and will only read data
-   * if data is available.
-   */
-  int readList(List<int> buffer, int offset, int count);
-
-  /**
    * Writes up to [count] bytes of the buffer from [offset] buffer offset to
    * the socket. The number of successfully written bytes is returned. This
    * function is non-blocking and will only write data if buffer space is
    * available in the socket.
    */
-  int writeList(List<int> buffer, int offset, int count);
-
-  /**
-   * The connect handler gets called when connection to a given host
-   * succeeded.
-   */
-  void set onConnect(void callback());
-
-  /**
-   * The data handler gets called when data becomes available at the socket.
-   */
-  void set onData(void callback());
-
-  /**
-   * The write handler gets called once when the socket becomes
-   * available for writing. Then the handler is automatically reset to null.
-   * This handler is mainly used when writeList has reported an incomplete
-   * write, to schedule writing the remaining data to the socket.
-   */
-  void set onWrite(void callback());
-
-  /**
-   * The close handler gets called when a the last byte have been read
-   * from a socket. At this point the socket might still be open for
-   * writing for sending more data.
-   */
-  void set onClosed(void callback());
-
-  /**
-   * The error handler gets called when a socket error occurs.
-   */
-  void set onError(void callback(e));
-
-  /**
-   * Returns input stream to the socket.
-   */
-  InputStream get inputStream;
-
-  /**
-   * Returns output stream of the socket.
-   */
-  OutputStream get outputStream;
+  int write(List<int> buffer, [int offset, int count]);
 
   /**
    * Returns the port used by this socket.
@@ -131,12 +153,61 @@
 
   /**
    * Closes the socket. Calling [close] will never throw an exception
-   * and calling it several times is supported. If [halfClose] is true
-   * the socket will only be closed for writing and it might still be
-   * possible to read data. Calling [close] will not trigger a call to
-   * [onClosed].
+   * and calling it several times is supported. Calling [close] can result in
+   * a [RawSocketEvent.READ_CLOSED] event.
    */
-  void close([bool halfClose = false]);
+  void close();
+
+  /**
+   * Shutdown the socket in the [direction]. Calling [shutdown] will never
+   * throw an exception and calling it several times is supported. Calling
+   * shutdown with either [SocketDirection.BOTH] or [SocketDirection.RECEIVE]
+   * can result in a [RawSocketEvent.READ_CLOSED] event.
+   */
+  void shutdown(SocketDirection direction);
+
+  /**
+   * Set or get, if the [RawSocket] should listen for [RawSocketEvent.READ]
+   * events. Default is [true].
+   */
+  bool readEventsEnabled;
+
+  /**
+   * Set or get, if the [RawSocket] should listen for [RawSocketEvent.WRITE]
+   * events. Default is [true].
+   * This is a one-shot listener, and writeEventsEnabled must be set
+   * to true again to receive another write event.
+   */
+  bool writeEventsEnabled;
+}
+
+/**
+ * A high-level class for communicating over a TCP socket. The [Socket] exposes
+ * both a [Stream] and a [IOSink] interface, making it ideal for
+ * using together with other [Stream]s.
+ */
+abstract class Socket implements Stream<List<int>>,
+                                 IOSink<Socket> {
+  /**
+   * Creats a new socket connection to the host and port and returns a [Future]
+   * that will complete with either a [RawSocket] once connected or an error
+   * if the host-lookup or connection failed.
+   */
+  external static Future<Socket> connect(String host, int port);
+
+  /**
+   * Destroy the socket in both directions. Calling [destroy] will make the
+   * send a close event on the stream and will no longer react on data being
+   * piped to it.
+   *
+   * Call [close](inherited by [IOSink]) to only close the [Socket]
+   * for sending data.
+   */
+  void destroy();
+
+  int get port;
+  String get remoteHost;
+  int get remotePort;
 }
 
 
diff --git a/sdk/lib/io/socket_stream_impl.dart b/sdk/lib/io/socket_stream_impl.dart
deleted file mode 100644
index d156bd7..0000000
--- a/sdk/lib/io/socket_stream_impl.dart
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.io;
-
-class _SocketInputStream implements InputStream {
-  _SocketInputStream(Socket socket) : _socket = socket {
-    if (_socket._closed) _closed = true;
-    _socket.onClosed = _onClosed;
-  }
-
-  List<int> read([int len]) {
-    return _socket.read(len);
-  }
-
-  int readInto(List<int> buffer, [int offset = 0, int len]) {
-    if (_closed) return null;
-    if (len == null) len = buffer.length;
-    if (offset < 0) throw new StreamException("Illegal offset $offset");
-    if (len < 0) throw new StreamException("Illegal length $len");
-    return _socket.readList(buffer, offset, len);
-  }
-
-  int available() => _socket.available();
-
-  void pipe(OutputStream output, {bool close: true}) {
-    _pipe(this, output, close: close);
-  }
-
-  void close() {
-    if (!_closed) {
-      _socket.close();
-    }
-  }
-
-  bool get closed => _closed;
-
-  void set onData(void callback()) {
-    _socket._onData = callback;
-  }
-
-  void set onClosed(void callback()) {
-    _clientCloseHandler = callback;
-    _socket._onClosed = _onClosed;
-  }
-
-  void set onError(void callback(e)) {
-    _onError = callback;
-  }
-
-  void _onClosed() {
-    _closed = true;
-    if (_clientCloseHandler != null) {
-      _clientCloseHandler();
-    }
-  }
-
-  bool _onSocketError(e) {
-    close();
-    if (_onError != null) {
-      _onError(e);
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  Socket _socket;
-  bool _closed = false;
-  Function _clientCloseHandler;
-  Function _onError;
-}
-
-
-class _SocketOutputStream
-    extends _BaseOutputStream implements OutputStream {
-  _SocketOutputStream(Socket socket)
-      : _socket = socket, _pendingWrites = new _BufferList();
-
-  bool write(List<int> buffer, [bool copyBuffer = true]) {
-    return _write(buffer, 0, buffer.length, copyBuffer);
-  }
-
-  bool writeFrom(List<int> buffer, [int offset = 0, int len]) {
-    return _write(
-        buffer, offset, (len == null) ? buffer.length - offset : len, true);
-  }
-
-  void flush() {
-    // Nothing to do on a socket output stream.
-  }
-
-  void close() {
-    if (_closing) return;
-    _closing = true;
-    if (!_pendingWrites.isEmpty) {
-      // Mark the socket for close when all data is written.
-      _socket._onWrite = _onWrite;
-    } else {
-      // Close the socket for writing.
-      _socket._closeWrite();
-      _closed = true;
-      // Invoke the callback asynchronously.
-      Timer.run(() {
-        if (_onClosed != null) _onClosed();
-      });
-    }
-  }
-
-  void destroy() {
-    _socket._onWrite = null;
-    _pendingWrites.clear();
-    _socket.close();
-    _closed = true;
-  }
-
-  bool get closed => _closed;
-
-  void set onNoPendingWrites(void callback()) {
-    _onNoPendingWrites = callback;
-    if (_onNoPendingWrites != null) {
-      _socket._onWrite = _onWrite;
-    }
-  }
-
-  void set onClosed(void callback()) {
-    _onClosed = callback;
-  }
-
-  bool _write(List<int> buffer, int offset, int len, bool copyBuffer) {
-    if (_closing || _closed) {
-      if (_error) return false;
-      _error = true;
-      var e = new StreamException.streamClosed();
-      if (_onError != null) {
-        _onError(e);
-        return false;
-      } else {
-        throw e;
-      }
-    }
-    int bytesWritten = 0;
-    if (_pendingWrites.isEmpty) {
-      // If nothing is buffered write as much as possible and buffer
-      // the rest.
-      try {
-        bytesWritten = _socket.writeList(buffer, offset, len);
-        if (bytesWritten == len) return true;
-      } catch (e) {
-        if (_error) return false;
-        _error = true;
-        if (_onError != null) {
-          _onError(e);
-          return false;
-        } else {
-          throw e;
-        }
-      }
-    }
-
-    // Place remaining data on the pending writes queue.
-    int notWrittenOffset = offset + bytesWritten;
-    if (copyBuffer) {
-      List<int> newBuffer =
-          buffer.getRange(notWrittenOffset, len - bytesWritten);
-      _pendingWrites.add(newBuffer);
-    } else {
-      assert(offset + len == buffer.length);
-      _pendingWrites.add(buffer, notWrittenOffset);
-    }
-    _socket._onWrite = _onWrite;
-    return false;
-  }
-
-  void _onWrite() {
-    // Write as much buffered data to the socket as possible.
-    while (!_pendingWrites.isEmpty) {
-      List<int> buffer = _pendingWrites.first;
-      int offset = _pendingWrites.index;
-      int bytesToWrite = buffer.length - offset;
-      int bytesWritten;
-      try {
-        bytesWritten = _socket.writeList(buffer, offset, bytesToWrite);
-      } catch (e) {
-        _pendingWrites.clear();
-        if (_onError != null) _onError(e);
-        return;
-      }
-      _pendingWrites.removeBytes(bytesWritten);
-      if (bytesWritten < bytesToWrite) {
-        _socket._onWrite = _onWrite;
-        return;
-      }
-    }
-
-    // All buffered data was written.
-    if (_closing) {
-      _socket._closeWrite();
-      _closed = true;
-      if (_onClosed != null) {
-        _onClosed();
-      }
-    } else {
-      if (_onNoPendingWrites != null) _onNoPendingWrites();
-    }
-    if (_onNoPendingWrites == null) {
-      _socket._onWrite = null;
-    } else {
-      _socket._onWrite = _onWrite;
-    }
-  }
-
-  bool _onSocketError(e) {
-    destroy();
-    if (_error) return true;
-    if (_onError != null) {
-      _onError(e);
-      return true;
-    } else {
-      throw e;
-    }
-  }
-
-  Socket _socket;
-  _BufferList _pendingWrites;
-  Function _onNoPendingWrites;
-  Function _onClosed;
-  bool _closing = false;
-  bool _closed = false;
-  bool _error = false;
-}
diff --git a/sdk/lib/io/stdio.dart b/sdk/lib/io/stdio.dart
index ae66488..eb7119c 100644
--- a/sdk/lib/io/stdio.dart
+++ b/sdk/lib/io/stdio.dart
@@ -21,12 +21,12 @@
 }
 
 
-InputStream _stdin;
-OutputStream _stdout;
-OutputStream _stderr;
+Stream<List<int>> _stdin;
+IOSink _stdout;
+IOSink _stderr;
 
 
-InputStream get stdin {
+Stream<List<int>> get stdin {
   if (_stdin == null) {
     _stdin = _StdIOUtils._getStdioInputStream();
   }
@@ -34,7 +34,7 @@
 }
 
 
-OutputStream get stdout {
+IOSink get stdout {
   if (_stdout == null) {
     _stdout = _StdIOUtils._getStdioOutputStream(1);
   }
@@ -42,7 +42,7 @@
 }
 
 
-OutputStream get stderr {
+IOSink get stderr {
   if (_stderr == null) {
     _stderr = _StdIOUtils._getStdioOutputStream(2);
   }
@@ -51,23 +51,31 @@
 
 
 StdioType stdioType(object) {
-  if (object is _FileOutputStream || object is _FileInputStream) {
+  if (object is _FileStream) {
     return StdioType.FILE;
   }
-  if (object is !_SocketOutputStream && object is !_SocketInputStream) {
-    return StdioType.OTHER;
+  if (object is Socket) {
+    switch (_StdIOUtils._socketType(object._nativeSocket)) {
+      case _STDIO_HANDLE_TYPE_TERMINAL: return StdioType.TERMINAL;
+      case _STDIO_HANDLE_TYPE_PIPE: return StdioType.PIPE;
+      case _STDIO_HANDLE_TYPE_FILE:  return StdioType.FILE;
+    }
   }
-  switch (_StdIOUtils._socketType(object._socket)) {
-    case _STDIO_HANDLE_TYPE_TERMINAL: return StdioType.TERMINAL;
-    case _STDIO_HANDLE_TYPE_PIPE: return StdioType.PIPE;
-    case _STDIO_HANDLE_TYPE_FILE:  return StdioType.FILE;
-    default: return StdioType.OTHER;
+  if (object is IOSink) {
+    try {
+      if (object._sink.target is _FileStreamConsumer) {
+        return StdioType.FILE;
+      }
+    } catch (e) {
+      // Only the interface implemented, _sink not available.
+    }
   }
+  return StdioType.OTHER;
 }
 
 
 class _StdIOUtils {
-  external static OutputStream _getStdioOutputStream(int fd);
-  external static InputStream _getStdioInputStream();
-  external static int _socketType(Socket socket);
+  external static IOSink _getStdioOutputStream(int fd);
+  external static Stream<List<int>> _getStdioInputStream();
+  external static int _socketType(nativeSocket);
 }
diff --git a/sdk/lib/io/stream_util.dart b/sdk/lib/io/stream_util.dart
deleted file mode 100644
index b68b8fd..0000000
--- a/sdk/lib/io/stream_util.dart
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.io;
-
-abstract class _BaseDataInputStream {
-  int available();
-
-  List<int> read([int len]) {
-    if (_closeCallbackCalled || _scheduledCloseCallback != null) return null;
-    int bytesToRead = available();
-    if (bytesToRead == 0) {
-      _checkScheduleCallbacks();
-      return null;
-    }
-    if (len != null) {
-      if (len <= 0) {
-        throw new StreamException("Illegal length $len");
-      } else if (bytesToRead > len) {
-        bytesToRead = len;
-      }
-    }
-    return _read(bytesToRead);
-  }
-
-  int readInto(List<int> buffer, [int offset = 0, int len]) {
-    if (_closeCallbackCalled || _scheduledCloseCallback != null) return 0;
-    if (len == null) len = buffer.length;
-    if (offset < 0) throw new StreamException("Illegal offset $offset");
-    if (len < 0) throw new StreamException("Illegal length $len");
-    int bytesToRead = min(len, available());
-    return _readInto(buffer, offset, bytesToRead);
-  }
-
-  void pipe(OutputStream output, {bool close: true}) {
-    _pipe(this, output, close: close);
-  }
-
-  void close() {
-    _cancelScheduledDataCallback();
-    _close();
-    _checkScheduleCallbacks();
-  }
-
-  bool get closed => _closeCallbackCalled;
-
-  void set onData(void callback()) {
-    _clientDataHandler = callback;
-    _checkScheduleCallbacks();
-  }
-
-  void set onClosed(void callback()) {
-    _clientCloseHandler = callback;
-    _checkScheduleCallbacks();
-  }
-
-  void set onError(void callback(e)) {
-    _clientErrorHandler = callback;
-  }
-
-  void _reportError(e) {
-    if (_clientErrorHandler != null) {
-      _clientErrorHandler(e);
-    } else {
-      throw e;
-    }
-  }
-
-  List<int> _read(int bytesToRead);
-
-  void _dataReceived() {
-    // More data has been received asynchronously. Perform the data
-    // handler callback now.
-    _cancelScheduledDataCallback();
-    if (_clientDataHandler != null) {
-      _clientDataHandler();
-    }
-    _checkScheduleCallbacks();
-  }
-
-  void _closeReceived() {
-    // Close indication has been received asynchronously. Perform the
-    // close callback now if all data has been delivered.
-    _streamMarkedClosed = true;
-    if (available() == 0) {
-      _closeCallbackCalled = true;
-      if (_clientCloseHandler != null) _clientCloseHandler();
-    } else {
-      _checkScheduleCallbacks();
-    }
-  }
-
-  void _cancelScheduledDataCallback() {
-    if (_scheduledDataCallback != null) {
-      _scheduledDataCallback.cancel();
-      _scheduledDataCallback = null;
-    }
-  }
-
-  void _checkScheduleCallbacks() {
-    void issueDataCallback() {
-      _scheduledDataCallback = null;
-      if (_clientDataHandler != null) {
-        _clientDataHandler();
-        _checkScheduleCallbacks();
-      }
-    }
-
-    void issueCloseCallback() {
-      _scheduledCloseCallback = null;
-      _closeCallbackCalled = true;
-      if (_clientCloseHandler != null) _clientCloseHandler();
-    }
-
-    // Schedule data callback if there is more data to read. Schedule
-    // close callback once when all data has been read. Only schedule
-    // a new callback if the previous one has actually been called.
-    if (!_closeCallbackCalled) {
-      if (available() > 0) {
-        if (_scheduledDataCallback == null) {
-          _scheduledDataCallback = Timer.run(issueDataCallback);
-        }
-      } else if (_streamMarkedClosed && _scheduledCloseCallback == null) {
-        _cancelScheduledDataCallback();
-        _close();
-        _scheduledCloseCallback = Timer.run(issueCloseCallback);
-      }
-    }
-  }
-
-  // When this is set to true the stream is marked closed. When a
-  // stream is marked closed no more data can arrive and the value
-  // from available is now all remaining data. If this is true and the
-  // value of available is zero the close handler is called.
-  bool _streamMarkedClosed = false;
-
-  // When this is set to true the close callback has been called and
-  // the stream is fully closed.
-  bool _closeCallbackCalled = false;
-
-  Timer _scheduledDataCallback;
-  Timer _scheduledCloseCallback;
-  Function _clientDataHandler;
-  Function _clientCloseHandler;
-  Function _clientErrorHandler;
-}
-
-
-void _pipe(InputStream input, OutputStream output, {bool close}) {
-  Function pipeDataHandler;
-  Function pipeCloseHandler;
-  Function pipeNoPendingWriteHandler;
-
-  Function _inputCloseHandler;
-
-  pipeDataHandler = () {
-    List<int> data;
-    while ((data = input.read()) != null) {
-      if (!output.write(data)) {
-        input.onData = null;
-        output.onNoPendingWrites = pipeNoPendingWriteHandler;
-        break;
-      }
-    }
-  };
-
-  pipeCloseHandler = () {
-    if (close) output.close();
-    if (_inputCloseHandler != null) {
-      _inputCloseHandler();
-    }
-  };
-
-  pipeNoPendingWriteHandler = () {
-    input.onData = pipeDataHandler;
-    output.onNoPendingWrites = null;
-  };
-
-  _inputCloseHandler = input._clientCloseHandler;
-  input.onData = pipeDataHandler;
-  input.onClosed = pipeCloseHandler;
-  output.onNoPendingWrites = null;
-}
-
-
-class _BaseOutputStream {
-  bool writeString(String string, [Encoding encoding = Encoding.UTF_8]) {
-    if (string.length > 0) {
-      // Encode and write data.
-      _StringEncoder encoder = _StringEncoders.encoder(encoding);
-      List<int> data = encoder.encodeString(string);
-      return write(data, false);
-    }
-    return true;
-  }
-
-  void set onError(void callback(e)) {
-    _onError = callback;
-  }
-
-  void _reportError(e) {
-    if (_onError != null) {
-      _onError(e);
-    } else {
-      throw e;
-    }
-  }
-
-  Function _onError;
-}
diff --git a/sdk/lib/io/string_stream.dart b/sdk/lib/io/string_stream.dart
deleted file mode 100644
index cd38e2c..0000000
--- a/sdk/lib/io/string_stream.dart
+++ /dev/null
@@ -1,594 +0,0 @@
-// 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.io;
-
-// Interface for decoders decoding binary data into string data. The
-// decoder keeps track of line breaks during decoding.
-abstract class _StringDecoder {
-  // Add more binary data to be decoded. The ownership of the buffer
-  // is transfered to the decoder and the caller most not modify it any more.
-  int write(List<int> buffer);
-
-  void done();
-
-  // Returns whether any decoded data is available.
-  bool get isEmpty;
-
-  // Returns the number of available decoded characters.
-  int available();
-
-  // Get the number of line breaks present in the current decoded
-  // data.
-  int get lineBreaks;
-
-  // Get up to [len] characters of string data decoded since the last
-  // call to [decode] or [decodeLine]. Returns null if no decoded data
-  // is available. If [len] is not specified all decoded characters
-  // are returned.
-  String decoded([int len]);
-
-  // Get the string data decoded since the last call to [decode] or
-  // [decodeLine] up to the next line break present. Returns null if
-  // no line break is present. The line break character sequence is
-  // discarded.
-  String get decodedLine;
-
-  // Set the handler that will be called if an error ocurs while decoding.
-  void set onError(Function callback);
-}
-
-
-class _StringDecoders {
-  static _StringDecoder decoder(Encoding encoding) {
-    if (encoding == Encoding.UTF_8) {
-      return new _UTF8Decoder();
-    } else if (encoding == Encoding.ISO_8859_1) {
-      return new _Latin1Decoder();
-    } else if (encoding == Encoding.ASCII) {
-      return new _AsciiDecoder();
-    } else if (encoding == Encoding.SYSTEM) {
-      if (Platform.operatingSystem == 'windows') {
-        return new _WindowsCodePageDecoder();
-      }
-      return new _UTF8Decoder();
-    } else {
-      if (encoding is Encoding) {
-        throw new StreamException("Unsupported encoding ${encoding.name}");
-      } else {
-        throw new StreamException("Unsupported encoding ${encoding}");
-      }
-    }
-  }
-}
-
-
-class DecoderException implements Exception {
-  const DecoderException([String this.message]);
-  String toString() => "DecoderException: $message";
-  final String message;
-}
-
-
-// Utility class for decoding UTF-8 from data delivered as a stream of
-// bytes.
-abstract class _StringDecoderBase implements _StringDecoder {
-  _StringDecoderBase()
-      : _bufferList = new _BufferList(),
-        _result = new List<int>(),
-        _lineBreakEnds = new Queue<int>();
-
-  int write(List<int> buffer) {
-    _bufferList.add(buffer);
-    // Decode as many bytes into characters as possible.
-    while (_bufferList.length > 0) {
-      if (!_processNext()) {
-        break;
-      }
-    }
-    return buffer.length;
-  }
-
-  void done() { }
-
-  bool get isEmpty => _result.isEmpty;
-
-  int get lineBreaks => _lineBreaks;
-
-  String decoded([int length]) {
-    if (isEmpty) return null;
-
-    List<int> result;
-    if (length != null && length < available()) {
-      result = _result.getRange(_resultOffset, length);
-    } else if (_resultOffset == 0) {
-      result = _result;
-    } else {
-      result = _result.getRange(_resultOffset, _result.length - _resultOffset);
-    }
-
-    _resultOffset += result.length;
-    while (!_lineBreakEnds.isEmpty &&
-           _lineBreakEnds.first < _charOffset + _resultOffset) {
-      _lineBreakEnds.removeFirst();
-      _lineBreaks--;
-    }
-    if (_result.length == _resultOffset) _resetResult();
-    return new String.fromCharCodes(result);
-  }
-
-  String get decodedLine {
-    if (_lineBreakEnds.isEmpty) return null;
-    int lineEnd = _lineBreakEnds.removeFirst();
-    int terminationSequenceLength = 1;
-    if (_result[lineEnd - _charOffset] == LF &&
-        lineEnd > _charOffset &&
-        _resultOffset < lineEnd &&
-        _result[lineEnd - _charOffset - 1] == CR) {
-      terminationSequenceLength = 2;
-    }
-    var lineLength =
-        lineEnd - _charOffset - _resultOffset - terminationSequenceLength + 1;
-    String result =
-        new String.fromCharCodes(_result.getRange(_resultOffset, lineLength));
-    _lineBreaks--;
-    _resultOffset += (lineLength + terminationSequenceLength);
-    if (_result.length == _resultOffset) _resetResult();
-    return result;
-  }
-
-  // Add another decoded character.
-  void addChar(int charCode) {
-    _result.add(charCode);
-    _charCount++;
-    // Check for line ends (\r, \n and \r\n).
-    if (charCode == LF) {
-      _recordLineBreakEnd(_charCount - 1);
-    } else if (_lastCharCode == CR) {
-      _recordLineBreakEnd(_charCount - 2);
-    }
-    _lastCharCode = charCode;
-  }
-
-  int available() => _result.length - _resultOffset;
-
-  void _recordLineBreakEnd(int charPos) {
-    _lineBreakEnds.add(charPos);
-    _lineBreaks++;
-  }
-
-  void _resetResult() {
-    _charOffset += _result.length;
-    _result = new List<int>();
-    _resultOffset = 0;
-  }
-
-  bool _processNext();
-
-  _BufferList _bufferList;
-  int _resultOffset = 0;
-  List<int> _result;
-  int _lineBreaks = 0;  // Number of line breaks in the current list.
-  // The positions of the line breaks are tracked in terms of absolute
-  // character positions from the begining of the decoded data.
-  Queue<int> _lineBreakEnds;  // Character position of known line breaks.
-  int _charOffset = 0;  // Character number of the first character in the list.
-  int _charCount = 0;  // Total number of characters decoded.
-  int _lastCharCode = -1;
-  Function onError;
-
-  final int LF = 10;
-  final int CR = 13;
-}
-
-
-// Utility class for decoding UTF-8 from data delivered as a stream of
-// bytes.
-class _UTF8Decoder extends _StringDecoderBase {
-  static const kMaxCodePoint = 0x10FFFF;
-  static const kReplacementCodePoint = 0x3f;
-
-  void done() {
-    if (!_bufferList.isEmpty) {
-      _reportError(new DecoderException("Illegal UTF-8"));
-    }
-  }
-
-  bool _reportError(error) {
-    if (onError != null) {
-      onError(error);
-      return false;
-    } else {
-      throw error;
-    }
-  }
-
-  // Process the next UTF-8 encoded character.
-  bool _processNext() {
-    // Peek the next byte to calculate the number of bytes required for
-    // the next character.
-    int value = _bufferList.peek() & 0xFF;
-    if ((value & 0x80) == 0x80) {
-      int additionalBytes;
-      if ((value & 0xe0) == 0xc0) {  // 110xxxxx
-        value = value & 0x1F;
-        additionalBytes = 1;
-      } else if ((value & 0xf0) == 0xe0) {  // 1110xxxx
-        value = value & 0x0F;
-        additionalBytes = 2;
-      } else if ((value & 0xf8) == 0xf0) {  // 11110xxx
-        value = value & 0x07;
-        additionalBytes = 3;
-      } else if ((value & 0xfc) == 0xf8) {  // 111110xx
-        value = value & 0x03;
-        additionalBytes = 4;
-      } else if ((value & 0xfe) == 0xfc) {  // 1111110x
-        value = value & 0x01;
-        additionalBytes = 5;
-      } else {
-        return _reportError(new DecoderException("Illegal UTF-8"));
-      }
-      // Check if there are enough bytes to decode the character. Otherwise
-      // return false.
-      if (_bufferList.length < additionalBytes + 1) {
-        return false;
-      }
-      // Remove the value peeked from the buffer list.
-      _bufferList.next();
-      for (int i = 0; i < additionalBytes; i++) {
-        int byte = _bufferList.next();
-        if ((byte & 0xc0) != 0x80) {
-          return _reportError(new DecoderException("Illegal UTF-8"));
-        }
-        value = value << 6 | (byte & 0x3F);
-      }
-    } else {
-      // Remove the value peeked from the buffer list.
-      _bufferList.next();
-    }
-    if (value > kMaxCodePoint) {
-      addChar(kReplacementCodePoint);
-    } else {
-      addChar(value);
-    }
-    return true;
-  }
-}
-
-
-// Utility class for decoding ascii data delivered as a stream of
-// bytes.
-class _AsciiDecoder extends _StringDecoderBase {
-  // Process the next ascii encoded character.
-  bool _processNext() {
-    while (_bufferList.length > 0) {
-      int byte = _bufferList.next();
-      if (byte > 127) {
-        var error = new DecoderException("Illegal ASCII character $byte");
-        if (onError != null) {
-          onError(error);
-          return false;
-        } else {
-          throw error;
-        }
-      }
-      addChar(byte);
-    }
-    return true;
-  }
-}
-
-
-// Utility class for decoding Latin-1 data delivered as a stream of
-// bytes.
-class _Latin1Decoder extends _StringDecoderBase {
-  // Process the next Latin-1 encoded character.
-  bool _processNext() {
-    while (_bufferList.length > 0) {
-      int byte = _bufferList.next();
-      addChar(byte);
-    }
-    return true;
-  }
-}
-
-
-// Utility class for decoding Windows current code page data delivered
-// as a stream of bytes.
-class _WindowsCodePageDecoder extends _StringDecoderBase {
-  // Process the next chunk of data.
-  bool _processNext() {
-    List<int> bytes = _bufferList.readBytes(_bufferList.length);
-    for (var charCode in _decodeBytes(bytes).charCodes) {
-      addChar(charCode);
-    }
-    return true;
-  }
-
-  external static String _decodeBytes(List<int> bytes);
-}
-
-
-// Interface for encoders encoding string data into binary data.
-abstract class _StringEncoder {
-  List<int> encodeString(String string);
-}
-
-
-// Utility class for encoding a string into UTF-8 byte stream.
-class _UTF8Encoder implements _StringEncoder {
-  List<int> encodeString(String string) {
-    int size = _encodingSize(string);
-    List<int> result = new Uint8List(size);
-    _encodeString(string, result);
-    return result;
-  }
-
-  static int _encodingSize(String string) => _encodeString(string, null);
-
-  static int _encodeString(String string, List<int> buffer) {
-    List<int> utf8CodeUnits = encodeUtf8(string);
-    if (buffer != null) {
-      for (int i = 0; i < utf8CodeUnits.length; i++) {
-        buffer[i] = utf8CodeUnits[i];
-      }
-    }
-    return utf8CodeUnits.length;
-  }
-}
-
-
-// Utility class for encoding a string into a Latin1 byte stream.
-class _Latin1Encoder implements _StringEncoder {
-  List<int> encodeString(String string) {
-    List<int> result = new Uint8List(string.length);
-    for (int i = 0; i < string.length; i++) {
-      int charCode = string.charCodeAt(i);
-      if (charCode > 255) {
-        throw new EncoderException(
-            "No ISO_8859_1 encoding for code point $charCode");
-      }
-      result[i] = charCode;
-    }
-    return result;
-  }
-}
-
-
-// Utility class for encoding a string into an ASCII byte stream.
-class _AsciiEncoder implements _StringEncoder {
-  List<int> encodeString(String string) {
-    List<int> result = new Uint8List(string.length);
-    for (int i = 0; i < string.length; i++) {
-      int charCode = string.charCodeAt(i);
-      if (charCode > 127) {
-        throw new EncoderException(
-            "No ASCII encoding for code point $charCode");
-      }
-      result[i] = charCode;
-    }
-    return result;
-  }
-}
-
-
-// Utility class for encoding a string into a current windows
-// code page byte list.
-class _WindowsCodePageEncoder implements _StringEncoder {
-  List<int> encodeString(String string) {
-    return _encodeString(string);
-  }
-
-  external static List<int> _encodeString(String string);
-}
-
-
-class _StringEncoders {
-  static _StringEncoder encoder(Encoding encoding) {
-    if (encoding == Encoding.UTF_8) {
-      return new _UTF8Encoder();
-    } else if (encoding == Encoding.ISO_8859_1) {
-      return new _Latin1Encoder();
-    } else if (encoding == Encoding.ASCII) {
-      return new _AsciiEncoder();
-    } else if (encoding == Encoding.SYSTEM) {
-      if (Platform.operatingSystem == 'windows') {
-        return new _WindowsCodePageEncoder();
-      }
-      return new _UTF8Encoder();
-    } else {
-      throw new StreamException("Unsupported encoding ${encoding.name}");
-    }
-  }
-}
-
-
-class EncoderException implements Exception {
-  const EncoderException([String this.message]);
-  String toString() => "EncoderException: $message";
-  final String message;
-}
-
-
-class _StringInputStream implements StringInputStream {
-  _StringInputStream(InputStream this._input, Encoding this._encoding) {
-    _decoder = _StringDecoders.decoder(encoding);
-    _input.onData = _onData;
-    _input.onClosed = _onClosed;
-  }
-
-  String read([int len]) {
-    String result = _decoder.decoded(len);
-    _checkInstallDataHandler();
-    return result;
-  }
-
-  String readLine() {
-    String decodedLine = _decoder.decodedLine;
-    if (decodedLine == null) {
-      if (_inputClosed) {
-        // Last line might not have a line separator.
-        decodedLine = _decoder.decoded();
-        if (decodedLine != null &&
-            decodedLine[decodedLine.length - 1] == '\r') {
-          decodedLine = decodedLine.substring(0, decodedLine.length - 1);
-        }
-      }
-    }
-    _checkInstallDataHandler();
-    return decodedLine;
-  }
-
-  int available() => _decoder.available();
-
-  Encoding get encoding => _encoding;
-
-  bool get closed => _inputClosed && _decoder.isEmpty;
-
-  void set onData(void callback()) {
-    _clientDataHandler = callback;
-    _clientLineHandler = null;
-    _checkInstallDataHandler();
-    _checkScheduleCallback();
-  }
-
-  void set onLine(void callback()) {
-    _clientLineHandler = callback;
-    _clientDataHandler = null;
-    _checkInstallDataHandler();
-    _checkScheduleCallback();
-  }
-
-  void set onClosed(void callback()) {
-    _clientCloseHandler = callback;
-  }
-
-  void set onError(void callback(e)) {
-    _input.onError = callback;
-    _decoder.onError = (e) {
-      _clientCloseHandler = null;
-      _input.close();
-      callback(e);
-    };
-  }
-
-  void _onData() {
-    _readData();
-    if (!_decoder.isEmpty && _clientDataHandler != null) {
-      _clientDataHandler();
-    }
-    if (_decoder.lineBreaks > 0 && _clientLineHandler != null) {
-      _clientLineHandler();
-    }
-    _checkScheduleCallback();
-    _checkInstallDataHandler();
-  }
-
-  void _onClosed() {
-    _inputClosed = true;
-    _decoder.done();
-    if (_decoder.isEmpty && _clientCloseHandler !=  null) {
-      _clientCloseHandler();
-    } else {
-      _checkScheduleCallback();
-    }
-  }
-
-  void _readData() {
-    List<int> data = _input.read();
-    if (data != null) {
-      _decoder.write(data);
-    }
-  }
-
-  void _checkInstallDataHandler() {
-    if (_inputClosed ||
-        (_clientDataHandler == null && _clientLineHandler == null)) {
-      _input.onData = null;
-    } else if (_clientDataHandler != null) {
-      if (_decoder.isEmpty) {
-        _input.onData = _onData;
-      } else {
-        _input.onData = null;
-      }
-    } else {
-      assert(_clientLineHandler != null);
-      if (_decoder.lineBreaks == 0) {
-        _input.onData = _onData;
-      } else {
-        _input.onData = null;
-      }
-    }
-  }
-
-  // TODO(sgjesse): Find a better way of scheduling callbacks from
-  // the event loop.
-  void _checkScheduleCallback() {
-    void issueDataCallback() {
-      _scheduledDataCallback = null;
-      if (_clientDataHandler != null) {
-        _clientDataHandler();
-        _checkScheduleCallback();
-      }
-    }
-
-    void issueLineCallback() {
-      _scheduledLineCallback = null;
-      if (_clientLineHandler != null) {
-        _clientLineHandler();
-        _checkScheduleCallback();
-      }
-    }
-
-    void issueCloseCallback() {
-      _scheduledCloseCallback = null;
-      if (!_closed) {
-        if (_clientCloseHandler != null) _clientCloseHandler();
-        _closed = true;
-      }
-    }
-
-    if (!_closed) {
-      // Schedule data callback if string data available.
-      if (_clientDataHandler != null &&
-          !_decoder.isEmpty &&
-          _scheduledDataCallback == null) {
-        if (_scheduledLineCallback != null) {
-          _scheduledLineCallback.cancel();
-        }
-        _scheduledDataCallback = Timer.run(issueDataCallback);
-      }
-
-      // Schedule line callback if a line is available.
-      if (_clientLineHandler != null &&
-          (_decoder.lineBreaks > 0 || (!_decoder.isEmpty && _inputClosed)) &&
-          _scheduledLineCallback == null) {
-        if (_scheduledDataCallback != null) {
-          _scheduledDataCallback.cancel();
-        }
-        _scheduledLineCallback = Timer.run(issueLineCallback);
-      }
-
-      // Schedule close callback if no more data and input is closed.
-      if (_decoder.isEmpty &&
-          _inputClosed &&
-          _scheduledCloseCallback == null) {
-        _scheduledCloseCallback = Timer.run(issueCloseCallback);
-      }
-    }
-  }
-
-  InputStream _input;
-  Encoding _encoding;
-  _StringDecoder _decoder;
-  bool _inputClosed = false;  // Is the underlying input stream closed?
-  bool _closed = false;  // Is this stream closed.
-  bool _eof = false;  // Has all data been read from the decoder?
-  Timer _scheduledDataCallback;
-  Timer _scheduledLineCallback;
-  Timer _scheduledCloseCallback;
-  Function _clientDataHandler;
-  Function _clientLineHandler;
-  Function _clientCloseHandler;
-}
diff --git a/sdk/lib/io/string_transformer.dart b/sdk/lib/io/string_transformer.dart
new file mode 100644
index 0000000..857b8dc
--- /dev/null
+++ b/sdk/lib/io/string_transformer.dart
@@ -0,0 +1,414 @@
+// 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.io;
+
+/**
+ * String encodings.
+ */
+class Encoding {
+  static const Encoding UTF_8 = const Encoding._internal("UTF-8");
+  static const Encoding ISO_8859_1 = const Encoding._internal("ISO-8859-1");
+  static const Encoding ASCII = const Encoding._internal("ASCII");
+  /**
+   * SYSTEM encoding is the current code page on Windows and UTF-8 on
+   * Linux and Mac.
+   */
+  static const Encoding SYSTEM = const Encoding._internal("SYSTEM");
+  const Encoding._internal(String this.name);
+  final String name;
+}
+
+
+/**
+ * Stream transformer that can decode a stream of bytes into a stream of
+ * strings using [encoding].
+ *
+ * Invalid or forbidden byte-sequences will not produce errors, but will instead
+ * insert [replacementChar] in the decoded strings.
+ */
+class StringDecoder implements StreamTransformer<List<int>, String> {
+  var _decoder;
+
+  /**
+   * Create a new [StringDecoder] with an optional [encoding] and
+   * [replacementChar].
+   */
+  StringDecoder([Encoding encoding = Encoding.UTF_8, int replacementChar]) {
+    switch (encoding) {
+      case Encoding.UTF_8:
+        if (replacementChar == null) {
+          replacementChar = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT;
+        }
+        _decoder = new Utf8DecoderTransformer(replacementChar);
+        break;
+      case Encoding.ASCII:
+        if (replacementChar == null) {
+          replacementChar = '?'.charCodeAt(0);
+        } else if (replacementChar > 127) {
+          throw new ArgumentError("Invalid replacement character for ASCII");
+        }
+        _decoder = new _AsciiDecoder(replacementChar);
+        break;
+      case Encoding.ISO_8859_1:
+        if (replacementChar == null) {
+          replacementChar = '?'.charCodeAt(0);
+        } else if (replacementChar > 255) {
+          throw new ArgumentError(
+              "Invalid replacement character for ISO_8859_1");
+        }
+        _decoder = new _Latin1Decoder(replacementChar);
+        break;
+      case Encoding.SYSTEM:
+        if (Platform.operatingSystem == "windows") {
+          _decoder = new _WindowsCodePageDecoder();
+        } else {
+          if (replacementChar != null) {
+            // TODO(ajohnsen): Handle replacement character.
+            throw new UnsupportedError(
+                "Replacement character is not supported for SYSTEM encoding");
+          }
+          _decoder = new Utf8DecoderTransformer();
+        }
+        break;
+      default:
+        throw new ArgumentError("Unsupported encoding '$encoding'");
+    }
+  }
+
+  Stream<String> bind(Stream<List<int>> stream) => _decoder.bind(stream);
+}
+
+
+/**
+ * Stream transformer that can encode a stream of strings info a stream of
+ * bytes using [encoding].
+ *
+ * Strings that cannot be represented in the given encoding will result in an
+ * error and a close event on the stream.
+ */
+class StringEncoder implements StreamTransformer<String, List<int>> {
+  var _encoder;
+
+  /**
+   * Create a new [StringDecoder] with an optional [encoding] and
+   * [replacementChar].
+   */
+  StringEncoder([Encoding encoding = Encoding.UTF_8]) {
+    switch (encoding) {
+      case Encoding.UTF_8:
+        _encoder = new Utf8EncoderTransformer();
+        break;
+      case Encoding.ASCII:
+        _encoder = new _AsciiEncoder();
+        break;
+      case Encoding.ISO_8859_1:
+        _encoder = new _Latin1Encoder();
+        break;
+      case Encoding.SYSTEM:
+        if (Platform.operatingSystem == "windows") {
+          _encoder = new _WindowsCodePageEncoder();
+        } else {
+          _encoder = new Utf8EncoderTransformer();
+        }
+        break;
+      default:
+        throw new ArgumentError("Unsupported encoding '$encoding'");
+    }
+  }
+
+  Stream<List<int>> bind(Stream<String> stream) => _encoder.bind(stream);
+}
+
+
+// Utility function to synchronously decode a list of bytes.
+String _decodeString(List<int> bytes, [Encoding encoding = Encoding.UTF_8]) {
+  if (bytes.length == 0) return "";
+  var string;
+  var controller = new StreamController();
+  controller.stream
+    .transform(new StringDecoder(encoding))
+    .listen((data) => string = data);
+  controller.add(bytes);
+  controller.close();
+  assert(string != null);
+  return string;
+}
+
+
+// Utility function to synchronously encode a String.
+// Will throw an exception if the encoding is invalid.
+List<int> _encodeString(String string, [Encoding encoding = Encoding.UTF_8]) {
+  if (string.length == 0) return [];
+  var bytes;
+  var controller = new StreamController();
+  controller.stream
+    .transform(new StringEncoder(encoding))
+    .listen((data) => bytes = data);
+  controller.add(string);
+  controller.close();
+  assert(bytes != null);
+  return bytes;
+}
+
+
+class LineTransformer implements StreamTransformer<String, String> {
+  const int _LF = 10;
+  const int _CR = 13;
+
+  final StringBuffer _buffer = new StringBuffer();
+
+  StreamSubscription<String> _subscription;
+  StreamController<String> _controller;
+  String _carry;
+
+  Stream<String> bind(Stream<String> stream) {
+    _controller = new StreamController<String>(
+        onPauseStateChange: _pauseChanged,
+        onSubscriptionStateChange: _subscriptionChanged);
+
+    void handle(String data, bool isClosing) {
+      if (_carry != null) {
+        data = _carry.concat(data);
+        _carry = null;
+      }
+      int startPos = 0;
+      int pos = 0;
+      while (pos < data.length) {
+        int skip = 0;
+        int char = data.charCodeAt(pos);
+        if (char == _LF) {
+          skip = 1;
+        } else if (char == _CR) {
+          skip = 1;
+          if (pos + 1 < data.length) {
+            if (data.charCodeAt(pos + 1) == _LF) {
+              skip = 2;
+            }
+          } else if (!isClosing) {
+            _carry = data.substring(startPos);
+            return;
+          }
+        }
+        if (skip > 0) {
+          _buffer.add(data.substring(startPos, pos));
+          _controller.add(_buffer.toString());
+          _buffer.clear();
+          startPos = pos = pos + skip;
+        } else {
+          pos++;
+        }
+      }
+      if (pos != startPos) {
+        // Add remaining
+        _buffer.add(data.substring(startPos, pos));
+      }
+      if (isClosing && !_buffer.isEmpty) {
+        _controller.add(_buffer.toString());
+        _buffer.clear();
+      }
+    }
+
+    _subscription = stream.listen(
+        (data) => handle(data, false),
+        onDone: () {
+          // Handle remaining data (mainly _carry).
+          handle("", true);
+          _controller.close();
+        },
+        onError: _controller.signalError);
+    return _controller.stream;
+  }
+
+  void _pauseChanged() {
+    if (_controller.isPaused) {
+      _subscription.pause();
+    } else {
+      _subscription.resume();
+    }
+  }
+
+  void _subscriptionChanged() {
+    if (!_controller.hasSubscribers) {
+      _subscription.cancel();
+    }
+  }
+}
+
+
+class _SingleByteDecoder implements StreamTransformer<List<int>, String> {
+  StreamSubscription<List<int>> _subscription;
+  StreamController<String> _controller;
+  final int _replacementChar;
+
+  _SingleByteDecoder(this._replacementChar);
+
+  Stream<String> bind(Stream<List<int>> stream) {
+    _controller = new StreamController<String>(
+        onPauseStateChange: _pauseChanged,
+        onSubscriptionStateChange: _subscriptionChanged);
+    _subscription = stream.listen(
+        (data) {
+          var buffer = new List<int>.fixedLength(data.length);
+          for (int i = 0; i < data.length; i++) {
+            int char = _decodeByte(data[i]);
+            if (char < 0) char = _replacementChar;
+            buffer[i] = char;
+          }
+          _controller.add(new String.fromCharCodes(buffer));
+        },
+        onDone: _controller.close,
+        onError: _controller.signalError);
+    return _controller.stream;
+  }
+
+  int _decodeByte(int byte);
+
+  void _pauseChanged() {
+    if (_controller.isPaused) {
+      _subscription.pause();
+    } else {
+      _subscription.resume();
+    }
+  }
+
+  void _subscriptionChanged() {
+    if (!_controller.hasSubscribers) {
+      _subscription.cancel();
+    }
+  }
+}
+
+
+// Utility class for decoding ascii data delivered as a stream of
+// bytes.
+class _AsciiDecoder extends _SingleByteDecoder {
+  _AsciiDecoder(int replacementChar) : super(replacementChar);
+
+  int _decodeByte(int byte) => ((byte & 0x7f) == byte) ? byte : -1;
+}
+
+
+// Utility class for decoding Latin-1 data delivered as a stream of
+// bytes.
+class _Latin1Decoder extends _SingleByteDecoder {
+  _Latin1Decoder(int replacementChar) : super(replacementChar);
+
+  int _decodeByte(int byte) => ((byte & 0xFF) == byte) ? byte : -1;
+}
+
+
+class _SingleByteEncoder implements StreamTransformer<String, List<int>> {
+  StreamSubscription<String> _subscription;
+  StreamController<List<int>> _controller;
+
+  Stream<List<int>> bind(Stream<String> stream) {
+    _controller = new StreamController<List<int>>(
+        onPauseStateChange: _pauseChanged,
+        onSubscriptionStateChange: _subscriptionChanged);
+    _subscription = stream.listen(
+        (string) {
+          var bytes = _encode(string);
+          if (bytes == null) {
+            _controller.signalError(new FormatException(
+                "Invalid character for encoding"));
+            _controller.close();
+            _subscription.cancel();
+          } else {
+            _controller.add(bytes);
+          }
+        },
+        onDone: _controller.close,
+        onError: _controller.signalError);
+    return _controller.stream;
+  }
+
+  List<int> _encode(String string);
+
+  void _pauseChanged() {
+    if (_controller.isPaused) {
+      _subscription.pause();
+    } else {
+      _subscription.resume();
+    }
+  }
+
+  void _subscriptionChanged() {
+    if (!_controller.hasSubscribers) {
+      _subscription.cancel();
+    }
+  }
+}
+
+
+// Utility class for encoding a string into an ASCII byte stream.
+class _AsciiEncoder extends _SingleByteEncoder {
+  List<int> _encode(String string) {
+    var bytes = string.charCodes;
+    for (var byte in bytes) {
+      if (byte > 127) return null;
+    }
+    return bytes;
+  }
+}
+
+
+// Utility class for encoding a string into a Latin1 byte stream.
+class _Latin1Encoder extends _SingleByteEncoder {
+  List<int> _encode(String string) {
+    var bytes = string.charCodes;
+    for (var byte in bytes) {
+      if (byte > 255) return null;
+    }
+    return bytes;
+  }
+}
+
+
+// Utility class for encoding a string into a current windows
+// code page byte list.
+// Implemented on top of a _SingleByteEncoder, even though it's not really a
+// single byte encoder, to avoid copying boilerplate.
+class _WindowsCodePageEncoder extends _SingleByteEncoder {
+  List<int> _encode(String string) => _encodeString(string);
+
+  external static List<int> _encodeString(String string);
+}
+
+
+// Utility class for decoding Windows current code page data delivered
+// as a stream of bytes.
+class _WindowsCodePageDecoder implements StreamTransformer<List<int>, String> {
+  StreamSubscription<List<int>> _subscription;
+  StreamController<String> _controller;
+
+  Stream<String> bind(Stream<List<int>> stream) {
+    _controller = new StreamController<String>(
+        onPauseStateChange: _pauseChanged,
+        onSubscriptionStateChange: _subscriptionChanged);
+    _subscription = stream.listen(
+        (data) {
+          _controller.add(_decodeBytes(data));
+        },
+        onDone: _controller.close,
+        onError: _controller.signalError);
+    return _controller.stream;
+  }
+
+  external static String _decodeBytes(List<int> bytes);
+
+  void _pauseChanged() {
+    if (_controller.isPaused) {
+      _subscription.pause();
+    } else {
+      _subscription.resume();
+    }
+  }
+
+  void _subscriptionChanged() {
+    if (!_controller.hasSubscribers) {
+      _subscription.cancel();
+    }
+  }
+}
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 415c108..c08f3bb 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -18,7 +18,7 @@
     if (_timers == null) {
       _timers = new DoubleLinkedQueue<_Timer>();
     }
-    Timer timer = new _Timer._internal();
+    _Timer timer = new _Timer._internal();
     timer._callback = callback;
     timer._milliSeconds = milliSeconds;
     timer._wakeupTime = (new DateTime.now()).millisecondsSinceEpoch + milliSeconds;
diff --git a/sdk/lib/io/websocket.dart b/sdk/lib/io/websocket.dart
index 9ded504..48cf54a 100644
--- a/sdk/lib/io/websocket.dart
+++ b/sdk/lib/io/websocket.dart
@@ -24,145 +24,25 @@
 }
 
 /**
- * The web socket protocol is implemented by a HTTP or HTTPS server handler
- * which can be instantiated like this:
+ * The [WebSocketTransformer] is implemented as a stream transformer that
+ * transforms a stream of HttpRequest into a stream of WebSockets by upgrading
+ * each HttpRequest from the HTTP or HTTPS server, to the WebSocket protocol.
  *
- *     WebSocketHandler wsHandler = new WebSocketHandler();
+ * Example of usage:
  *
- * and then its onRequest method can be assigned to the HTTP server, e.g.
- *
- *     server.defaultHandler = wsHandler.onRequest;
+ *     server.transform(new WebSocketTransformer()).listen((webSocket) => ...);
  *
  * or
  *
- *     server.addRequestHandler((req) => req.path == "/ws",
- *                              wsHandler.onRequest);
+ *     server
+ *         .where((request) => request.uri.scheme == "ws")
+ *         .transform(new WebSocketTransformer()).listen((webSocket) => ...);
  *
- * This handler strives to implement web sockets as specified by RFC6455.
+ * This transformer strives to implement web sockets as specified by RFC6455.
  */
-abstract class WebSocketHandler {
-  factory WebSocketHandler() => new _WebSocketHandler();
-
-  /**
-   * Request handler to be registered with the HTTP server.
-   */
-  void onRequest(HttpRequest request, HttpResponse response);
-
-  /**
-   * Sets the callback to be called when a new web socket connection
-   * has been established.
-   */
-  void set onOpen(callback(WebSocketConnection connection));
-}
-
-
-/**
- * Server web socket connection.
- */
-abstract class WebSocketConnection {
-  /**
-   * Sets the callback to be called when a message has been
-   * received. The type on [message] is either [:String:] or
-   * [:List<int>:] depending on whether it is a text or binary
-   * message. If the message is empty [message] will be [:null:].
-   * If [message] is a [:List<int>:] then it will contain byte values
-   * from 0 to 255.
-   */
-  void set onMessage(void callback(message));
-
-  /**
-   * Sets the callback to be called when the web socket connection is
-   * closed. [status] indicate the reason for closing. For network
-   * errors the value of [status] will be
-   * WebSocketStatus.ABNORMAL_CLOSURE]. In this callback it is
-   * possible to call [close] if [close] has not already been called.
-   * If [close] has still not been called after the close callback
-   * returns the received close status will automatically be echoed
-   * back to the other end to finish the close handshake.
-   */
-  void set onClosed(void callback(int status, String reason));
-
-  /**
-   * Sends a message. The [message] must be a [:String:], a
-   * [:List<int>:] containing bytes, or [:null:].
-   */
-  send(Object message);
-
-  /**
-   * Close the web socket connection. The default value for [status]
-   * and [reason] are [:null:].
-   */
-  close([int status, String reason]);
-}
-
-
-/**
- * Client web socket connection.
- */
-abstract class WebSocketClientConnection {
-  /**
-   * Creates a new web socket client connection based on a HTTP(S) client
-   * connection. The HTTP or HTTPS client connection must be freshly opened.
-   */
-  factory WebSocketClientConnection(HttpClientConnection conn,
-                                    [List<String> protocols]) {
-    return new _WebSocketClientConnection(conn, protocols);
-  }
-
-  /**
-   * Sets the callback to be called when the request object for the
-   * opening handshake request is ready. This callback can be used if
-   * one needs to add additional headers to the opening handshake
-   * request.
-   */
-  void set onRequest(void callback(HttpClientRequest request));
-
-  /**
-   * Sets the callback to be called when a web socket connection has
-   * been established.
-   */
-  void set onOpen(void callback());
-
-  /**
-   * Sets the callback to be called when a message has been
-   * received. The type of [message] is either [:String:] or
-   * [:List<int>:], depending on whether it is a text or binary
-   * message. If the message is empty [message] will be [:null:].
-   * If the message is a [:List<int>:] then it will contain byte values
-   * from 0 to 255.
-   */
-  void set onMessage(void callback(message));
-
-  /**
-   * Sets the callback to be called when the web socket connection is
-   * closed. [status] indicates the reason for closing. For network
-   * errors the value of [status] will be
-   * WebSocketStatus.ABNORMAL_CLOSURE].
-   */
-  void set onClosed(void callback(int status, String reason));
-
-  /**
-   * Sets the callback to be called when the response object for the
-   * opening handshake did not cause a web socket connection
-   * upgrade. This will be called in case the response status code is
-   * not 101 (Switching Protocols). If this callback is not set and the
-   * server does not upgrade the connection, the [:onError:] callback will
-   * be called.
-   */
-  void set onNoUpgrade(void callback(HttpClientResponse response));
-
-  /**
-   * Sends a message. The [message] must be a [:String:] or a
-   * [:List<int>:] containing bytes. To send an empty message send either
-   * an empty [:String:] or an empty [:List<int>:]. [:null:] cannot be sent.
-   */
-  send(message);
-
-  /**
-   * Close the web socket connection. The default value for [status]
-   * and [reason] are [:null:].
-   */
-  close([int status, String reason]);
+abstract class WebSocketTransformer
+    implements StreamTransformer<HttpRequest, WebSocket> {
+  factory WebSocketTransformer() => new _WebSocketTransformerImpl();
 }
 
 
@@ -182,7 +62,6 @@
    * message is empty [message] will be [:null:]
    * If the message is a [:List<int>:] then it will contain byte values
    * from 0 to 255.
-
    */
   get data;
 }
@@ -216,7 +95,7 @@
  * with the W3C browser API for web sockets specified in
  * http://dev.w3.org/html5/websockets/.
  */
-abstract class WebSocket {
+abstract class WebSocket implements Stream<Event> {
   /**
    * Possible states of the connection.
    */
@@ -227,11 +106,12 @@
 
   /**
    * Create a new web socket connection. The URL supplied in [url]
-   * must use the scheme [:ws:]. The [protocols] argument is either a
-   * [:String:] or [:List<String>:] specifying the subprotocols the
+   * must use the scheme [:ws:] or [:wss:]. The [protocols] argument is either
+   * a [:String:] or [:List<String>:] specifying the subprotocols the
    * client is willing to speak.
    */
-  factory WebSocket(String url, [protocols]) => new _WebSocket(url, protocols);
+  static Future<WebSocket> connect(String url, [protocols]) =>
+      _WebSocketImpl.connect(url, protocols);
 
   /**
    * Returns the current state of the connection.
@@ -244,24 +124,6 @@
   int get bufferedAmount;
 
   /**
-   * Sets the callback to be called when a web socket connection has
-   * been established.
-   */
-  void set onopen(void callback());
-
-  /**
-   * Sets the callback to be called when the web socket connection
-   * encountered an error.
-   */
-  void set onerror(void callback(e));
-
-  /**
-   * Sets the callback to be called when the web socket connection is
-   * closed.
-   */
-  void set onclose(void callback(CloseEvent event));
-
-  /**
    * The extensions property is initially the empty string. After the
    * web socket connection is established this string reflects the
    * extensions used by the server.
@@ -279,13 +141,7 @@
   /**
    * Closes the web socket connection.
    */
-  void close(int code, String reason);
-
-  /**
-   * Sets the callback to be called when a message has been
-   * received.
-   */
-  void set onmessage(void callback(MessageEvent event));
+  void close([int code, String reason]);
 
   /**
    * Sends data on the web socket connection. The data in [data] must
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 673fe23..a8d01c2 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
@@ -42,7 +42,6 @@
  *   [:onMessageData:]
  *   [:onMessageEnd:]
  *   [:onClosed:]
- *   [:onError:]
  *
  */
 class _WebSocketProtocolProcessor {
@@ -62,9 +61,9 @@
   /**
    * Process data received from the underlying communication channel.
    */
-  void update(List<int> buffer) {
-    int index = 0;
-    int lastIndex = buffer.length;
+  void update(List<int> buffer, int offset, int count) {
+    int index = offset;
+    int lastIndex = offset + count;
     try {
       if (_state == CLOSED) {
         throw new WebSocketException("Data on closed connection");
@@ -296,10 +295,8 @@
             throw new WebSocketException("Protocol error");
           }
           if (_controlPayload.length > 2) {
-            var decoder = _StringDecoders.decoder(Encoding.UTF_8);
-            decoder.write(
+            reason = _decodeString(
                 _controlPayload.getRange(2, _controlPayload.length - 2));
-            reason = decoder.decoded();
           }
         }
         if (onClosed != null) onClosed(status, reason);
@@ -360,253 +357,43 @@
 }
 
 
-class _WebSocketConnectionBase {
-  void _socketConnected(Socket socket) {
-    _socket = socket;
-    _socket.onError = (e) => _socket.close();
-  }
+class _WebSocketTransformerImpl implements WebSocketTransformer {
+  final StreamController<WebSocket> _controller =
+      new StreamController<WebSocket>();
 
-  void _startProcessing(List<int> unparsedData) {
-    _WebSocketProtocolProcessor processor = new _WebSocketProtocolProcessor();
-    processor.onMessageStart = _onWebSocketMessageStart;
-    processor.onMessageData = _onWebSocketMessageData;
-    processor.onMessageEnd = _onWebSocketMessageEnd;
-    processor.onPing = _onWebSocketPing;
-    processor.onPong = _onWebSocketPong;
-    processor.onClosed = _onWebSocketClosed;
-    if (unparsedData != null) {
-      processor.update(unparsedData);
-    }
-    _socket.onData = () {
-      processor.update(_socket.read());
-    };
-    _socket.onClosed = () {
-      processor.closed();
-      if (_closeSent) {
-        // Got socket close in response to close frame. Don't treat
-        // that as an error.
-        if (_closeTimer != null) _closeTimer.cancel();
-      } else {
-        if (_onClosed != null) _onClosed(WebSocketStatus.ABNORMAL_CLOSURE,
-                                          "Unexpected close");
+  Stream<WebSocket> bind(Stream<HttpRequest> stream) {
+    stream.listen((request) {
+      var response = request.response;
+      if (!_isWebSocketUpgrade(request)) {
+        _controller.signalError(
+            new AsyncError(
+                new WebSocketException("Invalid WebSocket upgrade request")));
+        request.listen((_) {}, onDone: () {
+          response.statusCode = HttpStatus.BAD_REQUEST;
+          response.contentLength = 0;
+          response.close();
+        });
+        return;
       }
-      _socket.close();
-    };
-  }
+      // Send the upgrade response.
+      response.statusCode = HttpStatus.SWITCHING_PROTOCOLS;
+      response.headers.add(HttpHeaders.CONNECTION, "Upgrade");
+      response.headers.add(HttpHeaders.UPGRADE, "websocket");
+      String key = request.headers.value("Sec-WebSocket-Key");
+      SHA1 sha1 = new SHA1();
+      sha1.add("$key$_webSocketGUID".charCodes);
+      String accept = _Base64._encode(sha1.close());
+      response.headers.add("Sec-WebSocket-Accept", accept);
+      response.headers.contentLength = 0;
+      response.detachSocket()
+        .then((socket) {
+          _controller.add(new _WebSocketImpl._fromSocket(socket));
+        }, onError: (error) {
+          _controller.signalError(error);
+        });
+    });
 
-  void set onMessage(void callback(Object message)) {
-    _onMessage = callback;
-  }
-
-  void set onClosed(void callback(int status, String reason)) {
-    _onClosed = callback;
-  }
-
-  send(message) {
-    if (_closeSent) {
-      throw new WebSocketException("Connection closed");
-    }
-    List<int> data;
-    int opcode;
-    if (message != null) {
-      if (message is String) {
-        opcode = _WebSocketOpcode.TEXT;
-        data = _StringEncoders.encoder(Encoding.UTF_8).encodeString(message);
-      } else {
-        if (message is !List<int>) {
-          throw new ArgumentError(message);
-        }
-        opcode = _WebSocketOpcode.BINARY;
-        data = message;
-      }
-    } else {
-      opcode = _WebSocketOpcode.TEXT;
-    }
-    _sendFrame(opcode, data);
-  }
-
-  close([int status, String reason]) {
-    if (status == WebSocketStatus.RESERVED_1004 ||
-        status == WebSocketStatus.NO_STATUS_RECEIVED ||
-        status == WebSocketStatus.RESERVED_1015) {
-      throw new WebSocketException("Reserved status code $status");
-    }
-
-    if (_closeSent) return;
-    List<int> data;
-    if (status != null) {
-      data = new List<int>();
-      data.add((status >> 8) & 0xFF);
-      data.add(status & 0xFF);
-      if (reason != null) {
-        data.addAll(
-           _StringEncoders.encoder(Encoding.UTF_8).encodeString(reason));
-      }
-    }
-    _sendFrame(_WebSocketOpcode.CLOSE, data);
-
-    if (_closeReceived) {
-      // Close the socket when the close frame has been sent - if it
-      // does not take too long.
-      _socket.outputStream.close();
-      _socket.outputStream.onClosed = () {
-        if (_closeTimer != null) _closeTimer.cancel();
-        _socket.close();
-      };
-      _closeTimer = new Timer(const Duration(seconds: 5), _socket.close);
-    } else {
-      // Half close the socket and expect a close frame in response
-      // before closing the socket. If a close frame does not arrive
-      // within a reasonable amount of time just close the socket.
-      _socket.outputStream.close();
-      _closeTimer = new Timer(const Duration(seconds: 5), _socket.close);
-    }
-    _closeSent = true;
-  }
-
-  int get hashCode => _hash;
-
-  _onWebSocketMessageStart(int type) {
-    _currentMessageType = type;
-    if (_currentMessageType == _WebSocketMessageType.TEXT) {
-      _decoder = _StringDecoders.decoder(Encoding.UTF_8);
-    } else {
-      _outputStream = new ListOutputStream();
-    }
-  }
-
-  _onWebSocketMessageData(List<int> buffer, int offset, int count) {
-    if (_currentMessageType == _WebSocketMessageType.TEXT) {
-      _decoder.write(buffer.getRange(offset, count));
-    } else {
-      _outputStream.write(buffer.getRange(offset, count));
-    }
-  }
-
-  _onWebSocketMessageEnd() {
-    if (_onMessage != null) {
-      if (_currentMessageType == _WebSocketMessageType.TEXT) {
-        _onMessage(_decoder.decoded());
-      } else {
-        _onMessage(_outputStream.read());
-      }
-    }
-    _decoder = null;
-    _outputStream = null;
-  }
-
-  _onWebSocketPing(List<int> payload) {
-    _sendFrame(_WebSocketOpcode.PONG, payload);
-  }
-
-  _onWebSocketPong(List<int> payload) {
-    // Currently pong messages are ignored.
-  }
-
-  _onWebSocketClosed(int status, String reason) {
-    _closeReceived = true;
-    if (_onClosed != null) _onClosed(status, reason);
-    if (_closeSent) {
-      // Got close frame in response to close frame. Now close the socket.
-      if (_closeTimer != null) _closeTimer.cancel();
-      _socket.close();
-    } else {
-      if (status != WebSocketStatus.NO_STATUS_RECEIVED) {
-        close(status);
-      } else {
-        close();
-      }
-    }
-  }
-
-  _sendFrame(int opcode, [List<int> data]) {
-    bool mask = false;  // Masking not implemented for server.
-    int dataLength = data == null ? 0 : data.length;
-    // Determine the header size.
-    int headerSize = (mask) ? 6 : 2;
-    if (dataLength > 65535) {
-      headerSize += 8;
-    } else if (dataLength > 125) {
-      headerSize += 2;
-    }
-    List<int> header = new List<int>.fixedLength(headerSize);
-    int index = 0;
-    // Set FIN and opcode.
-    header[index++] = 0x80 | opcode;
-    // Determine size and position of length field.
-    int lengthBytes = 1;
-    int firstLengthByte = 1;
-    if (dataLength > 65535) {
-      header[index++] = 127;
-      lengthBytes = 8;
-    } else if (dataLength > 125) {
-      header[index++] = 126;
-      lengthBytes = 2;
-    }
-    // Write the length in network byte order into the header.
-    for (int i = 0; i < lengthBytes; i++) {
-      header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF;
-    }
-    assert(index == headerSize);
-    _socket.outputStream.write(header);
-    if (data != null) {
-      _socket.outputStream.write(data);
-    }
-  }
-
-  Socket _socket;
-  Timer _closeTimer;
-  int _hash;
-
-  Function _onMessage;
-  Function _onClosed;
-
-  int _currentMessageType = _WebSocketMessageType.NONE;
-  _StringDecoder _decoder;
-  ListOutputStream _outputStream;
-  bool _closeReceived = false;
-  bool _closeSent = false;
-}
-
-
-class _WebSocketConnection
-    extends _WebSocketConnectionBase implements WebSocketConnection {
-  _WebSocketConnection(DetachedSocket detached) {
-    _hash = detached.socket.hashCode;
-    _socketConnected(detached.socket);
-    _startProcessing(detached.unparsedData);
-  }
-}
-
-
-class _WebSocketHandler implements WebSocketHandler {
-  void onRequest(HttpRequest request, HttpResponse response) {
-    // Check that this is a web socket upgrade.
-    if (!_isWebSocketUpgrade(request)) {
-      response.statusCode = HttpStatus.BAD_REQUEST;
-      response.outputStream.close();
-      return;
-    }
-
-    // Send the upgrade response.
-    response.statusCode = HttpStatus.SWITCHING_PROTOCOLS;
-    response.headers.add(HttpHeaders.CONNECTION, "Upgrade");
-    response.headers.add(HttpHeaders.UPGRADE, "websocket");
-    String key = request.headers.value("Sec-WebSocket-Key");
-    SHA1 sha1 = new SHA1();
-    sha1.add("$key$_webSocketGUID".charCodes);
-    String accept = _Base64._encode(sha1.close());
-    response.headers.add("Sec-WebSocket-Accept", accept);
-    response.contentLength = 0;
-
-    // Upgrade the connection and get the underlying socket.
-    WebSocketConnection conn =
-        new _WebSocketConnection(response.detachSocket());
-    if (_onOpen != null) _onOpen(conn);
-  }
-
-  void set onOpen(callback(WebSocketConnection connection)) {
-    _onOpen = callback;
+    return _controller.stream;
   }
 
   bool _isWebSocketUpgrade(HttpRequest request) {
@@ -635,222 +422,248 @@
     }
     return true;
   }
-
-  Function _onOpen;
 }
 
 
-class _WebSocketClientConnection
-    extends _WebSocketConnectionBase implements WebSocketClientConnection {
-  _WebSocketClientConnection(HttpClientConnection this._conn,
-                             [List<String> protocols]) {
-    _conn.onRequest = _onHttpClientRequest;
-    _conn.onResponse = _onHttpClientResponse;
-    _conn.onError = (e) {
-      if (_onClosed != null) {
-        _onClosed(WebSocketStatus.ABNORMAL_CLOSURE, "$e");
-      }
-    };
+class _WebSocketImpl extends Stream<Event> implements WebSocket {
+  final StreamController<Event> _controller = new StreamController<Event>();
 
-    // Generate the nonce now as it is also used to set the hash code.
-    _generateNonceAndHash();
-  }
+  final _WebSocketProtocolProcessor _processor =
+      new _WebSocketProtocolProcessor();
 
-  void set onRequest(void callback(HttpClientRequest request)) {
-    _onRequest = callback;
-  }
+  final Socket _socket;
+  int _readyState = WebSocket.CONNECTING;
 
-  void set onOpen(void callback()) {
-    _onOpen = callback;
-  }
+  static final HttpClient _httpClient = new HttpClient();
 
-  void set onNoUpgrade(void callback(HttpClientResponse request)) {
-    _onNoUpgrade = callback;
-  }
-
-  void _onHttpClientRequest(HttpClientRequest request) {
-    if (_onRequest != null) {
-      _onRequest(request);
-    }
-    // Setup the initial handshake.
-    request.headers.add(HttpHeaders.CONNECTION, "upgrade");
-    request.headers.set(HttpHeaders.UPGRADE, "websocket");
-    request.headers.set("Sec-WebSocket-Key", _nonce);
-    request.headers.set("Sec-WebSocket-Version", "13");
-    request.contentLength = 0;
-    request.outputStream.close();
-  }
-
-  void _onHttpClientResponse(HttpClientResponse response) {
-    if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS) {
-      if (_onNoUpgrade != null) {
-        _onNoUpgrade(response);
-      } else {
-        _conn.detachSocket().socket.close();
-        throw new WebSocketException("Protocol upgrade refused");
-      }
-      return;
-    }
-
-    if (!_isWebSocketUpgrade(response)) {
-      _conn.detachSocket().socket.close();
-      throw new WebSocketException("Protocol upgrade failed");
-    }
-
-    // Connection upgrade successful.
-    DetachedSocket detached = _conn.detachSocket();
-    _socketConnected(detached.socket);
-    if (_onOpen != null) _onOpen();
-    _startProcessing(detached.unparsedData);
-  }
-
-  void _generateNonceAndHash() {
-    Random random = new Random();
-    assert(_nonce == null);
-    void intToBigEndianBytes(int value, List<int> bytes, int offset) {
-      bytes[offset] = (value >> 24) & 0xFF;
-      bytes[offset + 1] = (value >> 16) & 0xFF;
-      bytes[offset + 2] = (value >> 8) & 0xFF;
-      bytes[offset + 3] = value & 0xFF;
-    }
-
-    // Generate 16 random bytes. Use the last four bytes for the hash code.
-    List<int> nonce = new List<int>.fixedLength(16);
-    for (int i = 0; i < 4; i++) {
-      int r = random.nextInt(0x100000000);
-      intToBigEndianBytes(r, nonce, i * 4);
-    }
-    _nonce = _Base64._encode(nonce);
-    _hash = random.nextInt(0x100000000);
-  }
-
-  bool _isWebSocketUpgrade(HttpClientResponse response) {
-    if (response.headers[HttpHeaders.CONNECTION] == null) {
-      return false;
-    }
-    bool isUpgrade = false;
-    response.headers[HttpHeaders.CONNECTION].forEach((String value) {
-      if (value.toLowerCase() == "upgrade") isUpgrade = true;
-    });
-    if (!isUpgrade) return false;
-    String upgrade = response.headers.value(HttpHeaders.UPGRADE);
-    if (upgrade == null || upgrade.toLowerCase() != "websocket") {
-      return false;
-    }
-    String accept = response.headers.value("Sec-WebSocket-Accept");
-    if (accept == null) {
-      return false;
-    }
-    SHA1 sha1 = new SHA1();
-    sha1.add("$_nonce$_webSocketGUID".charCodes);
-    List<int> expectedAccept = sha1.close();
-    List<int> receivedAccept = _Base64._decode(accept);
-    if (expectedAccept.length != receivedAccept.length) return false;
-    for (int i = 0; i < expectedAccept.length; i++) {
-      if (expectedAccept[i] != receivedAccept[i]) return false;
-    }
-    return true;
-  }
-
-  Function _onRequest;
-  Function _onOpen;
-  Function _onNoUpgrade;
-  HttpClientConnection _conn;
-  String _nonce;
-}
-
-
-class _WebSocket implements WebSocket {
-  _WebSocket(String url, [protocols]) {
+  static Future<WebSocket> connect(String url, [protocols]) {
     Uri uri = Uri.parse(url);
     if (uri.scheme != "ws" && uri.scheme != "wss") {
-      throw new WebSocketException("Unsupported URL scheme ${uri.scheme}");
+      throw new WebSocketException("Unsupported URL scheme '${uri.scheme}'");
     }
     if (uri.userInfo != "") {
-      throw new WebSocketException("Unsupported user info ${uri.userInfo}");
-    }
-    int port = uri.port == 0 ? HttpClient.DEFAULT_HTTP_PORT : uri.port;
-    String path = uri.path;
-    if (path.length == 0) path = "/";
-    if (uri.query != "") {
-      if (uri.fragment != "") {
-        path = "${path}?${uri.query}#${uri.fragment}";
-      } else {
-        path = "${path}?${uri.query}";
-      }
+      throw new WebSocketException("Unsupported user info '${uri.userInfo}'");
     }
 
-    HttpClient client = new HttpClient();
-    bool secure = (uri.scheme == 'wss');
-    HttpClientConnection conn = client.openUrl("GET",
-        new Uri.fromComponents(scheme: secure ? "https" : "http",
-                               domain: uri.domain,
-                               port: port,
-                               path: path));
-    if (protocols is String) protocols = [protocols];
-    _wsconn = new WebSocketClientConnection(conn, protocols);
-    _wsconn.onOpen = () {
-      // HTTP client not needed after socket have been detached.
-      client.shutdown();
-      client = null;
-      _readyState = WebSocket.OPEN;
-      if (_onopen != null) _onopen();
-    };
-    _wsconn.onMessage = (message) {
-      if (_onmessage != null) {
-        _onmessage(new _WebSocketMessageEvent(message));
+    Random random = new Random();
+    // Generate 16 random bytes.
+    List<int> nonceData = new List<int>.fixedLength(16);
+    for (int i = 0; i < 16; i++) {
+      nonceData[i] = random.nextInt(256);
+    }
+    String nonce = _Base64._encode(nonceData);
+
+    uri = new Uri.fromComponents(scheme: uri.scheme == "wss" ? "https" : "http",
+                                 userInfo: uri.userInfo,
+                                 domain: uri.domain,
+                                 port: uri.port,
+                                 path: uri.path,
+                                 query: uri.query,
+                                 fragment: uri.fragment);
+    return _httpClient.openUrl("GET", uri)
+      .then((request) {
+        // Setup the initial handshake.
+        request.headers.add(HttpHeaders.CONNECTION, "upgrade");
+        request.headers.set(HttpHeaders.UPGRADE, "websocket");
+        request.headers.set("Sec-WebSocket-Key", nonce);
+        request.headers.set("Sec-WebSocket-Version", "13");
+        return request.close();
+      })
+      .then((response) {
+        void error(String message) {
+          // Flush data.
+          response.detachSocket().then((socket) {
+            socket.destroy();
+          });
+          throw new WebSocketException(message);
+        }
+        if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS ||
+            response.headers[HttpHeaders.CONNECTION] == null ||
+            !response.headers[HttpHeaders.CONNECTION].any(
+                (value) => value.toLowerCase() == "upgrade") ||
+            response.headers.value(HttpHeaders.UPGRADE).toLowerCase() !=
+                "websocket") {
+          error("Connection to '$uri' was not upgraded to websocket");
+        }
+        String accept = response.headers.value("Sec-WebSocket-Accept");
+        if (accept == null) {
+          error("Response did not contain a 'Sec-WebSocket-Accept' header");
+        }
+        SHA1 sha1 = new SHA1();
+        sha1.add("$nonce$_webSocketGUID".charCodes);
+        List<int> expectedAccept = sha1.close();
+        List<int> receivedAccept = _Base64._decode(accept);
+        if (expectedAccept.length != receivedAccept.length) {
+          error("Reasponse header 'Sec-WebSocket-Accept' is the wrong length");
+        }
+        for (int i = 0; i < expectedAccept.length; i++) {
+          if (expectedAccept[i] != receivedAccept[i]) {
+            error("Bad response 'Sec-WebSocket-Accept' header");
+          }
+        }
+        return response.detachSocket()
+            .then((socket) => new _WebSocketImpl._fromSocket(socket));
+      });
+  }
+
+  _WebSocketImpl._fromSocket(Socket this._socket) {
+    _readyState = WebSocket.OPEN;
+
+    int type;
+    var data;
+    _processor.onMessageStart = (int t) {
+      type = t;
+      if (type == _WebSocketMessageType.TEXT) {
+        data = new StringBuffer();
+      } else {
+        data = [];
       }
     };
-    _wsconn.onClosed = (status, reason) {
-      _readyState = WebSocket.CLOSED;
-      if (_onclose != null) {
-        _onclose(new _WebSocketCloseEvent(true, status, reason));
+    _processor.onMessageData = (buffer, offset, count) {
+      if (type == _WebSocketMessageType.TEXT) {
+        data.add(_decodeString(buffer.getRange(offset, count)));
+      } else {
+        data.addAll(buffer.getRange(offset, count));
       }
     };
-    _wsconn.onNoUpgrade = (response) {
-      if (_onclose != null) {
-        _onclose(
-            new _WebSocketCloseEvent(true,
-                                     WebSocketStatus.ABNORMAL_CLOSURE,
-                                     "Connection not upgraded"));
+    _processor.onMessageEnd = () {
+      if (type == _WebSocketMessageType.TEXT) {
+        _controller.add(new _WebSocketMessageEvent(data.toString()));
+      } else {
+        _controller.add(new _WebSocketMessageEvent(data));
       }
     };
+    _processor.onClosed = (code, reason) {
+      bool clean = true;
+      if (_readyState == WebSocket.OPEN) {
+        _readyState = WebSocket.CLOSING;
+        if (code != WebSocketStatus.NO_STATUS_RECEIVED) {
+          _close(code);
+        } else {
+          _close();
+          clean = false;
+        }
+        _readyState = WebSocket.CLOSED;
+      }
+      _controller.add(new _WebSocketCloseEvent(clean, code, reason));
+      _controller.close();
+    };
+
+    _socket.listen(
+        (data) => _processor.update(data, 0, data.length),
+        onDone: () => _processor.closed(),
+        onError: (error) => _controller.signalError(error));
+  }
+
+  StreamSubscription<Event> listen(void onData(Event event),
+                                   {void onError(AsyncError error),
+                                    void onDone(),
+                                    bool unsubscribeOnError}) {
+    return _controller.stream.listen(onData,
+                                     onError: onError,
+                                     onDone: onDone,
+                                     unsubscribeOnError: unsubscribeOnError);
   }
 
   int get readyState => _readyState;
   int get bufferedAmount => 0;
 
-  void set onopen(Function callback) {
-    _onopen = callback;
-  }
-
-  void set onerror(Function callback) {}
-
-  void set onclose(Function callback) {
-    _onclose = callback;
-  }
-
   String get extensions => null;
   String get protocol => null;
 
-  void close(int code, String reason) {
+  void close([int code, String reason]) {
     if (_readyState < WebSocket.CLOSING) _readyState = WebSocket.CLOSING;
-    _wsconn.close(code, reason);
+    if (code == WebSocketStatus.RESERVED_1004 ||
+        code == WebSocketStatus.NO_STATUS_RECEIVED ||
+        code == WebSocketStatus.RESERVED_1015) {
+      throw new WebSocketException("Reserved status code $code");
+    }
+    _close(code, reason);
   }
 
-  void set onmessage(Function callback) {
-    _onmessage = callback;
+  void _close([int code, String reason]) {
+    List<int> data;
+    if (code != null) {
+      data = new List<int>();
+      data.add((code >> 8) & 0xFF);
+      data.add(code & 0xFF);
+      if (reason != null) {
+        data.addAll(_encodeString(reason));
+      }
+    }
+    _sendFrame(_WebSocketOpcode.CLOSE, data);
+
+    if (_readyState == WebSocket.CLOSED) {
+      // Close the socket when the close frame has been sent - if it
+      // does not take too long.
+      // TODO(ajohnsen): Honor comment.
+      _socket.destroy();
+    } else {
+      // Half close the socket and expect a close frame in response
+      // before closing the socket. If a close frame does not arrive
+      // within a reasonable amount of time just close the socket.
+      // TODO(ajohnsen): Honor comment.
+      _socket.close();
+    }
   }
 
-  void send(data) {
-    _wsconn.send(data);
+  void send(message) {
+    if (readyState != WebSocket.OPEN) {
+      throw new StateError("Connection not open");
+    }
+    List<int> data;
+    int opcode;
+    if (message != null) {
+      if (message is String) {
+        opcode = _WebSocketOpcode.TEXT;
+        data = _encodeString(message);
+      } else {
+        if (message is !List<int>) {
+          throw new ArgumentError(message);
+        }
+        opcode = _WebSocketOpcode.BINARY;
+        data = message;
+      }
+    } else {
+      opcode = _WebSocketOpcode.TEXT;
+    }
+    _sendFrame(opcode, data);
   }
 
-  WebSocketClientConnection _wsconn;
-  int _readyState = WebSocket.CONNECTING;
-  Function _onopen;
-  Function _onclose;
-  Function _onmessage;
+  void _sendFrame(int opcode, [List<int> data]) {
+    bool mask = false;  // Masking not implemented for server.
+    int dataLength = data == null ? 0 : data.length;
+    // Determine the header size.
+    int headerSize = (mask) ? 6 : 2;
+    if (dataLength > 65535) {
+      headerSize += 8;
+    } else if (dataLength > 125) {
+      headerSize += 2;
+    }
+    List<int> header = new List<int>.fixedLength(headerSize);
+    int index = 0;
+    // Set FIN and opcode.
+    header[index++] = 0x80 | opcode;
+    // Determine size and position of length field.
+    int lengthBytes = 1;
+    int firstLengthByte = 1;
+    if (dataLength > 65535) {
+      header[index++] = 127;
+      lengthBytes = 8;
+    } else if (dataLength > 125) {
+      header[index++] = 126;
+      lengthBytes = 2;
+    }
+    // Write the length in network byte order into the header.
+    for (int i = 0; i < lengthBytes; i++) {
+      header[index++] = dataLength >> (((lengthBytes - 1) - i) * 8) & 0xFF;
+    }
+    assert(index == headerSize);
+    _socket.add(header);
+    if (data != null) {
+      _socket.add(data);
+    }
+  }
 }
 
 
diff --git a/sdk/lib/json/json.dart b/sdk/lib/json/json.dart
index 4348767..17147e1 100644
--- a/sdk/lib/json/json.dart
+++ b/sdk/lib/json/json.dart
@@ -4,801 +4,4 @@
 
 library dart.json;
 
-// JSON parsing and serialization.
-
-/**
- * Error thrown by JSON serialization if an object cannot be serialized.
- *
- * The [unsupportedObject] field holds that object that failed to be serialized.
- *
- * If an object isn't directly serializable, the serializer calls the 'toJson'
- * method on the object. If that call fails, the error will be stored in the
- * [cause] field. If the call returns an object that isn't directly
- * serializable, the [cause] will be null.
- */
-class JsonUnsupportedObjectError implements Error {
-  /** The object that could not be serialized. */
-  final unsupportedObject;
-  /** The exception thrown by object's [:toJson:] method, if any. */
-  final cause;
-  JsonUnsupportedObjectError(this.unsupportedObject) : cause = null;
-  JsonUnsupportedObjectError.withCause(this.unsupportedObject, this.cause);
-
-  String toString() {
-    if (cause != null) {
-      return "Calling toJson method on object failed.";
-    } else {
-      return "Object toJson method returns non-serializable value.";
-    }
-  }
-}
-
-
-/**
- * Parses [json] and build the corresponding parsed JSON value.
- *
- * Parsed JSON values are of the types [num], [String], [bool], [Null],
- * [List]s of parsed JSON values or [Map]s from [String] to parsed
- * JSON values.
- *
- * The optional [revivier] function, if provided, is called once for each
- * object or list property parsed. The arguments are the property name
- * ([String]) or list index ([int]), and the value is the parsed value.
- * The return value of the revivier will be used as the value of that property
- * instead the parsed value.
- *
- * Throws [FormatException] if the input is not valid JSON text.
- */
-parse(String json, [reviver(var key, var value)]) {
-  BuildJsonListener listener;
-  if (reviver == null) {
-    listener = new BuildJsonListener();
-  } else {
-    listener = new ReviverJsonListener(reviver);
-  }
-  new JsonParser(json, listener).parse();
-  return listener.result;
-}
-
-/**
- * Serializes [object] into a JSON string.
- *
- * Directly serializable types are [num], [String], [bool], [Null], [List]
- * and [Map].
- * For [List], the elements must all be serializable.
- * For [Map], the keys must be [String] and the values must be serializable.
- * If a value is any other type is attempted serialized, a "toJson()" method
- * is invoked on the object and the result, which must be a directly
- * serializable type, is serialized instead of the original value.
- * If the object does not support this method, throws, or returns a
- * value that is not directly serializable, a [JsonUnsupportedObjectError]
- * exception is thrown. If the call throws (including the case where there
- * is no nullary "toJson" method, the error is caught and stored in the
- * [JsonUnsupportedObjectError]'s [:cause:] field.
- *Json
- * Objects should not change during serialization.
- * If an object is serialized more than once, [stringify] is allowed to cache
- * the JSON text for it. I.e., if an object changes after it is first
- * serialized, the new values may or may not be reflected in the result.
- */
-String stringify(Object object) {
-  return _JsonStringifier.stringify(object);
-}
-
-/**
- * Serializes [object] into [output] stream.
- *
- * Performs the same operations as [stringify] but outputs the resulting
- * string to an existing [StringBuffer] instead of creating a new [String].
- *
- * If serialization fails by throwing, some data might have been added to
- * [output], but it won't contain valid JSON text.
- */
-void printOn(Object object, StringBuffer output) {
-  return _JsonStringifier.printOn(object, output);
-}
-
-//// Implementation ///////////////////////////////////////////////////////////
-
-// Simple API for JSON parsing.
-
-abstract class JsonListener {
-  void handleString(String value) {}
-  void handleNumber(num value) {}
-  void handleBool(bool value) {}
-  void handleNull() {}
-  void beginObject() {}
-  void propertyName() {}
-  void propertyValue() {}
-  void endObject() {}
-  void beginArray() {}
-  void arrayElement() {}
-  void endArray() {}
-  /** Called on failure to parse [source]. */
-  void fail(String source, int position, String message) {}
-}
-
-/**
- * A [JsonListener] that builds data objects from the parser events.
- *
- * This is a simple stack-based object builder. It keeps the most recently
- * seen value in a variable, and uses it depending on the following event.
- */
-class BuildJsonListener extends JsonListener {
-  /**
-   * Stack used to handle nested containers.
-   *
-   * The current container is pushed on the stack when a new one is
-   * started. If the container is a [Map], there is also a current [key]
-   * which is also stored on the stack.
-   */
-  List stack = [];
-  /** The current [Map] or [List] being built. */
-  var currentContainer;
-  /** The most recently read property key. */
-  String key;
-  /** The most recently read value. */
-  var value;
-
-  /** Pushes the currently active container (and key, if a [Map]). */
-  void pushContainer() {
-    if (currentContainer is Map) stack.add(key);
-    stack.add(currentContainer);
-  }
-
-  /** Pops the top container from the [stack], including a key if applicable. */
-  void popContainer() {
-    value = currentContainer;
-    currentContainer = stack.removeLast();
-    if (currentContainer is Map) key = stack.removeLast();
-  }
-
-  void handleString(String value) { this.value = value; }
-  void handleNumber(num value) { this.value = value; }
-  void handleBool(bool value) { this.value = value; }
-  void handleNull() { this.value = value; }
-
-  void beginObject() {
-    pushContainer();
-    currentContainer = {};
-  }
-
-  void propertyName() {
-    key = value;
-    value = null;
-  }
-
-  void propertyValue() {
-    Map map = currentContainer;
-    map[key] = value;
-    key = value = null;
-  }
-
-  void endObject() {
-    popContainer();
-  }
-
-  void beginArray() {
-    pushContainer();
-    currentContainer = [];
-  }
-
-  void arrayElement() {
-    List list = currentContainer;
-    currentContainer.add(value);
-    value = null;
-  }
-
-  void endArray() {
-    popContainer();
-  }
-
-  /** Read out the final result of parsing a JSON string. */
-  get result {
-    assert(currentContainer == null);
-    return value;
-  }
-}
-
-typedef _Reviver(var key, var value);
-
-class ReviverJsonListener extends BuildJsonListener {
-  final _Reviver reviver;
-  ReviverJsonListener(reviver(key, value)) : this.reviver = reviver;
-
-  void arrayElement() {
-    List list = currentContainer;
-    value = reviver(list.length, value);
-    super.arrayElement();
-  }
-
-  void propertyValue() {
-    value = reviver(key, value);
-    super.propertyValue();
-  }
-
-  get result {
-    return reviver("", value);
-  }
-}
-
-class JsonParser {
-  // A simple non-recursive state-based parser for JSON.
-  //
-  // Literal values accepted in states ARRAY_EMPTY, ARRAY_COMMA, OBJECT_COLON
-  // and strings also in OBJECT_EMPTY, OBJECT_COMMA.
-  //               VALUE  STRING  :  ,  }  ]        Transitions to
-  // EMPTY            X      X                   -> END
-  // ARRAY_EMPTY      X      X             @     -> ARRAY_VALUE / pop
-  // ARRAY_VALUE                     @     @     -> ARRAY_COMMA / pop
-  // ARRAY_COMMA      X      X                   -> ARRAY_VALUE
-  // OBJECT_EMPTY            X          @        -> OBJECT_KEY / pop
-  // OBJECT_KEY                   @              -> OBJECT_COLON
-  // OBJECT_COLON     X      X                   -> OBJECT_VALUE
-  // OBJECT_VALUE                    @  @        -> OBJECT_COMMA / pop
-  // OBJECT_COMMA            X                   -> OBJECT_KEY
-  // END
-  // Starting a new array or object will push the current state. The "pop"
-  // above means restoring this state and then marking it as an ended value.
-  // X means generic handling, @ means special handling for just that
-  // state - that is, values are handled generically, only punctuation
-  // cares about the current state.
-  // Values for states are chosen so bits 0 and 1 tell whether
-  // a string/value is allowed, and setting bits 0 through 2 after a value
-  // gets to the next state (not empty, doesn't allow a value).
-
-  // State building-block constants.
-  static const int INSIDE_ARRAY = 1;
-  static const int INSIDE_OBJECT = 2;
-  static const int AFTER_COLON = 3;  // Always inside object.
-
-  static const int ALLOW_STRING_MASK = 8;  // Allowed if zero.
-  static const int ALLOW_VALUE_MASK = 4;  // Allowed if zero.
-  static const int ALLOW_VALUE = 0;
-  static const int STRING_ONLY = 4;
-  static const int NO_VALUES = 12;
-
-  // Objects and arrays are "empty" until their first property/element.
-  static const int EMPTY = 0;
-  static const int NON_EMPTY = 16;
-  static const int EMPTY_MASK = 16;  // Empty if zero.
-
-
-  static const int VALUE_READ_BITS = NO_VALUES | NON_EMPTY;
-
-  // Actual states.
-  static const int STATE_INITIAL      = EMPTY | ALLOW_VALUE;
-  static const int STATE_END          = NON_EMPTY | NO_VALUES;
-
-  static const int STATE_ARRAY_EMPTY  = INSIDE_ARRAY | EMPTY | ALLOW_VALUE;
-  static const int STATE_ARRAY_VALUE  = INSIDE_ARRAY | NON_EMPTY | NO_VALUES;
-  static const int STATE_ARRAY_COMMA  = INSIDE_ARRAY | NON_EMPTY | ALLOW_VALUE;
-
-  static const int STATE_OBJECT_EMPTY = INSIDE_OBJECT | EMPTY | STRING_ONLY;
-  static const int STATE_OBJECT_KEY   = INSIDE_OBJECT | NON_EMPTY | NO_VALUES;
-  static const int STATE_OBJECT_COLON = AFTER_COLON | NON_EMPTY | ALLOW_VALUE;
-  static const int STATE_OBJECT_VALUE = AFTER_COLON | NON_EMPTY | NO_VALUES;
-  static const int STATE_OBJECT_COMMA = INSIDE_OBJECT | NON_EMPTY | STRING_ONLY;
-
-  // Character code constants.
-  static const int BACKSPACE       = 0x08;
-  static const int TAB             = 0x09;
-  static const int NEWLINE         = 0x0a;
-  static const int CARRIAGE_RETURN = 0x0d;
-  static const int FORM_FEED       = 0x0c;
-  static const int SPACE           = 0x20;
-  static const int QUOTE           = 0x22;
-  static const int PLUS            = 0x2b;
-  static const int COMMA           = 0x2c;
-  static const int MINUS           = 0x2d;
-  static const int DECIMALPOINT    = 0x2e;
-  static const int SLASH           = 0x2f;
-  static const int CHAR_0          = 0x30;
-  static const int CHAR_9          = 0x39;
-  static const int COLON           = 0x3a;
-  static const int CHAR_E          = 0x45;
-  static const int LBRACKET        = 0x5b;
-  static const int BACKSLASH       = 0x5c;
-  static const int RBRACKET        = 0x5d;
-  static const int CHAR_a          = 0x61;
-  static const int CHAR_b          = 0x62;
-  static const int CHAR_e          = 0x65;
-  static const int CHAR_f          = 0x66;
-  static const int CHAR_l          = 0x6c;
-  static const int CHAR_n          = 0x6e;
-  static const int CHAR_r          = 0x72;
-  static const int CHAR_s          = 0x73;
-  static const int CHAR_t          = 0x74;
-  static const int CHAR_u          = 0x75;
-  static const int LBRACE          = 0x7b;
-  static const int RBRACE          = 0x7d;
-
-  final String source;
-  final JsonListener listener;
-  JsonParser(this.source, this.listener);
-
-  /** Parses [source], or throws if it fails. */
-  void parse() {
-    final List<int> states = <int>[];
-    int state = STATE_INITIAL;
-    int position = 0;
-    int length = source.length;
-    while (position < length) {
-      int char = source.charCodeAt(position);
-      switch (char) {
-        case SPACE:
-        case CARRIAGE_RETURN:
-        case NEWLINE:
-        case TAB:
-          position++;
-          break;
-        case QUOTE:
-          if ((state & ALLOW_STRING_MASK) != 0) fail(position);
-          position = parseString(position + 1);
-          state |= VALUE_READ_BITS;
-          break;
-        case LBRACKET:
-          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
-          listener.beginArray();
-          states.add(state);
-          state = STATE_ARRAY_EMPTY;
-          position++;
-          break;
-        case LBRACE:
-          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
-          listener.beginObject();
-          states.add(state);
-          state = STATE_OBJECT_EMPTY;
-          position++;
-          break;
-        case CHAR_n:
-          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
-          position = parseNull(position);
-          state |= VALUE_READ_BITS;
-          break;
-        case CHAR_f:
-          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
-          position = parseFalse(position);
-          state |= VALUE_READ_BITS;
-          break;
-        case CHAR_t:
-          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
-          position = parseTrue(position);
-          state |= VALUE_READ_BITS;
-          break;
-        case COLON:
-          if (state != STATE_OBJECT_KEY) fail(position);
-          listener.propertyName();
-          state = STATE_OBJECT_COLON;
-          position++;
-          break;
-        case COMMA:
-          if (state == STATE_OBJECT_VALUE) {
-            listener.propertyValue();
-            state = STATE_OBJECT_COMMA;
-            position++;
-          } else if (state == STATE_ARRAY_VALUE) {
-            listener.arrayElement();
-            state = STATE_ARRAY_COMMA;
-            position++;
-          } else {
-            fail(position);
-          }
-          break;
-        case RBRACKET:
-          if (state == STATE_ARRAY_EMPTY) {
-            listener.endArray();
-          } else if (state == STATE_ARRAY_VALUE) {
-            listener.arrayElement();
-            listener.endArray();
-          } else {
-            fail(position);
-          }
-          state = states.removeLast() | VALUE_READ_BITS;
-          position++;
-          break;
-        case RBRACE:
-          if (state == STATE_OBJECT_EMPTY) {
-            listener.endObject();
-          } else if (state == STATE_OBJECT_VALUE) {
-            listener.propertyValue();
-            listener.endObject();
-          } else {
-            fail(position);
-          }
-          state = states.removeLast() | VALUE_READ_BITS;
-          position++;
-          break;
-        default:
-          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
-          position = parseNumber(char, position);
-          state |= VALUE_READ_BITS;
-          break;
-      }
-    }
-    if (state != STATE_END) fail(position);
-  }
-
-  /**
-   * Parses a "true" literal starting at [position].
-   *
-   * [:source[position]:] must be "t".
-   */
-  int parseTrue(int position) {
-    assert(source.charCodeAt(position) == CHAR_t);
-    if (source.length < position + 4) fail(position, "Unexpected identifier");
-    if (source.charCodeAt(position + 1) != CHAR_r ||
-        source.charCodeAt(position + 2) != CHAR_u ||
-        source.charCodeAt(position + 3) != CHAR_e) {
-      fail(position);
-    }
-    listener.handleBool(true);
-    return position + 4;
-  }
-
-  /**
-   * Parses a "false" literal starting at [position].
-   *
-   * [:source[position]:] must be "f".
-   */
-  int parseFalse(int position) {
-    assert(source.charCodeAt(position) == CHAR_f);
-    if (source.length < position + 5) fail(position, "Unexpected identifier");
-    if (source.charCodeAt(position + 1) != CHAR_a ||
-        source.charCodeAt(position + 2) != CHAR_l ||
-        source.charCodeAt(position + 3) != CHAR_s ||
-        source.charCodeAt(position + 4) != CHAR_e) {
-      fail(position);
-    }
-    listener.handleBool(false);
-    return position + 5;
-  }
-
-  /** Parses a "null" literal starting at [position].
-   *
-   * [:source[position]:] must be "n".
-   */
-  int parseNull(int position) {
-    assert(source.charCodeAt(position) == CHAR_n);
-    if (source.length < position + 4) fail(position, "Unexpected identifier");
-    if (source.charCodeAt(position + 1) != CHAR_u ||
-        source.charCodeAt(position + 2) != CHAR_l ||
-        source.charCodeAt(position + 3) != CHAR_l) {
-      fail(position);
-    }
-    listener.handleNull();
-    return position + 4;
-  }
-
-  int parseString(int position) {
-    // Format: '"'([^\x00-\x1f\\\"]|'\\'[bfnrt/\\"])*'"'
-    // Initial position is right after first '"'.
-    int start = position;
-    int char;
-    do {
-      if (position == source.length) {
-        fail(start - 1, "Unterminated string");
-      }
-      char = source.charCodeAt(position);
-      if (char == QUOTE) {
-        listener.handleString(source.substring(start, position));
-        return position + 1;
-      }
-      if (char < SPACE) {
-        fail(position, "Control character in string");
-      }
-      position++;
-    } while (char != BACKSLASH);
-    // Backslash escape detected. Collect character codes for rest of string.
-    int firstEscape = position - 1;
-    List<int> chars = <int>[];
-    while (true) {
-      if (position == source.length) {
-        fail(start - 1, "Unterminated string");
-      }
-      char = source.charCodeAt(position);
-      switch (char) {
-        case CHAR_b: char = BACKSPACE; break;
-        case CHAR_f: char = FORM_FEED; break;
-        case CHAR_n: char = NEWLINE; break;
-        case CHAR_r: char = CARRIAGE_RETURN; break;
-        case CHAR_t: char = TAB; break;
-        case SLASH:
-        case BACKSLASH:
-        case QUOTE:
-          break;
-        case CHAR_u:
-          int hexStart = position - 1;
-          int value = 0;
-          for (int i = 0; i < 4; i++) {
-            position++;
-            if (position == source.length) {
-              fail(start - 1, "Unterminated string");
-            }
-            char = source.charCodeAt(position);
-            char -= 0x30;
-            if (char < 0) fail(hexStart, "Invalid unicode escape");
-            if (char < 10) {
-              value = value * 16 + char;
-            } else {
-              char = (char | 0x20) - 0x31;
-              if (char < 0 || char > 5) {
-                fail(hexStart, "Invalid unicode escape");
-              }
-              value = value * 16 + char + 10;
-            }
-          }
-          char = value;
-          break;
-        default:
-          if (char < SPACE) fail(position, "Control character in string");
-          fail(position, "Unrecognized string escape");
-      }
-      do {
-        chars.add(char);
-        position++;
-        if (position == source.length) fail(start - 1, "Unterminated string");
-        char = source.charCodeAt(position);
-        if (char == QUOTE) {
-          String result = new String.fromCharCodes(chars);
-          if (start < firstEscape) {
-            result = "${source.substring(start, firstEscape)}$result";
-          }
-          listener.handleString(result);
-          return position + 1;
-        }
-        if (char < SPACE) {
-          fail(position, "Control character in string");
-        }
-      } while (char != BACKSLASH);
-      position++;
-    }
-  }
-
-  int parseNumber(int char, int position) {
-    // Format:
-    //  '-'?('0'|[1-9][0-9]*)('.'[0-9]+)?([eE][+-]?[0-9]+)?
-    int start = position;
-    int length = source.length;
-    bool isDouble = false;
-    if (char == MINUS) {
-      position++;
-      if (position == length) fail(position, "Missing expected digit");
-      char = source.charCodeAt(position);
-    }
-    if (char < CHAR_0 || char > CHAR_9) {
-      fail(position, "Missing expected digit");
-    }
-    int handleLiteral(position) {
-      String literal = source.substring(start, position);
-      // This correctly creates -0 for doubles.
-      num value = (isDouble ? double.parse(literal) : int.parse(literal));
-      listener.handleNumber(value);
-      return position;
-    }
-    if (char == CHAR_0) {
-      position++;
-      if (position == length) return handleLiteral(position);
-      char = source.charCodeAt(position);
-      if (CHAR_0 <= char && char <= CHAR_9) {
-        fail(position);
-      }
-    } else {
-      do {
-        position++;
-        if (position == length) return handleLiteral(position);
-        char = source.charCodeAt(position);
-      } while (CHAR_0 <= char && char <= CHAR_9);
-    }
-    if (char == DECIMALPOINT) {
-      isDouble = true;
-      position++;
-      if (position == length) fail(position, "Missing expected digit");
-      char = source.charCodeAt(position);
-      if (char < CHAR_0 || char > CHAR_9) fail(position);
-      do {
-        position++;
-        if (position == length) return handleLiteral(position);
-        char = source.charCodeAt(position);
-      } while (CHAR_0 <= char && char <= CHAR_9);
-    }
-    if (char == CHAR_e || char == CHAR_E) {
-      isDouble = true;
-      position++;
-      if (position == length) fail(position, "Missing expected digit");
-      char = source.charCodeAt(position);
-      if (char == PLUS || char == MINUS) {
-        position++;
-        if (position == length) fail(position, "Missing expected digit");
-        char = source.charCodeAt(position);
-      }
-      if (char < CHAR_0 || char > CHAR_9) {
-        fail(position, "Missing expected digit");
-      }
-      do {
-        position++;
-        if (position == length) return handleLiteral(position);
-        char = source.charCodeAt(position);
-      } while (CHAR_0 <= char && char <= CHAR_9);
-    }
-    return handleLiteral(position);
-  }
-
-  void fail(int position, [String message]) {
-    if (message == null) message = "Unexpected character";
-    listener.fail(source, position, message);
-    // If the listener didn't throw, do it here.
-    String slice;
-    int sliceEnd = position + 20;
-    if (sliceEnd > source.length) {
-      slice = "'${source.substring(position)}'";
-    } else {
-      slice = "'${source.substring(position, sliceEnd)}...'";
-    }
-    throw new FormatException("Unexpected character at $position: $slice");
-  }
-}
-
-
-class _JsonStringifier {
-  StringBuffer sb;
-  List<Object> seen;  // TODO: that should be identity set.
-
-  _JsonStringifier(this.sb) : seen = [];
-
-  static String stringify(final object) {
-    StringBuffer output = new StringBuffer();
-    _JsonStringifier stringifier = new _JsonStringifier(output);
-    stringifier.stringifyValue(object);
-    return output.toString();
-  }
-
-  static void printOn(final object, StringBuffer output) {
-    _JsonStringifier stringifier = new _JsonStringifier(output);
-    stringifier.stringifyValue(object);
-  }
-
-  static String numberToString(num x) {
-    return x.toString();
-  }
-
-  // ('0' + x) or ('a' + x - 10)
-  static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
-
-  static void escape(StringBuffer sb, String s) {
-    final int length = s.length;
-    bool needsEscape = false;
-    final charCodes = new List<int>();
-    for (int i = 0; i < length; i++) {
-      int charCode = s.charCodeAt(i);
-      if (charCode < 32) {
-        needsEscape = true;
-        charCodes.add(JsonParser.BACKSLASH);
-        switch (charCode) {
-        case JsonParser.BACKSPACE:
-          charCodes.add(JsonParser.CHAR_b);
-          break;
-        case JsonParser.TAB:
-          charCodes.add(JsonParser.CHAR_t);
-          break;
-        case JsonParser.NEWLINE:
-          charCodes.add(JsonParser.CHAR_n);
-          break;
-        case JsonParser.FORM_FEED:
-          charCodes.add(JsonParser.CHAR_f);
-          break;
-        case JsonParser.CARRIAGE_RETURN:
-          charCodes.add(JsonParser.CHAR_r);
-          break;
-        default:
-          charCodes.add(JsonParser.CHAR_u);
-          charCodes.add(hexDigit((charCode >> 12) & 0xf));
-          charCodes.add(hexDigit((charCode >> 8) & 0xf));
-          charCodes.add(hexDigit((charCode >> 4) & 0xf));
-          charCodes.add(hexDigit(charCode & 0xf));
-          break;
-        }
-      } else if (charCode == JsonParser.QUOTE ||
-          charCode == JsonParser.BACKSLASH) {
-        needsEscape = true;
-        charCodes.add(JsonParser.BACKSLASH);
-        charCodes.add(charCode);
-      } else {
-        charCodes.add(charCode);
-      }
-    }
-    sb.add(needsEscape ? new String.fromCharCodes(charCodes) : s);
-  }
-
-  void checkCycle(final object) {
-    // TODO: use Iterables.
-    for (int i = 0; i < seen.length; i++) {
-      if (identical(seen[i], object)) {
-        throw 'Cyclic structure';
-      }
-    }
-    seen.add(object);
-  }
-
-  void stringifyValue(final object) {
-    // Tries stringifying object directly. If it's not a simple value, List or
-    // Map, call toJson() to get a custom representation and try serializing
-    // that.
-    if (!stringifyJsonValue(object)) {
-      checkCycle(object);
-      try {
-        var customJson = object.toJson();
-        if (!stringifyJsonValue(customJson)) {
-          throw new JsonUnsupportedObjectError(object);
-        }
-        seen.removeLast();
-      } catch (e) {
-        throw new JsonUnsupportedObjectError.withCause(object, e);
-      }
-    }
-  }
-
-  /**
-   * Serializes a [num], [String], [bool], [Null], [List] or [Map] value.
-   *
-   * Returns true if the value is one of these types, and false if not.
-   * If a value is both a [List] and a [Map], it's serialized as a [List].
-   */
-  bool stringifyJsonValue(final object) {
-    if (object is num) {
-      // TODO: use writeOn.
-      sb.add(numberToString(object));
-      return true;
-    } else if (identical(object, true)) {
-      sb.add('true');
-      return true;
-    } else if (identical(object, false)) {
-      sb.add('false');
-       return true;
-    } else if (object == null) {
-      sb.add('null');
-      return true;
-    } else if (object is String) {
-      sb.add('"');
-      escape(sb, object);
-      sb.add('"');
-      return true;
-    } else if (object is List) {
-      checkCycle(object);
-      List a = object;
-      sb.add('[');
-      if (a.length > 0) {
-        stringifyValue(a[0]);
-        // TODO: switch to Iterables.
-        for (int i = 1; i < a.length; i++) {
-          sb.add(',');
-          stringifyValue(a[i]);
-        }
-      }
-      sb.add(']');
-      seen.removeLast();
-      return true;
-    } else if (object is Map) {
-      checkCycle(object);
-      Map<String, Object> m = object;
-      sb.add('{');
-      bool first = true;
-      m.forEach((String key, Object value) {
-        if (!first) {
-          sb.add(',"');
-        } else {
-          sb.add('"');
-        }
-        escape(sb, key);
-        sb.add('":');
-        stringifyValue(value);
-        first = false;
-      });
-      sb.add('}');
-      seen.removeLast();
-      return true;
-    } else {
-      return false;
-    }
-  }
-}
+part 'json_base.dart';
diff --git a/sdk/lib/json/json_base.dart b/sdk/lib/json/json_base.dart
new file mode 100644
index 0000000..9f74d65
--- /dev/null
+++ b/sdk/lib/json/json_base.dart
@@ -0,0 +1,802 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// JSON parsing and serialization.
+
+/**
+ * Error thrown by JSON serialization if an object cannot be serialized.
+ *
+ * The [unsupportedObject] field holds that object that failed to be serialized.
+ *
+ * If an object isn't directly serializable, the serializer calls the 'toJson'
+ * method on the object. If that call fails, the error will be stored in the
+ * [cause] field. If the call returns an object that isn't directly
+ * serializable, the [cause] will be null.
+ */
+class JsonUnsupportedObjectError implements Error {
+  /** The object that could not be serialized. */
+  final unsupportedObject;
+  /** The exception thrown by object's [:toJson:] method, if any. */
+  final cause;
+  JsonUnsupportedObjectError(this.unsupportedObject) : cause = null;
+  JsonUnsupportedObjectError.withCause(this.unsupportedObject, this.cause);
+
+  String toString() {
+    if (cause != null) {
+      return "Calling toJson method on object failed.";
+    } else {
+      return "Object toJson method returns non-serializable value.";
+    }
+  }
+}
+
+
+/**
+ * Parses [json] and build the corresponding parsed JSON value.
+ *
+ * Parsed JSON values are of the types [num], [String], [bool], [Null],
+ * [List]s of parsed JSON values or [Map]s from [String] to parsed
+ * JSON values.
+ *
+ * The optional [revivier] function, if provided, is called once for each
+ * object or list property parsed. The arguments are the property name
+ * ([String]) or list index ([int]), and the value is the parsed value.
+ * The return value of the revivier will be used as the value of that property
+ * instead the parsed value.
+ *
+ * Throws [FormatException] if the input is not valid JSON text.
+ */
+parse(String json, [reviver(var key, var value)]) {
+  BuildJsonListener listener;
+  if (reviver == null) {
+    listener = new BuildJsonListener();
+  } else {
+    listener = new ReviverJsonListener(reviver);
+  }
+  new JsonParser(json, listener).parse();
+  return listener.result;
+}
+
+/**
+ * Serializes [object] into a JSON string.
+ *
+ * Directly serializable types are [num], [String], [bool], [Null], [List]
+ * and [Map].
+ * For [List], the elements must all be serializable.
+ * For [Map], the keys must be [String] and the values must be serializable.
+ * If a value is any other type is attempted serialized, a "toJson()" method
+ * is invoked on the object and the result, which must be a directly
+ * serializable type, is serialized instead of the original value.
+ * If the object does not support this method, throws, or returns a
+ * value that is not directly serializable, a [JsonUnsupportedObjectError]
+ * exception is thrown. If the call throws (including the case where there
+ * is no nullary "toJson" method, the error is caught and stored in the
+ * [JsonUnsupportedObjectError]'s [:cause:] field.
+ *Json
+ * Objects should not change during serialization.
+ * If an object is serialized more than once, [stringify] is allowed to cache
+ * the JSON text for it. I.e., if an object changes after it is first
+ * serialized, the new values may or may not be reflected in the result.
+ */
+String stringify(Object object) {
+  return _JsonStringifier.stringify(object);
+}
+
+/**
+ * Serializes [object] into [output] stream.
+ *
+ * Performs the same operations as [stringify] but outputs the resulting
+ * string to an existing [StringBuffer] instead of creating a new [String].
+ *
+ * If serialization fails by throwing, some data might have been added to
+ * [output], but it won't contain valid JSON text.
+ */
+void printOn(Object object, StringBuffer output) {
+  return _JsonStringifier.printOn(object, output);
+}
+
+//// Implementation ///////////////////////////////////////////////////////////
+
+// Simple API for JSON parsing.
+
+abstract class JsonListener {
+  void handleString(String value) {}
+  void handleNumber(num value) {}
+  void handleBool(bool value) {}
+  void handleNull() {}
+  void beginObject() {}
+  void propertyName() {}
+  void propertyValue() {}
+  void endObject() {}
+  void beginArray() {}
+  void arrayElement() {}
+  void endArray() {}
+  /** Called on failure to parse [source]. */
+  void fail(String source, int position, String message) {}
+}
+
+/**
+ * A [JsonListener] that builds data objects from the parser events.
+ *
+ * This is a simple stack-based object builder. It keeps the most recently
+ * seen value in a variable, and uses it depending on the following event.
+ */
+class BuildJsonListener extends JsonListener {
+  /**
+   * Stack used to handle nested containers.
+   *
+   * The current container is pushed on the stack when a new one is
+   * started. If the container is a [Map], there is also a current [key]
+   * which is also stored on the stack.
+   */
+  List stack = [];
+  /** The current [Map] or [List] being built. */
+  var currentContainer;
+  /** The most recently read property key. */
+  String key;
+  /** The most recently read value. */
+  var value;
+
+  /** Pushes the currently active container (and key, if a [Map]). */
+  void pushContainer() {
+    if (currentContainer is Map) stack.add(key);
+    stack.add(currentContainer);
+  }
+
+  /** Pops the top container from the [stack], including a key if applicable. */
+  void popContainer() {
+    value = currentContainer;
+    currentContainer = stack.removeLast();
+    if (currentContainer is Map) key = stack.removeLast();
+  }
+
+  void handleString(String value) { this.value = value; }
+  void handleNumber(num value) { this.value = value; }
+  void handleBool(bool value) { this.value = value; }
+  void handleNull() { this.value = value; }
+
+  void beginObject() {
+    pushContainer();
+    currentContainer = {};
+  }
+
+  void propertyName() {
+    key = value;
+    value = null;
+  }
+
+  void propertyValue() {
+    Map map = currentContainer;
+    map[key] = value;
+    key = value = null;
+  }
+
+  void endObject() {
+    popContainer();
+  }
+
+  void beginArray() {
+    pushContainer();
+    currentContainer = [];
+  }
+
+  void arrayElement() {
+    List list = currentContainer;
+    currentContainer.add(value);
+    value = null;
+  }
+
+  void endArray() {
+    popContainer();
+  }
+
+  /** Read out the final result of parsing a JSON string. */
+  get result {
+    assert(currentContainer == null);
+    return value;
+  }
+}
+
+typedef _Reviver(var key, var value);
+
+class ReviverJsonListener extends BuildJsonListener {
+  final _Reviver reviver;
+  ReviverJsonListener(reviver(key, value)) : this.reviver = reviver;
+
+  void arrayElement() {
+    List list = currentContainer;
+    value = reviver(list.length, value);
+    super.arrayElement();
+  }
+
+  void propertyValue() {
+    value = reviver(key, value);
+    super.propertyValue();
+  }
+
+  get result {
+    return reviver("", value);
+  }
+}
+
+class JsonParser {
+  // A simple non-recursive state-based parser for JSON.
+  //
+  // Literal values accepted in states ARRAY_EMPTY, ARRAY_COMMA, OBJECT_COLON
+  // and strings also in OBJECT_EMPTY, OBJECT_COMMA.
+  //               VALUE  STRING  :  ,  }  ]        Transitions to
+  // EMPTY            X      X                   -> END
+  // ARRAY_EMPTY      X      X             @     -> ARRAY_VALUE / pop
+  // ARRAY_VALUE                     @     @     -> ARRAY_COMMA / pop
+  // ARRAY_COMMA      X      X                   -> ARRAY_VALUE
+  // OBJECT_EMPTY            X          @        -> OBJECT_KEY / pop
+  // OBJECT_KEY                   @              -> OBJECT_COLON
+  // OBJECT_COLON     X      X                   -> OBJECT_VALUE
+  // OBJECT_VALUE                    @  @        -> OBJECT_COMMA / pop
+  // OBJECT_COMMA            X                   -> OBJECT_KEY
+  // END
+  // Starting a new array or object will push the current state. The "pop"
+  // above means restoring this state and then marking it as an ended value.
+  // X means generic handling, @ means special handling for just that
+  // state - that is, values are handled generically, only punctuation
+  // cares about the current state.
+  // Values for states are chosen so bits 0 and 1 tell whether
+  // a string/value is allowed, and setting bits 0 through 2 after a value
+  // gets to the next state (not empty, doesn't allow a value).
+
+  // State building-block constants.
+  static const int INSIDE_ARRAY = 1;
+  static const int INSIDE_OBJECT = 2;
+  static const int AFTER_COLON = 3;  // Always inside object.
+
+  static const int ALLOW_STRING_MASK = 8;  // Allowed if zero.
+  static const int ALLOW_VALUE_MASK = 4;  // Allowed if zero.
+  static const int ALLOW_VALUE = 0;
+  static const int STRING_ONLY = 4;
+  static const int NO_VALUES = 12;
+
+  // Objects and arrays are "empty" until their first property/element.
+  static const int EMPTY = 0;
+  static const int NON_EMPTY = 16;
+  static const int EMPTY_MASK = 16;  // Empty if zero.
+
+
+  static const int VALUE_READ_BITS = NO_VALUES | NON_EMPTY;
+
+  // Actual states.
+  static const int STATE_INITIAL      = EMPTY | ALLOW_VALUE;
+  static const int STATE_END          = NON_EMPTY | NO_VALUES;
+
+  static const int STATE_ARRAY_EMPTY  = INSIDE_ARRAY | EMPTY | ALLOW_VALUE;
+  static const int STATE_ARRAY_VALUE  = INSIDE_ARRAY | NON_EMPTY | NO_VALUES;
+  static const int STATE_ARRAY_COMMA  = INSIDE_ARRAY | NON_EMPTY | ALLOW_VALUE;
+
+  static const int STATE_OBJECT_EMPTY = INSIDE_OBJECT | EMPTY | STRING_ONLY;
+  static const int STATE_OBJECT_KEY   = INSIDE_OBJECT | NON_EMPTY | NO_VALUES;
+  static const int STATE_OBJECT_COLON = AFTER_COLON | NON_EMPTY | ALLOW_VALUE;
+  static const int STATE_OBJECT_VALUE = AFTER_COLON | NON_EMPTY | NO_VALUES;
+  static const int STATE_OBJECT_COMMA = INSIDE_OBJECT | NON_EMPTY | STRING_ONLY;
+
+  // Character code constants.
+  static const int BACKSPACE       = 0x08;
+  static const int TAB             = 0x09;
+  static const int NEWLINE         = 0x0a;
+  static const int CARRIAGE_RETURN = 0x0d;
+  static const int FORM_FEED       = 0x0c;
+  static const int SPACE           = 0x20;
+  static const int QUOTE           = 0x22;
+  static const int PLUS            = 0x2b;
+  static const int COMMA           = 0x2c;
+  static const int MINUS           = 0x2d;
+  static const int DECIMALPOINT    = 0x2e;
+  static const int SLASH           = 0x2f;
+  static const int CHAR_0          = 0x30;
+  static const int CHAR_9          = 0x39;
+  static const int COLON           = 0x3a;
+  static const int CHAR_E          = 0x45;
+  static const int LBRACKET        = 0x5b;
+  static const int BACKSLASH       = 0x5c;
+  static const int RBRACKET        = 0x5d;
+  static const int CHAR_a          = 0x61;
+  static const int CHAR_b          = 0x62;
+  static const int CHAR_e          = 0x65;
+  static const int CHAR_f          = 0x66;
+  static const int CHAR_l          = 0x6c;
+  static const int CHAR_n          = 0x6e;
+  static const int CHAR_r          = 0x72;
+  static const int CHAR_s          = 0x73;
+  static const int CHAR_t          = 0x74;
+  static const int CHAR_u          = 0x75;
+  static const int LBRACE          = 0x7b;
+  static const int RBRACE          = 0x7d;
+
+  final String source;
+  final JsonListener listener;
+  JsonParser(this.source, this.listener);
+
+  /** Parses [source], or throws if it fails. */
+  void parse() {
+    final List<int> states = <int>[];
+    int state = STATE_INITIAL;
+    int position = 0;
+    int length = source.length;
+    while (position < length) {
+      int char = source.charCodeAt(position);
+      switch (char) {
+        case SPACE:
+        case CARRIAGE_RETURN:
+        case NEWLINE:
+        case TAB:
+          position++;
+          break;
+        case QUOTE:
+          if ((state & ALLOW_STRING_MASK) != 0) fail(position);
+          position = parseString(position + 1);
+          state |= VALUE_READ_BITS;
+          break;
+        case LBRACKET:
+          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
+          listener.beginArray();
+          states.add(state);
+          state = STATE_ARRAY_EMPTY;
+          position++;
+          break;
+        case LBRACE:
+          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
+          listener.beginObject();
+          states.add(state);
+          state = STATE_OBJECT_EMPTY;
+          position++;
+          break;
+        case CHAR_n:
+          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
+          position = parseNull(position);
+          state |= VALUE_READ_BITS;
+          break;
+        case CHAR_f:
+          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
+          position = parseFalse(position);
+          state |= VALUE_READ_BITS;
+          break;
+        case CHAR_t:
+          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
+          position = parseTrue(position);
+          state |= VALUE_READ_BITS;
+          break;
+        case COLON:
+          if (state != STATE_OBJECT_KEY) fail(position);
+          listener.propertyName();
+          state = STATE_OBJECT_COLON;
+          position++;
+          break;
+        case COMMA:
+          if (state == STATE_OBJECT_VALUE) {
+            listener.propertyValue();
+            state = STATE_OBJECT_COMMA;
+            position++;
+          } else if (state == STATE_ARRAY_VALUE) {
+            listener.arrayElement();
+            state = STATE_ARRAY_COMMA;
+            position++;
+          } else {
+            fail(position);
+          }
+          break;
+        case RBRACKET:
+          if (state == STATE_ARRAY_EMPTY) {
+            listener.endArray();
+          } else if (state == STATE_ARRAY_VALUE) {
+            listener.arrayElement();
+            listener.endArray();
+          } else {
+            fail(position);
+          }
+          state = states.removeLast() | VALUE_READ_BITS;
+          position++;
+          break;
+        case RBRACE:
+          if (state == STATE_OBJECT_EMPTY) {
+            listener.endObject();
+          } else if (state == STATE_OBJECT_VALUE) {
+            listener.propertyValue();
+            listener.endObject();
+          } else {
+            fail(position);
+          }
+          state = states.removeLast() | VALUE_READ_BITS;
+          position++;
+          break;
+        default:
+          if ((state & ALLOW_VALUE_MASK) != 0) fail(position);
+          position = parseNumber(char, position);
+          state |= VALUE_READ_BITS;
+          break;
+      }
+    }
+    if (state != STATE_END) fail(position);
+  }
+
+  /**
+   * Parses a "true" literal starting at [position].
+   *
+   * [:source[position]:] must be "t".
+   */
+  int parseTrue(int position) {
+    assert(source.charCodeAt(position) == CHAR_t);
+    if (source.length < position + 4) fail(position, "Unexpected identifier");
+    if (source.charCodeAt(position + 1) != CHAR_r ||
+        source.charCodeAt(position + 2) != CHAR_u ||
+        source.charCodeAt(position + 3) != CHAR_e) {
+      fail(position);
+    }
+    listener.handleBool(true);
+    return position + 4;
+  }
+
+  /**
+   * Parses a "false" literal starting at [position].
+   *
+   * [:source[position]:] must be "f".
+   */
+  int parseFalse(int position) {
+    assert(source.charCodeAt(position) == CHAR_f);
+    if (source.length < position + 5) fail(position, "Unexpected identifier");
+    if (source.charCodeAt(position + 1) != CHAR_a ||
+        source.charCodeAt(position + 2) != CHAR_l ||
+        source.charCodeAt(position + 3) != CHAR_s ||
+        source.charCodeAt(position + 4) != CHAR_e) {
+      fail(position);
+    }
+    listener.handleBool(false);
+    return position + 5;
+  }
+
+  /** Parses a "null" literal starting at [position].
+   *
+   * [:source[position]:] must be "n".
+   */
+  int parseNull(int position) {
+    assert(source.charCodeAt(position) == CHAR_n);
+    if (source.length < position + 4) fail(position, "Unexpected identifier");
+    if (source.charCodeAt(position + 1) != CHAR_u ||
+        source.charCodeAt(position + 2) != CHAR_l ||
+        source.charCodeAt(position + 3) != CHAR_l) {
+      fail(position);
+    }
+    listener.handleNull();
+    return position + 4;
+  }
+
+  int parseString(int position) {
+    // Format: '"'([^\x00-\x1f\\\"]|'\\'[bfnrt/\\"])*'"'
+    // Initial position is right after first '"'.
+    int start = position;
+    int char;
+    do {
+      if (position == source.length) {
+        fail(start - 1, "Unterminated string");
+      }
+      char = source.charCodeAt(position);
+      if (char == QUOTE) {
+        listener.handleString(source.substring(start, position));
+        return position + 1;
+      }
+      if (char < SPACE) {
+        fail(position, "Control character in string");
+      }
+      position++;
+    } while (char != BACKSLASH);
+    // Backslash escape detected. Collect character codes for rest of string.
+    int firstEscape = position - 1;
+    List<int> chars = <int>[];
+    while (true) {
+      if (position == source.length) {
+        fail(start - 1, "Unterminated string");
+      }
+      char = source.charCodeAt(position);
+      switch (char) {
+        case CHAR_b: char = BACKSPACE; break;
+        case CHAR_f: char = FORM_FEED; break;
+        case CHAR_n: char = NEWLINE; break;
+        case CHAR_r: char = CARRIAGE_RETURN; break;
+        case CHAR_t: char = TAB; break;
+        case SLASH:
+        case BACKSLASH:
+        case QUOTE:
+          break;
+        case CHAR_u:
+          int hexStart = position - 1;
+          int value = 0;
+          for (int i = 0; i < 4; i++) {
+            position++;
+            if (position == source.length) {
+              fail(start - 1, "Unterminated string");
+            }
+            char = source.charCodeAt(position);
+            char -= 0x30;
+            if (char < 0) fail(hexStart, "Invalid unicode escape");
+            if (char < 10) {
+              value = value * 16 + char;
+            } else {
+              char = (char | 0x20) - 0x31;
+              if (char < 0 || char > 5) {
+                fail(hexStart, "Invalid unicode escape");
+              }
+              value = value * 16 + char + 10;
+            }
+          }
+          char = value;
+          break;
+        default:
+          if (char < SPACE) fail(position, "Control character in string");
+          fail(position, "Unrecognized string escape");
+      }
+      do {
+        chars.add(char);
+        position++;
+        if (position == source.length) fail(start - 1, "Unterminated string");
+        char = source.charCodeAt(position);
+        if (char == QUOTE) {
+          String result = new String.fromCharCodes(chars);
+          if (start < firstEscape) {
+            result = "${source.substring(start, firstEscape)}$result";
+          }
+          listener.handleString(result);
+          return position + 1;
+        }
+        if (char < SPACE) {
+          fail(position, "Control character in string");
+        }
+      } while (char != BACKSLASH);
+      position++;
+    }
+  }
+
+  int parseNumber(int char, int position) {
+    // Format:
+    //  '-'?('0'|[1-9][0-9]*)('.'[0-9]+)?([eE][+-]?[0-9]+)?
+    int start = position;
+    int length = source.length;
+    bool isDouble = false;
+    if (char == MINUS) {
+      position++;
+      if (position == length) fail(position, "Missing expected digit");
+      char = source.charCodeAt(position);
+    }
+    if (char < CHAR_0 || char > CHAR_9) {
+      fail(position, "Missing expected digit");
+    }
+    int handleLiteral(position) {
+      String literal = source.substring(start, position);
+      // This correctly creates -0 for doubles.
+      num value = (isDouble ? double.parse(literal) : int.parse(literal));
+      listener.handleNumber(value);
+      return position;
+    }
+    if (char == CHAR_0) {
+      position++;
+      if (position == length) return handleLiteral(position);
+      char = source.charCodeAt(position);
+      if (CHAR_0 <= char && char <= CHAR_9) {
+        fail(position);
+      }
+    } else {
+      do {
+        position++;
+        if (position == length) return handleLiteral(position);
+        char = source.charCodeAt(position);
+      } while (CHAR_0 <= char && char <= CHAR_9);
+    }
+    if (char == DECIMALPOINT) {
+      isDouble = true;
+      position++;
+      if (position == length) fail(position, "Missing expected digit");
+      char = source.charCodeAt(position);
+      if (char < CHAR_0 || char > CHAR_9) fail(position);
+      do {
+        position++;
+        if (position == length) return handleLiteral(position);
+        char = source.charCodeAt(position);
+      } while (CHAR_0 <= char && char <= CHAR_9);
+    }
+    if (char == CHAR_e || char == CHAR_E) {
+      isDouble = true;
+      position++;
+      if (position == length) fail(position, "Missing expected digit");
+      char = source.charCodeAt(position);
+      if (char == PLUS || char == MINUS) {
+        position++;
+        if (position == length) fail(position, "Missing expected digit");
+        char = source.charCodeAt(position);
+      }
+      if (char < CHAR_0 || char > CHAR_9) {
+        fail(position, "Missing expected digit");
+      }
+      do {
+        position++;
+        if (position == length) return handleLiteral(position);
+        char = source.charCodeAt(position);
+      } while (CHAR_0 <= char && char <= CHAR_9);
+    }
+    return handleLiteral(position);
+  }
+
+  void fail(int position, [String message]) {
+    if (message == null) message = "Unexpected character";
+    listener.fail(source, position, message);
+    // If the listener didn't throw, do it here.
+    String slice;
+    int sliceEnd = position + 20;
+    if (sliceEnd > source.length) {
+      slice = "'${source.substring(position)}'";
+    } else {
+      slice = "'${source.substring(position, sliceEnd)}...'";
+    }
+    throw new FormatException("Unexpected character at $position: $slice");
+  }
+}
+
+
+class _JsonStringifier {
+  StringBuffer sb;
+  List<Object> seen;  // TODO: that should be identity set.
+
+  _JsonStringifier(this.sb) : seen = [];
+
+  static String stringify(final object) {
+    StringBuffer output = new StringBuffer();
+    _JsonStringifier stringifier = new _JsonStringifier(output);
+    stringifier.stringifyValue(object);
+    return output.toString();
+  }
+
+  static void printOn(final object, StringBuffer output) {
+    _JsonStringifier stringifier = new _JsonStringifier(output);
+    stringifier.stringifyValue(object);
+  }
+
+  static String numberToString(num x) {
+    return x.toString();
+  }
+
+  // ('0' + x) or ('a' + x - 10)
+  static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
+
+  static void escape(StringBuffer sb, String s) {
+    final int length = s.length;
+    bool needsEscape = false;
+    final charCodes = new List<int>();
+    for (int i = 0; i < length; i++) {
+      int charCode = s.charCodeAt(i);
+      if (charCode < 32) {
+        needsEscape = true;
+        charCodes.add(JsonParser.BACKSLASH);
+        switch (charCode) {
+        case JsonParser.BACKSPACE:
+          charCodes.add(JsonParser.CHAR_b);
+          break;
+        case JsonParser.TAB:
+          charCodes.add(JsonParser.CHAR_t);
+          break;
+        case JsonParser.NEWLINE:
+          charCodes.add(JsonParser.CHAR_n);
+          break;
+        case JsonParser.FORM_FEED:
+          charCodes.add(JsonParser.CHAR_f);
+          break;
+        case JsonParser.CARRIAGE_RETURN:
+          charCodes.add(JsonParser.CHAR_r);
+          break;
+        default:
+          charCodes.add(JsonParser.CHAR_u);
+          charCodes.add(hexDigit((charCode >> 12) & 0xf));
+          charCodes.add(hexDigit((charCode >> 8) & 0xf));
+          charCodes.add(hexDigit((charCode >> 4) & 0xf));
+          charCodes.add(hexDigit(charCode & 0xf));
+          break;
+        }
+      } else if (charCode == JsonParser.QUOTE ||
+          charCode == JsonParser.BACKSLASH) {
+        needsEscape = true;
+        charCodes.add(JsonParser.BACKSLASH);
+        charCodes.add(charCode);
+      } else {
+        charCodes.add(charCode);
+      }
+    }
+    sb.add(needsEscape ? new String.fromCharCodes(charCodes) : s);
+  }
+
+  void checkCycle(final object) {
+    // TODO: use Iterables.
+    for (int i = 0; i < seen.length; i++) {
+      if (identical(seen[i], object)) {
+        throw 'Cyclic structure';
+      }
+    }
+    seen.add(object);
+  }
+
+  void stringifyValue(final object) {
+    // Tries stringifying object directly. If it's not a simple value, List or
+    // Map, call toJson() to get a custom representation and try serializing
+    // that.
+    if (!stringifyJsonValue(object)) {
+      checkCycle(object);
+      try {
+        var customJson = object.toJson();
+        if (!stringifyJsonValue(customJson)) {
+          throw new JsonUnsupportedObjectError(object);
+        }
+        seen.removeLast();
+      } catch (e) {
+        throw new JsonUnsupportedObjectError.withCause(object, e);
+      }
+    }
+  }
+
+  /**
+   * Serializes a [num], [String], [bool], [Null], [List] or [Map] value.
+   *
+   * Returns true if the value is one of these types, and false if not.
+   * If a value is both a [List] and a [Map], it's serialized as a [List].
+   */
+  bool stringifyJsonValue(final object) {
+    if (object is num) {
+      // TODO: use writeOn.
+      sb.add(numberToString(object));
+      return true;
+    } else if (identical(object, true)) {
+      sb.add('true');
+      return true;
+    } else if (identical(object, false)) {
+      sb.add('false');
+       return true;
+    } else if (object == null) {
+      sb.add('null');
+      return true;
+    } else if (object is String) {
+      sb.add('"');
+      escape(sb, object);
+      sb.add('"');
+      return true;
+    } else if (object is List) {
+      checkCycle(object);
+      List a = object;
+      sb.add('[');
+      if (a.length > 0) {
+        stringifyValue(a[0]);
+        // TODO: switch to Iterables.
+        for (int i = 1; i < a.length; i++) {
+          sb.add(',');
+          stringifyValue(a[i]);
+        }
+      }
+      sb.add(']');
+      seen.removeLast();
+      return true;
+    } else if (object is Map) {
+      checkCycle(object);
+      Map<String, Object> m = object;
+      sb.add('{');
+      bool first = true;
+      m.forEach((String key, Object value) {
+        if (!first) {
+          sb.add(',"');
+        } else {
+          sb.add('"');
+        }
+        escape(sb, key);
+        sb.add('":');
+        stringifyValue(value);
+        first = false;
+      });
+      sb.add('}');
+      seen.removeLast();
+      return true;
+    } else {
+      return false;
+    }
+  }
+}
diff --git a/runtime/bin/json_sources.gypi b/sdk/lib/json/json_sources.gypi
similarity index 71%
rename from runtime/bin/json_sources.gypi
rename to sdk/lib/json/json_sources.gypi
index 6c9ca3d..f9a7160 100644
--- a/runtime/bin/json_sources.gypi
+++ b/sdk/lib/json/json_sources.gypi
@@ -2,9 +2,9 @@
 # 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.
 
-# This file contains all sources for the dart:io library.
+# This file contains all sources for the dart:json library.
 {
   'sources': [
-    '../../sdk/lib/json/json.dart',
+    'json_base.dart',
   ],
 }
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index 4b26804..c34dc27 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -6,7 +6,8 @@
 import 'dart:html_common';
 import 'dart:_js_helper' show Creates, Returns, JavaScriptIndexingBehavior, JSName;
 import 'dart:_foreign_helper' show JS;
-// DO NOT EDIT
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:svg library.
 
 
@@ -5757,7 +5758,7 @@
   Set<String> readClasses() {
     var classname = _element.attributes['class'];
 
-    Set<String> s = new Set<String>();
+    Set<String> s = new LinkedHashSet<String>();
     if (classname == null) {
       return s;
     }
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index 1c03b3a..d6b19dd 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -6506,7 +6506,7 @@
   Set<String> readClasses() {
     var classname = _element.attributes['class'];
 
-    Set<String> s = new Set<String>();
+    Set<String> s = new LinkedHashSet<String>();
     if (classname == null) {
       return s;
     }
diff --git a/sdk/lib/uri/uri.dart b/sdk/lib/uri/uri.dart
index abd1223..f3876f6 100644
--- a/sdk/lib/uri/uri.dart
+++ b/sdk/lib/uri/uri.dart
@@ -7,259 +7,6 @@
 import 'dart:math';
 import 'dart:utf';
 
+part 'uri_base.dart';
 part 'encode_decode.dart';
 part 'helpers.dart';
-
-/**
- * A parsed URI, inspired by Closure's [URI][] class. Implements [RFC-3986][].
- * [uri]: http://closure-library.googlecode.com/svn/docs/class_goog_Uri.html
- * [RFC-3986]: http://tools.ietf.org/html/rfc3986#section-4.3)
- */
-class Uri {
-  final String scheme;
-  final String userInfo;
-  final String domain;
-  final int port;
-  final String path;
-  final String query;
-  final String fragment;
-
-  /**
-   * Deprecated. Please use [parse] instead.
-   */
-  Uri.fromString(String uri) : this._fromMatch(_splitRe.firstMatch(uri));
-
-  static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri));
-
-  Uri._fromMatch(Match m) :
-    this.fromComponents(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]),
-                        userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]),
-                        domain: _emptyIfNull(m[_COMPONENT_DOMAIN]),
-                        port: _parseIntOrZero(m[_COMPONENT_PORT]),
-                        path: _emptyIfNull(m[_COMPONENT_PATH]),
-                        query: _emptyIfNull(m[_COMPONENT_QUERY_DATA]),
-                        fragment: _emptyIfNull(m[_COMPONENT_FRAGMENT]));
-
-  const Uri.fromComponents({this.scheme: "",
-                            this.userInfo: "",
-                            this.domain: "",
-                            this.port: 0,
-                            this.path: "",
-                            this.query: "",
-                            this.fragment: ""});
-
-  Uri(String uri) : this.fromString(uri);
-
-  static String _emptyIfNull(String val) => val != null ? val : '';
-
-  static int _parseIntOrZero(String val) {
-    if (val != null && val != '') {
-      return int.parse(val);
-    } else {
-      return 0;
-    }
-  }
-
-  // NOTE: This code was ported from: closure-library/closure/goog/uri/utils.js
-  static final RegExp _splitRe = new RegExp(
-      '^'
-      '(?:'
-        '([^:/?#.]+)'                   // scheme - ignore special characters
-                                        // used by other URL parts such as :,
-                                        // ?, /, #, and .
-      ':)?'
-      '(?://'
-        '(?:([^/?#]*)@)?'               // userInfo
-        '([\\w\\d\\-\\u0100-\\uffff.%]*)'
-                                        // domain - restrict to letters,
-                                        // digits, dashes, dots, percent
-                                        // escapes, and unicode characters.
-        '(?::([0-9]+))?'                // port
-      ')?'
-      '([^?#]+)?'                       // path
-      '(?:\\?([^#]*))?'                 // query
-      '(?:#(.*))?'                      // fragment
-      '\$');
-
-  static const _COMPONENT_SCHEME = 1;
-  static const _COMPONENT_USER_INFO = 2;
-  static const _COMPONENT_DOMAIN = 3;
-  static const _COMPONENT_PORT = 4;
-  static const _COMPONENT_PATH = 5;
-  static const _COMPONENT_QUERY_DATA = 6;
-  static const _COMPONENT_FRAGMENT = 7;
-
-  /**
-   * Returns `true` if the URI is absolute.
-   */
-  bool get isAbsolute {
-    if ("" == scheme) return false;
-    if ("" != fragment) return false;
-    return true;
-
-    /* absolute-URI  = scheme ":" hier-part [ "?" query ]
-     * hier-part   = "//" authority path-abempty
-     *             / path-absolute
-     *             / path-rootless
-     *             / path-empty
-     *
-     * path          = path-abempty    ; begins with "/" or is empty
-     *               / path-absolute   ; begins with "/" but not "//"
-     *               / path-noscheme   ; begins with a non-colon segment
-     *               / path-rootless   ; begins with a segment
-     *               / path-empty      ; zero characters
-     *
-     * path-abempty  = *( "/" segment )
-     * path-absolute = "/" [ segment-nz *( "/" segment ) ]
-     * path-noscheme = segment-nz-nc *( "/" segment )
-     * path-rootless = segment-nz *( "/" segment )
-     * path-empty    = 0<pchar>
-     * segment       = *pchar
-     * segment-nz    = 1*pchar
-     * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
-     *               ; non-zero-length segment without any colon ":"
-     *
-     * pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
-     */
-  }
-
-  Uri resolve(String uri) {
-    return resolveUri(Uri.parse(uri));
-  }
-
-  Uri resolveUri(Uri reference) {
-    // From RFC 3986.
-    String targetScheme;
-    String targetUserInfo;
-    String targetDomain;
-    int targetPort;
-    String targetPath;
-    String targetQuery;
-    if (reference.scheme != "") {
-      targetScheme = reference.scheme;
-      targetUserInfo = reference.userInfo;
-      targetDomain = reference.domain;
-      targetPort = reference.port;
-      targetPath = removeDotSegments(reference.path);
-      targetQuery = reference.query;
-    } else {
-      if (reference.hasAuthority) {
-        targetUserInfo = reference.userInfo;
-        targetDomain = reference.domain;
-        targetPort = reference.port;
-        targetPath = removeDotSegments(reference.path);
-        targetQuery = reference.query;
-      } else {
-        if (reference.path == "") {
-          targetPath = this.path;
-          if (reference.query != "") {
-            targetQuery = reference.query;
-          } else {
-            targetQuery = this.query;
-          }
-        } else {
-          if (reference.path.startsWith("/")) {
-            targetPath = removeDotSegments(reference.path);
-          } else {
-            targetPath = removeDotSegments(merge(this.path, reference.path));
-          }
-          targetQuery = reference.query;
-        }
-        targetUserInfo = this.userInfo;
-        targetDomain = this.domain;
-        targetPort = this.port;
-      }
-      targetScheme = this.scheme;
-    }
-    return new Uri.fromComponents(scheme: targetScheme,
-                                  userInfo: targetUserInfo,
-                                  domain: targetDomain,
-                                  port: targetPort,
-                                  path: targetPath,
-                                  query: targetQuery,
-                                  fragment: reference.fragment);
-  }
-
-  bool get hasAuthority {
-    return (userInfo != "") || (domain != "") || (port != 0);
-  }
-
-  /**
-   * For http/https schemes returns URI's [origin][] - scheme://domain:port.
-   * For all other schemes throws ArgumentError.
-   * [origin]: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
-   */
-  String get origin {
-    if (scheme == "") {
-      // TODO(aprelev@gmail.com): Use StateException instead
-      throw new ArgumentError("Cannot use origin without a scheme");
-    }
-    if (scheme != "http" && scheme != "https") {
-      // TODO(aprelev@gmail.com): Use StateException instead
-      throw new ArgumentError(
-        "origin is applicable to http/https schemes only. Not \'$scheme\'");
-    }
-    StringBuffer sb = new StringBuffer();
-    sb.add(scheme);
-    sb.add(":");
-    if (domain == null || domain == "") {
-      // TODO(aprelev@gmail.com): Use StateException instead
-      throw new ArgumentError("Cannot use origin without a domain");
-    }
-
-    sb.add("//");
-    sb.add(domain);
-    if (port != 0) {
-      sb.add(":");
-      sb.add(port);
-    }
-    return sb.toString();
-  }
-
-  String toString() {
-    StringBuffer sb = new StringBuffer();
-    _addIfNonEmpty(sb, scheme, scheme, ':');
-    if (hasAuthority || (scheme == "file")) {
-      sb.add("//");
-      _addIfNonEmpty(sb, userInfo, userInfo, "@");
-      sb.add(domain == null ? "null" : domain);
-      if (port != 0) {
-        sb.add(":");
-        sb.add(port.toString());
-      }
-    }
-    sb.add(path == null ? "null" : path);
-    _addIfNonEmpty(sb, query, "?", query);
-    _addIfNonEmpty(sb, fragment, "#", fragment);
-    return sb.toString();
-  }
-
-  bool operator==(other) {
-    if (other is! Uri) return false;
-    Uri uri = other;
-    return scheme == uri.scheme &&
-        userInfo == uri.userInfo &&
-        domain == uri.domain &&
-        port == uri.port &&
-        path == uri.path &&
-        query == uri.query &&
-        fragment == uri.fragment;
-  }
-
-  int get hashCode {
-    int combine(part, current) {
-      // The sum is truncated to 30 bits to make sure it fits into a Smi.
-      return (current * 31 + part.hashCode) & 0x3FFFFFFF;
-    }
-    return combine(scheme, combine(userInfo, combine(domain, combine(port,
-        combine(path, combine(query, combine(fragment, 1)))))));
-  }
-
-  static void _addIfNonEmpty(StringBuffer sb, String test,
-                             String first, String second) {
-    if ("" != test) {
-      sb.add(first == null ? "null" : first);
-      sb.add(second == null ? "null" : second);
-    }
-  }
-}
diff --git a/sdk/lib/uri/uri_base.dart b/sdk/lib/uri/uri_base.dart
new file mode 100644
index 0000000..c775080
--- /dev/null
+++ b/sdk/lib/uri/uri_base.dart
@@ -0,0 +1,259 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.uri;
+
+/**
+ * A parsed URI, inspired by Closure's [URI][] class. Implements [RFC-3986][].
+ * [uri]: http://closure-library.googlecode.com/svn/docs/class_goog_Uri.html
+ * [RFC-3986]: http://tools.ietf.org/html/rfc3986#section-4.3)
+ */
+class Uri {
+  final String scheme;
+  final String userInfo;
+  final String domain;
+  final int port;
+  final String path;
+  final String query;
+  final String fragment;
+
+  /**
+   * Deprecated. Please use [parse] instead.
+   */
+  Uri.fromString(String uri) : this._fromMatch(_splitRe.firstMatch(uri));
+
+  static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri));
+
+  Uri._fromMatch(Match m) :
+    this.fromComponents(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]),
+                        userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]),
+                        domain: _emptyIfNull(m[_COMPONENT_DOMAIN]),
+                        port: _parseIntOrZero(m[_COMPONENT_PORT]),
+                        path: _emptyIfNull(m[_COMPONENT_PATH]),
+                        query: _emptyIfNull(m[_COMPONENT_QUERY_DATA]),
+                        fragment: _emptyIfNull(m[_COMPONENT_FRAGMENT]));
+
+  const Uri.fromComponents({this.scheme: "",
+                            this.userInfo: "",
+                            this.domain: "",
+                            this.port: 0,
+                            this.path: "",
+                            this.query: "",
+                            this.fragment: ""});
+
+  Uri(String uri) : this.fromString(uri);
+
+  static String _emptyIfNull(String val) => val != null ? val : '';
+
+  static int _parseIntOrZero(String val) {
+    if (val != null && val != '') {
+      return int.parse(val);
+    } else {
+      return 0;
+    }
+  }
+
+  // NOTE: This code was ported from: closure-library/closure/goog/uri/utils.js
+  static final RegExp _splitRe = new RegExp(
+      '^'
+      '(?:'
+        '([^:/?#.]+)'                   // scheme - ignore special characters
+                                        // used by other URL parts such as :,
+                                        // ?, /, #, and .
+      ':)?'
+      '(?://'
+        '(?:([^/?#]*)@)?'               // userInfo
+        '([\\w\\d\\-\\u0100-\\uffff.%]*)'
+                                        // domain - restrict to letters,
+                                        // digits, dashes, dots, percent
+                                        // escapes, and unicode characters.
+        '(?::([0-9]+))?'                // port
+      ')?'
+      '([^?#]+)?'                       // path
+      '(?:\\?([^#]*))?'                 // query
+      '(?:#(.*))?'                      // fragment
+      '\$');
+
+  static const _COMPONENT_SCHEME = 1;
+  static const _COMPONENT_USER_INFO = 2;
+  static const _COMPONENT_DOMAIN = 3;
+  static const _COMPONENT_PORT = 4;
+  static const _COMPONENT_PATH = 5;
+  static const _COMPONENT_QUERY_DATA = 6;
+  static const _COMPONENT_FRAGMENT = 7;
+
+  /**
+   * Returns `true` if the URI is absolute.
+   */
+  bool get isAbsolute {
+    if ("" == scheme) return false;
+    if ("" != fragment) return false;
+    return true;
+
+    /* absolute-URI  = scheme ":" hier-part [ "?" query ]
+     * hier-part   = "//" authority path-abempty
+     *             / path-absolute
+     *             / path-rootless
+     *             / path-empty
+     *
+     * path          = path-abempty    ; begins with "/" or is empty
+     *               / path-absolute   ; begins with "/" but not "//"
+     *               / path-noscheme   ; begins with a non-colon segment
+     *               / path-rootless   ; begins with a segment
+     *               / path-empty      ; zero characters
+     *
+     * path-abempty  = *( "/" segment )
+     * path-absolute = "/" [ segment-nz *( "/" segment ) ]
+     * path-noscheme = segment-nz-nc *( "/" segment )
+     * path-rootless = segment-nz *( "/" segment )
+     * path-empty    = 0<pchar>
+     * segment       = *pchar
+     * segment-nz    = 1*pchar
+     * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+     *               ; non-zero-length segment without any colon ":"
+     *
+     * pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
+     */
+  }
+
+  Uri resolve(String uri) {
+    return resolveUri(Uri.parse(uri));
+  }
+
+  Uri resolveUri(Uri reference) {
+    // From RFC 3986.
+    String targetScheme;
+    String targetUserInfo;
+    String targetDomain;
+    int targetPort;
+    String targetPath;
+    String targetQuery;
+    if (reference.scheme != "") {
+      targetScheme = reference.scheme;
+      targetUserInfo = reference.userInfo;
+      targetDomain = reference.domain;
+      targetPort = reference.port;
+      targetPath = removeDotSegments(reference.path);
+      targetQuery = reference.query;
+    } else {
+      if (reference.hasAuthority) {
+        targetUserInfo = reference.userInfo;
+        targetDomain = reference.domain;
+        targetPort = reference.port;
+        targetPath = removeDotSegments(reference.path);
+        targetQuery = reference.query;
+      } else {
+        if (reference.path == "") {
+          targetPath = this.path;
+          if (reference.query != "") {
+            targetQuery = reference.query;
+          } else {
+            targetQuery = this.query;
+          }
+        } else {
+          if (reference.path.startsWith("/")) {
+            targetPath = removeDotSegments(reference.path);
+          } else {
+            targetPath = removeDotSegments(merge(this.path, reference.path));
+          }
+          targetQuery = reference.query;
+        }
+        targetUserInfo = this.userInfo;
+        targetDomain = this.domain;
+        targetPort = this.port;
+      }
+      targetScheme = this.scheme;
+    }
+    return new Uri.fromComponents(scheme: targetScheme,
+                                  userInfo: targetUserInfo,
+                                  domain: targetDomain,
+                                  port: targetPort,
+                                  path: targetPath,
+                                  query: targetQuery,
+                                  fragment: reference.fragment);
+  }
+
+  bool get hasAuthority {
+    return (userInfo != "") || (domain != "") || (port != 0);
+  }
+
+  /**
+   * For http/https schemes returns URI's [origin][] - scheme://domain:port.
+   * For all other schemes throws ArgumentError.
+   * [origin]: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
+   */
+  String get origin {
+    if (scheme == "") {
+      // TODO(aprelev@gmail.com): Use StateException instead
+      throw new ArgumentError("Cannot use origin without a scheme");
+    }
+    if (scheme != "http" && scheme != "https") {
+      // TODO(aprelev@gmail.com): Use StateException instead
+      throw new ArgumentError(
+        "origin is applicable to http/https schemes only. Not \'$scheme\'");
+    }
+    StringBuffer sb = new StringBuffer();
+    sb.add(scheme);
+    sb.add(":");
+    if (domain == null || domain == "") {
+      // TODO(aprelev@gmail.com): Use StateException instead
+      throw new ArgumentError("Cannot use origin without a domain");
+    }
+
+    sb.add("//");
+    sb.add(domain);
+    if (port != 0) {
+      sb.add(":");
+      sb.add(port);
+    }
+    return sb.toString();
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    _addIfNonEmpty(sb, scheme, scheme, ':');
+    if (hasAuthority || (scheme == "file")) {
+      sb.add("//");
+      _addIfNonEmpty(sb, userInfo, userInfo, "@");
+      sb.add(domain == null ? "null" : domain);
+      if (port != 0) {
+        sb.add(":");
+        sb.add(port.toString());
+      }
+    }
+    sb.add(path == null ? "null" : path);
+    _addIfNonEmpty(sb, query, "?", query);
+    _addIfNonEmpty(sb, fragment, "#", fragment);
+    return sb.toString();
+  }
+
+  bool operator==(other) {
+    if (other is! Uri) return false;
+    Uri uri = other;
+    return scheme == uri.scheme &&
+        userInfo == uri.userInfo &&
+        domain == uri.domain &&
+        port == uri.port &&
+        path == uri.path &&
+        query == uri.query &&
+        fragment == uri.fragment;
+  }
+
+  int get hashCode {
+    int combine(part, current) {
+      // The sum is truncated to 30 bits to make sure it fits into a Smi.
+      return (current * 31 + part.hashCode) & 0x3FFFFFFF;
+    }
+    return combine(scheme, combine(userInfo, combine(domain, combine(port,
+        combine(path, combine(query, combine(fragment, 1)))))));
+  }
+
+  static void _addIfNonEmpty(StringBuffer sb, String test,
+                             String first, String second) {
+    if ("" != test) {
+      sb.add(first == null ? "null" : first);
+      sb.add(second == null ? "null" : second);
+    }
+  }
+}
diff --git a/runtime/bin/uri_sources.gypi b/sdk/lib/uri/uri_sources.gypi
similarity index 71%
rename from runtime/bin/uri_sources.gypi
rename to sdk/lib/uri/uri_sources.gypi
index 36a9e3c..87e234a 100644
--- a/runtime/bin/uri_sources.gypi
+++ b/sdk/lib/uri/uri_sources.gypi
@@ -5,8 +5,8 @@
 # This file contains all sources for the dart:uri library.
 {
   'sources': [
-    '../../sdk/lib/uri/uri.dart',
-    '../../sdk/lib/uri/helpers.dart',
-    '../../sdk/lib/uri/encode_decode.dart',
+    'uri_base.dart',
+    'helpers.dart',
+    'encode_decode.dart',
   ],
 }
diff --git a/sdk/lib/utf/utf.dart b/sdk/lib/utf/utf.dart
index cc3c573..abc3f84 100644
--- a/sdk/lib/utf/utf.dart
+++ b/sdk/lib/utf/utf.dart
@@ -3,7 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 library dart.utf;
+import "dart:async";
 part "utf_core.dart";
+part "utf_stream.dart";
 part "utf8.dart";
 part "utf16.dart";
 part "utf32.dart";
diff --git a/sdk/lib/utf/utf_sources.gypi b/sdk/lib/utf/utf_sources.gypi
new file mode 100644
index 0000000..9d86ff1
--- /dev/null
+++ b/sdk/lib/utf/utf_sources.gypi
@@ -0,0 +1,17 @@
+# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This file contains all sources for the dart:utf library.
+#
+# TODO(ager): When the VM can use the #source directive for libraries.
+# At that point utf.dart should be the only utf library file.
+{
+  'sources': [
+    'utf_core.dart',
+    'utf_stream.dart',
+    'utf8.dart',
+    'utf16.dart',
+    'utf32.dart',
+  ],
+}
diff --git a/sdk/lib/utf/utf_stream.dart b/sdk/lib/utf/utf_stream.dart
new file mode 100644
index 0000000..ad69c62
--- /dev/null
+++ b/sdk/lib/utf/utf_stream.dart
@@ -0,0 +1,224 @@
+// 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.utf;
+
+class _HelperStreamController<T> extends StreamController<T> {
+  final Function onPauseChanged;
+
+  _HelperStreamController(this.onPauseChanged);
+
+  void onPauseStateChange() {
+    onPauseChanged();
+  }
+}
+
+abstract class _StringDecoder implements StreamTransformer<List<int>, String> {
+  _HelperStreamController<String> _controller;
+  StreamSubscription<List<int>> _subscription;
+  List<int> _carry;
+  List<int> _buffer;
+  int _replacementChar;
+  bool _paused = false;
+
+  _StringDecoder(int this._replacementChar) {
+    _controller = new _HelperStreamController<String>(_onPauseChanged);
+  }
+
+  void _onPauseChanged() {
+    _paused = _controller.isPaused;
+    if (_subscription == null) return;
+    if (_paused) {
+      _subscription.pause();
+    } else {
+      _subscription.resume();
+    }
+  }
+
+  Stream<String> bind(Stream<List<int>> stream) {
+    _subscription = stream.listen(
+        _onData,
+        onError: _controller.signalError,
+        onDone: () {
+          if (_carry != null) {
+            _controller.add(new String.fromCharCodes(
+                new List.fixedLength(_carry.length, fill: _replacementChar)));
+          }
+          _controller.close();
+        },
+        unsubscribeOnError: false);
+    if (_paused) _subscription.pause();
+    return _controller.stream;
+  }
+
+  void _onData(List<int> bytes) {
+    _buffer = <int>[];
+    List<int> carry = _carry;
+    _carry = null;
+    int pos = 0;
+    int available = bytes.length;
+    // If we have carry-over data, start from negative index, indicating carry
+    // index.
+    int goodChars = 0;
+    if (carry != null) pos = -carry.length;
+    while (pos < available) {
+      int currentPos = pos;
+      int getNext() {
+        if (pos < 0) {
+          return carry[pos++ + carry.length];
+        } else if (pos < available) {
+          return bytes[pos++];
+        }
+        return null;
+      }
+      int consumed = _processBytes(getNext);
+      if (consumed > 0) {
+        goodChars = _buffer.length;
+      } else if (consumed == 0) {
+        _buffer.length = goodChars;
+        if (currentPos < 0) {
+          _carry = [];
+          _carry.addAll(carry);
+          _carry.addAll(bytes);
+        } else {
+          _carry = bytes.getRange(currentPos, bytes.length - currentPos);
+        }
+        break;
+      } else {
+        // Invalid byte at position pos - 1
+        _buffer.length = goodChars;
+        _addChar(-1);
+        goodChars = _buffer.length;
+      }
+    }
+    if (_buffer.length > 0) {
+      // Limit to 'goodChars', if lower than actual charCodes in the buffer.
+      _controller.add(new String.fromCharCodes(_buffer));
+    }
+    _buffer = null;
+  }
+
+  int _processBytes(int getNext());
+
+  void _addChar(int char) {
+    if (char > 0x10FFFF || char < 0) char = _replacementChar;
+    _buffer.add(char);
+  }
+}
+
+/**
+ * StringTransformer that decodes a stream of UTF-8 encoded bytes.
+ */
+class Utf8DecoderTransformer extends _StringDecoder {
+  Utf8DecoderTransformer(
+      [int replacementChar = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT])
+    : super(replacementChar);
+
+  int _processBytes(int getNext()) {
+    int value = getNext();
+    if ((value & 0xFF) != value) return -1;  // Not a byte.
+    if ((value & 0x80) == 0x80) {
+      int additionalBytes;
+      int min;
+      if ((value & 0xe0) == 0xc0) {  // 110xxxxx
+        value = value & 0x1F;
+        additionalBytes = 1;
+        min = 0x80;
+      } else if ((value & 0xf0) == 0xe0) {  // 1110xxxx
+        value = value & 0x0F;
+        additionalBytes = 2;
+        min = 0x800;
+      } else if ((value & 0xf8) == 0xf0) {  // 11110xxx
+        value = value & 0x07;
+        additionalBytes = 3;
+        min = 0x10000;
+      } else if ((value & 0xfc) == 0xf8) {  // 111110xx
+        value = value & 0x03;
+        additionalBytes = 4;
+        min = 0x200000;
+      } else if ((value & 0xfe) == 0xfc) {  // 1111110x
+        value = value & 0x01;
+        additionalBytes = 5;
+        min = 0x4000000;
+      } else {
+        return -1;
+      }
+      for (int i = 0; i < additionalBytes; i++) {
+        int next = getNext();
+        if (next == null) return 0;  // Not enough chars, reset.
+        if ((next & 0xc0) != 0x80 || (next & 0xff) != next) return -1;
+        value = value << 6 | (next & 0x3f);
+      }
+      // Invalid charCode if less then minimum expected.
+      if (value < min) value = -1;
+      _addChar(value);
+      return 1 + additionalBytes;
+    }
+    _addChar(value);
+    return 1;
+  }
+}
+
+
+abstract class _StringEncoder implements StreamTransformer<String, List<int>> {
+  _HelperStreamController<List<int>> _controller;
+  StreamSubscription<String> _subscription;
+
+  void _onPauseChanged() {
+    if (_controller.isPaused) {
+      _subscription.pause();
+    } else {
+      _subscription.resume();
+    }
+  }
+  Stream<List<int>> bind(Stream<String> stream) {
+    _controller = new _HelperStreamController(_onPauseChanged);
+    _subscription = stream.listen(
+        (string) => _controller.add(_processString(string)),
+        onError: _controller.signalError,
+        onDone: _controller.close,
+        unsubscribeOnError: false);
+    return _controller.stream;
+  }
+
+  List<int> _processString(String string);
+}
+
+/**
+ * StringTransformer that UTF-8 encodes a stream of strings.
+ */
+class Utf8EncoderTransformer extends _StringEncoder {
+  List<int> _processString(String string) {
+    var bytes = [];
+    int pos = 0;
+    List<int> codepoints = _utf16CodeUnitsToCodepoints(string.charCodes);
+    int length = codepoints.length;
+    for (int i = 0; i < length; i++) {
+      int additionalBytes;
+      int charCode = codepoints[i];
+      if (charCode <= 0x007F) {
+        additionalBytes = 0;
+        bytes.add(charCode);
+      } else if (charCode <= 0x07FF) {
+        // 110xxxxx (xxxxx is top 5 bits).
+        bytes.add(((charCode >> 6) & 0x1F) | 0xC0);
+        additionalBytes = 1;
+      } else if (charCode <= 0xFFFF) {
+        // 1110xxxx (xxxx is top 4 bits)
+        bytes.add(((charCode >> 12) & 0x0F)| 0xE0);
+        additionalBytes = 2;
+      } else {
+        // 11110xxx (xxx is top 3 bits)
+        bytes.add(((charCode >> 18) & 0x07) | 0xF0);
+        additionalBytes = 3;
+      }
+      for (int i = additionalBytes; i > 0; i--) {
+        // 10xxxxxx (xxxxxx is next 6 bits from the top).
+        bytes.add(((charCode >> (6 * (i - 1))) & 0x3F) | 0x80);
+      }
+      pos += additionalBytes + 1;
+    }
+    return bytes;
+  }
+}
diff --git a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
index 6680a44..7bc07f1 100644
--- a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
+++ b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
@@ -5,7 +5,8 @@
 import 'dart:html';
 import 'dart:html_common';
 import 'dart:_foreign_helper' show JS;
-// DO NOT EDIT
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:audio library.
 
 
diff --git a/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart b/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart
new file mode 100644
index 0000000..8559913
--- /dev/null
+++ b/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart
@@ -0,0 +1,450 @@
+library dart.dom.web_sql;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_js_helper' show convertDartClosureToJS, Creates, JavaScriptIndexingBehavior, JSName;
+import 'dart:_foreign_helper' show JS;
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:audio library.
+
+
+
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void DatabaseCallback(database);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void SqlStatementCallback(SqlTransaction transaction, SqlResultSet resultSet);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void SqlStatementErrorCallback(SqlTransaction transaction, SqlError error);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void SqlTransactionCallback(SqlTransaction transaction);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void SqlTransactionErrorCallback(SqlError error);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void SqlTransactionSyncCallback(SqlTransactionSync transaction);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
+@DomName('Database')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class SqlDatabase native "*Database" {
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => JS('bool', '!!(window.openDatabase)');
+
+  @DomName('Database.version')
+  @DocsEditable
+  final String version;
+
+  @DomName('Database.changeVersion')
+  @DocsEditable
+  void changeVersion(String oldVersion, String newVersion, [SqlTransactionCallback callback, SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native;
+
+  @DomName('Database.readTransaction')
+  @DocsEditable
+  void readTransaction(SqlTransactionCallback callback, [SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native;
+
+  @DomName('Database.transaction')
+  @DocsEditable
+  void transaction(SqlTransactionCallback callback, [SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
+@DomName('DatabaseSync')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class SqlDatabaseSync native "*DatabaseSync" {
+
+  @DomName('DatabaseSync.lastErrorMessage')
+  @DocsEditable
+  final String lastErrorMessage;
+
+  @DomName('DatabaseSync.version')
+  @DocsEditable
+  final String version;
+
+  @DomName('DatabaseSync.changeVersion')
+  @DocsEditable
+  void changeVersion(String oldVersion, String newVersion, [SqlTransactionSyncCallback callback]) native;
+
+  @DomName('DatabaseSync.readTransaction')
+  @DocsEditable
+  void readTransaction(SqlTransactionSyncCallback callback) native;
+
+  @DomName('DatabaseSync.transaction')
+  @DocsEditable
+  void transaction(SqlTransactionSyncCallback callback) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
+@DomName('SQLError')
+class SqlError native "*SQLError" {
+
+  static const int CONSTRAINT_ERR = 6;
+
+  static const int DATABASE_ERR = 1;
+
+  static const int QUOTA_ERR = 4;
+
+  static const int SYNTAX_ERR = 5;
+
+  static const int TIMEOUT_ERR = 7;
+
+  static const int TOO_LARGE_ERR = 3;
+
+  static const int UNKNOWN_ERR = 0;
+
+  static const int VERSION_ERR = 2;
+
+  @DomName('SQLError.code')
+  @DocsEditable
+  final int code;
+
+  @DomName('SQLError.message')
+  @DocsEditable
+  final String message;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
+@DomName('SQLException')
+class SqlException native "*SQLException" {
+
+  static const int CONSTRAINT_ERR = 6;
+
+  static const int DATABASE_ERR = 1;
+
+  static const int QUOTA_ERR = 4;
+
+  static const int SYNTAX_ERR = 5;
+
+  static const int TIMEOUT_ERR = 7;
+
+  static const int TOO_LARGE_ERR = 3;
+
+  static const int UNKNOWN_ERR = 0;
+
+  static const int VERSION_ERR = 2;
+
+  @DomName('SQLException.code')
+  @DocsEditable
+  final int code;
+
+  @DomName('SQLException.message')
+  @DocsEditable
+  final String message;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
+@DomName('SQLResultSet')
+class SqlResultSet native "*SQLResultSet" {
+
+  @DomName('SQLResultSet.insertId')
+  @DocsEditable
+  final int insertId;
+
+  @DomName('SQLResultSet.rows')
+  @DocsEditable
+  final SqlResultSetRowList rows;
+
+  @DomName('SQLResultSet.rowsAffected')
+  @DocsEditable
+  final int rowsAffected;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
+@DomName('SQLResultSetRowList')
+class SqlResultSetRowList implements JavaScriptIndexingBehavior, List<Map> native "*SQLResultSetRowList" {
+
+  @DomName('SQLResultSetRowList.length')
+  @DocsEditable
+  int get length => JS("int", "#.length", this);
+
+  Map operator[](int index) => JS("Map", "#[#]", this, index);
+
+  void operator[]=(int index, Map value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Map> mixins.
+  // Map is the element type.
+
+  // From Iterable<Map>:
+
+  Iterator<Map> get iterator {
+    // Note: NodeLists are not fixed size. And most probably length shouldn't
+    // be cached in both iterator _and_ forEach method. For now caching it
+    // for consistency.
+    return new FixedSizeListIterator<Map>(this);
+  }
+
+  dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Map)) {
+    return IterableMixinWorkaround.reduce(this, initialValue, combine);
+  }
+
+  bool contains(Map element) => IterableMixinWorkaround.contains(this, element);
+
+  void forEach(void f(Map element)) => IterableMixinWorkaround.forEach(this, f);
+
+  String join([String separator]) =>
+      IterableMixinWorkaround.joinList(this, separator);
+
+  Iterable map(f(Map element)) =>
+      IterableMixinWorkaround.mapList(this, f);
+
+  Iterable<Map> where(bool f(Map element)) =>
+      IterableMixinWorkaround.where(this, f);
+
+  Iterable expand(Iterable f(Map element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
+  bool every(bool f(Map element)) => IterableMixinWorkaround.every(this, f);
+
+  bool any(bool f(Map element)) => IterableMixinWorkaround.any(this, f);
+
+  List<Map> toList() => new List<Map>.from(this);
+  Set<Map> toSet() => new Set<Map>.from(this);
+
+  bool get isEmpty => this.length == 0;
+
+  Iterable<Map> take(int n) => IterableMixinWorkaround.takeList(this, n);
+
+  Iterable<Map> takeWhile(bool test(Map value)) {
+    return IterableMixinWorkaround.takeWhile(this, test);
+  }
+
+  Iterable<Map> skip(int n) => IterableMixinWorkaround.skipList(this, n);
+
+  Iterable<Map> skipWhile(bool test(Map value)) {
+    return IterableMixinWorkaround.skipWhile(this, test);
+  }
+
+  Map firstMatching(bool test(Map value), { Map orElse() }) {
+    return IterableMixinWorkaround.firstMatching(this, test, orElse);
+  }
+
+  Map lastMatching(bool test(Map value), {Map orElse()}) {
+    return IterableMixinWorkaround.lastMatchingInList(this, test, orElse);
+  }
+
+  Map singleMatching(bool test(Map value)) {
+    return IterableMixinWorkaround.singleMatching(this, test);
+  }
+
+  Map elementAt(int index) {
+    return this[index];
+  }
+
+  // From Collection<Map>:
+
+  void add(Map value) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void addLast(Map value) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void addAll(Iterable<Map> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  // From List<Map>:
+  void set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  void clear() {
+    throw new UnsupportedError("Cannot clear immutable List.");
+  }
+
+  Iterable<Map> get reversed {
+    return IterableMixinWorkaround.reversedList(this);
+  }
+
+  void sort([int compare(Map a, Map b)]) {
+    throw new UnsupportedError("Cannot sort immutable List.");
+  }
+
+  int indexOf(Map element, [int start = 0]) =>
+      Lists.indexOf(this, element, start, this.length);
+
+  int lastIndexOf(Map element, [int start]) {
+    if (start == null) start = length - 1;
+    return Lists.lastIndexOf(this, element, start);
+  }
+
+  Map get first {
+    if (this.length > 0) return this[0];
+    throw new StateError("No elements");
+  }
+
+  Map get last {
+    if (this.length > 0) return this[this.length - 1];
+    throw new StateError("No elements");
+  }
+
+  Map get single {
+    if (length == 1) return this[0];
+    if (length == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Map min([int compare(Map a, Map b)]) =>
+      IterableMixinWorkaround.min(this, compare);
+
+  Map max([int compare(Map a, Map b)]) =>
+      IterableMixinWorkaround.max(this, compare);
+
+  Map removeAt(int pos) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  Map removeLast() {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void remove(Object object) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void removeAll(Iterable elements) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void retainAll(Iterable elements) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void removeMatching(bool test(Map element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void retainMatching(bool test(Map element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void setRange(int start, int rangeLength, List<Map> from, [int startFrom]) {
+    throw new UnsupportedError("Cannot setRange on immutable List.");
+  }
+
+  void removeRange(int start, int rangeLength) {
+    throw new UnsupportedError("Cannot removeRange on immutable List.");
+  }
+
+  void insertRange(int start, int rangeLength, [Map initialValue]) {
+    throw new UnsupportedError("Cannot insertRange on immutable List.");
+  }
+
+  List<Map> getRange(int start, int rangeLength) =>
+      Lists.getRange(this, start, rangeLength, <Map>[]);
+
+  // -- end List<Map> mixins.
+
+  @DomName('SQLResultSetRowList.item')
+  @DocsEditable
+  @Creates('=Object')
+  Map item(int index) {
+    return convertNativeToDart_Dictionary(_item_1(index));
+  }
+  @JSName('item')
+  @DomName('SQLResultSetRowList.item')
+  @DocsEditable
+  @Creates('=Object')
+  _item_1(index) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
+@DomName('SQLTransaction')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class SqlTransaction native "*SQLTransaction" {
+
+  @DomName('SQLTransaction.executeSql')
+  @DocsEditable
+  void executeSql(String sqlStatement, List arguments, [SqlStatementCallback callback, SqlStatementErrorCallback errorCallback]) native;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
+@DomName('SQLTransactionSync')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class SqlTransactionSync native "*SQLTransactionSync" {
+
+  @DomName('SQLTransactionSync.executeSql')
+  @DocsEditable
+  SqlResultSet executeSql(String sqlStatement, List arguments) native;
+}
diff --git a/sdk/lib/web_sql/dartium/web_sql_dartium.dart b/sdk/lib/web_sql/dartium/web_sql_dartium.dart
new file mode 100644
index 0000000..c25f0ae
--- /dev/null
+++ b/sdk/lib/web_sql/dartium/web_sql_dartium.dart
@@ -0,0 +1,473 @@
+library dart.dom.web_sql;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:nativewrappers';
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:audio library.
+
+
+
+
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void DatabaseCallback(database);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void SqlStatementCallback(SqlTransaction transaction, SqlResultSet resultSet);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void SqlStatementErrorCallback(SqlTransaction transaction, SqlError error);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void SqlTransactionCallback(SqlTransaction transaction);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void SqlTransactionErrorCallback(SqlError error);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+typedef void SqlTransactionSyncCallback(SqlTransactionSync transaction);
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
+@DomName('Database')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class SqlDatabase extends NativeFieldWrapperClass1 {
+  SqlDatabase.internal();
+
+  /// Checks if this type is supported on the current platform.
+  static bool get supported => true;
+
+  @DomName('Database.version')
+  @DocsEditable
+  String get version native "Database_version_Getter";
+
+  @DomName('Database.changeVersion')
+  @DocsEditable
+  void changeVersion(String oldVersion, String newVersion, [SqlTransactionCallback callback, SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native "Database_changeVersion_Callback";
+
+  @DomName('Database.readTransaction')
+  @DocsEditable
+  void readTransaction(SqlTransactionCallback callback, [SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native "Database_readTransaction_Callback";
+
+  @DomName('Database.transaction')
+  @DocsEditable
+  void transaction(SqlTransactionCallback callback, [SqlTransactionErrorCallback errorCallback, VoidCallback successCallback]) native "Database_transaction_Callback";
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
+@DomName('DatabaseSync')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class SqlDatabaseSync extends NativeFieldWrapperClass1 {
+  SqlDatabaseSync.internal();
+
+  @DomName('DatabaseSync.lastErrorMessage')
+  @DocsEditable
+  String get lastErrorMessage native "DatabaseSync_lastErrorMessage_Getter";
+
+  @DomName('DatabaseSync.version')
+  @DocsEditable
+  String get version native "DatabaseSync_version_Getter";
+
+  @DomName('DatabaseSync.changeVersion')
+  @DocsEditable
+  void changeVersion(String oldVersion, String newVersion, [SqlTransactionSyncCallback callback]) native "DatabaseSync_changeVersion_Callback";
+
+  @DomName('DatabaseSync.readTransaction')
+  @DocsEditable
+  void readTransaction(SqlTransactionSyncCallback callback) native "DatabaseSync_readTransaction_Callback";
+
+  @DomName('DatabaseSync.transaction')
+  @DocsEditable
+  void transaction(SqlTransactionSyncCallback callback) native "DatabaseSync_transaction_Callback";
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
+@DomName('SQLError')
+class SqlError extends NativeFieldWrapperClass1 {
+  SqlError.internal();
+
+  static const int CONSTRAINT_ERR = 6;
+
+  static const int DATABASE_ERR = 1;
+
+  static const int QUOTA_ERR = 4;
+
+  static const int SYNTAX_ERR = 5;
+
+  static const int TIMEOUT_ERR = 7;
+
+  static const int TOO_LARGE_ERR = 3;
+
+  static const int UNKNOWN_ERR = 0;
+
+  static const int VERSION_ERR = 2;
+
+  @DomName('SQLError.code')
+  @DocsEditable
+  int get code native "SQLError_code_Getter";
+
+  @DomName('SQLError.message')
+  @DocsEditable
+  String get message native "SQLError_message_Getter";
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
+@DomName('SQLException')
+class SqlException extends NativeFieldWrapperClass1 {
+  SqlException.internal();
+
+  static const int CONSTRAINT_ERR = 6;
+
+  static const int DATABASE_ERR = 1;
+
+  static const int QUOTA_ERR = 4;
+
+  static const int SYNTAX_ERR = 5;
+
+  static const int TIMEOUT_ERR = 7;
+
+  static const int TOO_LARGE_ERR = 3;
+
+  static const int UNKNOWN_ERR = 0;
+
+  static const int VERSION_ERR = 2;
+
+  @DomName('SQLException.code')
+  @DocsEditable
+  int get code native "SQLException_code_Getter";
+
+  @DomName('SQLException.message')
+  @DocsEditable
+  String get message native "SQLException_message_Getter";
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
+@DomName('SQLResultSet')
+class SqlResultSet extends NativeFieldWrapperClass1 {
+  SqlResultSet.internal();
+
+  @DomName('SQLResultSet.insertId')
+  @DocsEditable
+  int get insertId native "SQLResultSet_insertId_Getter";
+
+  @DomName('SQLResultSet.rows')
+  @DocsEditable
+  SqlResultSetRowList get rows native "SQLResultSet_rows_Getter";
+
+  @DomName('SQLResultSet.rowsAffected')
+  @DocsEditable
+  int get rowsAffected native "SQLResultSet_rowsAffected_Getter";
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
+@DomName('SQLResultSetRowList')
+class SqlResultSetRowList extends NativeFieldWrapperClass1 implements List<Map> {
+  SqlResultSetRowList.internal();
+
+  @DomName('SQLResultSetRowList.length')
+  @DocsEditable
+  int get length native "SQLResultSetRowList_length_Getter";
+
+  Map operator[](int index) native "SQLResultSetRowList_item_Callback";
+
+  void operator[]=(int index, Map value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Map> mixins.
+  // Map is the element type.
+
+  // From Iterable<Map>:
+
+  Iterator<Map> get iterator {
+    // Note: NodeLists are not fixed size. And most probably length shouldn't
+    // be cached in both iterator _and_ forEach method. For now caching it
+    // for consistency.
+    return new FixedSizeListIterator<Map>(this);
+  }
+
+  dynamic reduce(dynamic initialValue, dynamic combine(dynamic, Map)) {
+    return IterableMixinWorkaround.reduce(this, initialValue, combine);
+  }
+
+  bool contains(Map element) => IterableMixinWorkaround.contains(this, element);
+
+  void forEach(void f(Map element)) => IterableMixinWorkaround.forEach(this, f);
+
+  String join([String separator]) =>
+      IterableMixinWorkaround.joinList(this, separator);
+
+  Iterable map(f(Map element)) =>
+      IterableMixinWorkaround.mapList(this, f);
+
+  Iterable<Map> where(bool f(Map element)) =>
+      IterableMixinWorkaround.where(this, f);
+
+  Iterable expand(Iterable f(Map element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
+  bool every(bool f(Map element)) => IterableMixinWorkaround.every(this, f);
+
+  bool any(bool f(Map element)) => IterableMixinWorkaround.any(this, f);
+
+  List<Map> toList() => new List<Map>.from(this);
+  Set<Map> toSet() => new Set<Map>.from(this);
+
+  bool get isEmpty => this.length == 0;
+
+  Iterable<Map> take(int n) => IterableMixinWorkaround.takeList(this, n);
+
+  Iterable<Map> takeWhile(bool test(Map value)) {
+    return IterableMixinWorkaround.takeWhile(this, test);
+  }
+
+  Iterable<Map> skip(int n) => IterableMixinWorkaround.skipList(this, n);
+
+  Iterable<Map> skipWhile(bool test(Map value)) {
+    return IterableMixinWorkaround.skipWhile(this, test);
+  }
+
+  Map firstMatching(bool test(Map value), { Map orElse() }) {
+    return IterableMixinWorkaround.firstMatching(this, test, orElse);
+  }
+
+  Map lastMatching(bool test(Map value), {Map orElse()}) {
+    return IterableMixinWorkaround.lastMatchingInList(this, test, orElse);
+  }
+
+  Map singleMatching(bool test(Map value)) {
+    return IterableMixinWorkaround.singleMatching(this, test);
+  }
+
+  Map elementAt(int index) {
+    return this[index];
+  }
+
+  // From Collection<Map>:
+
+  void add(Map value) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void addLast(Map value) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void addAll(Iterable<Map> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  // From List<Map>:
+  void set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  void clear() {
+    throw new UnsupportedError("Cannot clear immutable List.");
+  }
+
+  Iterable<Map> get reversed {
+    return IterableMixinWorkaround.reversedList(this);
+  }
+
+  void sort([int compare(Map a, Map b)]) {
+    throw new UnsupportedError("Cannot sort immutable List.");
+  }
+
+  int indexOf(Map element, [int start = 0]) =>
+      Lists.indexOf(this, element, start, this.length);
+
+  int lastIndexOf(Map element, [int start]) {
+    if (start == null) start = length - 1;
+    return Lists.lastIndexOf(this, element, start);
+  }
+
+  Map get first {
+    if (this.length > 0) return this[0];
+    throw new StateError("No elements");
+  }
+
+  Map get last {
+    if (this.length > 0) return this[this.length - 1];
+    throw new StateError("No elements");
+  }
+
+  Map get single {
+    if (length == 1) return this[0];
+    if (length == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  Map min([int compare(Map a, Map b)]) =>
+      IterableMixinWorkaround.min(this, compare);
+
+  Map max([int compare(Map a, Map b)]) =>
+      IterableMixinWorkaround.max(this, compare);
+
+  Map removeAt(int pos) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  Map removeLast() {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void remove(Object object) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void removeAll(Iterable elements) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void retainAll(Iterable elements) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void removeMatching(bool test(Map element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void retainMatching(bool test(Map element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void setRange(int start, int rangeLength, List<Map> from, [int startFrom]) {
+    throw new UnsupportedError("Cannot setRange on immutable List.");
+  }
+
+  void removeRange(int start, int rangeLength) {
+    throw new UnsupportedError("Cannot removeRange on immutable List.");
+  }
+
+  void insertRange(int start, int rangeLength, [Map initialValue]) {
+    throw new UnsupportedError("Cannot insertRange on immutable List.");
+  }
+
+  List<Map> getRange(int start, int rangeLength) =>
+      Lists.getRange(this, start, rangeLength, <Map>[]);
+
+  // -- end List<Map> mixins.
+
+  @DomName('SQLResultSetRowList.item')
+  @DocsEditable
+  Map item(int index) native "SQLResultSetRowList_item_Callback";
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
+@DomName('SQLTransaction')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class SqlTransaction extends NativeFieldWrapperClass1 {
+  SqlTransaction.internal();
+
+  @DomName('SQLTransaction.executeSql')
+  @DocsEditable
+  void executeSql(String sqlStatement, List arguments, [SqlStatementCallback callback, SqlStatementErrorCallback errorCallback]) native "SQLTransaction_executeSql_Callback";
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
+@DomName('SQLTransactionSync')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class SqlTransactionSync extends NativeFieldWrapperClass1 {
+  SqlTransactionSync.internal();
+
+  @DomName('SQLTransactionSync.executeSql')
+  @DocsEditable
+  SqlResultSet executeSql(String sqlStatement, List arguments) native "SQLTransactionSync_executeSql_Callback";
+
+}
diff --git a/tests/co19/co19-compiler.status b/tests/co19/co19-compiler.status
index 423a814..60c8924 100644
--- a/tests/co19/co19-compiler.status
+++ b/tests/co19/co19-compiler.status
@@ -490,6 +490,7 @@
 LibTest/core/Queue/removeLast_A02_t01: Fail # Moved collection classes from core to collection. co19 issue 371.
 LibTest/core/Set/Set.from_A01_t01: Fail # Moved collection classes from core to collection. co19 issue 371.
 
+LibTest/core/Date/compareTo_A03_t01: Fail # Comparable<T>.compareTo now statically accepts type T arguments.
 
 LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A03_t01: Fail # Strings class has been removed. co19 issue 380
 LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A04_t01: Fail # Strings class has been removed. co19 issue 380
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 8d256ea..659bf48 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -1,4 +1,4 @@
-# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# 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.
 
@@ -58,8 +58,6 @@
 Language/05_Variables/05_Variables_A01_t14: Fail # http://dartbug.com/5519
 Language/05_Variables/05_Variables_A01_t15: Fail # http://dartbug.com/5519
 Language/05_Variables/05_Variables_A04_t01: Fail # http://dartbug.com/5519
-Language/05_Variables/05_Variables_A05_t01: Fail # http://dartbug.com/5519
-Language/05_Variables/05_Variables_A05_t02: Fail # http://dartbug.com/5519
 Language/05_Variables/05_Variables_A05_t04: Fail # Inherited from dart2js
 Language/05_Variables/05_Variables_A05_t05: Fail # Inherited from dart2js
 Language/05_Variables/05_Variables_A05_t06: Fail # Inherited from dart2js
@@ -67,7 +65,6 @@
 Language/05_Variables/05_Variables_A05_t08: Fail # Inherited from dart2js
 Language/05_Variables/05_Variables_A05_t09: Fail # Inherited from dart2js
 Language/05_Variables/05_Variables_A05_t10: Fail # Inherited from dart2js
-Language/05_Variables/05_Variables_A05_t11: Fail # Inherited from VM (assignment to final variable does not throw NSME).
 Language/05_Variables/05_Variables_A05_t13: Fail # Inherited from VM (assignment to final variable does not throw NSME).
 Language/05_Variables/05_Variables_A05_t14: Fail # Inherited from VM (assignment to final variable does not throw NSME).
 Language/05_Variables/05_Variables_A05_t15: Fail # Inherited from VM (assignment to final variable does not throw NSME).
@@ -144,7 +141,6 @@
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: Fail # http://dartbug.com/5519
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A15_t07: Fail # inherited from VM
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A16_t07: Fail # http://dartbug.com/6242
-Language/07_Classes/6_Constructors/1_Generative_Constructors_A21_t01: Fail # http://dartbug.com/5519
 Language/07_Classes/6_Constructors/2_Factories_A01_t05: Fail # Inherited from dartjs
 Language/07_Classes/6_Constructors/2_Factories_A07_t01: Fail # inherited from VM
 Language/07_Classes/6_Constructors/3_Constant_Constructors_A03_t01: Fail # http://dartbug.com/5519
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 41e3a33..e311447 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -7,7 +7,6 @@
 [ $compiler == dart2js ]
 Language/03_Overview/1_Scoping_A02_t05: Fail # TODO(ahe): Please triage this failure.
 Language/03_Overview/1_Scoping_A02_t06: Fail # TODO(ahe): Please triage this failure.
-Language/05_Variables/05_Variables_A05_t02: Fail # TODO(ahe): Please triage this failure.
 Language/05_Variables/05_Variables_A05_t04: Fail # TODO(ahe): Please triage this failure.
 Language/05_Variables/05_Variables_A05_t05: Fail # TODO(ahe): Please triage this failure.
 Language/05_Variables/05_Variables_A05_t06: Fail # TODO(ahe): Please triage this failure.
@@ -15,10 +14,6 @@
 Language/05_Variables/05_Variables_A05_t08: Fail # TODO(ahe): Please triage this failure.
 Language/05_Variables/05_Variables_A05_t09: Fail # TODO(ahe): Please triage this failure.
 Language/05_Variables/05_Variables_A05_t10: Fail # TODO(ahe): Please triage this failure.
-Language/05_Variables/05_Variables_A05_t11: Fail # TODO(ahe): Please triage this failure.
-Language/05_Variables/05_Variables_A05_t13: Fail # TODO(ahe): Please triage this failure.
-Language/05_Variables/05_Variables_A05_t14: Fail # TODO(ahe): Please triage this failure.
-Language/05_Variables/05_Variables_A05_t15: Fail # TODO(ahe): Please triage this failure.
 Language/05_Variables/05_Variables_A07_t01: Fail # TODO(ahe): Please triage this failure.
 Language/05_Variables/05_Variables_A07_t02: Fail # TODO(ahe): Please triage this failure.
 Language/05_Variables/05_Variables_A07_t03: Fail # TODO(ahe): Please triage this failure.
@@ -115,9 +110,6 @@
 Language/12_Statements/09_Switch_A03_t02: Fail # TODO(ahe): Please triage this failure.
 Language/12_Statements/09_Switch_A04_t01: Fail # TODO(ahe): Please triage this failure.
 Language/12_Statements/09_Switch_A06_t02: Fail # TODO(ahe): Please triage this failure.
-Language/12_Statements/10_Try_A03_t01: Fail # TODO(ahe): Please triage this failure.
-Language/12_Statements/10_Try_A03_t02: Fail # TODO(ahe): Please triage this failure.
-Language/12_Statements/10_Try_A03_t03: Fail # TODO(ahe): Please triage this failure.
 Language/12_Statements/10_Try_A06_t01: Fail # TODO(ahe): Please triage this failure.
 Language/12_Statements/10_Try_A07_t03: Fail # TODO(ahe): Please triage this failure.
 Language/12_Statements/11_Return_A05_t01: Fail # TODO(ahe): Please triage this failure.
@@ -180,10 +172,6 @@
 
 [ $compiler == dart2js && $runtime == jsshell ]
 LibTest/core/Map/Map_class_A01_t04: Pass, Slow # Issue 8096
-Language/05_Variables/05_Variables_A13_t02: Fail # TODO(ngeoaffray): Please triage these failure.
-Language/06_Functions/3_Type_of_a_Function_A01_t01: Fail # TODO(ngeoaffray): Please triage these failure.
-Language/11_Expressions/05_Strings/1_String_Interpolation_A03_t02: Fail # TODO(ngeoaffray): Please triage these failure.
-Language/11_Expressions/05_Strings/1_String_Interpolation_A04_t02: Fail # TODO(ngeoaffray): Please triage these failure.
 Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A03_t01: Fail # TODO(ngeoaffray): Please triage these failure.
 Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: Fail # TODO(ngeoaffray): Please triage these failure.
 LibTest/core/double/round_A01_t01: Fail # TODO(ngeoaffray): Please triage these failure.
@@ -575,6 +563,10 @@
 
 LibTest/core/Date/operator_equality_A01_t01: Fail # DateTime.== now looks at timezone, co19 issue 379.
 
+Language/12_Statements/10_Try_A03_t01: Fail # co19 issue 381
+Language/12_Statements/10_Try_A03_t02: Fail # co19 issue 381
+Language/12_Statements/10_Try_A03_t03: Fail # co19 issue 381
+
 LibTest/core/Strings/join_A01_t01: Fail # Strings class has been removed. co19 issue 380
 LibTest/core/Strings/join_A04_t01: Fail # Strings class has been removed. co19 issue 380
 LibTest/core/Strings/concatAll_A01_t01: Fail # Strings class has been removed. co19 issue 380
@@ -627,6 +619,11 @@
 LibTest/math/atan_A01_t01: Fail, OK # co19 issue 44
 
 
+[ $compiler == dart2js && $host_checked ]
+Language/14_Types/4_Interface_Types_A11_t01: Crash # Issue 8557
+Language/14_Types/4_Interface_Types_A11_t02: Crash # Issue 8557
+
+
 #
 # The following tests are failing. Please add the error message
 # (either a compiler error or exception message). The error messages
@@ -677,7 +674,6 @@
 Language/05_Variables/05_Variables_A01_t14: Fail # Checks that variable declaration cannot contain 'const', 'final' and 'var' simultaneously.
 Language/05_Variables/05_Variables_A01_t15: Fail # Checks that a variable declaration cannot contain the 'abstract' keyword.
 Language/05_Variables/05_Variables_A04_t01: Fail # Checks that a compile-time error occurs if a local constant variable is redefined.
-Language/05_Variables/05_Variables_A05_t01: Fail # Checks that a compile-time error occurs if a constant variable is not initialized.
 Language/06_Functions/06_Functions_A01_t31: Fail # Checks that functions can't be declared as static inside of a function body.
 Language/06_Functions/1_Function_Declaration_A01_t01: Fail # Checks that it is a compile-time error to preface library function with 'static'.
 Language/06_Functions/2_Formal_Parameters/1_Required_Formals_A02_t03: Fail # Checks that a required parameter can be constant. Reassigning it should produce a compile-time error.
@@ -713,7 +709,6 @@
 Language/07_Classes/4_Abstract_Instance_Members_A04_t06: Fail # Checks that a compile-time error is produced when the overriding non-abstract  instance method has almost the same set of named parameters as the abstract method being overriden,  except for one that has a different name.
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t05: Fail # Checks that redirecting constructor can not have initializing formals.
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: Fail # Checks that error is produced if a final variable is not initialized in one  of the specified ways.
-Language/07_Classes/6_Constructors/1_Generative_Constructors_A21_t01: Fail # Checks that a compile-time error occur if k’s initializer list contains an initializer for a final variable whose declaration includes an initialization expression.
 Language/07_Classes/6_Constructors/3_Constant_Constructors_A03_t01: Fail # Checks that a compile-time error is produced when a class with constant  constructor also declares a non-final instance variable.
 Language/07_Classes/6_Constructors/3_Constant_Constructors_A03_t02: Fail # Checks that compile-time error is produced when a class with constant constructor inherits a non-final instance variable.
 Language/07_Classes/6_Constructors_A01_t01: Fail # Checks that a compile-error is produced when a constructor's id coincides with the name of a field in the same class.
@@ -777,16 +772,6 @@
 Language/14_Types/3_Type_Declarations/1_Typedef_A07_t03: Fail # dartbug.com/7202
 Language/14_Types/3_Type_Declarations/1_Typedef_A07_t04: Fail # dartbug.com/7202
 
-Language/14_Types/5_Function_Types_A01_t08: Fail # dartbug.com/7342
-Language/14_Types/5_Function_Types_A01_t09: Fail # dartbug.com/7342
-Language/14_Types/5_Function_Types_A01_t11: Fail # dartbug.com/7342
-Language/14_Types/5_Function_Types_A02_t05: Fail # dartbug.com/7342
-Language/14_Types/5_Function_Types_A02_t09: Fail # dartbug.com/7342
-Language/14_Types/5_Function_Types_A02_t10: Fail # dartbug.com/7342
-Language/14_Types/5_Function_Types_A03_t06: Fail # dartbug.com/7342
-Language/14_Types/5_Function_Types_A03_t10: Fail # dartbug.com/7342
-Language/14_Types/5_Function_Types_A03_t11: Fail # dartbug.com/7342
-
 # Doesn't expect null to be allowed in Set or Map keys (issue 377).
 LibTest/core/Map/containsKey_A01_t02: Fail
 LibTest/core/Map/operator_subscript_A01_t02: Fail
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 0c4e1d2..fb79c4e 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -11,9 +11,9 @@
 Language/13_Libraries_and_Scripts/1_Imports_A02_t22: Crash # Dart issue 6060
 
 Language/06_Functions/2_Formal_Parameters/2_Optional_Formals_A01_t10: Fail # co19 issue 348
-Language/07_Classes/3_Setters_A04_t01: Fail # Dart issue 5840
-Language/07_Classes/3_Setters_A04_t04: Fail # Dart issue 5840
-Language/07_Classes/3_Setters_A04_t05: Fail # Dart issue 5840
+Language/07_Classes/3_Setters_A04_t01: Fail # co19 issue 383
+Language/07_Classes/3_Setters_A04_t04: Fail # co19 issue 383
+Language/07_Classes/3_Setters_A04_t05: Fail # co19 issue 383
 Language/07_Classes/4_Abstract_Instance_Members_A03_t02: Fail # Dart issue 978
 Language/07_Classes/4_Abstract_Instance_Members_A03_t03: Fail # Dart issue 978
 Language/07_Classes/4_Abstract_Instance_Members_A03_t04: Fail # Dart issue 978
diff --git a/tests/compiler/dart2js/analyze_all_test.dart b/tests/compiler/dart2js/analyze_all_test.dart
index f172ada..c972f82 100644
--- a/tests/compiler/dart2js/analyze_all_test.dart
+++ b/tests/compiler/dart2js/analyze_all_test.dart
@@ -2,13 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:uri';
-
 import 'compiler_helper.dart';
 
-import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
-       show MessageKind;
-
 const String SOURCE = """
 class Foo {
   // Deliberately not const to ensure compile error.
diff --git a/tests/compiler/dart2js/analyze_api_test.dart b/tests/compiler/dart2js/analyze_api_test.dart
index 9e1d365..1432d40 100644
--- a/tests/compiler/dart2js/analyze_api_test.dart
+++ b/tests/compiler/dart2js/analyze_api_test.dart
@@ -14,18 +14,88 @@
 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
 import '../../../sdk/lib/_internal/libraries.dart';
 
+/**
+ * Map of white-listed warnings and errors.
+ *
+ * Only add a white-listing together with a bug report to dartbug.com and add
+ * the bug issue number as a comment on the white-listing.
+ *
+ * Use an identifiable suffix of the file uri as key. Use a fixed substring of
+ * the error/warning message in the list of white-listings for each file.
+ */
+// TODO(johnniwinther): Support canonical URIs as keys and message kinds as
+// values.
+const Map<String,List<String>> WHITE_LIST = const { };
+
 class CollectingDiagnosticHandler extends FormattingDiagnosticHandler {
   bool hasWarnings = false;
   bool hasErrors = false;
 
-  CollectingDiagnosticHandler(SourceFileProvider provider) : super(provider);
+  Map<String,Map<String,int>> whiteListMap = new Map<String,Map<String,int>>();
+
+  CollectingDiagnosticHandler(SourceFileProvider provider) : super(provider) {
+    WHITE_LIST.forEach((String file, List<String> messageParts) {
+      var useMap = new Map<String,int>();
+      for (String messagePart in messageParts) {
+        useMap[messagePart] = 0;
+      }
+      whiteListMap[file] = useMap;
+    });
+  }
+
+  bool checkWhiteListUse() {
+    bool allUsed = true;
+    for (String file in whiteListMap.keys) {
+      for (String messagePart in whiteListMap[file].keys) {
+        if (whiteListMap[file][messagePart] == 0) {
+          print("White-listing '$messagePart' is unused in '$file'. "
+                "Remove the white-listing from the WHITE_LIST map.");
+          allUsed = false;
+        }
+      }
+    }
+    return allUsed;
+  }
+
+  void reportWhiteListUse() {
+    for (String file in whiteListMap.keys) {
+      for (String messagePart in whiteListMap[file].keys) {
+        int useCount = whiteListMap[file][messagePart];
+        print("White-listed message '$messagePart' suppressed $useCount "
+              "time(s) in '$file'.");
+      }
+    }
+  }
+
+  bool checkWhiteList(Uri uri, String message) {
+    String path = uri.path;
+    for (String file in whiteListMap.keys) {
+      if (path.endsWith(file)) {
+        for (String messagePart in whiteListMap[file].keys) {
+          if (message.contains(messagePart)) {
+            whiteListMap[file][messagePart]++;
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
 
   void diagnosticHandler(Uri uri, int begin, int end, String message,
                          api.Diagnostic kind) {
     if (kind == api.Diagnostic.WARNING) {
+      if (checkWhiteList(uri, message)) {
+        // Suppress white listed warnings.
+        return;
+      }
       hasWarnings = true;
     }
     if (kind == api.Diagnostic.ERROR) {
+      if (checkWhiteList(uri, message)) {
+        // Suppress white listed warnings.
+        return;
+      }
       hasErrors = true;
     }
     super.diagnosticHandler(uri, begin, end, message, kind);
@@ -54,4 +124,6 @@
   compiler.run(null);
   Expect.isFalse(handler.hasWarnings);
   Expect.isFalse(handler.hasErrors);
+  Expect.isTrue(handler.checkWhiteListUse());
+  handler.reportWhiteListUse();
 }
diff --git a/tests/compiler/dart2js/backend_htype_list_test.dart b/tests/compiler/dart2js/backend_htype_list_test.dart
index 7cd5d3b..93d37a4 100644
--- a/tests/compiler/dart2js/backend_htype_list_test.dart
+++ b/tests/compiler/dart2js/backend_htype_list_test.dart
@@ -2,13 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:uri';
-
-import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/ssa/ssa.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
-       show Selector;
 
 import 'compiler_helper.dart';
 import 'parser_helper.dart';
diff --git a/tests/compiler/dart2js/call_site_type_inferer_static_test.dart b/tests/compiler/dart2js/call_site_type_inferer_static_test.dart
index 8b73b45..bc4e2c5 100644
--- a/tests/compiler/dart2js/call_site_type_inferer_static_test.dart
+++ b/tests/compiler/dart2js/call_site_type_inferer_static_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import "dart:uri";
-
 import "../../../sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart";
 import "../../../sdk/lib/_internal/compiler/implementation/ssa/ssa.dart";
 
diff --git a/tests/compiler/dart2js/call_site_type_inferer_test.dart b/tests/compiler/dart2js/call_site_type_inferer_test.dart
index c868f4b..f3c9e76 100644
--- a/tests/compiler/dart2js/call_site_type_inferer_test.dart
+++ b/tests/compiler/dart2js/call_site_type_inferer_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:uri';
-
 import '../../../sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/ssa/ssa.dart';
 
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index 57ef07d..405fb63 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -5,22 +5,41 @@
 
 library compiler_helper;
 
-import "dart:uri";
+import 'dart:uri';
+export 'dart:uri' show Uri;
 
-import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart"
+import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart'
        as lego;
-import "../../../sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart"
+export '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart';
+
+import '../../../sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart'
        as js;
-import "../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart"
+
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
        as leg;
-import "../../../sdk/lib/_internal/compiler/implementation/ssa/ssa.dart" as ssa;
-import "../../../sdk/lib/_internal/compiler/implementation/util/util.dart";
+export '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
+       show Constant,
+            Message,
+            MessageKind,
+            Selector,
+            SourceSpan;
+
+import '../../../sdk/lib/_internal/compiler/implementation/ssa/ssa.dart' as ssa;
+
+import '../../../sdk/lib/_internal/compiler/implementation/util/util.dart';
+export '../../../sdk/lib/_internal/compiler/implementation/util/util.dart';
+
 import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart';
+
 import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
        show Compiler;
 
-import "mock_compiler.dart";
-import "parser_helper.dart";
+export '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart';
+
+import 'mock_compiler.dart';
+export 'mock_compiler.dart';
+
+import 'parser_helper.dart';
 
 String compile(String code, {String entry: 'main',
                              String coreSource: DEFAULT_CORELIB,
@@ -39,6 +58,7 @@
   compiler.phase = Compiler.PHASE_RESOLVING;
   compiler.backend.enqueueHelpers(compiler.enqueuer.resolution);
   compiler.processQueue(compiler.enqueuer.resolution, element);
+  compiler.world.populate();
   var context = new js.JavaScriptItemCompilationContext();
   leg.ResolutionWorkItem resolutionWork =
       new leg.ResolutionWorkItem(element, context);
@@ -79,6 +99,23 @@
   return check(compiler, element);
 }
 
+compileSources(Map<String, String> sources,
+               check(MockCompiler compiler)) {
+  Uri base = new Uri.fromComponents(scheme: 'source');
+  Uri mainUri = base.resolve('main.dart');
+  String mainCode = sources['main.dart'];
+  Expect.isNotNull(mainCode, 'No source code found for "main.dart"');
+  MockCompiler compiler = compilerFor(mainCode, mainUri);
+
+  sources.forEach((String path, String code) {
+    if (path == 'main.dart') return;
+    compiler.registerSource(base.resolve(path), code);
+  });
+
+  compiler.runCompiler(mainUri);
+  return check(compiler);
+}
+
 lego.Element findElement(compiler, String name) {
   var element = compiler.mainApp.find(buildSourceString(name));
   Expect.isNotNull(element, 'Could not locate $name.');
diff --git a/tests/compiler/dart2js/concrete_type_inference_test.dart b/tests/compiler/dart2js/concrete_type_inference_test.dart
index 90c479e..324b79d 100644
--- a/tests/compiler/dart2js/concrete_type_inference_test.dart
+++ b/tests/compiler/dart2js/concrete_type_inference_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:uri';
-
 import 'compiler_helper.dart';
 import 'parser_helper.dart';
 
diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart
index 8aa2bae..a204b4d 100644
--- a/tests/compiler/dart2js/cpa_inference_test.dart
+++ b/tests/compiler/dart2js/cpa_inference_test.dart
@@ -2,17 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import "dart:uri";
-import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart";
 import '../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/types/types.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart';
-import "../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart" as leg;
 
 import "parser_helper.dart";
 import "compiler_helper.dart";
-import "mock_compiler.dart";
 
 /**
  * Finds the node corresponding to the last occurence of the substring
@@ -168,7 +163,9 @@
   class Null {}
   class Type {}
   class Dynamic_ {}
-  bool identical(Object a, Object b) {}''';
+  bool identical(Object a, Object b) {}
+  dynamic JS(String typeDescription, String codeTemplate,
+             [var arg0, var arg1, var arg2]) {}''';
 
 AnalysisResult analyze(String code, {int maxConcreteTypeSize: 1000}) {
   Uri uri = new Uri.fromComponents(scheme: 'source');
@@ -1023,6 +1020,17 @@
   result.checkNodeHasUnknownType('x');
 }
 
+testJsCall() {
+  final String source = r"""
+    main () {
+      var x = JS('', '', null);
+      x;
+    }
+    """;
+  AnalysisResult result = analyze(source);
+  result.checkNodeHasUnknownType('x');
+}
+
 testIsCheck() {
   final String source = r"""
     main () {
@@ -1034,6 +1042,33 @@
   result.checkNodeHasType('x', [result.bool]);
 }
 
+testSeenClasses() {
+  final String source = r"""
+      class A {
+        witness() => 42;
+      }
+      class B {
+        witness() => "abc";
+      }
+      class AFactory {
+        onlyCalledInAFactory() => new A();
+      }
+      class BFactory {
+        onlyCalledInAFactory() => new B();
+      }
+
+      main() {
+        new AFactory().onlyCalledInAFactory();
+        new BFactory();
+        // should be of type {int} and not {int, String} since B is unreachable
+        var foo = "__dynamic_for_test".witness();
+        foo;
+      }
+      """;
+  AnalysisResult result = analyze(source);
+  result.checkNodeHasType('foo', [result.int]);
+}
+
 void main() {
   testDynamicBackDoor();
   testLiterals();
@@ -1074,5 +1109,7 @@
   testLists();
   testListWithCapacity();
   testEmptyList();
+  testJsCall();
   testIsCheck();
+  testSeenClasses();
 }
diff --git a/tests/compiler/dart2js/dart_backend_test.dart b/tests/compiler/dart2js/dart_backend_test.dart
index 6bf38fb..23f830d 100644
--- a/tests/compiler/dart2js/dart_backend_test.dart
+++ b/tests/compiler/dart2js/dart_backend_test.dart
@@ -21,8 +21,8 @@
 interface double extends num {}
 abstract class String {}
 interface Function {}
-interface List {}
-interface Map {}
+interface List<T> {}
+interface Map<K,V> {}
 interface Closure {}
 interface Dynamic_ {}
 interface Null {}
diff --git a/tests/compiler/dart2js/field_type_inferer_test.dart b/tests/compiler/dart2js/field_type_inferer_test.dart
index a3253b4..04773aa 100644
--- a/tests/compiler/dart2js/field_type_inferer_test.dart
+++ b/tests/compiler/dart2js/field_type_inferer_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:uri';
-
 import '../../../sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/ssa/ssa.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart';
diff --git a/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart b/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart
index ae87042..9d42462 100644
--- a/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart
+++ b/tests/compiler/dart2js/gvn_dynamic_field_get_test.dart
@@ -6,7 +6,6 @@
 
 import 'compiler_helper.dart';
 import 'parser_helper.dart';
-import 'dart:uri';
 
 const String TEST = r"""
 class A {
@@ -31,7 +30,9 @@
   checkNumberOfMatches(matches, 1);
   var cls = findElement(compiler, 'A');
   Expect.isNotNull(cls);
-  var element = cls.lookupLocalMember(buildSourceString('foo'));
+  SourceString name = buildSourceString('foo');
+  var element = cls.lookupLocalMember(name);
   Expect.isNotNull(element);
-  Expect.isFalse(compiler.world.userDefinedGetters.contains(element));
+  Selector selector = new Selector.getter(name, null);
+  Expect.isFalse(compiler.world.hasAnyUserDefinedGetter(selector));
 }
diff --git a/tests/compiler/dart2js/interceptor_test.dart b/tests/compiler/dart2js/interceptor_test.dart
index 3a346e1..ff0076a 100644
--- a/tests/compiler/dart2js/interceptor_test.dart
+++ b/tests/compiler/dart2js/interceptor_test.dart
@@ -41,14 +41,14 @@
   // Check that one-shot interceptors preserve variable names, see
   // https://code.google.com/p/dart/issues/detail?id=8106.
   generated = compile(TEST_TWO, entry: 'foo');
-  Expect.isTrue(generated.contains('\$.\$\$add(a, 42)'));
+  Expect.isTrue(generated.contains(r'$.$$add$n(a, 42)'));
   Expect.isTrue(generated.contains('myVariableName'));
 
   // Check that an intercepted getter that does not need to be
   // intercepted, is turned into a regular getter call or field
   // access.
   generated = compile(TEST_THREE, entry: 'foo');
-  Expect.isFalse(generated.contains(r'get$length'));
+  Expect.isFalse(generated.contains(r'a.get$length()'));
   Expect.isTrue(generated.contains(r'$.A$().length'));
-  Expect.isTrue(generated.contains(r'length(a)'));
+  Expect.isTrue(generated.contains(r'$.get$length$a(a)'));
 }
diff --git a/tests/compiler/dart2js/js_parser_test.dart b/tests/compiler/dart2js/js_parser_test.dart
new file mode 100644
index 0000000..3bd6559
--- /dev/null
+++ b/tests/compiler/dart2js/js_parser_test.dart
@@ -0,0 +1,156 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'mock_compiler.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/js/js.dart' as jsAst;
+import '../../../sdk/lib/_internal/compiler/implementation/js/js.dart' show js;
+
+void testExpression(String expression, [String expect = ""]) {
+  jsAst.Node node = js[expression];
+  MockCompiler compiler = new MockCompiler();
+  String jsText =
+      jsAst.prettyPrint(node,
+                        compiler,
+                        allowVariableMinification: false).getText();
+  if (expect == "") {
+    Expect.stringEquals(expression, jsText);
+  } else {
+    Expect.stringEquals(expect, jsText);
+  }
+}
+
+void testError(String expression, [String expect = ""]) {
+  bool doCheck(exception) {
+    Expect.isTrue(exception.toString().contains(expect));
+    return true;
+  }
+  Expect.throws(() => js[expression], doCheck);
+}
+    
+
+
+void main() {
+  // Asterisk indicates deviations from real JS.
+  // Simple var test.
+  testExpression('var a = ""');
+  // Parse and print will normalize whitespace.
+  testExpression(' var  a  =  "" ', 'var a = ""');
+  // *We don't do operator prescedence.
+  testError('x = a + b * c', 'Mixed + and *');
+  // But we can chain binary operators (with left associativity).
+  testExpression('x = a + b + c');
+  // We can cope with relational operators and non-relational.
+  testExpression('a + b == c + d');
+  // The prettyprinter will insert braces where needed.
+  testExpression('a + (b == c) + d');
+  // We can handle () for calls.
+  testExpression('foo(bar)');
+  testExpression('foo(bar, baz)');
+  // *But we can't handle chained calls without parentheses.
+  testError('foo(bar)(baz)');
+  // The prettyprinter understands chained calls without extra parentheses.
+  testExpression('(foo(bar))(baz)', 'foo(bar)(baz)');
+  // Chains of dotting and calls.
+  testExpression('foo.bar(baz)');
+  // String literal.
+  testExpression('var x = "fisk"');
+  // String literal with \n.
+  testExpression(r'var x = "\n"');
+  // String literal with escaped quote.
+  testExpression(r'var x = "\""');
+  // *No clever escapes.
+  testError(r'var x = "\x42"', 'escapes allowed in string literals');
+  // Operator new.
+  testExpression('new Foo()');
+  // New with dotted access.
+  testExpression('new Frobinator.frobinate()');
+  // The prettyprinter is smarter than we are.
+  testExpression('(new Frobinator()).frobinate()',
+                 'new Frobinator().frobinate()');
+  // *We want a bracket on 'new'.
+  testError('new Foo');
+  testError('(new Foo)');
+  // Bogus operators.
+  testError('a +++ b', 'Unknown operator');
+  // This isn't perl.  There are rules.
+  testError('a <=> b', 'Unknown operator');
+  // Typeof.
+  testExpression('typeof foo == "number"');
+  // *Strange relation.
+  testError('a < b < c', 'RELATION');
+  // Chained var.
+  testExpression('var x = 0, y = 1.2, z = 42');
+  // Empty object literal.
+  testExpression('foo({}, {})');
+  // *Can't handle non-empty object literals
+  testError('foo({meaning: 42})', 'Expected RBRACE');
+  // Literals.
+  testExpression('x(false, true, null)');
+  // *We should really throw here.
+  testExpression('var false = 42');
+  testExpression('var new = 42');
+  testExpression('var typeof = 42');
+  // Malformed decimal
+  testError('var x = 42.', "Unparseable number");
+  testError('var x = 1.1.1', "Unparseable number");
+  // More unary.
+  testExpression('x = !x');
+  testExpression('!x == false');
+  testExpression('var foo = void 0');
+  testExpression('delete foo.bar');
+  testExpression('delete foo');
+  testError('x typeof y', 'Unparsed junk');
+  testExpression('x &= ~mask');
+  // Adjacent tokens.
+  testExpression('foo[x[bar]]');
+  // Prefix ++ etc.
+  testExpression("++x");
+  testExpression("++foo.bar");
+  testExpression("+x");
+  testExpression("+foo.bar");
+  testExpression("-x");
+  testExpression("-foo.bar");
+  testExpression("--x");
+  testExpression("--foo.bar");
+  // Postfix ++ etc.
+  testExpression("x++");
+  testExpression("foo.bar++");
+  testExpression("x--");
+  testExpression("foo.bar--");
+  // Both!
+  testExpression("++x++");
+  testExpression("++foo.bar++");
+  testExpression("--x--");
+  testExpression("--foo.bar--");
+  // *We can't handle stacked unary operators.
+  testError("x++ ++");
+  testError("++ typeof x");
+  // ++ used as a binary operator.
+  testError("x++ ++ 42");
+  // Shift operators.
+  testExpression("x << 5");
+  testExpression("x << y + 1");
+  testExpression("x <<= y + 1");
+  // Array initializers.
+  testExpression("x = ['foo', 'bar', x[4]]");
+  testExpression("[]");
+  testError("[42 42]");
+  testExpression('beebop([1, 2, 3])');
+  // *We can't parse array literals with holes in them.
+  testError("[1,, 2]");
+  testError("[1,]");
+  testError("[,]");
+  testError("[, 42]");
+  // Ternary operator.
+  testExpression("x = a ? b : c");
+  testExpression("y = a == null ? b : a");
+  testExpression("y = a == null ? b + c : a + c");
+  testExpression("foo = a ? b : c ? d : e");
+  testExpression("foo = a ? b ? c : d : e");
+  testExpression("foo = (a = v) ? b = w : c = x ? d = y : e = z");
+  testExpression("foo = (a = v) ? b = w ? c = x : d = y : e = z");
+  // Stacked assignment.
+  testExpression("a = b = c");
+  testExpression("var a = b = c");
+}
diff --git a/tests/compiler/dart2js/metadata_test.dart b/tests/compiler/dart2js/metadata_test.dart
index 1591ebc..b90ca18 100644
--- a/tests/compiler/dart2js/metadata_test.dart
+++ b/tests/compiler/dart2js/metadata_test.dart
@@ -2,18 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import "dart:uri";
-
 import 'compiler_helper.dart';
 import 'parser_helper.dart';
 
-import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/util/util.dart'
-    show Spannable, Link;
-import '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart'
-    show Node, LibraryTag;
-
 void checkPosition(Spannable spannable, Node node, String source, compiler) {
   SourceSpan span = compiler.spanFromSpannable(spannable);
   Expect.isTrue(span.begin < span.end,
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 39ab912..686c8ff 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -25,6 +25,10 @@
 
 import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart';
 
+import '../../../sdk/lib/_internal/compiler/implementation/deferred_load.dart'
+    show DeferredLoadTask;
+
+
 class WarningMessage {
   Node node;
   Message message;
@@ -53,6 +57,7 @@
   class LinkedHashMap {}
   S() {}
   assertHelper(a){}
+  createRuntimeType(a) {}
   throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) {}
   throwAbstractClassInstantiationError(className) {}''';
 
@@ -89,9 +94,9 @@
     operator <=(other) => true;
     operator ==(other) => true;
   }
-  class JSInt {
+  class JSInt extends JSNumber {
   }
-  class JSDouble {
+  class JSDouble extends JSNumber {
   }
   class JSNull {
   }
@@ -107,7 +112,10 @@
   print(var obj) {}
   abstract class num {}
   abstract class int extends num { }
-  abstract class double extends num { }
+  abstract class double extends num {
+    static var NAN = 0;
+    static parse(s) {}
+  }
   class bool {}
   class String {}
   class Object {
@@ -118,6 +126,10 @@
   class Function {}
   class List<E> {}
   abstract class Map<K,V> {}
+  class DateTime {
+    DateTime(year);
+    DateTime.utc(year);
+  }
   bool identical(Object a, Object b) {}''';
 
 const String DEFAULT_ISOLATE_HELPERLIB = r'''
@@ -167,6 +179,8 @@
     // Our unit tests check code generation output that is affected by
     // inlining support.
     disableInlining = true;
+
+    deferredLoadTask = new MockDeferredLoadTask(this);
   }
 
   /**
@@ -182,11 +196,12 @@
    * is fixed to export its top-level declarations.
    */
   LibraryElement createLibrary(String name, String source) {
-    Uri uri = new Uri.fromComponents(scheme: "source", path: name);
+    Uri uri = new Uri.fromComponents(scheme: "dart", path: name);
     var script = new Script(uri, new MockFile(source));
     var library = new LibraryElementX(script);
     parseScript(source, library);
     library.setExports(library.localScope.values.toList());
+    registerSource(uri, source);
     return library;
   }
 
@@ -342,3 +357,11 @@
     map.remove(node);
   }
 }
+
+class MockDeferredLoadTask extends DeferredLoadTask {
+  MockDeferredLoadTask(Compiler compiler) : super(compiler);
+
+  void registerMainApp(LibraryElement mainApp) {
+    // Do nothing.
+  }
+}
diff --git a/tests/compiler/dart2js/resolution_test.dart b/tests/compiler/dart2js/resolution_test.dart
new file mode 100644
index 0000000..cd588bd
--- /dev/null
+++ b/tests/compiler/dart2js/resolution_test.dart
@@ -0,0 +1,118 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that resolution does not resolve things we know will not be
+// needed by the backend.
+
+import 'compiler_helper.dart';
+import 'parser_helper.dart';
+
+const String NO_RUNTIME_TYPE = r"""
+import 'dart:core' as prefix;
+class A {
+  A();
+  A.z();
+  static var bar;
+  static foo() {}
+}
+main() {
+  var print = prefix.print;
+  // Check when accessing a static field.
+  print(A.bar);
+  print(A.bar());
+  // Check when calling a static method.
+  print(A.foo());
+  print(A.foo);
+  // Check when using a constructor.
+  print(new A());
+  // Check when using a named constructor.
+  print(new A.z());
+  // Check when using a type annotation.
+  A a = new A();
+  // Check when using a prefix.
+  print(prefix.double.NAN);
+  print(prefix.double.NAN());
+  print(prefix.double.parse(''));
+  print(prefix.double.parse);
+  print(new prefix.DateTime(0));
+  print(new prefix.DateTime.utc(0));
+  prefix.DateTime c = new prefix.DateTime(0);
+}
+""";
+
+const String HAS_RUNTIME_TYPE_1 = r"""
+class A {
+}
+main() {
+  print(A);
+}
+""";
+
+const String HAS_RUNTIME_TYPE_2 = r"""
+class A {
+}
+main() {
+  print(2 + A);
+}
+""";
+
+const String HAS_RUNTIME_TYPE_3 = r"""
+class A {
+}
+main() {
+  print(A[0]);
+}
+""";
+
+const String HAS_RUNTIME_TYPE_4 = r"""
+class A {
+}
+main() {
+  var c = A;
+}
+""";
+
+const String HAS_RUNTIME_TYPE_5 = r"""
+import 'dart:core' as prefix;
+main() {
+  prefix.print(prefix.Object);
+}
+""";
+
+const String HAS_RUNTIME_TYPE_6 = r"""
+class A {
+  static var foo;
+}
+main() {
+  (A).foo;
+}
+""";
+
+void test(String code, void check(Compiler compiler)) {
+  Uri uri = new Uri.fromComponents(scheme: 'source');
+  var compiler = compilerFor(code, uri);
+  compiler.runCompiler(uri);
+  check(compiler);
+}
+
+void testHasRuntimeType(String code) {
+  test(code, (compiler) {
+    var element = compiler.findHelper(buildSourceString('createRuntimeType'));
+    Expect.isTrue(compiler.enqueuer.resolution.isProcessed(element));
+  });
+}
+
+main() {
+  test(NO_RUNTIME_TYPE, (compiler) {
+    var element = compiler.findHelper(buildSourceString('createRuntimeType'));
+    Expect.isFalse(compiler.enqueuer.resolution.isProcessed(element));
+  });
+
+  testHasRuntimeType(HAS_RUNTIME_TYPE_1);
+  testHasRuntimeType(HAS_RUNTIME_TYPE_2);
+  testHasRuntimeType(HAS_RUNTIME_TYPE_3);
+  testHasRuntimeType(HAS_RUNTIME_TYPE_4);
+  testHasRuntimeType(HAS_RUNTIME_TYPE_5);
+  testHasRuntimeType(HAS_RUNTIME_TYPE_6);
+}
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index a8b08ed..e1cbda1 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -3,18 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:collection';
-import 'dart:uri';
 
 import "../../../sdk/lib/_internal/compiler/implementation/resolution/resolution.dart";
-import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart";
-import "../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart";
-import "../../../sdk/lib/_internal/compiler/implementation/util/util.dart";
 import "compiler_helper.dart";
-import "mock_compiler.dart";
 import "parser_helper.dart";
 
-import "../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart"
-    hide TreeElementMapping, TreeElements, SourceString;
 import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart';
 
 Node buildIdentifier(String name) => new Identifier(scan(name));
diff --git a/tests/compiler/dart2js/size_test.dart b/tests/compiler/dart2js/size_test.dart
index d25c4b1..9b39765 100644
--- a/tests/compiler/dart2js/size_test.dart
+++ b/tests/compiler/dart2js/size_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import "mock_compiler.dart";
 import "compiler_helper.dart";
 
 const String TEST = "main() => [];";
@@ -26,5 +25,5 @@
   var backend = compiler.backend;
 
   // Make sure no class is emitted.
-  Expect.isFalse(generated.contains(backend.emitter.defineClassName));
+  Expect.isFalse(generated.contains(backend.emitter.finishClassesName));
 }
diff --git a/tests/compiler/dart2js/subtype_test.dart b/tests/compiler/dart2js/subtype_test.dart
new file mode 100644
index 0000000..daded9a
--- /dev/null
+++ b/tests/compiler/dart2js/subtype_test.dart
@@ -0,0 +1,218 @@
+// 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 subtype_test;
+
+import 'type_test_helper.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart';
+import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart"
+       show Element, ClassElement;
+
+void main() {
+  testInterfaceSubtype();
+}
+
+void testInterfaceSubtype() {
+  var env = new TypeEnvironment(r"""
+      class A<T> {}
+      class B<T1,T2> extends A<T1> {}
+      // TODO(johnniwinther): Inheritance with different type arguments is
+      // currently not supported by the implementation.
+      class C<T1,T2> extends B<T2,T1> /*implements A<A<T1>>*/ {}
+      """);
+
+  void expect(bool value, DartType T, DartType S) {
+    Expect.equals(value, env.isSubtype(T, S), '$T <: $S');
+  }
+
+  ClassElement A = env.getElement('A');
+  ClassElement B = env.getElement('B');
+  ClassElement C = env.getElement('C');
+  DartType Object_ = env['Object'];
+  DartType num_ = env['num'];
+  DartType int_ = env['int'];
+  DartType String_ = env['String'];
+  DartType dynamic_ = env['dynamic'];
+
+  expect(true, Object_, Object_);
+  expect(true, num_, Object_);
+  expect(true, int_, Object_);
+  expect(true, String_, Object_);
+  expect(true, dynamic_, Object_);
+
+  expect(false, Object_, num_);
+  expect(true, num_, num_);
+  expect(true, int_, num_);
+  expect(false, String_, num_);
+  expect(true, dynamic_, num_);
+
+  expect(false, Object_, int_);
+  expect(false, num_, int_);
+  expect(true, int_, int_);
+  expect(false, String_, int_);
+  expect(true, dynamic_, int_);
+
+  expect(false, Object_, String_);
+  expect(false, num_, String_);
+  expect(false, int_, String_);
+  expect(true, String_, String_);
+  expect(true, dynamic_, String_);
+
+  expect(true, Object_, dynamic_);
+  expect(true, num_, dynamic_);
+  expect(true, int_, dynamic_);
+  expect(true, String_, dynamic_);
+  expect(true, dynamic_, dynamic_);
+
+  DartType A_Object = instantiate(A, [Object_]);
+  DartType A_num = instantiate(A, [num_]);
+  DartType A_int = instantiate(A, [int_]);
+  DartType A_String = instantiate(A, [String_]);
+  DartType A_dynamic = instantiate(A, [dynamic_]);
+
+  expect(true, A_Object, Object_);
+  expect(false, A_Object, num_);
+  expect(false, A_Object, int_);
+  expect(false, A_Object, String_);
+  expect(true, A_Object, dynamic_);
+
+  expect(true, A_Object, A_Object);
+  expect(true, A_num, A_Object);
+  expect(true, A_int, A_Object);
+  expect(true, A_String, A_Object);
+  expect(true, A_dynamic, A_Object);
+
+  expect(false, A_Object, A_num);
+  expect(true, A_num, A_num);
+  expect(true, A_int, A_num);
+  expect(false, A_String, A_num);
+  expect(true, A_dynamic, A_num);
+
+  expect(false, A_Object, A_int);
+  expect(false, A_num, A_int);
+  expect(true, A_int, A_int);
+  expect(false, A_String, A_int);
+  expect(true, A_dynamic, A_int);
+
+  expect(false, A_Object, A_String);
+  expect(false, A_num, A_String);
+  expect(false, A_int, A_String);
+  expect(true, A_String, A_String);
+  expect(true, A_dynamic, A_String);
+
+  expect(true, A_Object, A_dynamic);
+  expect(true, A_num, A_dynamic);
+  expect(true, A_int, A_dynamic);
+  expect(true, A_String, A_dynamic);
+  expect(true, A_dynamic, A_dynamic);
+
+  DartType B_Object_Object = instantiate(B, [Object_, Object_]);
+  DartType B_num_num = instantiate(B, [num_, num_]);
+  DartType B_int_num = instantiate(B, [int_, num_]);
+  DartType B_dynamic_dynamic = instantiate(B, [dynamic_, dynamic_]);
+  DartType B_String_dynamic = instantiate(B, [String_, dynamic_]);
+
+  expect(true, B_Object_Object, Object_);
+  expect(true, B_Object_Object, A_Object);
+  expect(false, B_Object_Object, A_num);
+  expect(false, B_Object_Object, A_int);
+  expect(false, B_Object_Object, A_String);
+  expect(true, B_Object_Object, A_dynamic);
+
+  expect(true, B_num_num, Object_);
+  expect(true, B_num_num, A_Object);
+  expect(true, B_num_num, A_num);
+  expect(false, B_num_num, A_int);
+  expect(false, B_num_num, A_String);
+  expect(true, B_num_num, A_dynamic);
+
+  expect(true, B_int_num, Object_);
+  expect(true, B_int_num, A_Object);
+  expect(true, B_int_num, A_num);
+  expect(true, B_int_num, A_int);
+  expect(false, B_int_num, A_String);
+  expect(true, B_int_num, A_dynamic);
+
+  expect(true, B_dynamic_dynamic, Object_);
+  expect(true, B_dynamic_dynamic, A_Object);
+  expect(true, B_dynamic_dynamic, A_num);
+  expect(true, B_dynamic_dynamic, A_int);
+  expect(true, B_dynamic_dynamic, A_String);
+  expect(true, B_dynamic_dynamic, A_dynamic);
+
+  expect(true, B_String_dynamic, Object_);
+  expect(true, B_String_dynamic, A_Object);
+  expect(false, B_String_dynamic, A_num);
+  expect(false, B_String_dynamic, A_int);
+  expect(true, B_String_dynamic, A_String);
+  expect(true, B_String_dynamic, A_dynamic);
+
+  expect(true, B_Object_Object, B_Object_Object);
+  expect(true, B_num_num, B_Object_Object);
+  expect(true, B_int_num, B_Object_Object);
+  expect(true, B_dynamic_dynamic, B_Object_Object);
+  expect(true, B_String_dynamic, B_Object_Object);
+
+  expect(false, B_Object_Object, B_num_num);
+  expect(true, B_num_num, B_num_num);
+  expect(true, B_int_num, B_num_num);
+  expect(true, B_dynamic_dynamic, B_num_num);
+  expect(false, B_String_dynamic, B_num_num);
+
+  expect(false, B_Object_Object, B_int_num);
+  expect(false, B_num_num, B_int_num);
+  expect(true, B_int_num, B_int_num);
+  expect(true, B_dynamic_dynamic, B_int_num);
+  expect(false, B_String_dynamic, B_int_num);
+
+  expect(true, B_Object_Object, B_dynamic_dynamic);
+  expect(true, B_num_num, B_dynamic_dynamic);
+  expect(true, B_int_num, B_dynamic_dynamic);
+  expect(true, B_dynamic_dynamic, B_dynamic_dynamic);
+  expect(true, B_String_dynamic, B_dynamic_dynamic);
+
+  expect(false, B_Object_Object, B_String_dynamic);
+  expect(false, B_num_num, B_String_dynamic);
+  expect(false, B_int_num, B_String_dynamic);
+  expect(true, B_dynamic_dynamic, B_String_dynamic);
+  expect(true, B_String_dynamic, B_String_dynamic);
+
+  DartType C_Object_Object = instantiate(C, [Object_, Object_]);
+  DartType C_num_num = instantiate(C, [num_, num_]);
+  DartType C_int_String = instantiate(C, [int_, String_]);
+  DartType C_dynamic_dynamic = instantiate(C, [dynamic_, dynamic_]);
+
+  expect(true, C_Object_Object, B_Object_Object);
+  expect(false, C_Object_Object, B_num_num);
+  expect(false, C_Object_Object, B_int_num);
+  expect(true, C_Object_Object, B_dynamic_dynamic);
+  expect(false, C_Object_Object, B_String_dynamic);
+
+  expect(true, C_num_num, B_Object_Object);
+  expect(true, C_num_num, B_num_num);
+  expect(false, C_num_num, B_int_num);
+  expect(true, C_num_num, B_dynamic_dynamic);
+  expect(false, C_num_num, B_String_dynamic);
+
+  expect(true, C_int_String, B_Object_Object);
+  expect(false, C_int_String, B_num_num);
+  expect(false, C_int_String, B_int_num);
+  expect(true, C_int_String, B_dynamic_dynamic);
+  expect(true, C_int_String, B_String_dynamic);
+
+  expect(true, C_dynamic_dynamic, B_Object_Object);
+  expect(true, C_dynamic_dynamic, B_num_num);
+  expect(true, C_dynamic_dynamic, B_int_num);
+  expect(true, C_dynamic_dynamic, B_dynamic_dynamic);
+  expect(true, C_dynamic_dynamic, B_String_dynamic);
+
+  expect(false, C_int_String, A_int);
+  expect(true, C_int_String, A_String);
+  // TODO(johnniwinther): Inheritance with different type arguments is
+  // currently not supported by the implementation.
+  //expect(true, C_int_String, instantiate(A, [A_int]));
+  expect(false, C_int_String, instantiate(A, [A_String]));
+}
+
+
diff --git a/tests/compiler/dart2js/tag_mapping_test.dart b/tests/compiler/dart2js/tag_mapping_test.dart
new file mode 100644
index 0000000..c9b5a82
--- /dev/null
+++ b/tests/compiler/dart2js/tag_mapping_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.
+
+// Test of import tag to library mapping.
+
+import 'compiler_helper.dart';
+
+const MAIN_CODE = """
+import 'library.dart';
+
+main() {
+}
+""";
+
+const LIB_CODE = """
+library lib;
+""";
+
+void main() {
+  var sources = <String, String>{
+    'main.dart': MAIN_CODE,
+    'library.dart': LIB_CODE,
+  };
+
+  compileSources(sources, (MockCompiler compiler) {
+    LibraryElement mainApp = compiler.libraries['source:/main.dart'];
+    LibraryElement lib = compiler.libraries['source:/library.dart'];
+    Expect.isNotNull(mainApp, 'Could not find main.dart library');
+    Expect.isNotNull(lib, 'Could not find library.dart library');
+
+    Import tag = mainApp.tags.single;
+    Expect.isNotNull(tag, 'Could not find import tag in $mainApp');
+
+    // Test that we can get from the import tag in main.dart to the
+    // library element representing library.dart.
+    Expect.identical(lib, mainApp.getLibraryFromTag(tag));
+  });
+}
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index f69acf9..39e688a 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -266,7 +266,14 @@
 
 void testMethodInvocations() {
   compiler.parseScript(CLASS_WITH_METHODS);
-  final String header = "{ ClassWithMethods c; SubClass d; int i; int j; ";
+  final String header = """{
+      ClassWithMethods c; 
+      SubClass d; 
+      var e; 
+      int i; 
+      int j;
+      int localMethod(String str) { return 0; }
+      """;
 
   analyze("${header}int k = c.untypedNoArgumentMethod(); }");
   analyze("${header}ClassWithMethods x = c.untypedNoArgumentMethod(); }");
@@ -306,8 +313,71 @@
   analyze("${header}ClassWithMethods x = c.intTwoArgumentMethod(i, j); }",
           MessageKind.NOT_ASSIGNABLE);
 
-  analyze("${header}c.intField(); }", MessageKind.METHOD_NOT_FOUND);
-  analyze("${header}d.intField(); }", MessageKind.METHOD_NOT_FOUND);
+  analyze("${header}c.functionField(); }");
+  analyze("${header}d.functionField(); }");
+  analyze("${header}c.functionField(1); }");
+  analyze("${header}d.functionField('string'); }");
+
+  analyze("${header}c.intField(); }", MessageKind.NOT_CALLABLE);
+  analyze("${header}d.intField(); }", MessageKind.NOT_CALLABLE);
+
+  analyze("${header}c.untypedField(); }");
+  analyze("${header}d.untypedField(); }");
+  analyze("${header}c.untypedField(1); }");
+  analyze("${header}d.untypedField('string'); }");
+
+  // Invocation of dynamic variable.
+  analyze("${header}e(); }");
+  analyze("${header}e(1); }");
+  analyze("${header}e('string'); }");
+
+  // Invocation on local method.
+  analyze("${header}localMethod(); }", MessageKind.MISSING_ARGUMENT);
+  analyze("${header}localMethod(1); }", MessageKind.NOT_ASSIGNABLE);
+  analyze("${header}localMethod('string'); }");
+  analyze("${header}int k = localMethod('string'); }");
+  analyze("${header}String k = localMethod('string'); }",
+      MessageKind.NOT_ASSIGNABLE);
+
+  // Invocation on parenthesized expressions.
+  analyze("${header}(e)(); }");
+  analyze("${header}(e)(1); }");
+  analyze("${header}(e)('string'); }");
+  analyze("${header}(foo)(); }");
+  analyze("${header}(foo)(1); }");
+  analyze("${header}(foo)('string'); }");
+
+  // Invocations on function expressions.
+  analyze("${header}(foo){}(); }", MessageKind.MISSING_ARGUMENT);
+  analyze("${header}(foo){}(1); }");
+  analyze("${header}(foo){}('string'); }");
+  analyze("${header}(int foo){}('string'); }", MessageKind.NOT_ASSIGNABLE);
+  analyze("${header}(String foo){}('string'); }");
+  analyze("${header}int k = int bar(String foo){ return 0; }('string'); }");
+  analyze("${header}int k = String bar(String foo){ return foo; }('string'); }",
+      MessageKind.NOT_ASSIGNABLE);
+
+  // Static invocations.
+  analyze("${header}ClassWithMethods.staticMethod(); }",
+      MessageKind.MISSING_ARGUMENT);
+  analyze("${header}ClassWithMethods.staticMethod(1); }",
+      MessageKind.NOT_ASSIGNABLE);
+  analyze("${header}ClassWithMethods.staticMethod('string'); }");
+  analyze("${header}int k = ClassWithMethods.staticMethod('string'); }");
+  analyze("${header}String k = ClassWithMethods.staticMethod('string'); }",
+      MessageKind.NOT_ASSIGNABLE);
+
+  // Invocation on dynamic variable.
+  analyze("${header}e.foo(); }");
+  analyze("${header}e.foo(1); }");
+  analyze("${header}e.foo('string'); }");
+
+  // Invocation on unresolved variable.
+  analyze("${header}foo(); }");
+  analyze("${header}foo(1); }");
+  analyze("${header}foo('string'); }");
+
+  // TODO(johnniwinther): Add tests of invocations using implicit this.
 }
 
 /** Tests analysis of returns (not required by the specification). */
@@ -589,6 +659,8 @@
   Function functionField;
   var untypedField;
   int intField;
+
+  static int staticMethod(String str) {}
 }
 interface I {
   int intMethod();
diff --git a/tests/compiler/dart2js/type_equals_test.dart b/tests/compiler/dart2js/type_equals_test.dart
index 57d468b..4da86a6 100644
--- a/tests/compiler/dart2js/type_equals_test.dart
+++ b/tests/compiler/dart2js/type_equals_test.dart
@@ -2,14 +2,9 @@
 // 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 "../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart";
 import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart';
-import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart";
-import "../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart";
-import "../../../sdk/lib/_internal/compiler/implementation/util/util.dart";
 import "compiler_helper.dart";
 import "parser_helper.dart";
-import "dart:uri";
 
 bool test(compiler, String name1, String name2, {bool expect}) {
   Expect.isTrue(?expect, 'required parameter "expect" not given');
diff --git a/tests/compiler/dart2js/type_substitution_test.dart b/tests/compiler/dart2js/type_substitution_test.dart
index 0c4ee89..e54b628 100644
--- a/tests/compiler/dart2js/type_substitution_test.dart
+++ b/tests/compiler/dart2js/type_substitution_test.dart
@@ -4,27 +4,10 @@
 
 library type_substitution_test;
 
-import "../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart";
 import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart';
-import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart";
-import "../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart";
-import "../../../sdk/lib/_internal/compiler/implementation/util/util.dart";
 import "compiler_helper.dart";
 import "parser_helper.dart";
-import "dart:uri";
-
-Element getElement(compiler, String name) {
-  var element = findElement(compiler, name);
-  Expect.isNotNull(element);
-  if (identical(element.kind, ElementKind.CLASS)) {
-    element.ensureResolved(compiler);
-  }
-  return element;
-}
-
-DartType getElementType(compiler, String name) {
-  return getElement(compiler, name).computeType(compiler);
-}
+import "type_test_helper.dart";
 
 DartType getType(compiler, String name) {
   var clazz = findElement(compiler, "Class");
@@ -63,46 +46,39 @@
   testTypeSubstitution();
 }
 
-InterfaceType instantiate(ClassElement element, List<DartType> arguments) {
-  return new InterfaceType(element, new Link<DartType>.fromList(arguments));
-}
-
 void testAsInstanceOf() {
-  var uri = new Uri.fromComponents(scheme: 'source');
-  Compiler compiler = compilerFor('''
-      main() {}
+  var env = new TypeEnvironment('''
       class A<T> {}
       class B<T> {}
       class C<T> extends A<T> {}
       class D<T> extends A<int> {}
       class E<T> extends A<A<T>> {}
-      class F<T, U> extends B<F<T, String>> implements A<F<B<U>, int>> {}''',
-    uri);
-  compiler.runCompiler(uri);
+      class F<T, U> extends B<F<T, String>> implements A<F<B<U>, int>> {}''');
+  var compiler = env.compiler;
 
-  ClassElement A = getElement(compiler, "A");
-  ClassElement B = getElement(compiler, "B");
-  ClassElement C = getElement(compiler, "C");
-  ClassElement D = getElement(compiler, "D");
-  ClassElement E = getElement(compiler, "E");
-  ClassElement F = getElement(compiler, "F");
+  ClassElement A = env.getElement("A");
+  ClassElement B = env.getElement("B");
+  ClassElement C = env.getElement("C");
+  ClassElement D = env.getElement("D");
+  ClassElement E = env.getElement("E");
+  ClassElement F = env.getElement("F");
 
-  DartType numType = compiler.numClass.computeType(compiler);
-  DartType intType = compiler.intClass.computeType(compiler);
-  DartType stringType = compiler.stringClass.computeType(compiler);
+  DartType numType = env['num'];
+  DartType intType = env['int'];
+  DartType stringType = env['String'];
 
-  DartType C_int = instantiate(C, [intType]);
+  InterfaceType C_int = instantiate(C, [intType]);
   Expect.equals(instantiate(C, [intType]), C_int);
   Expect.equals(instantiate(A, [intType]), C_int.asInstanceOf(A));
 
-  DartType D_int = instantiate(D, [stringType]);
+  InterfaceType D_int = instantiate(D, [stringType]);
   Expect.equals(instantiate(A, [intType]), D_int.asInstanceOf(A));
 
-  DartType E_int = instantiate(E, [intType]);
+  InterfaceType E_int = instantiate(E, [intType]);
   Expect.equals(instantiate(A, [instantiate(A, [intType])]),
                 E_int.asInstanceOf(A));
 
-  DartType F_int_string = instantiate(F, [intType, stringType]);
+  InterfaceType F_int_string = instantiate(F, [intType, stringType]);
   Expect.equals(instantiate(B, [instantiate(F, [intType, stringType])]),
                 F_int_string.asInstanceOf(B));
   Expect.equals(instantiate(A, [instantiate(F, [instantiate(B, [stringType]),
@@ -124,9 +100,7 @@
 }
 
 void testTypeSubstitution() {
-  var uri = new Uri.fromComponents(scheme: 'source');
-  var compiler = compilerFor(
-      r"""
+  var env = new TypeEnvironment(r"""
       typedef void Typedef1<X,Y>(X x1, Y y2);
       typedef void Typedef2<Z>(Z z1);
 
@@ -178,13 +152,10 @@
         void Typedef1e(Typedef2<S> a) {}
         void Typedef2e(Typedef2<String> b) {}
       }
+      """);
+  var compiler = env.compiler;
 
-      void main() {}
-      """,
-      uri);
-  compiler.runCompiler(uri);
-
-  DartType Class_T_S = getElementType(compiler, "Class");
+  InterfaceType Class_T_S = env["Class"];
   Expect.isNotNull(Class_T_S);
   Expect.identical(Class_T_S.kind, TypeKind.INTERFACE);
   Expect.equals(2, length(Class_T_S.typeArguments));
@@ -197,11 +168,11 @@
   Expect.isNotNull(S);
   Expect.identical(S.kind, TypeKind.TYPE_VARIABLE);
 
-  DartType intType = getType(compiler, "int1");
+  DartType intType = env['int'];//getType(compiler, "int1");
   Expect.isNotNull(intType);
   Expect.identical(intType.kind, TypeKind.INTERFACE);
 
-  DartType StringType = getType(compiler, "String1");
+  DartType StringType = env['String'];//getType(compiler, "String1");
   Expect.isNotNull(StringType);
   Expect.identical(StringType.kind, TypeKind.INTERFACE);
 
diff --git a/tests/compiler/dart2js/type_test_helper.dart b/tests/compiler/dart2js/type_test_helper.dart
new file mode 100644
index 0000000..94faace
--- /dev/null
+++ b/tests/compiler/dart2js/type_test_helper.dart
@@ -0,0 +1,50 @@
+// 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 type_test_helper;
+
+import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart';
+import "compiler_helper.dart";
+
+InterfaceType instantiate(ClassElement element, List<DartType> arguments) {
+  return new InterfaceType(element, new Link<DartType>.fromList(arguments));
+}
+
+class TypeEnvironment {
+  final MockCompiler compiler;
+
+  factory TypeEnvironment(String source) {
+    var uri = new Uri.fromComponents(scheme: 'source');
+    MockCompiler compiler = compilerFor('''
+        main() {}
+        $source''',
+        uri);
+    compiler.runCompiler(uri);
+    return new TypeEnvironment._(compiler);
+  }
+
+  TypeEnvironment._(MockCompiler this.compiler);
+
+  Element getElement(String name) {
+    var element = findElement(compiler, name);
+    Expect.isNotNull(element);
+    if (identical(element.kind, ElementKind.CLASS)) {
+      element.ensureResolved(compiler);
+    }
+    return element;
+  }
+
+  DartType getElementType(String name) {
+    return getElement(name).computeType(compiler);
+  }
+
+  DartType operator[] (String name) {
+    if (name == 'dynamic') return compiler.types.dynamicType;
+    return getElementType(name);
+  }
+
+  bool isSubtype(DartType T, DartType S) {
+    return compiler.types.isSubtype(T, S);
+  }
+}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index ddf9a3c..1660de8d 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -8,6 +8,8 @@
 typed_locals_test: Fail
 no_such_method_test: Fail # Wrong InvocationMirror.memberName.
 
+deferred_semantics_test/none: Fail # TODO(ahe): Multitest cannot use import.
+
 
 [ $compiler == dart2js && $checked ]
 parameter_bailout_test: Fail, OK
diff --git a/tests/compiler/dart2js_extra/deferred/deferred_class_library.dart b/tests/compiler/dart2js_extra/deferred/deferred_class_library.dart
new file mode 100644
index 0000000..bf9a9dd
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/deferred_class_library.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.
+
+// Imported by deferred_class_test.dart.
+
+library deferred_class_library;
+
+class MyClass {
+  foo(x) {
+    print('MyClass.foo($x)');
+    return (x - 3) ~/ 2;
+  }
+}
diff --git a/tests/compiler/dart2js_extra/deferred/deferred_class_test.dart b/tests/compiler/dart2js_extra/deferred/deferred_class_test.dart
new file mode 100644
index 0000000..1486e75
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/deferred_class_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 'dart:async';
+
+@lazy import 'deferred_class_library.dart';
+
+const lazy = const DeferredLibrary('deferred_class_library');
+
+isNoSuchMethodError(e) => e is NoSuchMethodError;
+
+main() {
+  var x;
+  Expect.throws(() { x = new MyClass(); }, isNoSuchMethodError);
+  Expect.isNull(x);
+  int counter = 0;
+  lazy.load().then((bool didLoad) {
+    Expect.isTrue(didLoad);
+    Expect.equals(1, ++counter);
+    print('deferred_class_library was loaded');
+    x = new MyClass();
+    Expect.equals(42, x.foo(87));
+  });
+  Expect.equals(0, counter);
+  Expect.isNull(x);
+  lazy.load().then((bool didLoad) {
+    Expect.isFalse(didLoad);
+    Expect.equals(2, ++counter);
+    print('deferred_class_library was loaded');
+    x = new MyClass();
+    Expect.equals(42, x.foo(87));
+  });
+  Expect.equals(0, counter);
+  Expect.isNull(x);
+  Expect.throws(() { x = new MyClass(); }, isNoSuchMethodError);
+  Expect.isNull(x);
+}
diff --git a/tests/compiler/dart2js_extra/deferred/deferred_function_library.dart b/tests/compiler/dart2js_extra/deferred/deferred_function_library.dart
new file mode 100644
index 0000000..0eaebc7
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/deferred_function_library.dart
@@ -0,0 +1,13 @@
+// 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.
+
+// Imported by deferred_function_test.dart and
+// deferred_semantics_test.dart.
+
+library deferred_function_library;
+
+foo(x) {
+  print('foo($x)');
+  return 42;
+}
diff --git a/tests/compiler/dart2js_extra/deferred/deferred_function_test.dart b/tests/compiler/dart2js_extra/deferred/deferred_function_test.dart
new file mode 100644
index 0000000..08eb6ac
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/deferred_function_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.
+
+// Test that loading of a library (with top-level functions only) can
+// be deferred.
+
+import 'dart:async';
+@lazy import 'deferred_function_library.dart';
+
+const lazy = const DeferredLibrary('deferred_function_library');
+
+isNoSuchMethodError(e) => e is NoSuchMethodError;
+
+main() {
+  print('unittest-suite-wait-for-done');
+
+  Expect.throws(() { foo('a'); }, isNoSuchMethodError);
+  int counter = 0;
+  lazy.load().then((bool didLoad) {
+    Expect.isTrue(didLoad);
+    Expect.equals(1, ++counter);
+    print('lazy was loaded');
+    Expect.equals(42, foo('b'));
+  });
+  Expect.equals(0, counter);
+  lazy.load().then((bool didLoad) {
+    Expect.isFalse(didLoad);
+    Expect.equals(2, ++counter);
+    print('lazy was loaded');
+    Expect.equals(42, foo('b'));
+    print('unittest-suite-success');
+  });
+  Expect.equals(0, counter);
+  Expect.throws(() { foo('a'); }, isNoSuchMethodError);
+}
diff --git a/tests/compiler/dart2js_extra/deferred/deferred_semantics_test.dart b/tests/compiler/dart2js_extra/deferred/deferred_semantics_test.dart
new file mode 100644
index 0000000..140faca
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred/deferred_semantics_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that deferred loading requires same library names.
+
+import 'dart:async';
+
+@lazy  /// 01: compile-time error
+import 'deferred_function_library.dart';
+
+const lazy = const DeferredLibrary('fisk');
+
+main() {
+}
diff --git a/tests/compiler/dart2js_extra/runtime_type_int_test.dart b/tests/compiler/dart2js_extra/runtime_type_int_test.dart
new file mode 100644
index 0000000..efb3861
--- /dev/null
+++ b/tests/compiler/dart2js_extra/runtime_type_int_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.
+
+// Test that in dart2js, the constant system matches the runtime
+// handling of numbers.
+
+main() {
+  var x = 10000000000000000;
+  var y = [x][0];
+  var a = x.runtimeType;
+  var b = y.runtimeType;
+
+  Expect.equals(x, y);
+  Expect.isTrue(x is int);
+  Expect.isTrue(y is int);
+  Expect.equals(x.runtimeType, int);
+  Expect.equals(y.runtimeType, int);
+}
diff --git a/tests/compiler/dart2js_native/compute_this_script_test.dart b/tests/compiler/dart2js_native/compute_this_script_test.dart
new file mode 100644
index 0000000..55092b4
--- /dev/null
+++ b/tests/compiler/dart2js_native/compute_this_script_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test of IsolateNatives.computeThisScript().
+
+import 'dart:_isolate_helper';
+
+main() {
+  String script = IsolateNatives.computeThisScript();
+
+  // This is somewhat brittle and relies on an implementation detail
+  // of our test runner, but I can think of no other way to test this.
+  // -- ahe
+  if (!script.endsWith('/out.js')) {
+    throw 'Unexpected script: "$script"';
+  }
+}
diff --git a/tests/compiler/dart2js_native/undefined_bailout_test.dart b/tests/compiler/dart2js_native/undefined_bailout_test.dart
new file mode 100644
index 0000000..d55fe7d
--- /dev/null
+++ b/tests/compiler/dart2js_native/undefined_bailout_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.
+
+// dart2js regression test where the SSA backend would use the wrong
+// type for an instruction: when doing a speculative type propagation,
+// if an instruction gets analyzed multiple times, we used to save the
+// last inferred type, which could be speculative, instead of the
+// first inferred type, which is the actual, non-speculative, type.
+//
+// Because we are doing speculative type propagation at the very end,
+// before emitting the bailout version, the only place where we might
+// do wrong optimizations is during the codegen. It turns out that the
+// codegen optimizes '==' comparisons on null to '===' in case it knows
+// the receiver cannot be null. So in the following example, the
+// [:e == null:] comparison in [foo] got wrongly generated to a
+// JavaScript identity check (that is, using '==='). But this
+// comparison does not work for undefined, which the DOM sometimes
+// returns.
+
+import 'dart:_foreign_helper' show JS;
+
+var a = 42;
+var b = 0;
+
+foo(e) {
+  // Loop to force a bailout.
+  for (int i = 0; i < b; i++) {
+    a = e[i]; // Will desire a readable primitive.
+  }
+  // Our heuristics for '==' on an indexable primitive is that it's
+  // more common to do it on string, so we'll want e to be a string.
+  return a == e || e == null;
+}
+
+main() {
+  Expect.isTrue(foo(JS('', 'void 0')));
+}
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 0e5f59b..8672c1c 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -47,7 +47,6 @@
 *: Fail, Pass # TODO(ahe): Triage these tests.
 
 [ $compiler == dart2js && $runtime == safari ]
-null_nosuchmethod_test: Fail # Issue: 7414
 core_runtime_types_test: Fail
 
 [ $compiler == dart2js && $runtime == ie9 ]
diff --git a/tests/html/crypto_test.dart b/tests/html/crypto_test.dart
new file mode 100644
index 0000000..0e06723
--- /dev/null
+++ b/tests/html/crypto_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.
+
+library crypto_test;
+import '../../pkg/unittest/lib/unittest.dart';
+import '../../pkg/unittest/lib/html_config.dart';
+import 'dart:html';
+
+main() {
+  useHtmlConfiguration();
+
+  test('exists', () {
+    var crypto = window.crypto;
+    expect(crypto is Crypto, isTrue);
+  });
+
+  test('successful call', () {
+    var crypto = window.crypto;
+    var data = new Uint8Array(100);
+    expect(data.every((e) => e == 0), isTrue);
+    crypto.getRandomValues(data);
+    // In theory this is flaky. However, in practice you will get 100 zeroes
+    // in a row from a cryptographically secure random number generator so
+    // rarely that we don't have to worry about it.
+    expect(data.any((e) => e != 0), isTrue);
+  });
+
+  test('type mismatch', () {
+    var crypto = window.crypto;
+    var data = new Float32Array(100);
+    expect(() {
+      crypto.getRandomValues(data);
+    }, throws, reason: 'Only typed array views with integer types allowed');
+  });
+}
diff --git a/tests/html/dromaeo_smoke-html.html b/tests/html/dromaeo_smoke-html.html
index 96d65b4..1cbeca4 100644
--- a/tests/html/dromaeo_smoke-html.html
+++ b/tests/html/dromaeo_smoke-html.html
@@ -4,8 +4,8 @@
 <html>
 <head>
 <script type="application/dart" src="dromaeo_noop/dromaeo_smoke.dart"></script>
-<script src='../../pkg/browser/lib/dart.js'></script>
-<script src='../../samples/third_party/dromaeo/htmlrunner.js'></script>
+<script src='/root_dart/pkg/browser/lib/dart.js'></script>
+<script src='/root_dart/samples/third_party/dromaeo/htmlrunner.js'></script>
 </head>
 <body>
 </body>
diff --git a/tests/html/dromaeo_smoke_test.dart b/tests/html/dromaeo_smoke_test.dart
index 686fe85..0463eff 100644
--- a/tests/html/dromaeo_smoke_test.dart
+++ b/tests/html/dromaeo_smoke_test.dart
@@ -24,7 +24,7 @@
   useHtmlConfiguration();
 
   var scriptSrc = new ScriptElement();
-  scriptSrc.src = '../../../../pkg/browser/lib/dart.js';
+  scriptSrc.src = '/root_dart/pkg/browser/lib/dart.js';
   document.head.children.add(scriptSrc);
   document.body.innerHtml = '''${document.body.innerHtml}
   <div id="main">
diff --git a/tests/html/element_classes_test.dart b/tests/html/element_classes_test.dart
index 966e5eb..65fc38f 100644
--- a/tests/html/element_classes_test.dart
+++ b/tests/html/element_classes_test.dart
@@ -5,6 +5,7 @@
 library ElementTest;
 import '../../pkg/unittest/lib/unittest.dart';
 import '../../pkg/unittest/lib/html_config.dart';
+import 'dart:collection';
 import 'dart:html';
 
 main() {
@@ -22,31 +23,31 @@
 
   Set<String> extractClasses(Element el) {
     final match = new RegExp('class="([^"]+)"').firstMatch(el.outerHtml);
-    return new Set.from(match[1].split(' '));
+    return new LinkedHashSet.from(match[1].split(' '));
   }
 
   test('affects the "class" attribute', () {
     final el = makeElementWithClasses();
     el.classes.add('qux');
-    expect(extractClasses(el), unorderedEquals(['foo', 'bar', 'baz', 'qux']));
+    expect(extractClasses(el), orderedEquals(['foo', 'bar', 'baz', 'qux']));
   });
 
   test('is affected by the "class" attribute', () {
     final el = makeElementWithClasses();
     el.attributes['class'] = 'foo qux';
-    expect(el.classes, unorderedEquals(['foo', 'qux']));
+    expect(el.classes, orderedEquals(['foo', 'qux']));
   });
 
   test('classes=', () {
     final el = makeElementWithClasses();
     el.classes = ['foo', 'qux'];
-    expect(el.classes, unorderedEquals(['foo', 'qux']));
-    expect(extractClasses(el), unorderedEquals(['foo', 'qux']));
+    expect(el.classes, orderedEquals(['foo', 'qux']));
+    expect(extractClasses(el), orderedEquals(['foo', 'qux']));
   });
 
   test('toString', () {
     expect(makeClassSet().toString().split(' '),
-        unorderedEquals(['foo', 'bar', 'baz']));
+        orderedEquals(['foo', 'bar', 'baz']));
     expect(makeElement().classes.toString(), '');
   });
 
@@ -55,7 +56,7 @@
     // TODO: Change to this when Issue 3484 is fixed.
     //    makeClassSet().forEach(classes.add);
     makeClassSet().forEach((c) => classes.add(c));
-    expect(classes, unorderedEquals(['foo', 'bar', 'baz']));
+    expect(classes, orderedEquals(['foo', 'bar', 'baz']));
   });
 
   test('iterator', () {
@@ -63,17 +64,17 @@
     for (var el in makeClassSet()) {
       classes.add(el);
     }
-    expect(classes, unorderedEquals(['foo', 'bar', 'baz']));
+    expect(classes, orderedEquals(['foo', 'bar', 'baz']));
   });
 
   test('map', () {
     expect(makeClassSet().map((c) => c.toUpperCase()).toList(),
-        unorderedEquals(['FOO', 'BAR', 'BAZ']));
+        orderedEquals(['FOO', 'BAR', 'BAZ']));
   });
 
   test('where', () {
     expect(makeClassSet().where((c) => c.contains('a')).toSet(),
-        unorderedEquals(['bar', 'baz']));
+        orderedEquals(['bar', 'baz']));
   });
 
   test('every', () {
@@ -104,41 +105,41 @@
   test('add', () {
     final classes = makeClassSet();
     classes.add('qux');
-    expect(classes, unorderedEquals(['foo', 'bar', 'baz', 'qux']));
+    expect(classes, orderedEquals(['foo', 'bar', 'baz', 'qux']));
 
     classes.add('qux');
     final list = new List.from(classes);
     list.sort((a, b) => a.compareTo(b));
-    expect(list, unorderedEquals(['bar', 'baz', 'foo', 'qux']),
+    expect(list, orderedEquals(['bar', 'baz', 'foo', 'qux']),
         reason: "The class set shouldn't have duplicate elements.");
   });
 
   test('remove', () {
     final classes = makeClassSet();
     classes.remove('bar');
-    expect(classes, unorderedEquals(['foo', 'baz']));
+    expect(classes, orderedEquals(['foo', 'baz']));
     classes.remove('qux');
-    expect(classes, unorderedEquals(['foo', 'baz']));
+    expect(classes, orderedEquals(['foo', 'baz']));
   });
 
   test('toggle', () {
     final classes = makeClassSet();
     classes.toggle('bar');
-    expect(classes, unorderedEquals(['foo', 'baz']));
+    expect(classes, orderedEquals(['foo', 'baz']));
     classes.toggle('qux');
-    expect(classes, unorderedEquals(['foo', 'baz', 'qux']));
+    expect(classes, orderedEquals(['foo', 'baz', 'qux']));
   });
 
   test('addAll', () {
     final classes = makeClassSet();
     classes.addAll(['bar', 'qux', 'bip']);
-    expect(classes, unorderedEquals(['foo', 'bar', 'baz', 'qux', 'bip']));
+    expect(classes, orderedEquals(['foo', 'bar', 'baz', 'qux', 'bip']));
   });
 
   test('removeAll', () {
     final classes = makeClassSet();
     classes.removeAll(['bar', 'baz', 'qux']);
-    expect(classes, unorderedEquals(['foo']));
+    expect(classes, orderedEquals(['foo']));
   });
 
   test('isSubsetOf', () {
@@ -165,4 +166,14 @@
     classes.clear();
     expect(classes, equals([]));
   });
+
+  test('order', () {
+    var classes = makeClassSet();
+    classes.add('aardvark');
+    expect(classes, orderedEquals(['foo', 'bar', 'baz', 'aardvark']));
+    classes.toggle('baz');
+    expect(classes, orderedEquals(['foo', 'bar', 'aardvark']));
+    classes.toggle('baz');
+    expect(classes, orderedEquals(['foo', 'bar', 'aardvark', 'baz']));
+  });
 }
diff --git a/tests/html/geolocation_test.dart b/tests/html/geolocation_test.dart
new file mode 100644
index 0000000..e6dd1b3
--- /dev/null
+++ b/tests/html/geolocation_test.dart
@@ -0,0 +1,18 @@
+ // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library geolocation_test;
+import '../../pkg/unittest/lib/unittest.dart';
+import '../../pkg/unittest/lib/html_config.dart';
+import 'dart:html';
+
+main() {
+  useHtmlConfiguration();
+
+  // Actual tests require browser interaction. This just makes sure the API
+  // is present.
+  test('is not null', () {
+    expect(window.navigator.geolocation, isNotNull);
+  });
+}
diff --git a/tests/html/html.status b/tests/html/html.status
index 0596b92..1f04561 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -1,4 +1,4 @@
-# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# 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.
 
@@ -7,21 +7,25 @@
 
 event_test: Skip  # Issue 1996
 custom_elements_test: Skip # Not yet implemented.
+interactive_test: Skip # Must be run manually.
 
 # Layout tests are only supported on DRT.
 [ $runtime == ie9 || $runtime == ie10 || $runtime == safari || $runtime == ff || $runtime == chrome || $runtime == opera ]
 *layout_test: Skip
 
+[ $runtime == drt || $runtime == dartium ]
+input_element_test/supported_datetime: Fail
+
 [ $runtime == chrome ]
-element_types_test/supported_content: Fail
-element_types_test/supported_shadow: Fail
+element_types_test/supported_content: Pass, Fail # Issue 8700
+element_types_test/supported_shadow: Pass, Fail # Issue 8700
 input_element_test/supported_date: Pass, Fail      # Chrome stable does not support this input type.
 input_element_test/supported_datetime: Fail
-input_element_test/supported_datetime-local: Fail
-input_element_test/supported_month: Fail
-input_element_test/supported_week: Fail
+input_element_test/supported_datetime-local: Pass, Fail # Issue 8700
+input_element_test/supported_month: Pass, Fail # Issue 8700
+input_element_test/supported_week: Pass, Fail # Issue 8700
 speechrecognition_test/supported: Pass, Fail       # Chrome stable does not support it.
-shadow_dom_test/supported: Fail
+shadow_dom_test/supported: Pass, Fail # Issue 8700
 speechrecognition_test/types: Pass, Fail
 touchevent_test/supported: Fail
 
@@ -52,6 +56,7 @@
 # TODO(efortuna, blois): Triage.
 audiobuffersourcenode_test: Fail
 audiocontext_test: Fail
+crypto_test: Fail
 css_test/supported_CssMatrix: Fail
 css_test/supported_DomPoint: Fail
 document_test/supports_cssCanvasContext: Fail
@@ -102,8 +107,10 @@
 xhr_test/supported_HttpRequestProgressEvent: Fail
 xsltprocessor_test/supported: Fail
 history_test/history: Pass, Fail # issue 8183
+canvasrenderingcontext2d_test: Fail # issue 8678
 
 [ $runtime == ie9 ]
+crypto_test: Fail
 document_test/supports_cssCanvasContext: Fail
 dromaeo_smoke_test: Skip #TODO(efortuna): investigating.
 element_test/click: Fail                # IE does not support firing this event.
@@ -236,6 +243,7 @@
 wheelevent_test: Fail # Issue: 7414
 
 [ $runtime == opera ]
+crypto_test: Fail
 document_test/supports_cssCanvasContext: Fail
 document_test/document: Fail # Issue: 7413
 form_data_test: Fail # Issue: 7413
@@ -279,6 +287,7 @@
 [ $runtime == ff ]
 audiobuffersourcenode_test: Fail # FF only has Audio element.
 audiocontext_test: Fail      # FF only has Audio element
+crypto_test: Fail
 css_test/supported_CssMatrix: Fail
 css_test/supported_DomPoint: Fail
 dart_object_local_storage_test: Skip  # sessionStorage NS_ERROR_DOM_NOT_SUPPORTED_ERR
diff --git a/tests/html/interactive_test.dart b/tests/html/interactive_test.dart
new file mode 100644
index 0000000..f688ee5b
--- /dev/null
+++ b/tests/html/interactive_test.dart
@@ -0,0 +1,65 @@
+ // 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 interactive_test;
+
+import 'dart:async';
+import 'dart:html';
+import '../../pkg/unittest/lib/unittest.dart';
+import '../../pkg/unittest/lib/html_individual_config.dart';
+import 'utils.dart';
+
+
+main() {
+  useHtmlIndividualConfiguration();
+
+  group('Geolocation', () {
+    futureTest('getCurrentPosition', () {
+      return window.navigator.geolocation.getCurrentPosition().then(
+        (position) {
+          expect(position.coords.latitude, isNotNull);
+          expect(position.coords.longitude, isNotNull);
+          expect(position.coords.accuracy, isNotNull);
+        });
+    });
+
+    futureTest('watchPosition', () {
+      return window.navigator.geolocation.watchPosition().first.then(
+        (position) {
+          expect(position.coords.latitude, isNotNull);
+          expect(position.coords.longitude, isNotNull);
+          expect(position.coords.accuracy, isNotNull);
+        });
+    });
+  });
+
+  group('MediaStream', () {
+    if (MediaStream.supported) {
+      futureTest('getUserMedia', () {
+        return window.navigator.getUserMedia(video: true).then((stream) {
+          expect(stream,  isNotNull);
+
+          var url = Url.createObjectUrl(stream);
+          expect(url,  isNotNull);
+
+          var video = new VideoElement()
+            ..autoplay = true;
+
+          var completer = new Completer();
+          video.onError.listen((e) {
+            completer.completeError(e);
+          });
+          video.onPlaying.first.then((e) {
+            completer.complete(video);
+          });
+
+          document.body.append(video);
+          video.src = url;
+
+          return completer.future;
+        });
+      });
+    }
+  });
+}
diff --git a/tests/html/websql_test.dart b/tests/html/websql_test.dart
index 16871b8..f98c6bb 100644
--- a/tests/html/websql_test.dart
+++ b/tests/html/websql_test.dart
@@ -3,6 +3,7 @@
 import '../../pkg/unittest/lib/html_individual_config.dart';
 import 'dart:async';
 import 'dart:html';
+import 'dart:web_sql';
 
 void fail(message) {
   guardAsync(() {
@@ -10,7 +11,7 @@
     });
 }
 
-Future<SqlTransaction> createTransaction(Database db) {
+Future<SqlTransaction> createTransaction(SqlDatabase db) {
   final completer = new Completer<SqlTransaction>();
 
   db.transaction((SqlTransaction transaction) {
@@ -91,13 +92,13 @@
 
   group('supported', () {
     test('supported', () {
-      expect(Database.supported, true);
+      expect(SqlDatabase.supported, true);
     });
   });
 
   group('functional', () {
     test('unsupported throws', () {
-      var expectation = Database.supported ? returnsNormally : throws;
+      var expectation = SqlDatabase.supported ? returnsNormally : throws;
       expect(() {
         window.openDatabase('test_db', '1.0', 'test_db', 1024 * 1024);
       }, expectation);
@@ -105,7 +106,7 @@
     });
     test('Web Database', () {
       // Skip if not supported.
-      if (!Database.supported) {
+      if (!SqlDatabase.supported) {
         return;
       }
 
diff --git a/tests/html/wheelevent_test.dart b/tests/html/wheelevent_test.dart
index 6de1528..2dc9adc 100644
--- a/tests/html/wheelevent_test.dart
+++ b/tests/html/wheelevent_test.dart
@@ -20,6 +20,7 @@
       expect(e.screenX, 100);
       expect(e.deltaX, 0);
       expect(e.deltaY, 240);
+      expect(e.deltaMode, isNotNull);
     }));
     var event = new WheelEvent(eventType,
       deltaX: 0,
diff --git a/tests/html/xhr_cross_origin_test.dart b/tests/html/xhr_cross_origin_test.dart
index 3bbb5ca..5f22ee7 100644
--- a/tests/html/xhr_cross_origin_test.dart
+++ b/tests/html/xhr_cross_origin_test.dart
@@ -30,7 +30,8 @@
   var port = crossOriginPort;
 
   test('XHR Cross-domain', () {
-    var url = "http://localhost:$port/tests/html/xhr_cross_origin_data.txt";
+    var url = "http://localhost:$port/"
+              "root_dart/tests/html/xhr_cross_origin_data.txt";
     var xhr = new HttpRequest();
     xhr.open('GET', url, true);
     var validate = expectAsync1((data) {
@@ -49,7 +50,8 @@
   });
 
   test('XHR.get Cross-domain', () {
-    var url = "http://localhost:$port/tests/html/xhr_cross_origin_data.txt";
+    var url = "http://localhost:$port/"
+              "root_dart/tests/html/xhr_cross_origin_data.txt";
     HttpRequest.request(url).then(expectAsync1((xhr) {
       var data = json.parse(xhr.response);
       expect(data, contains('feed'));
@@ -59,7 +61,8 @@
   });
 
   test('XHR.getWithCredentials Cross-domain', () {
-    var url = "http://localhost:$port/tests/html/xhr_cross_origin_data.txt";
+    var url = "http://localhost:$port/"
+              "root_dart/tests/html/xhr_cross_origin_data.txt";
     HttpRequest.request(url, withCredentials: true).then(expectAsync1((xhr) {
       var data = json.parse(xhr.response);
       expect(data, contains('feed'));
diff --git a/tests/html/xhr_test.dart b/tests/html/xhr_test.dart
index 6c8393c..91e86d5 100644
--- a/tests/html/xhr_test.dart
+++ b/tests/html/xhr_test.dart
@@ -17,7 +17,7 @@
 
 main() {
   useHtmlIndividualConfiguration();
-  var url = "/tests/html/xhr_cross_origin_data.txt";
+  var url = "/root_dart/tests/html/xhr_cross_origin_data.txt";
 
   void validate200Response(xhr) {
     expect(xhr.status, equals(200));
diff --git a/tests/language/field_override2_test.dart b/tests/language/field_override2_test.dart
new file mode 100644
index 0000000..0a08402
--- /dev/null
+++ b/tests/language/field_override2_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that we are accessing the right field in a method of a super
+// class, when that field is overridden.
+
+class A {
+  final a = [42];
+  foo() => a[0];
+}
+
+class B extends A {
+  final a = new Map();
+}
+
+main() {
+  Expect.equals(null, new B().foo());
+  Expect.equals(42, new A().foo());
+}
diff --git a/tests/language/inline_test.dart b/tests/language/inline_test.dart
new file mode 100644
index 0000000..3470a3e
--- /dev/null
+++ b/tests/language/inline_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js that used to produce a non-valid SSA
+// graph when inlining within a loop.
+
+class X {
+  void x(a, b) {
+   do {
+     if (identical(a, b)) {
+       break;
+     }
+   } while (p(a, b));
+  }
+
+  bool p(a, b) {
+   return identical(a, b);
+  }
+}
+
+main() {
+  var x = new X();
+  x.x(1, 2);
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 8d65af7..10d2a54 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -56,6 +56,8 @@
 
 type_parameter_literal_test: Fail # Issue 7551
 
+on_catch_malformed_type_test: Fail # Issue 8601
+
 mixin_illegal_syntax_test/none: Fail
 mixin_type_parameters_mixin_test: Fail
 mixin_type_parameters_super_test: Fail
@@ -349,6 +351,8 @@
 many_overridden_no_such_method_test: Fail, Pass, OK # Fails in minified mode, test depends on method names.
 overridden_no_such_method_test: Fail, Pass, OK # Fails in minified mode, test depends on method names.
 
+on_catch_malformed_type_test: Fail # Issue 8601
+
 # Mixins fail on the VM.
 mixin_illegal_syntax_test/none: Fail            # VM issue
 mixin_illegal_constructor_test/none: Fail       # VM issue
@@ -389,7 +393,6 @@
 compile_time_constant_arguments_test/05: Fail # http://dartbug.com/5519
 compile_time_constant_arguments_test/06: Fail # http://dartbug.com/5519
 const_constructor_syntax_test/04: Fail # http://dartbug.com/5519
-const_constructor_syntax_test/05: Fail # http://dartbug.com/5519
 const_syntax_test/01: Fail # http://dartbug.com/5519
 const_syntax_test/02: Fail # http://dartbug.com/5519
 const_syntax_test/03: Fail # http://dartbug.com/5519
@@ -398,7 +401,6 @@
 const_syntax_test/06: Fail # http://dartbug.com/5519
 const_syntax_test/07: Fail # http://dartbug.com/5519
 const_syntax_test/08: Fail # http://dartbug.com/5519
-const_syntax_test/09: Fail # http://dartbug.com/5519
 const_syntax_test/10: Fail # http://dartbug.com/5519
 constructor_named_arguments_test/01: Fail # http://dartbug.com/5519
 final_for_in_variable_test/01: Fail # http://dartbug.com/5519
@@ -407,7 +409,6 @@
 final_syntax_test/02: Fail # http://dartbug.com/5519
 final_syntax_test/03: Fail # http://dartbug.com/5519
 final_syntax_test/04: Fail # http://dartbug.com/5519
-final_syntax_test/09: Fail # http://dartbug.com/5519
 getter_no_setter_test/01: Fail # http://dartbug.com/5519
 getter_no_setter2_test/01: Fail # http://dartbug.com/5519
 illegal_invocation_test/03: Fail # http://dartbug.com/5519
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index de512aa..332f08d 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -48,7 +48,6 @@
 f_bounded_quantification_test/01: Fail
 f_bounded_quantification_test/02: Fail
 closure_type_test: Fail # does not detect type error in checked mode.
-function_type_test: Fail # does not detect type error in checked mode.
 factory1_test/00: Fail
 factory1_test/01: Fail
 type_annotation_test/09: Fail # Named constructors interpreted as a type.
@@ -198,6 +197,7 @@
 super_implicit_closure_test: Fail # internal error: super property read not implemented
 super_operator_test: Fail # internal error: super property store not implemented
 switch_label_test: Fail # error: target of continue is not a loop or switch case
+on_catch_malformed_type_test: Fail # Malformed types cause compile-time errors.
 
 
 # Failing tests for mixin type parameters.
@@ -266,8 +266,6 @@
 field5_negative_test: Fail # Negative language test.
 field6a_negative_test: Fail # Negative language test.
 final_for_in_variable_test/01: Fail # Negative language test
-final_param_negative_test: Fail # Negative language test.
-final_var_negative_test: Fail # Negative language test.
 instantiate_type_variable_negative_test: Pass  # For the wrong reason.
 interface_factory3_negative_test: Fail # Negative language test.
 interface_factory_constructor_negative_test: Fail # Negative language test.
@@ -283,9 +281,6 @@
 pseudo_kw_illegal_test/03: Fail # Negative language test.
 pseudo_kw_illegal_test/14: Fail # Negative language test.
 scope_negative_test: Fail # Negative language test.
-static_field_test/01: Fail # Negative language test.
-static_field_test/03: Fail # Negative language test.
-static_final_field2_negative_test: Fail # Negative language test.too
 static_final_field_negative_test: Fail # Negative language test.
 static_top_level_test/00: Fail # Negative language test.
 static_top_level_test/01: Fail # Negative language test.
@@ -331,11 +326,10 @@
 [ $compiler == dart2js && $runtime == none ]
 *: Fail, Pass # TODO(ahe): Triage these tests.
 
+
 [ $compiler == dart2js && ($runtime == ff || $runtime == jsshell || $runtime == ie9)]
 arithmetic_test: Fail # Issue 7881
 
-[ $compiler == dart2js && ($runtime == ff || $runtime == jsshell)]
-call_through_null_getter_test: Fail # Expected: ObjectNotClosureException got: Instance of 'TypeError'
 
 [ $compiler == dart2js && $runtime == ie9 ]
 div_by_zero_test: Fail
@@ -353,14 +347,12 @@
 execute_finally8_test: Fail # Issue: 7414
 execute_finally9_test: Fail # Issue: 7414
 null_access_error_test: Fail # Issue: 7414
-string_interpolate_null_test: Fail # Issue: 7414
-call_through_null_getter_test: Fail # Expected: ObjectNotClosureException got: Instance of 'TypeError'
 closure3_test: Fail # Uncaught error: Instance of 'TypeError'
-method_invocation_test: Fail # Uncaught error: Instance of 'TypeError'
 null_pointer_exception_test: Fail # Uncaught error: Instance of 'TypeError'
 string_interpolate_npe_test: Fail # Uncaught error: Instance of 'TypeError'
 arithmetic_test: Fail # Issue: 7414
 
+
 [ $runtime == opera ]
 null_access_error_test: Fail # Issue: 7413
 string_interpolate_null_test: Fail # Issue: 7413
diff --git a/tests/language/mixin_extends_method_test.dart b/tests/language/mixin_extends_method_test.dart
index 9465ff0..e9423e4 100644
--- a/tests/language/mixin_extends_method_test.dart
+++ b/tests/language/mixin_extends_method_test.dart
@@ -8,7 +8,8 @@
 }
 
 class M1 {
-  bar() => "M1-bar";
+  static m1bar() => "M1-bar";
+  bar() => m1bar();
 }
 
 class M2 {
diff --git a/tests/language/mixin_override_regression_test.dart b/tests/language/mixin_override_regression_test.dart
new file mode 100644
index 0000000..bbc9b89
--- /dev/null
+++ b/tests/language/mixin_override_regression_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class C0 {
+  int m1() => 5;
+  int m2() => m1();
+}
+
+typedef C1 = Object with C0;
+
+class D {
+  int m1() => 7;
+}
+
+class E0 extends C0 with D {}
+class E1 extends C1 with D {}
+
+main() {
+  Expect.equals(7, new E0().m2());
+  Expect.equals(7, new E1().m2());
+}
diff --git a/tests/language/on_catch_malformed_type_test.dart b/tests/language/on_catch_malformed_type_test.dart
new file mode 100644
index 0000000..ae5e043
--- /dev/null
+++ b/tests/language/on_catch_malformed_type_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Check that malformed types in on-catch are handled correctly, that is
+// catches all in production mode and throws a type error in checked mode.
+
+isCheckedMode() {
+  try {
+    String s = 1;
+    return false;
+  } on TypeError catch(e) {
+    return true;
+  }
+}
+
+checkTypeError(f()) {
+  if(isCheckedMode()) {
+    try {
+      f();
+      Expect.fail("Type error expected in checking mode");
+    } on TypeError catch(ok) {
+    }
+  } else {
+    f();
+  }
+}
+
+catchUnresolvedBefore() {
+  try {
+    throw "foo";
+    Expect.fail("This code shouldn't be executed");
+  } on String catch(oks) {
+    // This is tested before the catch block below.
+  } on Unavailable catch(ex) {
+    Expect.fail("This code shouldn't be executed");
+  }
+}
+
+catchUnresolvedAfter() {
+  try {
+    throw "foo";
+    Expect.fail("This code shouldn't be executed");
+  } on Unavailable catch(ex) {
+    // This is tested before the catch block below.
+    // In production mode the test is always true, in checked mode
+    // it throws a type error.
+  } on String catch(oks) {
+    Expect.fail("This code shouldn't be executed");
+  }
+}
+
+main() {
+  catchUnresolvedBefore();
+  checkTypeError(catchUnresolvedAfter);
+}
diff --git a/tests/lib/async/deferred/deferred_api_library.dart b/tests/lib/async/deferred/deferred_api_library.dart
new file mode 100644
index 0000000..b590770
--- /dev/null
+++ b/tests/lib/async/deferred/deferred_api_library.dart
@@ -0,0 +1,12 @@
+// 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.
+
+// Imported by deferred_api_test.dart.
+
+library deferred_api_library;
+
+foo(x) {
+  print('foo($x)');
+  return 42;
+}
diff --git a/tests/lib/async/deferred/deferred_api_test.dart b/tests/lib/async/deferred/deferred_api_test.dart
new file mode 100644
index 0000000..a144468
--- /dev/null
+++ b/tests/lib/async/deferred/deferred_api_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.
+
+// Test that that the basic API for deferred/lazy loading works.  This
+// test deliberately does not test that the deferred elements throw a
+// NoSuchMethodError before the deferred library is loaded.  This
+// makes it possible to pass this test without having implemented
+// deferred loading correctly.
+
+import 'dart:async';
+
+@lazy
+import 'deferred_api_library.dart';
+
+const lazy = const DeferredLibrary('deferred_api_library');
+
+main() {
+  print('unittest-suite-wait-for-done');
+
+  int counter = 0;
+  lazy.load().then((bool didLoad) {
+    Expect.isTrue(didLoad);
+    Expect.equals(1, ++counter);
+    Expect.equals(42, foo('b'));
+    print('lazy was loaded');
+  });
+  Expect.equals(0, counter);
+  lazy.load().then((bool didLoad) {
+    Expect.isFalse(didLoad);
+    Expect.equals(2, ++counter);
+    Expect.equals(42, foo('b'));
+    print('lazy was loaded');
+    print('unittest-suite-success');
+  });
+  Expect.equals(0, counter);
+}
diff --git a/tests/lib/async/slow_consumer_test.dart b/tests/lib/async/slow_consumer_test.dart
index 4b14924..2d40658 100644
--- a/tests/lib/async/slow_consumer_test.dart
+++ b/tests/lib/async/slow_consumer_test.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// VMOptions=--old_gen_heap_size=32
+// VMOptions=--old_gen_heap_size=64
 
 library slow_consumer_test;
 
@@ -20,6 +20,7 @@
   SlowConsumer(int this.bytesPerSecond);
 
   Future consume(Stream stream) {
+    bool done = false;
     Completer completer = new Completer();
     var subscription;
     subscription = stream.listen(
@@ -29,15 +30,18 @@
             // Simulated amount of time it takes to handle the data.
             int ms = data.length * 1000 ~/ bytesPerSecond;
             Duration duration = new Duration(milliseconds: ms);
-            subscription.pause();
+            if (!done) subscription.pause();
             return new Future.delayed(duration, () {
-              subscription.resume();
+              if (!done) subscription.resume();
               // Make sure we use data here to keep tracking it.
               return count + data.length;
             });
           });
         },
-      onDone: () { current.then((count) { completer.complete(count); }); });
+      onDone: () {
+        done = true;
+        current.then((count) { completer.complete(count); });
+      });
     return completer.future;
   }
 }
@@ -48,6 +52,7 @@
   int sentCount = 0;
   int targetCount;
   StreamController controller;
+  Timer pendingSend;
 
   DataProvider(int this.bytesPerSecond, int this.targetCount, this.chunkSize) {
     controller = new StreamController(onPauseStateChange: onPauseStateChange);
@@ -57,6 +62,10 @@
   Stream get stream => controller.stream;
 
   send() {
+    if (pendingSend != null) {
+      pendingSend.cancel();
+      pendingSend = null;
+    }
     if (controller.isPaused) return;
     if (sentCount == targetCount) {
       controller.close();
@@ -71,7 +80,9 @@
     controller.add(new List.fixedLength(listSize));
     int ms = listSize * 1000 ~/ bytesPerSecond;
     Duration duration = new Duration(milliseconds: ms);
-    if (!controller.isPaused) new Timer(duration, send);
+    if (!controller.isPaused) {
+      pendingSend = new Timer(duration, send);
+    }
   }
 
   onPauseStateChange() {
@@ -87,7 +98,7 @@
   // the slower consumer who can only read 200MB/s. The data is sent in 1MB
   // chunks.
   //
-  // This test is limited to 32MB of heap-space (see VMOptions on top of the
+  // This test is limited to 64MB of heap-space (see VMOptions on top of the
   // file). If the consumer doesn't pause the data-provider it will run out of
   // heap-space.
 
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 8381332..73efcec 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -2,10 +2,15 @@
 # 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.
 
+async/slow_consumer_test: Skip # Issue 8647
+
 [ $compiler == dart2js ]
 math/*: Skip
 mirrors/*: Skip
 
+[ $compiler == dart2js && $checked ]
+async/stream_event_transform_test: Fail # Issue 7733.
+
 [ $compiler == dart2js && $jscl ]
 async/future_test: Fail # Timer interface not supported; dartbug.com/7728.
 async/slow_consumer2_test: Fail # Timer interface not supported; dartbug.com/7728.
@@ -17,9 +22,6 @@
 crypto/sha256_test: Slow, Pass
 crypto/sha1_test: Slow, Pass
 
-[ $runtime == safari]
-crypto/hmac_md5_test: Fail # Bug in JSC: the test only passes when being debugged.
-
 [ $compiler == dart2dart ]
 # Skip until we stabilize language tests.
 *: Skip
@@ -29,9 +31,16 @@
 crypto/hmac_sha1_test: Fail
 crypto/hmac_sha256_test: Fail
 
+[ $runtime == safari]
+ # Bug in JSC: the test only passes when being debugged.
+crypto/hmac_md5_test: Fail, Pass
+
 [ $runtime == vm && $arch == x64 ]
 async/slow_consumer2_test: Fail # Issue 7726
 
+[ $compiler == none && $runtime == drt ]
+async/deferred/deferred_api_test: Fail # http://dartbug.com/2264
+
 [ $arch == arm ]
 *: Skip
 
diff --git a/tests/standalone/debugger/debug_lib.dart b/tests/standalone/debugger/debug_lib.dart
index 6a38ca4..d71f3e6 100644
--- a/tests/standalone/debugger/debug_lib.dart
+++ b/tests/standalone/debugger/debug_lib.dart
@@ -310,8 +310,6 @@
   Process targetProcess;
   int portNumber;
   Socket socket;
-  OutputStream to;
-  StringInputStream from;
   JsonBuffer responses = new JsonBuffer();
 
   DebugScript script;
@@ -324,22 +322,33 @@
   String scriptUrl = null;
   bool shutdownEventSeen = false;
   int isolateId = 0;
-  
+
+  // stdin subscription to allow terminating the test via command-line.
+  var stdinSubscription;
+
   Debugger(this.targetProcess, this.portNumber) {
-    var targetStdout = new StringInputStream(targetProcess.stdout);
-    targetStdout.onLine = () {
-      var s = targetStdout.readLine();
+    stdinSubscription =
+        stdin.listen((d) {},
+                     onError: (error) => close(killDebugee: true),
+                     onDone: () => close(killDebugee: true));
+
+    var stdoutStringStream = targetProcess.stdout
+        .transform(new StringDecoder())
+        .transform(new LineTransformer());
+    stdoutStringStream.listen((line) {
       if (showDebuggeeOutput) {
-        print("TARG: $s");
+        print("TARG: $line");
       }
-    };
-    var targetStderr = new StringInputStream(targetProcess.stderr);
-    targetStderr.onLine = () {
-      var s = targetStderr.readLine();
+    });
+
+    var stderrStringStream = targetProcess.stderr
+        .transform(new StringDecoder())
+        .transform(new LineTransformer());
+    stderrStringStream.listen((line) {
       if (showDebuggeeOutput) {
-        print("TARG: $s");
+        print("TARG: $line");
       }
-    };
+    });
   }
 
   // Handle debugger events for which there is no explicit
@@ -451,7 +460,7 @@
   void sendMessage(Map<String,dynamic> msg) {
     String jsonMsg = JSON.stringify(msg);
     if (verboseWire) print("SEND: $jsonMsg");
-    to.writeString(jsonMsg, Encoding.UTF_8);
+    socket.addString(jsonMsg);
   }
 
   bool get errorsDetected => errors.length > 0;
@@ -462,34 +471,36 @@
   }
 
   void openConnection() {
-    socket = new Socket("127.0.0.1", portNumber);
-    to = socket.outputStream;
-    from = new StringInputStream(socket.inputStream, Encoding.UTF_8);
-    from.onData = () {
-      try {
-        responses.append(from.read());
-        handleMessages();
-      } catch(e, trace) {
-        print("Unexpected exception:\n$e\n$trace");
-        close(killDebugee: true);
-      }
-    };
-    from.onClosed = () {
-      print("Connection closed by debug target");
-      close(killDebugee: true);
-    };
-    from.onError = (e) {
-      print("Error '$e' detected in input stream from debug target");
-      close(killDebugee: true);
-    };
+    Socket.connect("127.0.0.1", portNumber).then((s) {
+      socket = s;
+      var stringStream = socket.transform(new StringDecoder());
+      stringStream.listen(
+          (str) {
+            try {
+              responses.append(str);
+              handleMessages();
+            } catch(e, trace) {
+              print("Unexpected exception:\n$e\n$trace");
+              close(killDebugee: true);
+            }
+          },
+          onDone: () {
+            print("Connection closed by debug target");
+            close(killDebugee: true);
+          },
+          onError: (e) {
+            print("Error '$e' detected in input stream from debug target");
+            close(killDebugee: true);
+          });
+      });
   }
 
   void close({killDebugee: false}) {
     if (errorsDetected) {
       for (int i = 0; i < errors.length; i++) print(errors[i]);
     }
-    to.close();
     socket.close();
+    stdinSubscription.cancel();
     if (killDebugee) {
       targetProcess.kill();
       print("Target process killed");
@@ -518,15 +529,12 @@
   Process.start(options.executable, targetOpts).then((Process process) {
     print("Debug target process started");
     process.stdin.close();
-    process.stdout.onData = process.stdout.read;
-    process.stderr.onData = process.stderr.read;
-    process.onExit = (int exitCode) {
+    process.exitCode.then((int exitCode) {
+      Expect.equals(0, exitCode);
       Expect.equals(0, exitCode);
       print("Debug target process exited with exit code $exitCode");
-    };
+    });
     var debugger = new Debugger(process, debugPort);
-    stdin.onClosed = () => debugger.close(killDebugee: true);
-    stdin.onError = (error) => debugger.close(killDebugee: true);
     debugger.runScript(script);
   });
   return true;
diff --git a/tests/standalone/io/chunked_stream_test.dart b/tests/standalone/io/chunked_stream_test.dart
deleted file mode 100644
index 2f34378..0000000
--- a/tests/standalone/io/chunked_stream_test.dart
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-import "dart:isolate";
-
-void test1() {
-  void testWithChunkSize(var data, int chunkSize, Function testDone) {
-    ListInputStream list_input_stream = new ListInputStream();
-    list_input_stream.write(data);
-    list_input_stream.markEndOfStream();
-    ChunkedInputStream stream = new ChunkedInputStream(list_input_stream);
-    int chunkCount = 0;
-    int byteCount = 0;
-    void chunkData() {
-      List<int> chunk = stream.read();
-      if (byteCount + chunkSize < data.length) {
-        Expect.equals(chunkSize, chunk.length);
-      } else {
-        if (byteCount == data.length) {
-          Expect.equals(null, chunk);
-        } else {
-          Expect.equals(data.length - byteCount, chunk.length);
-        }
-      }
-      if (chunk != null) {
-        for (int i = 0; i < chunk.length;i++) {
-          Expect.equals(data[byteCount], chunk[i]);
-          byteCount++;
-        }
-        chunkCount++;
-      }
-    }
-
-    void closeHandler() {
-      Expect.equals(data.length, byteCount);
-      testDone(byteCount);
-    }
-
-    stream.onData = chunkData;
-    stream.onClosed = closeHandler;
-    stream.chunkSize = chunkSize;
-  }
-
-  for (int i = 1; i <= 10; i++) {
-    var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
-
-    void testDone(int byteCount) {
-      Expect.equals(data.length, byteCount);
-    }
-
-    testWithChunkSize(data, i, testDone);
-  }
-
-  var _16k = 1024 * 16;
-  var data = new List<int>.fixedLength(_16k);
-  for (int i = 0; i < _16k; i++) { data[i] = i % 256; }
-
-  void testDone(int byteCount) {
-    Expect.equals(data.length, byteCount);
-  }
-
-  testWithChunkSize(data, 512, testDone);
-  testWithChunkSize(data, 1024, testDone);
-  testWithChunkSize(data, 2048, testDone);
-}
-
-
-void test2() {
-  ListInputStream s = new ListInputStream();
-  ChunkedInputStream stream = new ChunkedInputStream(s);
-  stream.chunkSize = 5;
-  ReceivePort donePort = new ReceivePort();
-
-  var stage = 0;
-
-  void chunkData() {
-    var chunk;
-    if (stage == 0) {
-      Expect.equals(stream.chunkSize, 5);
-      chunk = stream.read();  // 5 bytes read from stream.
-      Expect.equals(stream.chunkSize, chunk.length);
-      chunk = stream.read();  // 5 bytes read from stream.
-      Expect.equals(null, chunk);
-      stage++;
-      s.write([7, 8, 9]);  // 10 bytes written to stream.
-    } else if (stage == 1) {
-      Expect.equals(stream.chunkSize, 5);
-      chunk = stream.read();  // 10 bytes read from stream.
-      Expect.equals(stream.chunkSize, chunk.length);
-      chunk = stream.read();  // 10 bytes read from stream.
-      Expect.equals(null, chunk);
-      stage++;
-      s.write([10, 11, 12, 13, 14]);  // 15 bytes written to stream.
-      s.write([15, 16, 17, 18]);  // 19 bytes written to stream.
-    } else if (stage == 2) {
-      Expect.equals(stream.chunkSize, 5);
-      chunk = stream.read();  // 15 bytes read from stream.
-      Expect.equals(stream.chunkSize, chunk.length);
-      chunk = stream.read();  // 15 bytes read from stream.
-      Expect.equals(null, chunk);
-      stage++;
-      stream.chunkSize = 3;
-    } else if (stage == 3) {
-      Expect.equals(stream.chunkSize, 3);
-      chunk = stream.read();  // 18 bytes read from stream.
-      Expect.equals(stream.chunkSize, chunk.length);
-      chunk = stream.read();  // 18 bytes read from stream.
-      Expect.equals(null, chunk);
-      stage++;
-      s.markEndOfStream();  // 18 bytes written to stream.
-    } else if (stage == 4) {
-      chunk = stream.read();  // 19 bytes read from stream.
-      Expect.equals(1, chunk.length);
-      chunk = stream.read();  // 19 bytes read from stream.
-      Expect.equals(null, chunk);
-      stage++;
-      donePort.toSendPort().send(stage);
-    }
-  }
-
-  void streamClosed() {
-    Expect.equals(5, stage);
-  }
-
-  stream.onData = chunkData;
-  stream.onClosed = streamClosed;
-  s.write([0, 1, 2, 3]);  // 4 bytes written to stream.
-  Expect.equals(0, stage);
-  s.write([4, 5, 6]);  // 7 bytes written to stream.
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-
-main() {
-  test1();
-  test2();
-}
diff --git a/tests/standalone/io/dart_std_io_pipe_test.dart b/tests/standalone/io/dart_std_io_pipe_test.dart
index 967c48a..a4d4f24 100644
--- a/tests/standalone/io/dart_std_io_pipe_test.dart
+++ b/tests/standalone/io/dart_std_io_pipe_test.dart
@@ -42,7 +42,7 @@
       [executable, dartScript, type, pipeOutFile, redirectOutFile];
   var future = Process.start(shellScript, args);
   future.then((process) {
-    process.onExit = (exitCode) {
+    process.exitCode.then((exitCode) {
       Expect.equals(0, exitCode);
 
       // Check the expected file contents.
@@ -66,10 +66,10 @@
 
       // Cleanup test directory.
       dir.deleteSync(recursive: true);
-    };
+    });
     // Drain out and err streams so they close.
-    process.stdout.onData = process.stdout.read;
-    process.stderr.onData = process.stderr.read;
+    process.stdout.listen((_) {});
+    process.stderr.listen((_) {});
   });
   future.catchError((error) {
     dir.deleteSync(recursive: true);
diff --git a/tests/standalone/io/delete_symlink_test.dart b/tests/standalone/io/delete_symlink_test.dart
new file mode 100644
index 0000000..3161eb4
--- /dev/null
+++ b/tests/standalone/io/delete_symlink_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+import 'dart:isolate';
+
+void main() {
+  // temp/
+  //   a/
+  //     file.txt
+  //   b/
+  //     a_link -> a
+  var d = new Directory("").createTempSync();
+  var a = new Directory("${d.path}/a");
+  a.createSync();
+
+  var b = new Directory("${d.path}/b");
+  b.createSync();
+
+  var f = new File("${d.path}/a/file.txt");
+  f.createSync();
+  Expect.isTrue(f.existsSync());
+
+  // Create a symlink (or junction on Windows) from
+  // temp/b/a_link to temp/a.
+  var cmd = "ln";
+  var args = ['-s', "${d.path}/b/a_link", "${d.path}/a"];
+
+  if (Platform.operatingSystem == "windows") {
+    cmd = "cmd";
+    args = ["/c", "mklink", "/j", "${d.path}\\b\\a_link", "${d.path}\\a"];
+  }
+
+  var keepAlive = new ReceivePort();
+
+  Process.run(cmd, args).then((_) {
+    // Delete the directory containing the junction.
+    b.deleteSync(recursive: true);
+
+    // We should not have recursed through a_link into a.
+    Expect.isTrue(f.existsSync());
+
+    // Clean up after ourselves.
+    d.deleteSync(recursive: true);
+
+    // Terminate now that we are done with everything.
+    keepAlive.close();
+  });
+}
diff --git a/tests/standalone/io/directory_error_test.dart b/tests/standalone/io/directory_error_test.dart
index ed2b60c..950f025 100644
--- a/tests/standalone/io/directory_error_test.dart
+++ b/tests/standalone/io/directory_error_test.dart
@@ -4,6 +4,7 @@
 //
 // Dart test program for testing error handling in directory I/O.
 
+import "dart:async";
 import "dart:io";
 import "dart:isolate";
 
@@ -133,14 +134,21 @@
 }
 
 
+bool checkAsyncListNonExistentFileException(e) {
+  Expect.isTrue(e is AsyncError);
+  return checkListNonExistentFileException(e.error);
+}
+
+
 void testListNonExistent(Directory temp, Function done) {
   Directory nonExistent = new Directory("${temp.path}/nonExistent");
   Expect.throws(() => nonExistent.listSync(), (e) => e is DirectoryIOException);
-  var lister = nonExistent.list();
-  lister.onError = (e) {
-    checkListNonExistentFileException(e);
-    done();
-  };
+  nonExistent.list().listen(
+      (_) => Expect.fail("listing should not succeed"),
+      onError: (e) {
+        checkAsyncListNonExistentFileException(e);
+        done();
+      });
 }
 
 
diff --git a/tests/standalone/io/directory_fuzz_test.dart b/tests/standalone/io/directory_fuzz_test.dart
index 967ac0e..c1dadef 100644
--- a/tests/standalone/io/directory_fuzz_test.dart
+++ b/tests/standalone/io/directory_fuzz_test.dart
@@ -30,7 +30,6 @@
       typeMapping.forEach((k2, v2) {
         doItSync(() => d.renameSync(v2));
         doItSync(() => d.listSync(recursive: v2));
-        doItSync(() => d.list(recursive: v2).onError = (e) => null);
       });
     });
   });
@@ -57,6 +56,9 @@
     }));
     typeMapping.forEach((k2, v2) {
       futures.add(doItAsync(() => d.rename(v2)));
+      futures.add(doItAsync(() {
+        d.list(recursive: v2).listen((_) {}, onError: (e) => null);
+      }));
     });
   });
   Future.wait(futures).then((ignore) => port.close());
diff --git a/tests/standalone/io/directory_invalid_arguments_test.dart b/tests/standalone/io/directory_invalid_arguments_test.dart
index 029eccd..54cdfda 100644
--- a/tests/standalone/io/directory_invalid_arguments_test.dart
+++ b/tests/standalone/io/directory_invalid_arguments_test.dart
@@ -3,55 +3,52 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:io";
+import "dart:isolate";
 
-class DirectoryInvalidArgumentsTest {
-  static void testFailingList(Directory d, var recursive) {
-    int errors = 0;
-    var lister = d.list(recursive: recursive);
-    lister.onError = (error) {
+void testFailingList(Directory d, var recursive) {
+  var port = new ReceivePort();
+  int errors = 0;
+  d.list(recursive: recursive).listen(
+    () => Expect.fail("Unexpected listing result"),
+    onError: (error) {
       errors += 1;
-    };
-    lister.onDone = (completed) {
+    },
+    onDone: () {
+      port.close();
       Expect.equals(1, errors);
-      Expect.isFalse(completed);
-    };
-    Expect.equals(0, errors);
-  }
+    });
+  Expect.equals(0, errors);
+}
 
-  static void testInvalidArguments() {
-    Directory d = new Directory(12);
-    try {
-      d.existsSync();
-      Expect.fail("No exception thrown");
-    } catch (e) {
-      Expect.isTrue(e is ArgumentError);
-    }
-    try {
-      d.deleteSync();
-      Expect.fail("No exception thrown");
-    } catch (e) {
-      Expect.isTrue(e is ArgumentError);
-    }
-    try {
-      d.createSync();
-      Expect.fail("No exception thrown");
-    } catch (e) {
-      Expect.isTrue(e is ArgumentError);
-    }
-    testFailingList(d, false);
-    Expect.throws(() => d.listSync(recursive: true),
-                  (e) => e is ArgumentError);
-    d = new Directory(".");
-    testFailingList(d, 1);
-    Expect.throws(() => d.listSync(recursive: 1),
-                  (e) => e is ArgumentError);
+void testInvalidArguments() {
+  Directory d = new Directory(12);
+  try {
+    d.existsSync();
+    Expect.fail("No exception thrown");
+  } catch (e) {
+    Expect.isTrue(e is ArgumentError);
   }
-
-  static void testMain() {
-    testInvalidArguments();
+  try {
+    d.deleteSync();
+    Expect.fail("No exception thrown");
+  } catch (e) {
+    Expect.isTrue(e is ArgumentError);
   }
+  try {
+    d.createSync();
+    Expect.fail("No exception thrown");
+  } catch (e) {
+    Expect.isTrue(e is ArgumentError);
+  }
+  testFailingList(d, false);
+  Expect.throws(() => d.listSync(recursive: true),
+                (e) => e is ArgumentError);
+  d = new Directory(".");
+  testFailingList(d, 1);
+  Expect.throws(() => d.listSync(recursive: 1),
+                (e) => e is ArgumentError);
 }
 
 main() {
-  DirectoryInvalidArgumentsTest.testMain();
+  testInvalidArguments();
 }
diff --git a/tests/standalone/io/directory_list_nonexistent_test.dart b/tests/standalone/io/directory_list_nonexistent_test.dart
index 81c9ac0..e07cb22 100644
--- a/tests/standalone/io/directory_list_nonexistent_test.dart
+++ b/tests/standalone/io/directory_list_nonexistent_test.dart
@@ -11,16 +11,19 @@
 import "dart:isolate";
 
 void testListNonExistent() {
+  var keepAlive = new ReceivePort();
   new Directory("").createTemp().then((d) {
     d.delete().then((ignore) {
       Expect.throws(() => d.listSync(), (e) => e is DirectoryIOException);
       Expect.throws(() => d.listSync(recursive: true),
                     (e) => e is DirectoryIOException);
+      keepAlive.close();
     });
   });
 }
 
 void testListTooLongName() {
+  var keepAlive = new ReceivePort();
   new Directory("").createTemp().then((d) {
     var subDirName = 'subdir';
     var subDir = new Directory("${d.path}/$subDirName");
@@ -37,6 +40,8 @@
                     (e) => e is DirectoryIOException);
       Expect.throws(() => long.listSync(recursive: true),
                     (e) => e is DirectoryIOException);
+      d.deleteSync(recursive: true);
+      keepAlive.close();
     });
   });
 }
diff --git a/tests/standalone/io/directory_test.dart b/tests/standalone/io/directory_test.dart
index 8a3776a..0d6500e 100644
--- a/tests/standalone/io/directory_test.dart
+++ b/tests/standalone/io/directory_test.dart
@@ -50,31 +50,33 @@
     testSyncListing(false);
     Expect.equals(f.fullPathSync(), fLong.fullPathSync());
 
-    var lister = directory.list(recursive: true);
-
-    lister.onDir = (dir) {
-      listedDir = true;
-      Expect.isTrue(dir.contains(directory.path));
-      Expect.isTrue(dir.contains('subdir'));
-    };
-
-    lister.onFile = (f) {
-      listedFile = true;
-      Expect.isTrue(f.contains(directory.path));
-      Expect.isTrue(f.contains('subdir'));
-      Expect.isTrue(f.contains('file.txt'));
-    };
-
-    lister.onDone = (completed) {
-      Expect.isTrue(completed, "directory listing did not complete");
-      Expect.isTrue(listedDir, "directory not found");
-      Expect.isTrue(listedFile, "file not found");
-      directory.delete(recursive: true).then((ignore) {
-        f.exists().then((exists) => Expect.isFalse(exists));
-        directory.exists().then((exists) => Expect.isFalse(exists));
-        subDirectory.exists().then((exists) => Expect.isFalse(exists));
-      });
-    };
+    var listingDonePort = new ReceivePort();
+    directory.list(recursive: true).listen(
+        (FileSystemEntity entity) {
+          if (entity is File) {
+            var path = entity.name;
+            listedFile = true;
+            Expect.isTrue(path.contains(directory.path));
+            Expect.isTrue(path.contains('subdir'));
+            Expect.isTrue(path.contains('file.txt'));
+          } else {
+            var path = entity.path;
+            Expect.isTrue(entity is Directory);
+            listedDir = true;
+            Expect.isTrue(path.contains(directory.path));
+            Expect.isTrue(path.contains('subdir'));
+          }
+        },
+        onDone: () {
+          Expect.isTrue(listedDir, "directory not found");
+          Expect.isTrue(listedFile, "file not found");
+          directory.delete(recursive: true).then((ignore) {
+            f.exists().then((exists) => Expect.isFalse(exists));
+            directory.exists().then((exists) => Expect.isFalse(exists));
+            subDirectory.exists().then((exists) => Expect.isFalse(exists));
+            listingDonePort.close();
+          });
+        });
 
     // Listing is asynchronous, so nothing should be listed at this
     // point.
@@ -83,20 +85,13 @@
   }
 
   static void testListNonExistent() {
-    setupListerHandlers(DirectoryLister lister) {
-      // Test that listing a non-existing directory fails.
-      lister.onError = (e) {
-        Expect.isTrue(e is DirectoryIOException);
-      };
-      lister.onFile = (file) {
-        Expect.fail("Listing of non-existing directory should fail");
-      };
-      lister.onDir = (dir) {
-        Expect.fail("Listing of non-existing directory should fail");
-      };
-      lister.onDone = (success) {
-        Expect.isFalse(success);
-      };
+    setupListerHandlers(Stream<FileSystemEntity> stream) {
+      stream.listen(
+          (_) => Expect.fail("Listing of non-existing directory should fail"),
+          onError: (e) {
+            Expect.isTrue(e is AsyncError);
+            Expect.isTrue(e.error is DirectoryIOException);
+          });
     }
     new Directory("").createTemp().then((d) {
       d.delete().then((ignore) {
@@ -109,22 +104,19 @@
   static void testListTooLongName() {
     new Directory("").createTemp().then((d) {
       var errors = 0;
-      setupListHandlers(DirectoryLister lister) {
-        lister.onError = (e) {
-          Expect.isTrue(e is DirectoryIOException);
-          if (++errors == 2) {
-            d.delete(recursive: true);
-          }
-        };
-        lister.onFile = (file) {
-          Expect.fail("Listing of non-existing directory should fail");
-        };
-        lister.onDir = (dir) {
-          Expect.fail("Listing of non-existing directory should fail");
-        };
-        lister.onDone = (success) {
-          Expect.isFalse(success);
-        };
+      var port = new ReceivePort();
+      setupListHandlers(Stream<FileSystemEntity> stream) {
+        stream.listen(
+          (_) => Expect.fail("Listing of non-existing directory should fail"),
+          onError: (e) {
+            Expect.isTrue(e is AsyncError);
+            Expect.isTrue(e.error is DirectoryIOException);
+            if (++errors == 2) {
+              d.delete(recursive: true).then((_) {
+                port.close();
+              });
+            }
+          });
       }
       var subDirName = 'subdir';
       var subDir = new Directory("${d.path}/$subDirName");
@@ -214,45 +206,6 @@
     d.deleteSync(recursive: true);
   }
 
-  static void testDeleteSymlink() {
-    // temp/
-    //   a/
-    //     file.txt
-    //   b/
-    //     a_link -> a
-    var d = new Directory("").createTempSync();
-    var a = new Directory("${d.path}/a");
-    a.createSync();
-
-    var b = new Directory("${d.path}/b");
-    b.createSync();
-
-    var f = new File("${d.path}/a/file.txt");
-    f.createSync();
-    Expect.isTrue(f.existsSync());
-
-    // Create a symlink (or junction on Windows) from
-    // temp/b/a_link to temp/a.
-    var cmd = "ln";
-    var args = ['-s', "${d.path}/b/a_link", "${d.path}/a"];
-
-    if (Platform.operatingSystem == "windows") {
-      cmd = "cmd";
-      args = ["/c", "mklink", "/j", "${d.path}\\b\\a_link", "${d.path}\\a"];
-    }
-
-    Process.run(cmd, args).then((_) {
-      // Delete the directory containing the junction.
-      b.deleteSync(recursive: true);
-
-      // We should not have recursed through a_link into a.
-      Expect.isTrue(f.existsSync());
-
-      // Clean up after ourselves.
-      d.deleteSync(recursive: true);
-    });
-  }
-
   static void testExistsCreateDelete() {
     new Directory("").createTemp().then((d) {
       d.exists().then((bool exists) {
@@ -359,7 +312,6 @@
     testDeleteTooLongName();
     testDeleteNonExistentSync();
     testDeleteTooLongNameSync();
-    testDeleteSymlink();
     testExistsCreateDelete();
     testExistsCreateDeleteSync();
     testCreateTemp();
diff --git a/tests/standalone/io/echo_server_stream_test.dart b/tests/standalone/io/echo_server_stream_test.dart
index a350b59..3a59aba 100644
--- a/tests/standalone/io/echo_server_stream_test.dart
+++ b/tests/standalone/io/echo_server_stream_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
@@ -34,83 +34,44 @@
   }
 
   void sendData() {
+    int offset = 0;
+    List<int> data;
 
-    void errorHandler(Exception e) {
+    void onData(List<int> data) {
+      int bytesRead = data.length;
+      for (int i = 0; i < data.length; i++) {
+        Expect.equals(FIRSTCHAR + i + offset, data[i]);
+      }
+      offset += bytesRead;
+    }
+
+    void onClosed() {
+      Expect.equals(MSGSIZE, offset);
+      _messages++;
+      if (_messages < MESSAGES) {
+        sendData();
+      } else {
+        shutdown();
+      }
+    }
+
+    void errorHandler(e) {
       Expect.fail("Socket error $e");
     }
 
     void connectHandler() {
-
-      OutputStream stream = _socket.outputStream;
-
-      void dataSent() {
-        InputStream inputStream = _socket.inputStream;
-        int offset = 0;
-        List<int> data;
-
-        void onClosed() {
-          Expect.equals(MSGSIZE, offset);
-          _messages++;
-          if (_messages < MESSAGES) {
-            sendData();
-          } else {
-            shutdown();
-          }
-        }
-
-        void onData() {
-          // Test both read and readInto.
-          int bytesRead = 0;
-          if (_messages % 2 == 0) {
-            bytesRead = inputStream.readInto(data, offset, MSGSIZE - offset);
-            for (int i = 0; i < offset + bytesRead; i++) {
-              Expect.equals(FIRSTCHAR + i, data[i]);
-            }
-          } else {
-            data = inputStream.read();
-            bytesRead = data.length;
-            for (int i = 0; i < data.length; i++) {
-              Expect.equals(FIRSTCHAR + i + offset, data[i]);
-            }
-          }
-
-          offset += bytesRead;
-        }
-
-        if (_messages % 2 == 0) data = new List<int>.fixedLength(MSGSIZE);
-        inputStream.onData = onData;
-        inputStream.onClosed = onClosed;
-      }
-
-      _socket.onError = errorHandler;
-
-      // Test both write and writeFrom in different forms.
-      switch (_messages % 4) {
-        case 0:
-          stream.write(_buffer);
-          break;
-        case 1:
-          stream.write(_buffer, false);
-          break;
-        case 2:
-          stream.writeFrom(_buffer);
-          break;
-        case 3:
-          Expect.equals(0, _buffer.length % 2);
-          stream.writeFrom(_buffer, 0, _buffer.length ~/ 2);
-          stream.writeFrom(_buffer, _buffer.length ~/ 2);
-          break;
-      }
-      stream.close();
-      dataSent();
+      _socket.listen(onData,
+                     onError: errorHandler,
+                     onDone: onClosed);
+      _socket.add(_buffer);
+      _socket.close();
+      data = new List<int>.fixedLength(MSGSIZE);
     }
 
-    _socket = new Socket(TestingServer.HOST, _port);
-    if (_socket != null) {
-      _socket.onConnect = connectHandler;
-    } else {
-      Expect.fail("socket creation failed");
-    }
+    Socket.connect(TestingServer.HOST, _port).then((s) {
+      _socket = s;
+      connectHandler();
+    });
   }
 
   void initialize() {
@@ -146,33 +107,30 @@
   static const int MSGSIZE = EchoServerGame.MSGSIZE;
 
   void onConnection(Socket connection) {
-    InputStream inputStream;
     List<int> buffer = new List<int>.fixedLength(MSGSIZE);
     int offset = 0;
 
-    void dataReceived() {
+    void dataReceived(List<int> data) {
       int bytesRead;
-      OutputStream outputStream = connection.outputStream;
-      bytesRead = inputStream.readInto(buffer, offset, MSGSIZE - offset);
+      bytesRead = data.length;
       if (bytesRead > 0) {
+        buffer.setRange(offset, data.length, data);
         offset += bytesRead;
         for (int i = 0; i < offset; i++) {
           Expect.equals(EchoServerGame.FIRSTCHAR + i, buffer[i]);
         }
         if (offset == MSGSIZE) {
-          outputStream.write(buffer);
-          outputStream.close();
+          connection.add(buffer);
+          connection.close();
         }
       }
     }
 
-    void errorHandler(Exception e) {
+    void errorHandler(e) {
       Expect.fail("Socket error $e");
     }
 
-    inputStream = connection.inputStream;
-    inputStream.onData = dataReceived;
-    connection.onError = errorHandler;
+    connection.listen(dataReceived, onError: errorHandler);
   }
 }
 
diff --git a/tests/standalone/io/echo_server_test.dart b/tests/standalone/io/echo_server_test.dart
deleted file mode 100644
index 4208bb8..0000000
--- a/tests/standalone/io/echo_server_test.dart
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-//
-// Echo server test program for testing sockets.
-//
-// VMOptions=
-// VMOptions=--short_socket_read
-// VMOptions=--short_socket_write
-// VMOptions=--short_socket_read --short_socket_write
-
-library ServerTest;
-import "dart:io";
-import "dart:isolate";
-part "testing_server.dart";
-
-class EchoServerTest {
-
-  static void testMain() {
-    EchoServerGame echoServerGame = new EchoServerGame.start();
-  }
-}
-
-class EchoServerGame {
-
-  static const MSGSIZE = 10;
-  static const MESSAGES = 100;
-  static const FIRSTCHAR = 65;
-
-  EchoServerGame.start()
-      : _receivePort = new ReceivePort(),
-        _sendPort = null,
-        _buffer = new List<int>.fixedLength(MSGSIZE),
-        _messages = 0 {
-    for (int i = 0; i < MSGSIZE; i++) {
-      _buffer[i] = FIRSTCHAR + i;
-    }
-    _sendPort = spawnFunction(startEchoServer);
-    initialize();
-  }
-
-  void sendData() {
-    Socket _socket;
-
-    void messageHandler() {
-
-      List<int> bufferReceived = new List<int>.fixedLength(MSGSIZE);
-      int bytesRead = 0;
-
-      void handleRead() {
-        bytesRead += _socket.readList(
-            bufferReceived, bytesRead, MSGSIZE - bytesRead);
-        if (bytesRead < MSGSIZE) {
-          // We check every time the whole buffer to verify data integrity.
-          for (int i = 0; i < bytesRead; i++) {
-            Expect.equals(FIRSTCHAR + i, bufferReceived[i]);
-          }
-          _socket.onData = handleRead;
-        } else {
-          // We check every time the whole buffer to verify data integrity.
-          for (int i = 0; i < MSGSIZE; i++) {
-            Expect.equals(FIRSTCHAR + i, bufferReceived[i]);
-          }
-          _messages++;
-          _socket.close();
-          if (_messages < MESSAGES) {
-            sendData();
-          } else {
-            shutdown();
-          }
-        }
-      }
-
-      handleRead();
-    }
-
-    void errorHandler(Exception e) {
-      Expect.fail("Socket error $e");
-    }
-
-    void connectHandler() {
-
-      void writeMessage() {
-        int bytesWritten = 0;
-
-        void handleWrite() {
-          bytesWritten += _socket.writeList(
-              _buffer, bytesWritten, MSGSIZE - bytesWritten);
-          if (bytesWritten < MSGSIZE) {
-            _socket.onWrite = handleWrite;
-          }
-        }
-
-        handleWrite();
-      }
-
-      _socket.onData = messageHandler;
-      _socket.onError = errorHandler;
-      writeMessage();
-    }
-
-    _socket = new Socket(TestingServer.HOST, _port);
-    if (_socket != null) {
-      _socket.onConnect = connectHandler;
-    } else {
-      Expect.fail("Socket creation failed");
-    }
-  }
-
-  void initialize() {
-    _receivePort.receive((var message, SendPort replyTo) {
-      _port = message;
-      sendData();
-    });
-    _sendPort.send(TestingServer.INIT, _receivePort.toSendPort());
-  }
-
-  void shutdown() {
-    _sendPort.send(TestingServer.SHUTDOWN, _receivePort.toSendPort());
-    _receivePort.close();
-  }
-
-  int _port;
-  ReceivePort _receivePort;
-  SendPort _sendPort;
-  List<int> _buffer;
-  int _messages;
-}
-
-
-void startEchoServer() {
-  var server = new EchoServer();
-  port.receive(server.dispatch);
-}
-
-class EchoServer extends TestingServer {
-
-  static const msgSize = EchoServerGame.MSGSIZE;
-
-  void onConnection(Socket connection) {
-
-    void messageHandler() {
-
-      List<int> buffer = new List<int>.fixedLength(msgSize);
-      int bytesRead = 0;
-
-      void handleRead() {
-        int read = connection.readList(buffer, bytesRead, msgSize - bytesRead);
-        if (read > 0) {
-          bytesRead += read;
-          if (bytesRead < msgSize) {
-            // We check every time the whole buffer to verify data integrity.
-            for (int i = 0; i < bytesRead; i++) {
-              Expect.equals(EchoServerGame.FIRSTCHAR + i, buffer[i]);
-            }
-            connection.onData = handleRead;
-          } else {
-            // We check every time the whole buffer to verify data integrity.
-            for (int i = 0; i < msgSize; i++) {
-              Expect.equals(EchoServerGame.FIRSTCHAR + i, buffer[i]);
-            }
-
-            void writeMessage() {
-
-              int bytesWritten = 0;
-
-              void handleWrite() {
-                int written = connection.writeList(
-                    buffer, bytesWritten, msgSize - bytesWritten);
-                bytesWritten += written;
-                if (bytesWritten < msgSize) {
-                  connection.onWrite = handleWrite;
-                } else {
-                  connection.close(true);
-                }
-              }
-              handleWrite();
-            }
-            writeMessage();
-          }
-        }
-      }
-
-      handleRead();
-    }
-
-    void closeHandler() {
-      connection.close();
-    }
-
-    void errorHandler(Exception e) {
-      Expect.fail("Socket error $e");
-    }
-
-    connection.onData = messageHandler;
-    connection.onClosed = closeHandler;
-    connection.onError = errorHandler;
-  }
-}
-
-main() {
-  EchoServerTest.testMain();
-}
diff --git a/tests/standalone/io/file_fuzz_test.dart b/tests/standalone/io/file_fuzz_test.dart
index 2d02795..ffc32d9 100644
--- a/tests/standalone/io/file_fuzz_test.dart
+++ b/tests/standalone/io/file_fuzz_test.dart
@@ -22,13 +22,13 @@
       doItSync(f.lengthSync);
       doItSync(f.modifiedSync);
       doItSync(f.fullPathSync);
-      doItSync(() => f.openInputStream().onError = (e) => null);
+      doItSync(() => f.openRead().listen(() {}, onError: (e) {}));
       doItSync(f.readAsBytesSync);
       doItSync(f.readAsStringSync);
       doItSync(f.readAsLinesSync);
       typeMapping.forEach((k2, v2) {
         doItSync(() => f.openSync(v2));
-        doItSync(() => f.openOutputStream(v2).onError = (e) => null);
+        doItSync(() => f.openWrite(v2));
         doItSync(() => f.readAsStringSync(v2));
         doItSync(() => f.readAsLinesSync(v2));
       });
diff --git a/tests/standalone/io/file_input_stream_test.dart b/tests/standalone/io/file_input_stream_test.dart
index c46bd42..4e2e2c4 100644
--- a/tests/standalone/io/file_input_stream_test.dart
+++ b/tests/standalone/io/file_input_stream_test.dart
@@ -11,14 +11,15 @@
 String getFilename(String path) =>
     new File(path).existsSync() ? path : '../$path';
 
-void testStringInputStreamSync() {
+void testStringLineTransformer() {
   String fileName = getFilename("tests/standalone/io/readuntil_test.dat");
   // File contains "Hello Dart\nwassup!\n"
   File file = new File(fileName);
   int linesRead = 0;
-  StringInputStream x = new StringInputStream(file.openInputStream());
-  x.onLine = () {
-    String line = x.readLine();
+  var lineStream = file.openRead()
+    .transform(new StringDecoder())
+    .transform(new LineTransformer());
+  lineStream.listen((line) {
     linesRead++;
     if (linesRead == 1) {
       Expect.equals("Hello Dart", line);
@@ -27,101 +28,179 @@
     } else {
       Expect.fail("More or less than 2 lines read ($linesRead lines read).");
     }
-  };
+  });
 }
 
-void testInputStreamAsync() {
+
+void testOpenStreamAsync() {
+  var keepAlive = new ReceivePort();
   String fileName = getFilename("tests/standalone/io/readuntil_test.dat");
   // File contains "Hello Dart\nwassup!\n"
   var expected = "Hello Dart\nwassup!\n".charCodes;
-  InputStream x = (new File(fileName)).openInputStream();
   var byteCount = 0;
-  x.onData = () {
-    Expect.equals(expected[byteCount], x.read(1)[0]);
-    byteCount++;
-  };
-  x.onClosed = () {
-    Expect.equals(expected.length, byteCount);
-  };
+  (new File(fileName)).openRead().listen(
+      (d) => byteCount += d.length,
+      onDone: () {
+        Expect.equals(expected.length, byteCount);
+        keepAlive.close();
+      });
 }
 
-void testStringInputStreamAsync(String name, int length) {
+
+// Create a file that is big enough that a file stream will
+// read it in multiple chunks.
+int writeLongFileSync(File file) {
+  file.createSync();
+  StringBuffer buffer = new StringBuffer();
+  for (var i = 0; i < 10000; i++) {
+    buffer.add("Hello, world");
+  }
+  file.writeAsStringSync(buffer.toString());
+  var length = file.lengthSync();
+  Expect.equals(buffer.length, length);
+  return length;
+}
+
+
+void testInputStreamTruncate() {
+  var keepAlive = new ReceivePort();
+  var temp = new Directory('').createTempSync();
+  var file = new File('${temp.path}/input_stream_truncate.txt');
+  var originalLength = writeLongFileSync(file);
+  // Start streaming the file. Pause after first chunk. Truncate
+  // underlying file and check that the streaming stops with or
+  // without getting all data.
+  var streamedBytes = 0;
+  var subscription;
+  subscription = file.openRead().listen(
+      (d) {
+        if (streamedBytes == 0) {
+          subscription.pause();
+          // Truncate the file by opening it for writing.
+          file.open(FileMode.WRITE).then((opened) {
+            opened.close().then((_) {
+                Expect.equals(0, file.lengthSync());
+                subscription.resume();
+            });
+          });
+        }
+        streamedBytes += d.length;
+      },
+      onDone: () {
+        Expect.isTrue(streamedBytes > 0 && streamedBytes <= originalLength);
+        temp.delete(recursive: true).then((_) => keepAlive.close());
+      },
+      onError: (e) {
+        Expect.fail("Unexpected error");
+      });
+}
+
+
+void testInputStreamDelete() {
+  var keepAlive = new ReceivePort();
+  var temp = new Directory('').createTempSync();
+  var file = new File('${temp.path}/input_stream_delete.txt');
+  var originalLength = writeLongFileSync(file);
+  // Start streaming the file. Pause after first chunk. Truncate
+  // underlying file and check that the streaming stops with or
+  // without getting all data.
+  var streamedBytes = 0;
+  var subscription;
+  subscription = file.openRead().listen(
+      (d) {
+        if (streamedBytes == 0) {
+          subscription.pause();
+          // Delete the underlying file by opening it for writing.
+          file.delete()
+            .then((deleted) {
+              Expect.isFalse(deleted.existsSync());
+              subscription.resume();
+            })
+            .catchError((e) {
+              // On Windows, you cannot delete a file that is open
+              // somewhere else. The stream has this file open
+              // and therefore we get an error on deletion on Windows.
+              Expect.equals('windows', Platform.operatingSystem);
+              subscription.resume();
+            });
+        }
+        streamedBytes += d.length;
+      },
+      onDone: () {
+        Expect.equals(originalLength, streamedBytes);
+        temp.delete(recursive: true).then((_) => keepAlive.close());
+      },
+      onError: (e) {
+        Expect.fail("Unexpected error");
+      });
+}
+
+
+void testInputStreamAppend() {
+  var keepAlive = new ReceivePort();
+  var temp = new Directory('').createTempSync();
+  var file = new File('${temp.path}/input_stream_append.txt');
+  var originalLength = writeLongFileSync(file);
+  // Start streaming the file. Pause after first chunk. Append to
+  // underlying file and check that the stream gets all the data.
+  var streamedBytes = 0;
+  var subscription;
+  subscription = file.openRead().listen(
+      (d) {
+        if (streamedBytes == 0) {
+          subscription.pause();
+          // Double the length of the underlying file.
+          file.readAsBytes().then((bytes) {
+            file.writeAsBytes(bytes, FileMode.APPEND).then((_) {
+              Expect.equals(2 * originalLength, file.lengthSync());
+              subscription.resume();
+            });
+          });
+        }
+        streamedBytes += d.length;
+      },
+      onDone: () {
+        Expect.equals(2 * originalLength, streamedBytes);
+        temp.delete(recursive: true).then((_) => keepAlive.close());
+      },
+      onError: (e) {
+        Expect.fail("Unexpected error");
+      });
+}
+
+
+void testStringLineTransformerEnding(String name, int length) {
   String fileName = getFilename("tests/standalone/io/$name");
   // File contains 10 lines.
   File file = new File(fileName);
   Expect.equals(length, file.openSync().lengthSync());
-  StringInputStream x = new StringInputStream(file.openInputStream());
+  var lineStream = file.openRead()
+    .transform(new StringDecoder())
+    .transform(new LineTransformer());
   int lineCount = 0;
-  x.onLine = () {
-    var line = x.readLine();
-    lineCount++;
-    Expect.isTrue(lineCount <= 10);
-    if (line[0] != "#") {
-      Expect.equals("Line $lineCount", line);
-    }
-  };
-  x.onClosed = () {
-    Expect.equals(10, lineCount);
-  };
-}
-
-void testChunkedInputStream() {
-  // Force the test to timeout if it does not finish.
-  ReceivePort done = new ReceivePort();
-  done.receive((message, replyTo) { done.close(); });
-
-  String fileName = getFilename("tests/standalone/io/readuntil_test.dat");
-  // File contains 19 bytes ("Hello Dart\nwassup!")
-  File file = new File(fileName);
-  ChunkedInputStream x = new ChunkedInputStream(file.openInputStream());
-  x.chunkSize = 9;
-  x.onData = () {
-    List<int> chunk = x.read();
-    Expect.equals(9, chunk.length);
-    x.chunkSize = 5;
-    x.onData = () {
-      chunk = x.read();
-      Expect.equals(5, chunk.length);
-      x.onData = () {
-        chunk = x.read();
-        Expect.equals(5, chunk.length);
-        chunk = x.read();
-        Expect.equals(null, chunk);
-        done.toSendPort().send(null);
-      };
-    };
-  };
-}
-
-void testUnreadyInputStream() {
-  String fileName = getFilename("tests/standalone/io/readuntil_test.dat");
-  var expected = "Hello Dart\nwassup!\n".charCodes;
-  InputStream x = (new File(fileName)).openInputStream();
-  List<int> buffer = new List<int>.fixedLength(100);
-
-  x.onData = () {
-    Expect.fail("Input stream closed before opening called onData handler.");
-  };
-
-  x.onClosed = () { };
-
-  // Called before stream is ready.
-  int read = x.readInto(buffer);
-  Expect.equals(0, read);
-
-  // Called before stream is ready.
-  x.close();
+  lineStream.listen(
+      (line) {
+        lineCount++;
+        Expect.isTrue(lineCount <= 10);
+        if (line[0] != "#") {
+          Expect.equals("Line $lineCount", line);
+        }
+      },
+      onDone: () {
+        Expect.equals(10, lineCount);
+      });
 }
 
 
 main() {
-  testStringInputStreamSync();
-  testInputStreamAsync();
+  testStringLineTransformer();
+  testOpenStreamAsync();
+  testInputStreamTruncate();
+  testInputStreamDelete();
+  testInputStreamAppend();
   // Check the length of these files as both are text files where one
   // is without a terminating line separator which can easily be added
   // back if accidentally opened in a text editor.
-  testStringInputStreamAsync("readline_test1.dat", 111);
-  testStringInputStreamAsync("readline_test2.dat", 114);
-  testChunkedInputStream();
-  testUnreadyInputStream();
+  testStringLineTransformerEnding("readline_test1.dat", 111);
+  testStringLineTransformerEnding("readline_test2.dat", 114);
 }
diff --git a/tests/standalone/io/file_output_stream_test.dart b/tests/standalone/io/file_output_stream_test.dart
index e700c5c..645399a 100644
--- a/tests/standalone/io/file_output_stream_test.dart
+++ b/tests/standalone/io/file_output_stream_test.dart
@@ -19,88 +19,18 @@
   String fileName = "${tempDirectory.path}/test";
   File file = new File(fileName);
   file.createSync();
-  OutputStream x = file.openOutputStream();
-  x.write([65, 66, 67]);
-  Expect.isFalse(x.closed);
+  IOSink x = file.openWrite();
+  var data = [65, 66, 67];
+  x.add(data);
   x.close();
-  Expect.isTrue(x.closed);
-  x.onClosed = () {
-    Expect.isTrue(x.closed);
+  x.done.then((_) {
+    Expect.listEquals(file.readAsBytesSync(), data);
     file.deleteSync();
     done.toSendPort().send("done");
-  };
-}
-
-
-void testOutputStreamNoPendingWrite() {
-  var tempDirectory;
-
-  // Create a port for waiting on the final result of this test.
-  ReceivePort done = new ReceivePort();
-  done.receive((message, replyTo) {
-    tempDirectory.delete(recursive: true).then((ignore) => done.close());
-  });
-
-  new Directory('').createTemp().then((temp) {
-    tempDirectory = temp;
-    String fileName = "${tempDirectory.path}/test";
-    File file = new File(fileName);
-    file.create().then((ignore) {
-      OutputStream stream = file.openOutputStream();
-      final total = 100;
-      var count = 0;
-      stream.onNoPendingWrites = () {
-        stream.write([count++]);
-        if (count == total) {
-          stream.close();
-        }
-        stream.onClosed = () {
-          List buffer = new List<int>.fixedLength(total);
-          File fileSync = new File(fileName);
-          var openedFile = fileSync.openSync();
-          openedFile.readListSync(buffer, 0, total);
-          for (var i = 0; i < total; i++) {
-            Expect.equals(i, buffer[i]);
-          }
-          openedFile.closeSync();
-          fileSync.deleteSync();
-          done.toSendPort().send("done");
-        };
-      };
-    });
   });
 }
 
 
-void testOutputStreamFlush() {
-  Directory tempDirectory = new Directory('').createTempSync();
-
-  // Create a port for waiting on the final result of this test.
-  ReceivePort done = new ReceivePort();
-  done.receive((message, replyTo) {
-    tempDirectory.deleteSync();
-    done.close();
-  });
-
-  String fileName = "${tempDirectory.path}/test";
-  File file = new File(fileName);
-  file.createSync();
-  OutputStream x = file.openOutputStream();
-  x.write([65, 66, 67]);
-  x.flush();
-  x.write([68, 69, 70]);
-  x.flush();
-  x.write([71, 72, 73]);
-  x.onClosed = () {
-    file.deleteSync();
-    done.toSendPort().send("done");
-  };
-  x.close();
-  x.onError = (e) => Expect.fail("No error expected");
-}
-
 main() {
   testOpenOutputStreamSync();
-  testOutputStreamNoPendingWrite();
-  testOutputStreamFlush();
 }
diff --git a/tests/standalone/io/file_system_links_test.dart b/tests/standalone/io/file_system_links_test.dart
index 361f7e6..90e9692 100644
--- a/tests/standalone/io/file_system_links_test.dart
+++ b/tests/standalone/io/file_system_links_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:io";
+import "dart:isolate";
 
 
 createLink(String dst, String link, bool symbolic, void callback()) {
@@ -66,16 +67,16 @@
   new File(x).createSync();
   createLink(x, y, true, () {
     var data = "asdf".charCodes;
-    var output = new File(y).openOutputStream(FileMode.WRITE);
-    output.write(data);
-    output.onNoPendingWrites = () {
-      output.close();
+    var output = new File(y).openWrite(FileMode.WRITE);
+    output.add(data);
+    output.close();
+    output.done.then((_) {
       var read = new File(y).readAsBytesSync();
       Expect.listEquals(data, read);
       var read2 = new File(x).readAsBytesSync();
       Expect.listEquals(data, read2);
       temp.deleteSync(recursive: true);
-    };
+    });
   });
 }
 
@@ -119,6 +120,7 @@
 
 
 testDirectoryListing() {
+  var keepAlive = new ReceivePort();
   var temp = new Directory('').createTempSync();
   var temp2 = new Directory('').createTempSync();
   var y = '${temp.path}${Platform.pathSeparator}y';
@@ -136,29 +138,36 @@
       }
     }
     Expect.equals(1, files.length);
-    Expect.isTrue(files[0].endsWith(x));
+    Expect.isTrue(files[0].endsWith('$y${Platform.pathSeparator}x'));
     Expect.equals(1, dirs.length);
     Expect.isTrue(dirs[0].endsWith(y));
 
     files = [];
     dirs = [];
-    var lister = temp.list(recursive: true);
-    lister.onFile = (f) => files.add(f);
-    lister.onDir = (d) => dirs.add(d);
-    lister.onDone = (success) {
-      Expect.isTrue(success);
-      Expect.equals(1, files.length);
-      Expect.isTrue(files[0].endsWith(x));
-      Expect.equals(1, dirs.length);
-      Expect.isTrue(dirs[0].endsWith(y));
-      temp.deleteSync(recursive: true);
-      temp2.deleteSync(recursive: true);
-    };
+    var lister = temp.list(recursive: true).listen(
+        (entity) {
+          if (entity is File) {
+            files.add(entity.name);
+          } else {
+            Expect.isTrue(entity is Directory);
+            dirs.add(entity.path);
+          }
+        },
+        onDone: () {
+          Expect.equals(1, files.length);
+          Expect.isTrue(files[0].endsWith('$y${Platform.pathSeparator}x'));
+          Expect.equals(1, dirs.length);
+          Expect.isTrue(dirs[0].endsWith(y));
+          temp.deleteSync(recursive: true);
+          temp2.deleteSync(recursive: true);
+          keepAlive.close();
+        });
   });
 }
 
 
 testDirectoryListingBrokenLink() {
+  var keepAlive = new ReceivePort();
   var temp = new Directory('').createTempSync();
   var x = '${temp.path}${Platform.pathSeparator}x';
   var link = '${temp.path}${Platform.pathSeparator}link';
@@ -170,19 +179,25 @@
     var files = [];
     var dirs = [];
     var errors = [];
-    var lister = temp.list(recursive: true);
-    lister.onFile = (f) => files.add(f);
-    lister.onDir = (d) => dirs.add(d);
-    lister.onError = (d) => errors.add(d);
-    lister.onDone = (success) {
-      Expect.isFalse(success);
-      Expect.equals(1, files.length);
-      Expect.isTrue(files[0].endsWith(x));
-      Expect.equals(0, dirs.length);
-      Expect.equals(1, errors.length);
-      Expect.isTrue(errors[0].toString().contains(link));
-      temp.deleteSync(recursive: true);
-    };
+    temp.list(recursive: true).listen(
+        (entity) {
+          if (entity is File) {
+            files.add(entity.name);
+          } else {
+            Expect.isTrue(entity is Directory);
+            dirs.add(entity.path);
+          }
+        },
+        onError: (e) => errors.add(e),
+        onDone: () {
+          Expect.equals(1, files.length);
+          Expect.isTrue(files[0].endsWith(x));
+          Expect.equals(0, dirs.length);
+          Expect.equals(1, errors.length);
+          Expect.isTrue(errors[0].toString().contains(link));
+          temp.deleteSync(recursive: true);
+          keepAlive.close();
+        });
   });
 }
 
diff --git a/tests/standalone/io/file_test.dart b/tests/standalone/io/file_test.dart
index 4d7093d..a8daa32 100644
--- a/tests/standalone/io/file_test.dart
+++ b/tests/standalone/io/file_test.dart
@@ -46,27 +46,27 @@
     String filename = getFilename("bin/file_test.cc");
     File file = new File(filename);
     Expect.isTrue('$file'.contains(file.name));
-    InputStream input = file.openInputStream();
-    input.onData = () {
-      List<int> buffer = new List<int>.fixedLength(42);
-      int bytesRead = input.readInto(buffer, 0, 12);
-      Expect.equals(12, bytesRead);
-      bytesRead = input.readInto(buffer, 12, 30);
-      input.close();
-      Expect.equals(30, bytesRead);
-      Expect.equals(47, buffer[0]);  // represents '/' in the file.
-      Expect.equals(47, buffer[1]);  // represents '/' in the file.
-      Expect.equals(32, buffer[2]);  // represents ' ' in the file.
-      Expect.equals(67, buffer[3]);  // represents 'C' in the file.
-      Expect.equals(111, buffer[4]);  // represents 'o' in the file.
-      Expect.equals(112, buffer[5]);  // represents 'p' in the file.
-      Expect.equals(121, buffer[6]);  // represents 'y' in the file.
-      Expect.equals(114, buffer[7]);  // represents 'r' in the file.
-      Expect.equals(105, buffer[8]);  // represents 'i' in the file.
-      Expect.equals(103, buffer[9]);  // represents 'g' in the file.
-      Expect.equals(104, buffer[10]);  // represents 'h' in the file.
-      Expect.equals(116, buffer[11]);  // represents 't' in the file.
-    };
+    var subscription;
+    List<int> buffer = new List<int>();
+    subscription = file.openRead().listen(
+        (d) {
+          buffer.addAll(d);
+          if (buffer.length >= 12) {
+            subscription.cancel();
+            Expect.equals(47, buffer[0]);  // represents '/' in the file.
+            Expect.equals(47, buffer[1]);  // represents '/' in the file.
+            Expect.equals(32, buffer[2]);  // represents ' ' in the file.
+            Expect.equals(67, buffer[3]);  // represents 'C' in the file.
+            Expect.equals(111, buffer[4]);  // represents 'o' in the file.
+            Expect.equals(112, buffer[5]);  // represents 'p' in the file.
+            Expect.equals(121, buffer[6]);  // represents 'y' in the file.
+            Expect.equals(114, buffer[7]);  // represents 'r' in the file.
+            Expect.equals(105, buffer[8]);  // represents 'i' in the file.
+            Expect.equals(103, buffer[9]);  // represents 'g' in the file.
+            Expect.equals(104, buffer[10]);  // represents 'h' in the file.
+            Expect.equals(116, buffer[11]);  // represents 't' in the file.
+          }
+        });
   }
 
   // Test for file read and write functionality.
@@ -76,94 +76,44 @@
     // Read a file.
     String inFilename = getFilename("tests/vm/data/fixed_length_file");
     File file;
-    InputStream input;
     int bytesRead;
 
-    // Test reading all using readInto.
     var file1 = new File(inFilename);
-    var input1 = file1.openInputStream();
-    List<int> buffer1;
-    input1.onData = () {
-      buffer1 = new List<int>.fixedLength(42);
-      bytesRead = input1.readInto(buffer1, 0, 42);
-      Expect.equals(42, bytesRead);
-    };
-    input1.onError = (e) { throw e; };
-    input1.onClosed = () {
-      Expect.isTrue(input1.closed);
-
-      // Test reading all using readInto and read.
-      var file2 = new File(inFilename);
-      var input2 = file2.openInputStream();
-      input2.onData = () {
-        bytesRead = input2.readInto(buffer1, 0, 21);
-        Expect.equals(21, bytesRead);
-        buffer1 = input2.read();
-        Expect.equals(21, buffer1.length);
-      };
-      input2.onError = (e) { throw e; };
-      input2.onClosed = () {
-        Expect.isTrue(input2.closed);
-
-        // Test reading all using read and readInto.
-        var file3 = new File(inFilename);
-        var input3 = file3.openInputStream();
-        input3.onData = () {
-          buffer1 = input3.read(21);
-          Expect.equals(21, buffer1.length);
-          bytesRead = input3.readInto(buffer1, 0, 21);
-          Expect.equals(21, bytesRead);
-        };
-        input3.onError = (e) { throw e; };
-        input3.onClosed = () {
-          Expect.isTrue(input3.closed);
-
-          // Test reading all using read.
-          var file4 = new File(inFilename);
-          var input4 = file4.openInputStream();
-          input4.onData = () {
-            buffer1 = input4.read();
-            Expect.equals(42, buffer1.length);
-          };
-          input4.onError = (e) { throw e; };
-          input4.onClosed = () {
-            Expect.isTrue(input4.closed);
-
-            // Write the contents of the file just read into another file.
-            String outFilename =
-                tempDirectory.path.concat("/out_read_write_stream");
-            file = new File(outFilename);
-            OutputStream output = file.openOutputStream();
-            bool writeDone = output.writeFrom(buffer1, 0, 42);
-            Expect.equals(false, writeDone);
-            output.onNoPendingWrites = () {
-              output.close();
-              output.onClosed = () {
-                // Now read the contents of the file just written.
-                List<int> buffer2 = new List<int>.fixedLength(42);
-                var file6 = new File(outFilename);
-                var input6 = file6.openInputStream();
-                input6.onData = () {
-                  bytesRead = input6.readInto(buffer2, 0, 42);
-                  Expect.equals(42, bytesRead);
-                  // Now compare the two buffers to check if they are identical.
-                  for (int i = 0; i < buffer1.length; i++) {
-                    Expect.equals(buffer1[i],  buffer2[i]);
-                  }
-                };
-                input6.onError = (e) { throw e; };
-                input6.onClosed = () {
-                  // Delete the output file.
-                  file6.deleteSync();
-                  Expect.isFalse(file6.existsSync());
-                  asyncTestDone("testReadWriteStream");
-                };
-              };
-            };
-          };
-        };
-      };
-    };
+    List<int> buffer = new List<int>();
+    file1.openRead().listen(
+      (d) {
+        buffer.addAll(d);
+      },
+      onDone: () {
+        Expect.equals(42, buffer.length);
+        // Write the contents of the file just read into another file.
+        String outFilename =
+            tempDirectory.path.concat("/out_read_write_stream");
+        var file2 = new File(outFilename);
+        var output = file2.openWrite();
+        output.add(buffer);
+        output.close();
+        output.done.then((_) {
+          // Now read the contents of the file just written.
+          List<int> buffer2 = new List<int>();
+          new File(outFilename).openRead().listen(
+              (d) {
+                buffer2.addAll(d);
+              },
+              onDone: () {
+                Expect.equals(42, buffer2.length);
+                // Now compare the two buffers to check if they are
+                // identical.
+                for (int i = 0; i < buffer.length; i++) {
+                  Expect.equals(buffer[i],  buffer2[i]);
+                }
+                // Delete the output file.
+                file2.deleteSync();
+                Expect.isFalse(file2.existsSync());
+                asyncTestDone("testReadWriteStream");
+              });
+          });
+      });
   }
 
   // Test for file stream buffered handling of large files.
@@ -178,22 +128,12 @@
     String filename =
         tempDirectory.path.concat("/out_read_write_stream_large_file");
     File file = new File(filename);
-    OutputStream output = file.openOutputStream();
-    // Test a write immediately after the output stream is created.
-    output.writeFrom(buffer, 0, 20000);
-
-    output.onNoPendingWrites = () {
-      output.writeFrom(buffer, 20000, 60000);
-      output.writeFrom(buffer, 80000, 20000);
-      output.onNoPendingWrites = () {
-        output.writeFrom(buffer, 0, 0);
-        output.writeFrom(buffer, 0, 0);
-        output.writeFrom(buffer, 0, 100000);
-        output.close();
-      };
-    };
-    output.onClosed = () {
-      InputStream input = file.openInputStream();
+    IOSink output = file.openWrite();
+    output.add(buffer);
+    output.add(buffer);
+    output.close();
+    output.done.then((_) {
+      Stream input = file.openRead();
       int position = 0;
       final int expectedLength = 200000;
       // Start an independent asynchronous check on the length.
@@ -203,86 +143,55 @@
         asyncTestDone('testReadWriteStreamLargeFile: length check');
       });
 
-      List<int> inputBuffer =
-          new List<int>.fixedLength(expectedLength + 100000);
       // Immediate read should read 0 bytes.
-      Expect.equals(0, input.available());
-      Expect.equals(false, input.closed);
-      int bytesRead = input.readInto(inputBuffer);
-      Expect.equals(0, bytesRead);
-      Expect.equals(0, input.available());
-      Expect.isFalse(input.closed);
-      input.onError = (e) {
-        print('Error handler called on input in testReadWriteStreamLargeFile');
-        print('with error $e');
-        throw e;
-      };
-      input.onData = () {
-        Expect.isFalse(input.closed);
-        bytesRead = input.readInto(inputBuffer, position,
-                                   inputBuffer.length - position);
-        position += bytesRead;
-        // The buffer is large enough to hold all available data.
-        // So there should be no data left to read.
-        Expect.equals(0, input.available());
-        bytesRead = input.readInto(inputBuffer, position,
-                                   expectedLength - position);
-        Expect.equals(0, bytesRead);
-        Expect.equals(0, input.available());
-        Expect.isFalse(input.closed);
-      };
-      input.onClosed = () {
-        Expect.equals(0, input.available());
-        Expect.isTrue(input.closed);
-        input.close();  // This should be safe to call.
-
-        Expect.equals(expectedLength, position);
-        for (int i = 0; i < position; ++i) {
-          Expect.equals(buffer[i % buffer.length], inputBuffer[i]);
-        }
-
-        Future testPipeDone = testPipe(file, buffer);
-
-        Future futureDeleted = testPipeDone.then((ignored) => file.delete());
-        futureDeleted.then((ignored) {
-            asyncTestDone('testReadWriteStreamLargeFile: main test');
-        }).catchError((e) {
-          print('Exception while deleting ReadWriteStreamLargeFile file');
-          print('Exception $e');
+      input.listen(
+        (d) {
+          for (int i = 0; i < d.length; ++i) {
+            Expect.equals(buffer[(i + position) % buffer.length], d[i]);
+          }
+          position += d.length;
+        },
+        onError: (e) {
+          print('Error on input in testReadWriteStreamLargeFile');
+          print('with error $e');
+          throw e;
+        },
+        onDone: () {
+          Expect.equals(expectedLength, position);
+          testPipe(file, buffer)
+              .then((_) => file.delete())
+              .then((_) {
+                  asyncTestDone('testReadWriteStreamLargeFile: main test');
+              })
+              .catchError((e) {
+                print('Exception while deleting ReadWriteStreamLargeFile file');
+                print('Exception $e');
+              });
         });
-      };
-      // Try a read again after handlers are set.
-      bytesRead = input.readInto(inputBuffer);
-      Expect.equals(0, bytesRead);
-      Expect.equals(0, input.available());
-      Expect.isFalse(input.closed);
-    };
+    });
   }
 
   static Future testPipe(File file, buffer) {
     String outputFilename = '${file.name}_copy';
     File outputFile = new File(outputFilename);
-    InputStream input = file.openInputStream();
-    OutputStream output = outputFile.openOutputStream();
-    input.pipe(output);
+    var input = file.openRead();
+    var output = outputFile.openWrite();
     Completer done = new Completer();
-    output.onClosed = () {
-      InputStream copy = outputFile.openInputStream();
+    input.pipe(output).then((_) {
+      var copy = outputFile.openRead();
       int position = 0;
-      copy.onData = () {
-        var data;
-        while ((data = copy.read()) != null) {
-          for (int value in data) {
-            Expect.equals(buffer[position % buffer.length], value);
-            position++;
-          }
-        }
-      };
-      copy.onClosed = () {
-        Expect.equals(2 * buffer.length, position);
-        outputFile.delete().then((ignore) { done.complete(null); });
-      };
-    };
+      copy.listen(
+          (d) {
+            for (int i = 0; i < d.length; i++) {
+              Expect.equals(buffer[(position + i) % buffer.length], d[i]);
+            }
+            position += d.length;
+          },
+          onDone: () {
+            Expect.equals(2 * buffer.length, position);
+            outputFile.delete().then((ignore) { done.complete(); });
+          });
+      });
     return done.future;
   }
 
@@ -423,33 +332,28 @@
     File file = new File(filename);
     file.createSync();
     List<int> buffer = content.charCodes;
-    OutputStream outStream = file.openOutputStream();
-    outStream.write(buffer);
-    outStream.onNoPendingWrites = () {
-      outStream.close();
-      outStream.onClosed = () {
-        File file2 = new File(filename);
-        OutputStream appendingOutput =
-            file2.openOutputStream(FileMode.APPEND);
-        appendingOutput.write(buffer);
-        appendingOutput.onNoPendingWrites = () {
-          appendingOutput.close();
-          appendingOutput.onClosed = () {
-            File file3 = new File(filename);
-            file3.open(FileMode.READ).then((RandomAccessFile openedFile) {
-              openedFile.length().then((int length) {
-                Expect.equals(content.length * 2, length);
-                openedFile.close().then((ignore) {
-                  file3.delete().then((ignore) {
-                    asyncTestDone("testOutputStreamWriteAppend");
-                  });
-                });
+    var output = file.openWrite();
+    output.add(buffer);
+    output.close();
+    output.done.then((_) {
+      File file2 = new File(filename);
+      var appendingOutput = file2.openWrite(FileMode.APPEND);
+      appendingOutput.add(buffer);
+      appendingOutput.close();
+      appendingOutput.done.then((_) {
+        File file3 = new File(filename);
+        file3.open(FileMode.READ).then((RandomAccessFile openedFile) {
+          openedFile.length().then((int length) {
+            Expect.equals(content.length * 2, length);
+            openedFile.close().then((ignore) {
+              file3.delete().then((ignore) {
+                asyncTestDone("testOutputStreamWriteAppend");
               });
             });
-          };
-        };
-      };
-    };
+          });
+        });
+      });
+    });
     asyncTestStarted();
   }
 
@@ -460,22 +364,20 @@
     File file = new File(filename);
     file.createSync();
     List<int> buffer = content.charCodes;
-    OutputStream outStream = file.openOutputStream();
-    outStream.writeString("abcdABCD");
-    outStream.writeString("abcdABCD", Encoding.UTF_8);
-    outStream.writeString("abcdABCD", Encoding.ISO_8859_1);
-    outStream.writeString("abcdABCD", Encoding.ASCII);
-    outStream.writeString("æøå", Encoding.UTF_8);
-    outStream.onNoPendingWrites = () {
-      outStream.close();
-      outStream.onClosed = () {
-        RandomAccessFile raf = file.openSync();
-        Expect.equals(38, raf.lengthSync());
-        raf.close().then((ignore) {
-          asyncTestDone("testOutputStreamWriteString");
-        });
-      };
-    };
+    var output = file.openWrite();
+    output.addString("abcdABCD");
+    output.addString("abcdABCD", Encoding.UTF_8);
+    output.addString("abcdABCD", Encoding.ISO_8859_1);
+    output.addString("abcdABCD", Encoding.ASCII);
+    output.addString("æøå", Encoding.UTF_8);
+    output.close();
+    output.done.then((_) {
+      RandomAccessFile raf = file.openSync();
+      Expect.equals(38, raf.lengthSync());
+      raf.close().then((ignore) {
+        asyncTestDone("testOutputStreamWriteString");
+      });
+    });
     asyncTestStarted();
   }
 
@@ -846,18 +748,13 @@
     File file =
         new File(tempDirectory.path.concat("/out_close_exception_stream"));
     file.createSync();
-    InputStream input = file.openInputStream();
-    input.onClosed = () {
-      Expect.isTrue(input.closed);
-      Expect.equals(0, input.readInto(buffer, 0, 12));
-      OutputStream output = file.openOutputStream();
-      output.close();
-      Expect.throws(() => output.writeFrom(buffer, 0, 12));
-      output.onClosed = () {
-        file.deleteSync();
-        asyncTestDone("testCloseExceptionStream");
-      };
-    };
+    var output = file.openWrite();
+    output.close();
+    Expect.throws(() => output.add(buffer));
+    output.done.then((_) {
+      file.deleteSync();
+      asyncTestDone("testCloseExceptionStream");
+    });
   }
 
   // Tests buffer out of bounds exception.
@@ -1083,7 +980,10 @@
     Expect.equals(6, text.length);
     var expected = [955, 120, 46, 32, 120, 10];
     Expect.listEquals(expected, text.charCodes);
-    Expect.throws(() { new File(name).readAsStringSync(Encoding.ASCII); });
+    text = new File(name).readAsStringSync(Encoding.ASCII);
+    // Default replacement character is '?', char code 63.
+    expected = [63, 63, 120, 46, 32, 120, 10];
+    Expect.listEquals(expected, text.charCodes);
     text = new File(name).readAsStringSync(Encoding.ISO_8859_1);
     expected = [206, 187, 120, 46, 32, 120, 10];
     Expect.equals(7, text.length);
diff --git a/tests/standalone/io/http_advanced_test.dart b/tests/standalone/io/http_advanced_test.dart
index d6e1ad4..e19365f 100644
--- a/tests/standalone/io/http_advanced_test.dart
+++ b/tests/standalone/io/http_advanced_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
@@ -11,11 +11,11 @@
 import 'dart:io';
 import 'dart:isolate';
 
-class TestServerMain {
-  TestServerMain()
+class IsolatedHttpServer {
+  IsolatedHttpServer()
       : _statusPort = new ReceivePort(),
         _serverPort = null {
-    _serverPort = spawnFunction(startTestServer);
+    _serverPort = spawnFunction(startIsolatedHttpServer);
   }
 
   void setServerStartedHandler(void startedCallback(int port)) {
@@ -31,20 +31,22 @@
     });
 
     // Send server start message to the server.
-    var command = new TestServerCommand.start();
+    var command = new IsolatedHttpServerCommand.start();
     _serverPort.send(command, _statusPort.toSendPort());
   }
 
   void shutdown() {
     // Send server stop message to the server.
-    _serverPort.send(new TestServerCommand.stop(), _statusPort.toSendPort());
+    _serverPort.send(new IsolatedHttpServerCommand.stop(),
+                     _statusPort.toSendPort());
     _statusPort.close();
   }
 
   void chunkedEncoding() {
     // Send chunked encoding message to the server.
     _serverPort.send(
-        new TestServerCommand.chunkedEncoding(), _statusPort.toSendPort());
+        new IsolatedHttpServerCommand.chunkedEncoding(),
+        _statusPort.toSendPort());
   }
 
   ReceivePort _statusPort;  // Port for receiving messages from the server.
@@ -53,14 +55,14 @@
 }
 
 
-class TestServerCommand {
+class IsolatedHttpServerCommand {
   static const START = 0;
   static const STOP = 1;
   static const CHUNKED_ENCODING = 2;
 
-  TestServerCommand.start() : _command = START;
-  TestServerCommand.stop() : _command = STOP;
-  TestServerCommand.chunkedEncoding() : _command = CHUNKED_ENCODING;
+  IsolatedHttpServerCommand.start() : _command = START;
+  IsolatedHttpServerCommand.stop() : _command = STOP;
+  IsolatedHttpServerCommand.chunkedEncoding() : _command = CHUNKED_ENCODING;
 
   bool get isStart => _command == START;
   bool get isStop => _command == STOP;
@@ -70,14 +72,14 @@
 }
 
 
-class TestServerStatus {
+class IsolatedHttpServerStatus {
   static const STARTED = 0;
   static const STOPPED = 1;
   static const ERROR = 2;
 
-  TestServerStatus.started(this._port) : _state = STARTED;
-  TestServerStatus.stopped() : _state = STOPPED;
-  TestServerStatus.error() : _state = ERROR;
+  IsolatedHttpServerStatus.started(this._port) : _state = STARTED;
+  IsolatedHttpServerStatus.stopped() : _state = STOPPED;
+  IsolatedHttpServerStatus.error() : _state = ERROR;
 
   bool get isStarted => _state == STARTED;
   bool get isStopped => _state == STOPPED;
@@ -90,7 +92,7 @@
 }
 
 
-void startTestServer() {
+void startIsolatedHttpServer() {
   var server = new TestServer();
   server.init();
   port.receive(server.dispatch);
@@ -99,40 +101,45 @@
 
 class TestServer {
   // Return a 404.
-  void _notFoundHandler(HttpRequest request, HttpResponse response) {
+  void _notFoundHandler(HttpRequest request) {
+    var response = request.response;
     response.statusCode = HttpStatus.NOT_FOUND;
     response.headers.set("Content-Type", "text/html; charset=UTF-8");
     response.outputStream.writeString("Page not found");
-    response.outputStream.close();
+    response.close();
   }
 
   // Check the "Host" header.
-  void _hostHandler(HttpRequest request, HttpResponse response) {
+  void _hostHandler(HttpRequest request) {
+    var response = request.response;
     Expect.equals(1, request.headers["Host"].length);
     Expect.equals("www.dartlang.org:1234", request.headers["Host"][0]);
     Expect.equals("www.dartlang.org", request.headers.host);
     Expect.equals(1234, request.headers.port);
     response.statusCode = HttpStatus.OK;
-    response.outputStream.close();
+    response.close();
   }
 
   // Set the "Expires" header using the expires property.
-  void _expires1Handler(HttpRequest request, HttpResponse response) {
+  void _expires1Handler(HttpRequest request) {
+    var response = request.response;
     DateTime date = new DateTime.utc(1999, DateTime.JUN, 11, 18, 46, 53, 0);
     response.headers.expires = date;
     Expect.equals(date, response.headers.expires);
-    response.outputStream.close();
+    response.close();
   }
 
   // Set the "Expires" header.
-  void _expires2Handler(HttpRequest request, HttpResponse response) {
+  void _expires2Handler(HttpRequest request) {
+    var response = request.response;
     response.headers.set("Expires", "Fri, 11 Jun 1999 18:46:53 GMT");
     DateTime date = new DateTime.utc(1999, DateTime.JUN, 11, 18, 46, 53, 0);
     Expect.equals(date, response.headers.expires);
-    response.outputStream.close();
+    response.close();
   }
 
-  void _contentType1Handler(HttpRequest request, HttpResponse response) {
+  void _contentType1Handler(HttpRequest request) {
+    var response = request.response;
     Expect.equals("text/html", request.headers.contentType.value);
     Expect.equals("text", request.headers.contentType.primaryType);
     Expect.equals("html", request.headers.contentType.subType);
@@ -141,10 +148,11 @@
     ContentType contentType = new ContentType("text", "html");
     contentType.parameters["charset"] = "utf-8";
     response.headers.contentType = contentType;
-    response.outputStream.close();
+    response.close();
   }
 
-  void _contentType2Handler(HttpRequest request, HttpResponse response) {
+  void _contentType2Handler(HttpRequest request) {
+    var response = request.response;
     Expect.equals("text/html", request.headers.contentType.value);
     Expect.equals("text", request.headers.contentType.primaryType);
     Expect.equals("html", request.headers.contentType.subType);
@@ -152,10 +160,12 @@
 
     response.headers.set(HttpHeaders.CONTENT_TYPE,
                          "text/html;  charset = utf-8");
-    response.outputStream.close();
+    response.close();
   }
 
-  void _cookie1Handler(HttpRequest request, HttpResponse response) {
+  void _cookie1Handler(HttpRequest request) {
+    var response = request.response;
+
     // No cookies passed with this request.
     Expect.equals(0, request.cookies.length);
 
@@ -170,84 +180,56 @@
     cookie2.domain = ".example.com";
     cookie2.path = "/shop";
     response.cookies.add(cookie2);
-    response.outputStream.close();
+    response.close();
   }
 
-  void _cookie2Handler(HttpRequest request, HttpResponse response) {
+  void _cookie2Handler(HttpRequest request) {
+    var response = request.response;
+
     // Two cookies passed with this request.
     Expect.equals(2, request.cookies.length);
-    response.outputStream.close();
-  }
-
-  void _flushHandler(HttpRequest request, HttpResponse response) {
-    response.outputStream.flush();
-    response.outputStream.close();
+    response.close();
   }
 
   void init() {
     // Setup request handlers.
     _requestHandlers = new Map();
-    _requestHandlers["/host"] =
-        (HttpRequest request, HttpResponse response) {
-          _hostHandler(request, response);
-        };
-    _requestHandlers["/expires1"] =
-        (HttpRequest request, HttpResponse response) {
-          _expires1Handler(request, response);
-        };
-    _requestHandlers["/expires2"] =
-        (HttpRequest request, HttpResponse response) {
-          _expires2Handler(request, response);
-        };
-    _requestHandlers["/contenttype1"] =
-        (HttpRequest request, HttpResponse response) {
-          _contentType1Handler(request, response);
-        };
-    _requestHandlers["/contenttype2"] =
-        (HttpRequest request, HttpResponse response) {
-          _contentType2Handler(request, response);
-        };
-    _requestHandlers["/cookie1"] =
-        (HttpRequest request, HttpResponse response) {
-          _cookie1Handler(request, response);
-        };
-    _requestHandlers["/cookie2"] =
-        (HttpRequest request, HttpResponse response) {
-          _cookie2Handler(request, response);
-        };
-    _requestHandlers["/flush"] =
-        (HttpRequest request, HttpResponse response) {
-          _flushHandler(request, response);
-        };
+    _requestHandlers["/host"] = _hostHandler;
+    _requestHandlers["/expires1"] = _expires1Handler;
+    _requestHandlers["/expires2"] = _expires2Handler;
+    _requestHandlers["/contenttype1"] = _contentType1Handler;
+    _requestHandlers["/contenttype2"] = _contentType2Handler;
+    _requestHandlers["/cookie1"] = _cookie1Handler;
+    _requestHandlers["/cookie2"] = _cookie2Handler;
   }
 
   void dispatch(message, replyTo) {
     if (message.isStart) {
-      _server = new HttpServer();
       try {
-        _server.listen("127.0.0.1", 0);
-        _server.defaultRequestHandler = (HttpRequest req, HttpResponse rsp) {
-          _requestReceivedHandler(req, rsp);
-        };
-        replyTo.send(new TestServerStatus.started(_server.port), null);
+        HttpServer.bind().then((server) {
+          _server = server;
+          _server.listen(_requestReceivedHandler);
+          replyTo.send(new IsolatedHttpServerStatus.started(_server.port),
+                       null);
+        });
       } catch (e) {
-        replyTo.send(new TestServerStatus.error(), null);
+        replyTo.send(new IsolatedHttpServerStatus.error(), null);
       }
     } else if (message.isStop) {
       _server.close();
       port.close();
-      replyTo.send(new TestServerStatus.stopped(), null);
+      replyTo.send(new IsolatedHttpServerStatus.stopped(), null);
     } else if (message.isChunkedEncoding) {
       _chunkedEncoding = true;
     }
   }
 
-  void _requestReceivedHandler(HttpRequest request, HttpResponse response) {
-    var requestHandler =_requestHandlers[request.path];
+  void _requestReceivedHandler(HttpRequest request) {
+    var requestHandler =_requestHandlers[request.uri.path];
     if (requestHandler != null) {
-      requestHandler(request, response);
+      requestHandler(request);
     } else {
-      _notFoundHandler(request, response);
+      _notFoundHandler(request);
     }
   }
 
@@ -258,52 +240,52 @@
 
 Future testHost() {
   Completer completer = new Completer();
-  TestServerMain testServerMain = new TestServerMain();
-  testServerMain.setServerStartedHandler((int port) {
+  IsolatedHttpServer server = new IsolatedHttpServer();
+  server.setServerStartedHandler((int port) {
     HttpClient httpClient = new HttpClient();
-    HttpClientConnection conn =
-        httpClient.get("127.0.0.1", port, "/host");
-    conn.onRequest = (HttpClientRequest request) {
-      Expect.equals("127.0.0.1:$port", request.headers["host"][0]);
-      request.headers.host = "www.dartlang.com";
-      Expect.equals("www.dartlang.com:$port", request.headers["host"][0]);
-      Expect.equals("www.dartlang.com", request.headers.host);
-      Expect.equals(port, request.headers.port);
-      request.headers.port = 1234;
-      Expect.equals("www.dartlang.com:1234", request.headers["host"][0]);
-      Expect.equals(1234, request.headers.port);
-      request.headers.port = HttpClient.DEFAULT_HTTP_PORT;
-      Expect.equals(HttpClient.DEFAULT_HTTP_PORT, request.headers.port);
-      Expect.equals("www.dartlang.com", request.headers["host"][0]);
-      request.headers.set("Host", "www.dartlang.org");
-      Expect.equals("www.dartlang.org", request.headers.host);
-      Expect.equals(HttpClient.DEFAULT_HTTP_PORT, request.headers.port);
-      request.headers.set("Host", "www.dartlang.org:");
-      Expect.equals("www.dartlang.org", request.headers.host);
-      Expect.equals(HttpClient.DEFAULT_HTTP_PORT, request.headers.port);
-      request.headers.set("Host", "www.dartlang.org:1234");
-      Expect.equals("www.dartlang.org", request.headers.host);
-      Expect.equals(1234, request.headers.port);
-      request.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(HttpStatus.OK, response.statusCode);
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () {
-        httpClient.shutdown();
-        testServerMain.shutdown();
-        completer.complete(true);
-      };
-    };
+    httpClient.get("127.0.0.1", port, "/host")
+        .then((request) {
+          Expect.equals("127.0.0.1:$port", request.headers["host"][0]);
+          request.headers.host = "www.dartlang.com";
+          Expect.equals("www.dartlang.com:$port", request.headers["host"][0]);
+          Expect.equals("www.dartlang.com", request.headers.host);
+          Expect.equals(port, request.headers.port);
+          request.headers.port = 1234;
+          Expect.equals("www.dartlang.com:1234", request.headers["host"][0]);
+          Expect.equals(1234, request.headers.port);
+          request.headers.port = HttpClient.DEFAULT_HTTP_PORT;
+          Expect.equals(HttpClient.DEFAULT_HTTP_PORT, request.headers.port);
+          Expect.equals("www.dartlang.com", request.headers["host"][0]);
+          request.headers.set("Host", "www.dartlang.org");
+          Expect.equals("www.dartlang.org", request.headers.host);
+          Expect.equals(HttpClient.DEFAULT_HTTP_PORT, request.headers.port);
+          request.headers.set("Host", "www.dartlang.org:");
+          Expect.equals("www.dartlang.org", request.headers.host);
+          Expect.equals(HttpClient.DEFAULT_HTTP_PORT, request.headers.port);
+          request.headers.set("Host", "www.dartlang.org:1234");
+          Expect.equals("www.dartlang.org", request.headers.host);
+          Expect.equals(1234, request.headers.port);
+          return request.close();
+        })
+        .then((response) {
+          Expect.equals(HttpStatus.OK, response.statusCode);
+          response.listen(
+              (_) { },
+              onDone: () {
+                httpClient.close();
+                server.shutdown();
+                completer.complete(true);
+              });
+        });
   });
-  testServerMain.start();
+  server.start();
   return completer.future;
 }
 
 Future testExpires() {
   Completer completer = new Completer();
-  TestServerMain testServerMain = new TestServerMain();
-  testServerMain.setServerStartedHandler((int port) {
+  IsolatedHttpServer server = new IsolatedHttpServer();
+  server.setServerStartedHandler((int port) {
     int responses = 0;
     HttpClient httpClient = new HttpClient();
 
@@ -313,34 +295,32 @@
                     response.headers["expires"][0]);
       Expect.equals(new DateTime.utc(1999, DateTime.JUN, 11, 18, 46, 53, 0),
                     response.headers.expires);
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () {
-        responses++;
-        if (responses == 2) {
-          httpClient.shutdown();
-          testServerMain.shutdown();
-          completer.complete(true);
-        }
-      };
+      response.listen((_) { },
+                      onDone: () {
+                        responses++;
+                        if (responses == 2) {
+                          httpClient.close();
+                          server.shutdown();
+                          completer.complete(true);
+                        }
+                      });
     }
 
-    HttpClientConnection conn1 = httpClient.get("127.0.0.1", port, "/expires1");
-    conn1.onResponse = (HttpClientResponse response) {
-      processResponse(response);
-    };
-    HttpClientConnection conn2 = httpClient.get("127.0.0.1", port, "/expires2");
-    conn2.onResponse = (HttpClientResponse response) {
-      processResponse(response);
-    };
+    httpClient.get("127.0.0.1", port, "/expires1")
+        .then((request) => request.close())
+        .then(processResponse);
+    httpClient.get("127.0.0.1", port, "/expires2")
+        .then((request) => request.close())
+        .then(processResponse);
   });
-  testServerMain.start();
+  server.start();
   return completer.future;
 }
 
 Future testContentType() {
   Completer completer = new Completer();
-  TestServerMain testServerMain = new TestServerMain();
-  testServerMain.setServerStartedHandler((int port) {
+  IsolatedHttpServer server = new IsolatedHttpServer();
+  server.setServerStartedHandler((int port) {
     int responses = 0;
     HttpClient httpClient = new HttpClient();
 
@@ -353,132 +333,100 @@
       Expect.equals("html", response.headers.contentType.subType);
       Expect.equals("utf-8",
                     response.headers.contentType.parameters["charset"]);
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () {
-        responses++;
-        if (responses == 2) {
-          httpClient.shutdown();
-          testServerMain.shutdown();
-          completer.complete(true);
-        }
-      };
+      response.listen(
+          (_) { },
+          onDone: () {
+            responses++;
+            if (responses == 2) {
+              httpClient.close();
+              server.shutdown();
+              completer.complete(true);
+            }
+          });
     }
 
-    HttpClientConnection conn1 =
-        httpClient.get("127.0.0.1", port, "/contenttype1");
-    conn1.onRequest = (HttpClientRequest request) {
-      ContentType contentType = new ContentType();
-      contentType.value = "text/html";
-      contentType.parameters["charset"] = "utf-8";
-      request.headers.contentType = contentType;
-      request.outputStream.close();
-    };
-    conn1.onResponse = (HttpClientResponse response) {
-      processResponse(response);
-    };
-    HttpClientConnection conn2 =
-        httpClient.get("127.0.0.1", port, "/contenttype2");
-    conn2.onRequest = (HttpClientRequest request) {
-      request.headers.set(HttpHeaders.CONTENT_TYPE,
-                          "text/html;  charset = utf-8");
-      request.outputStream.close();
-    };
-    conn2.onResponse = (HttpClientResponse response) {
-      processResponse(response);
-    };
+    httpClient.get("127.0.0.1", port, "/contenttype1")
+        .then((request) {
+          ContentType contentType = new ContentType();
+          contentType.value = "text/html";
+          contentType.parameters["charset"] = "utf-8";
+          request.headers.contentType = contentType;
+          return request.close();
+        })
+        .then(processResponse);
+
+    httpClient.get("127.0.0.1", port, "/contenttype2")
+        .then((request) {
+          request.headers.set(HttpHeaders.CONTENT_TYPE,
+                              "text/html;  charset = utf-8");
+          return request.close();
+        })
+        .then(processResponse);
   });
-  testServerMain.start();
+  server.start();
   return completer.future;
 }
 
 Future testCookies() {
   Completer completer = new Completer();
-  TestServerMain testServerMain = new TestServerMain();
-  testServerMain.setServerStartedHandler((int port) {
+  IsolatedHttpServer server = new IsolatedHttpServer();
+  server.setServerStartedHandler((int port) {
     int responses = 0;
     HttpClient httpClient = new HttpClient();
 
-    HttpClientConnection conn1 =
-        httpClient.get("127.0.0.1", port, "/cookie1");
-    conn1.onResponse = (HttpClientResponse response) {
-      Expect.equals(2, response.cookies.length);
-      response.cookies.forEach((cookie) {
-        if (cookie.name == "name1") {
-          Expect.equals("value1", cookie.value);
-          DateTime date = new DateTime.utc(2014, DateTime.JAN, 5, 23, 59, 59, 0);
-          Expect.equals(date, cookie.expires);
-          Expect.equals("www.example.com", cookie.domain);
-          Expect.isTrue(cookie.httpOnly);
-        } else if (cookie.name == "name2") {
-          Expect.equals("value2", cookie.value);
-          Expect.equals(100, cookie.maxAge);
-          Expect.equals(".example.com", cookie.domain);
-          Expect.equals("/shop", cookie.path);
-        } else {
-          Expect.fail("Unexpected cookie");
-        }
-      });
-      HttpClientConnection conn2 =
-          httpClient.get("127.0.0.1", port, "/cookie2");
-      conn2.onRequest = (HttpClientRequest request) {
-        request.cookies.add(response.cookies[0]);
-        request.cookies.add(response.cookies[1]);
-        request.outputStream.close();
-      };
-      conn2.onResponse = (HttpClientResponse response) {
-        response.inputStream.onData = response.inputStream.read;
-        response.inputStream.onClosed = () {
-          httpClient.shutdown();
-          testServerMain.shutdown();
-          completer.complete(true);
-        };
-      };
-    };
-  });
-  testServerMain.start();
-  return completer.future;
-}
+    httpClient.get("127.0.0.1", port, "/cookie1")
+        .then((request) => request.close())
+        .then((response) {
+          Expect.equals(2, response.cookies.length);
+          response.cookies.forEach((cookie) {
+            if (cookie.name == "name1") {
+              Expect.equals("value1", cookie.value);
+              DateTime date =
+                  new DateTime.utc(2014, DateTime.JAN, 5, 23, 59, 59, 0);
+              Expect.equals(date, cookie.expires);
+              Expect.equals("www.example.com", cookie.domain);
+              Expect.isTrue(cookie.httpOnly);
+            } else if (cookie.name == "name2") {
+              Expect.equals("value2", cookie.value);
+              Expect.equals(100, cookie.maxAge);
+              Expect.equals(".example.com", cookie.domain);
+              Expect.equals("/shop", cookie.path);
+            } else {
+              Expect.fail("Unexpected cookie");
+            }
+          });
 
-Future testFlush() {
-  Completer completer = new Completer();
-  TestServerMain testServerMain = new TestServerMain();
-  testServerMain.setServerStartedHandler((int port) {
-    HttpClient httpClient = new HttpClient();
-
-    HttpClientConnection conn = httpClient.get("127.0.0.1", port, "/flush");
-    conn.onRequest = (HttpClientRequest request) {
-      request.outputStream.flush();
-      request.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(HttpStatus.OK, response.statusCode);
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () {
-        httpClient.shutdown();
-        testServerMain.shutdown();
-        completer.complete(true);
-      };
-    };
+          response.listen(
+              (_) { },
+              onDone: () {
+                httpClient.get("127.0.0.1", port, "/cookie2")
+                    .then((request) {
+                      request.cookies.add(response.cookies[0]);
+                      request.cookies.add(response.cookies[1]);
+                      return request.close();
+                    })
+                    .then((response) {
+                      response.listen(
+                          (_) { },
+                          onDone: () {
+                            httpClient.close();
+                            server.shutdown();
+                            completer.complete(true);
+                          });
+                    });
+              });
+        });
   });
-  testServerMain.start();
+  server.start();
   return completer.future;
 }
 
 void main() {
-  print('testHost()');
   testHost().then((_) {
-  print('testExpires()');
     return testExpires().then((_) {
-      print('testContentType()');
       return testContentType().then((_) {
-        print('testCookies()');
-        return testCookies().then((_) {
-          print('testFlush()');
-          return testFlush();
-        });
+        return testCookies();
       });
     });
-  }).then((_) {
-    print('done');
   });
 }
diff --git a/tests/standalone/io/http_auth_test.dart b/tests/standalone/io/http_auth_test.dart
index 7c8274f..cfc692b 100644
--- a/tests/standalone/io/http_auth_test.dart
+++ b/tests/standalone/io/http_auth_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -13,50 +13,53 @@
   HttpServer server;
   bool passwordChanged = false;
 
-  Server() : server = new HttpServer();
+  Future<Server> start() {
+    var completer = new Completer();
+    HttpServer.bind().then((s) {
+      server = s;
+      server.listen((HttpRequest request) {
+        var response = request.response;
+        if (request.uri.path == "/passwdchg") {
+          passwordChanged = true;
+          response.close();
+          return;
+        };
 
-  void start() {
-    server.listen("127.0.0.1", 0);
-    server.defaultRequestHandler =
-        (HttpRequest request, HttpResponse response) {
-          String username;
-          String password;
-          if (request.path == "/") {
-            username = "username";
-            password = "password";
-          } else {
-            username = request.path.substring(1, 6);
-            password = request.path.substring(1, 6);
-          }
-          if (passwordChanged) password = "${password}1";
-          if (request.headers[HttpHeaders.AUTHORIZATION] != null) {
-            Expect.equals(1, request.headers[HttpHeaders.AUTHORIZATION].length);
-            String authorization =
-              request.headers[HttpHeaders.AUTHORIZATION][0];
-            List<String> tokens = authorization.split(" ");
-            Expect.equals("Basic", tokens[0]);
-            String auth =
-                CryptoUtils.bytesToBase64(encodeUtf8("$username:$password"));
-            if (passwordChanged && auth != tokens[1]) {
-              response.statusCode = HttpStatus.UNAUTHORIZED;
-              response.headers.set(HttpHeaders.WWW_AUTHENTICATE,
-                                   "Basic, realm=realm");
-            } else {
-              Expect.equals(auth, tokens[1]);
-            }
-          } else {
+        String username;
+        String password;
+        if (request.uri.path == "/") {
+          username = "username";
+          password = "password";
+        } else {
+          username = request.uri.path.substring(1, 6);
+          password = request.uri.path.substring(1, 6);
+        }
+        if (passwordChanged) password = "${password}1";
+        if (request.headers[HttpHeaders.AUTHORIZATION] != null) {
+          Expect.equals(1, request.headers[HttpHeaders.AUTHORIZATION].length);
+          String authorization =
+            request.headers[HttpHeaders.AUTHORIZATION][0];
+          List<String> tokens = authorization.split(" ");
+          Expect.equals("Basic", tokens[0]);
+          String auth =
+              CryptoUtils.bytesToBase64(encodeUtf8("$username:$password"));
+          if (passwordChanged && auth != tokens[1]) {
             response.statusCode = HttpStatus.UNAUTHORIZED;
             response.headers.set(HttpHeaders.WWW_AUTHENTICATE,
                                  "Basic, realm=realm");
+          } else {
+            Expect.equals(auth, tokens[1]);
           }
-          response.outputStream.close();
-        };
-    server.addRequestHandler(
-        (HttpRequest request) => request.path == "/passwdchg",
-        (HttpRequest request, HttpResponse response) {
-          passwordChanged = true;
-          response.outputStream.close();
-        });
+        } else {
+          response.statusCode = HttpStatus.UNAUTHORIZED;
+          response.headers.set(HttpHeaders.WWW_AUTHENTICATE,
+                               "Basic, realm=realm");
+        }
+        response.close();
+      });
+      completer.complete(this);
+    });
+    return completer.future;
   }
 
   void shutdown() {
@@ -66,128 +69,39 @@
   int get port => server.port;
 }
 
-Server setupServer() {
-  Server server = new Server();
-  server.start();
-  return server;
+Future<Server> setupServer() {
+  return new Server().start();
 }
 
 void testUrlUserInfo() {
-  Server server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  HttpClientConnection conn =
-      client.getUrl(
-          Uri.parse(
-              "http://username:password@127.0.0.1:${server.port}/"));
-  conn.onResponse = (HttpClientResponse response) {
-    response.inputStream.onData = response.inputStream.read;
-    response.inputStream.onClosed = () {
-      server.shutdown();
-      client.shutdown();
-    };
-  };
+    client.getUrl(Uri.parse(
+        "http://username:password@127.0.0.1:${server.port}/"))
+      .then((request) => request.close())
+      .then((HttpClientResponse response) {
+        response.listen((_) {}, onDone: () {
+          server.shutdown();
+          client.close();
+        });
+      });
+  });
 }
 
 void testBasicNoCredentials() {
-  Server server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  Future makeRequest(Uri url) {
-    Completer completer = new Completer();
-    HttpClientConnection conn = client.getUrl(url);
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(HttpStatus.UNAUTHORIZED, response.statusCode);
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () => completer.complete(null);
-    };
-    return completer.future;
-  }
+    Future makeRequest(Uri url) {
+      return client.getUrl(url)
+        .then((HttpClientRequest request) => request.close())
+        .then((HttpClientResponse response) {
+          Expect.equals(HttpStatus.UNAUTHORIZED, response.statusCode);
+          return response.reduce(null, (x, y) {});
+        });
+    }
 
-  var futures = [];
-  for (int i = 0; i < 5; i++) {
-    futures.add(
-        makeRequest(
-            Uri.parse("http://127.0.0.1:${server.port}/test$i")));
-    futures.add(
-        makeRequest(
-            Uri.parse("http://127.0.0.1:${server.port}/test$i/xxx")));
-  }
-  Future.wait(futures).then((_) {
-    server.shutdown();
-    client.shutdown();
-  });
-}
-
-void testBasicCredentials() {
-  Server server = setupServer();
-  HttpClient client = new HttpClient();
-
-  Future makeRequest(Uri url) {
-    Completer completer = new Completer();
-    HttpClientConnection conn = client.getUrl(url);
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(HttpStatus.OK, response.statusCode);
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () => completer.complete(null);
-    };
-    return completer.future;
-  }
-
-  for (int i = 0; i < 5; i++) {
-    client.addCredentials(
-        Uri.parse("http://127.0.0.1:${server.port}/test$i"),
-        "realm",
-        new HttpClientBasicCredentials("test$i", "test$i"));
-  }
-
-  var futures = [];
-  for (int i = 0; i < 5; i++) {
-    futures.add(
-        makeRequest(
-            Uri.parse("http://127.0.0.1:${server.port}/test$i")));
-    futures.add(
-        makeRequest(
-            Uri.parse("http://127.0.0.1:${server.port}/test$i/xxx")));
-  }
-  Future.wait(futures).then((_) {
-    server.shutdown();
-    client.shutdown();
-  });
-}
-
-void testBasicAuthenticateCallback() {
-  Server server = setupServer();
-  HttpClient client = new HttpClient();
-  bool passwordChanged = false;
-
-  client.authenticate = (Uri url, String scheme, String realm) {
-    Expect.equals("Basic", scheme);
-    Expect.equals("realm", realm);
-    String username = url.path.substring(1, 6);
-    String password = url.path.substring(1, 6);
-    if (passwordChanged) password = "${password}1";
-    Completer completer = new Completer();
-    new Timer(const Duration(milliseconds: 10), () {
-      client.addCredentials(
-          url, realm, new HttpClientBasicCredentials(username, password));
-      completer.complete(true);
-    });
-    return completer.future;
-  };
-
-  Future makeRequest(Uri url) {
-    Completer completer = new Completer();
-    HttpClientConnection conn = client.getUrl(url);
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(HttpStatus.OK, response.statusCode);
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () => completer.complete(null);
-    };
-    return completer.future;
-  }
-
-  List<Future> makeRequests() {
     var futures = [];
     for (int i = 0; i < 5; i++) {
       futures.add(
@@ -198,17 +112,100 @@
               Uri.parse(
                   "http://127.0.0.1:${server.port}/test$i/xxx")));
     }
-    return futures;
-  }
+    Future.wait(futures).then((_) {
+      server.shutdown();
+      client.close();
+    });
+  });
+}
 
-  Future.wait(makeRequests()).then((_) {
-    makeRequest(
-        Uri.parse(
-            "http://127.0.0.1:${server.port}/passwdchg")).then((_) {
-      passwordChanged = true;
-      Future.wait(makeRequests()).then((_) {
-        server.shutdown();
-        client.shutdown();
+void testBasicCredentials() {
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
+
+    Future makeRequest(Uri url) {
+      return client.getUrl(url)
+        .then((HttpClientRequest request) => request.close())
+        .then((HttpClientResponse response) {
+          Expect.equals(HttpStatus.OK, response.statusCode);
+          return response.reduce(null, (x, y) {});
+        });
+    }
+
+    for (int i = 0; i < 5; i++) {
+      client.addCredentials(
+          Uri.parse("http://127.0.0.1:${server.port}/test$i"),
+          "realm",
+          new HttpClientBasicCredentials("test$i", "test$i"));
+    }
+
+    var futures = [];
+    for (int i = 0; i < 5; i++) {
+      futures.add(
+          makeRequest(
+              Uri.parse("http://127.0.0.1:${server.port}/test$i")));
+      futures.add(
+          makeRequest(
+              Uri.parse(
+                  "http://127.0.0.1:${server.port}/test$i/xxx")));
+    }
+    Future.wait(futures).then((_) {
+      server.shutdown();
+      client.close();
+    });
+  });
+}
+
+void testBasicAuthenticateCallback() {
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
+    bool passwordChanged = false;
+
+    client.authenticate = (Uri url, String scheme, String realm) {
+      Expect.equals("Basic", scheme);
+      Expect.equals("realm", realm);
+      String username = url.path.substring(1, 6);
+      String password = url.path.substring(1, 6);
+      if (passwordChanged) password = "${password}1";
+      Completer completer = new Completer();
+      new Timer(10, (_) {
+        client.addCredentials(
+            url, realm, new HttpClientBasicCredentials(username, password));
+        completer.complete(true);
+      });
+      return completer.future;
+    };
+
+    Future makeRequest(Uri url) {
+      return client.getUrl(url)
+        .then((HttpClientRequest request) => request.close())
+        .then((HttpClientResponse response) {
+          Expect.equals(HttpStatus.OK, response.statusCode);
+          return response.reduce(null, (x, y) {});
+        });
+    }
+
+    List<Future> makeRequests() {
+      var futures = [];
+      for (int i = 0; i < 5; i++) {
+        futures.add(
+            makeRequest(
+                Uri.parse("http://127.0.0.1:${server.port}/test$i")));
+        futures.add(
+            makeRequest(
+                Uri.parse("http://127.0.0.1:${server.port}/test$i/xxx")));
+      }
+      return futures;
+    }
+
+    Future.wait(makeRequests()).then((_) {
+      makeRequest(
+          Uri.parse("http://127.0.0.1:${server.port}/passwdchg")).then((_) {
+        passwordChanged = true;
+        Future.wait(makeRequests()).then((_) {
+          server.shutdown();
+          client.close();
+        });
       });
     });
   });
diff --git a/tests/standalone/io/http_basic_test.dart b/tests/standalone/io/http_basic_test.dart
index 9ec9a6a..eff6f5d 100644
--- a/tests/standalone/io/http_basic_test.dart
+++ b/tests/standalone/io/http_basic_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
@@ -34,7 +34,7 @@
     _serverPort.send(command, _statusPort.toSendPort());
   }
 
-  void shutdown() {
+  void close() {
     // Send server stop message to the server.
     _serverPort.send(new TestServerCommand.stop(), _statusPort.toSendPort());
     _statusPort.close();
@@ -98,45 +98,49 @@
 
 class TestServer {
   // Echo the request content back to the response.
-  void _echoHandler(HttpRequest request, HttpResponse response) {
+  void _echoHandler(HttpRequest request) {
+    var response = request.response;
     Expect.equals("POST", request.method);
     response.contentLength = request.contentLength;
-    request.inputStream.pipe(response.outputStream);
+    request.pipe(response);
   }
 
   // Echo the request content back to the response.
-  void _zeroToTenHandler(HttpRequest request, HttpResponse response) {
+  void _zeroToTenHandler(HttpRequest request) {
+    var response = request.response;
     Expect.equals("GET", request.method);
-    request.inputStream.onData = () {};
-    request.inputStream.onClosed = () {
-      response.outputStream.writeString("01234567890");
-      response.outputStream.close();
-    };
+    request.listen((_) {}, onDone: () {
+        response.addString("01234567890");
+        response.close();
+      });
   }
 
   // Return a 404.
-  void _notFoundHandler(HttpRequest request, HttpResponse response) {
+  void _notFoundHandler(HttpRequest request) {
+    var response = request.response;
     response.statusCode = HttpStatus.NOT_FOUND;
     response.headers.set("Content-Type", "text/html; charset=UTF-8");
-    response.outputStream.writeString("Page not found");
-    response.outputStream.close();
+    response.addString("Page not found");
+    response.close();
   }
 
   // Return a 301 with a custom reason phrase.
-  void _reasonForMovingHandler(HttpRequest request, HttpResponse response) {
+  void _reasonForMovingHandler(HttpRequest request) {
+    var response = request.response;
     response.statusCode = HttpStatus.MOVED_PERMANENTLY;
     response.reasonPhrase = "Don't come looking here any more";
-    response.outputStream.close();
+    response.close();
   }
 
   // Check the "Host" header.
-  void _hostHandler(HttpRequest request, HttpResponse response) {
+  void _hostHandler(HttpRequest request) {
+    var response = request.response;
     Expect.equals(1, request.headers["Host"].length);
     Expect.equals("www.dartlang.org:1234", request.headers["Host"][0]);
     Expect.equals("www.dartlang.org", request.headers.host);
     Expect.equals(1234, request.headers.port);
     response.statusCode = HttpStatus.OK;
-    response.outputStream.close();
+    response.close();
   }
 
   void init() {
@@ -150,11 +154,12 @@
 
   void dispatch(var message, SendPort replyTo) {
     if (message.isStart) {
-      _server = new HttpServer();
       try {
-        _server.listen("127.0.0.1", 0);
-        _server.defaultRequestHandler = _requestReceivedHandler;
-        replyTo.send(new TestServerStatus.started(_server.port), null);
+        HttpServer.bind().then((server) {
+          _server = server;
+          _server.listen(_requestReceivedHandler);
+          replyTo.send(new TestServerStatus.started(_server.port), null);
+        });
       } catch (e) {
         replyTo.send(new TestServerStatus.error(), null);
       }
@@ -167,12 +172,12 @@
     }
   }
 
-  void _requestReceivedHandler(HttpRequest request, HttpResponse response) {
-    var requestHandler =_requestHandlers[request.path];
+  void _requestReceivedHandler(HttpRequest request) {
+    var requestHandler =_requestHandlers[request.uri.path];
     if (requestHandler != null) {
-      requestHandler(request, response);
+      requestHandler(request);
     } else {
-      _notFoundHandler(request, response);
+      _notFoundHandler(request);
     }
   }
 
@@ -184,7 +189,7 @@
 void testStartStop() {
   TestServerMain testServerMain = new TestServerMain();
   testServerMain.setServerStartedHandler((int port) {
-    testServerMain.shutdown();
+    testServerMain.close();
   });
   testServerMain.start();
 }
@@ -193,19 +198,19 @@
   TestServerMain testServerMain = new TestServerMain();
   testServerMain.setServerStartedHandler((int port) {
     HttpClient httpClient = new HttpClient();
-    HttpClientConnection conn =
-        httpClient.get("127.0.0.1", port, "/0123456789");
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(HttpStatus.OK, response.statusCode);
-      StringInputStream stream = new StringInputStream(response.inputStream);
-      StringBuffer body = new StringBuffer();
-      stream.onData = () => body.add(stream.read());
-      stream.onClosed = () {
-        Expect.equals("01234567890", body.toString());
-        httpClient.shutdown();
-        testServerMain.shutdown();
-      };
-    };
+    httpClient.get("127.0.0.1", port, "/0123456789")
+        .then((request) => request.close())
+        .then((response) {
+          Expect.equals(HttpStatus.OK, response.statusCode);
+          StringBuffer body = new StringBuffer();
+          response.listen(
+            (data) => body.add(new String.fromCharCodes(data)),
+            onDone: () {
+              Expect.equals("01234567890", body.toString());
+              httpClient.close();
+              testServerMain.close();
+            });
+        });
   });
   testServerMain.start();
 }
@@ -220,34 +225,33 @@
     int count = 0;
     HttpClient httpClient = new HttpClient();
     void sendRequest() {
-      HttpClientConnection conn =
-          httpClient.post("127.0.0.1", port, "/echo");
-      conn.onRequest = (HttpClientRequest request) {
-        if (chunkedEncoding) {
-          request.outputStream.writeString(data.substring(0, 10));
-          request.outputStream.writeString(data.substring(10, data.length));
-        } else {
-          request.contentLength = data.length;
-          request.outputStream.write(data.charCodes);
-        }
-        request.outputStream.close();
-      };
-      conn.onResponse = (HttpClientResponse response) {
-        Expect.equals(HttpStatus.OK, response.statusCode);
-        StringInputStream stream = new StringInputStream(response.inputStream);
-        StringBuffer body = new StringBuffer();
-        stream.onData = () => body.add(stream.read());
-        stream.onClosed = () {
-          Expect.equals(data, body.toString());
-          count++;
-          if (count < kMessageCount) {
-            sendRequest();
-          } else {
-            httpClient.shutdown();
-            testServerMain.shutdown();
-          }
-        };
-      };
+      httpClient.post("127.0.0.1", port, "/echo")
+          .then((request) {
+            if (chunkedEncoding) {
+              request.addString(data.substring(0, 10));
+              request.addString(data.substring(10, data.length));
+            } else {
+              request.contentLength = data.length;
+              request.addString(data);
+            }
+            return request.close();
+          })
+          .then((response) {
+            Expect.equals(HttpStatus.OK, response.statusCode);
+            StringBuffer body = new StringBuffer();
+            response.listen(
+              (data) => body.add(new String.fromCharCodes(data)),
+              onDone: () {
+                Expect.equals(data, body.toString());
+                count++;
+                if (count < kMessageCount) {
+                  sendRequest();
+                } else {
+                  httpClient.close();
+                  testServerMain.close();
+                }
+              });
+          });
     }
 
     sendRequest();
@@ -264,19 +268,19 @@
   TestServerMain testServerMain = new TestServerMain();
   testServerMain.setServerStartedHandler((int port) {
     HttpClient httpClient = new HttpClient();
-    HttpClientConnection conn =
-        httpClient.get("127.0.0.1", port, "/thisisnotfound");
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(HttpStatus.NOT_FOUND, response.statusCode);
-      var body = new StringBuffer();
-      var stream = response.inputStream;
-      stream.onData = () => body.add(new String.fromCharCodes(stream.read()));
-      stream.onClosed = () {
-        Expect.equals("Page not found", body.toString());
-        httpClient.shutdown();
-        testServerMain.shutdown();
-      };
-    };
+    httpClient.get("127.0.0.1", port, "/thisisnotfound")
+        .then((request) => request.close())
+        .then((response) {
+          Expect.equals(HttpStatus.NOT_FOUND, response.statusCode);
+          var body = new StringBuffer();
+          response.listen(
+              (data) => body.add(new String.fromCharCodes(data)),
+              onDone: () {
+                Expect.equals("Page not found", body.toString());
+                httpClient.close();
+                testServerMain.close();
+              });
+        });
   });
   testServerMain.start();
 }
@@ -285,19 +289,22 @@
   TestServerMain testServerMain = new TestServerMain();
   testServerMain.setServerStartedHandler((int port) {
     HttpClient httpClient = new HttpClient();
-    HttpClientConnection conn =
-        httpClient.get("127.0.0.1", port, "/reasonformoving");
-    conn.followRedirects = false;
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(HttpStatus.MOVED_PERMANENTLY, response.statusCode);
-      Expect.equals("Don't come looking here any more", response.reasonPhrase);
-      var stream = response.inputStream;
-      stream.onData = () => Expect.fail("No data expected");
-      stream.onClosed = () {
-        httpClient.shutdown();
-        testServerMain.shutdown();
-      };
-    };
+    httpClient.get("127.0.0.1", port, "/reasonformoving")
+        .then((request) {
+          request.followRedirects = false;
+          return request.close();
+        })
+        .then((response) {
+          Expect.equals(HttpStatus.MOVED_PERMANENTLY, response.statusCode);
+          Expect.equals("Don't come looking here any more",
+                        response.reasonPhrase);
+          response.listen(
+              (data) => Expect.fail("No data expected"),
+              onDone: () {
+                httpClient.close();
+                testServerMain.close();
+              });
+        });
   });
   testServerMain.start();
 }
diff --git a/tests/standalone/io/http_client_connect_test.dart b/tests/standalone/io/http_client_connect_test.dart
new file mode 100644
index 0000000..dd8a3bf
--- /dev/null
+++ b/tests/standalone/io/http_client_connect_test.dart
@@ -0,0 +1,134 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:isolate';
+
+void testGetEmptyRequest() {
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+      request.pipe(request.response);
+    });
+
+    var client = new HttpClient();
+    client.get("127.0.0.1", server.port, "/")
+      .then((request) => request.close())
+      .then((response) {
+        response.listen(
+            (data) {},
+            onDone: server.close);
+      });
+  });
+}
+
+void testGetDataRequest() {
+  HttpServer.bind().then((server) {
+    var data = "lalala".charCodes;
+    server.listen((request) {
+      request.response.add(data);
+      request.pipe(request.response);
+    });
+
+    var client = new HttpClient();
+    client.get("127.0.0.1", server.port, "/")
+      .then((request) => request.close())
+      .then((response) {
+        int count = 0;
+        response.listen(
+          (data) => count += data.length,
+          onDone: () {
+            server.close();
+            Expect.equals(data.length, count);
+          });
+      });
+  });
+}
+
+void testGetInvalidHost() {
+  var port = new ReceivePort();
+  var client = new HttpClient();
+  client.get("__SOMETHING_INVALID__", 8888, "/")
+    .catchError((error) {
+      port.close();
+      client.close();
+    });
+}
+
+void testGetServerClose() {
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+      server.close();
+    });
+
+    var port = new ReceivePort();
+    var client = new HttpClient();
+    client.get("127.0.0.1", server.port, "/")
+      .then((request) => request.close())
+      .then((response) {
+        Expect.fail("Request not expected");
+      })
+        .catchError((error) => port.close(),
+                    test: (error) => error is HttpParserException);
+  });
+}
+
+void testGetDataServerClose() {
+  var completer = new Completer();
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+      request.response.contentLength = 100;
+      request.response.addString("data");
+      request.response.addString("more data");
+      completer.future.then((_) => server.close());
+    });
+
+    var port = new ReceivePort();
+    var client = new HttpClient();
+    client.get("127.0.0.1", server.port, "/")
+      .then((request) => request.close())
+      .then((response) {
+        // Close the (incomplete) response, now we have seen the response object.
+        completer.complete(null);
+        int errors = 0;
+        response.listen(
+          (data) {},
+          onError: (error) => errors++,
+          onDone: () {
+            port.close();
+            Expect.equals(1, errors);
+          });
+      });
+  });
+}
+
+void testPostEmptyRequest() {
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+      request.pipe(request.response);
+    });
+
+    var client = new HttpClient();
+    client.post("127.0.0.1", server.port, "/")
+      .then((request) => request.close())
+      .then((response) {
+        response.listen((data) {}, onDone: server.close);
+      });
+  });
+}
+
+
+void main() {
+  testGetEmptyRequest();
+  testGetDataRequest();
+  testGetInvalidHost();
+  testGetServerClose();
+  testGetDataServerClose();
+  testPostEmptyRequest();
+}
diff --git a/tests/standalone/io/http_client_request_test.dart b/tests/standalone/io/http_client_request_test.dart
new file mode 100644
index 0000000..02d0a86
--- /dev/null
+++ b/tests/standalone/io/http_client_request_test.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:io";
+import "dart:isolate";
+import "dart:scalarlist";
+
+void testClientRequest(void handler(request)) {
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+      request.listen((_) {}, onDone: () {
+        request.response.close();
+      }, onError: (e) {});
+    });
+
+    var client = new HttpClient();
+    client.get("127.0.0.1", server.port, "/")
+      .then((request) {
+        return handler(request);
+      })
+      .then((response) {
+        response.listen((_) {}, onDone: () {
+          client.close();
+          server.close();
+        });
+      })
+      .catchError((error) {
+        server.close();
+        client.close();
+      }, test: (e) => e is HttpParserException);
+  });
+}
+
+void testResponseDone() {
+  testClientRequest((request) {
+    request.close();
+    request.done.then((req) {
+      Expect.equals(request, req);
+    });
+    return request.response;
+  });
+}
+
+void testBadResponseAdd() {
+  testClientRequest((request) {
+    var port = new ReceivePort();
+    request.contentLength = 0;
+    request.add([0]);
+    request.done.catchError((error) {
+      port.close();
+    }, test: (e) => e is HttpException);
+    return request.response;
+  });
+
+  testClientRequest((request) {
+    var port = new ReceivePort();
+    request.contentLength = 5;
+    request.add([0, 0, 0]);
+    request.add([0, 0, 0]);
+    request.done.catchError((error) {
+      port.close();
+    }, test: (e) => e is HttpException);
+    return request.response;
+  });
+
+  testClientRequest((request) {
+    var port = new ReceivePort();
+    request.contentLength = 0;
+    request.add(new Uint8List(64 * 1024));
+    request.add(new Uint8List(64 * 1024));
+    request.add(new Uint8List(64 * 1024));
+    request.done.catchError((error) {
+      port.close();
+    }, test: (e) => e is HttpException);
+    return request.response;
+  });
+}
+
+void testBadResponseClose() {
+  testClientRequest((request) {
+    var port = new ReceivePort();
+    request.contentLength = 5;
+    request.close();
+    request.done.catchError((error) {
+      port.close();
+    }, test: (e) => e is HttpException);
+    return request.response;
+  });
+
+  testClientRequest((request) {
+    var port = new ReceivePort();
+    request.contentLength = 5;
+    request.add([0]);
+    request.close();
+    request.done.catchError((error) {
+      port.close();
+    }, test: (e) => e is HttpException);
+    return request.response;
+  });
+}
+
+void main() {
+  testResponseDone();
+  testBadResponseAdd();
+  testBadResponseClose();
+}
diff --git a/tests/standalone/io/http_client_socket_reuse_test.dart b/tests/standalone/io/http_client_socket_reuse_test.dart
new file mode 100644
index 0000000..715624a8
--- /dev/null
+++ b/tests/standalone/io/http_client_socket_reuse_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+import "dart:io";
+import "dart:uri";
+import "dart:isolate";
+
+// By running tests sequentially, we cover the socket reuse code in HttpClient.
+
+void testGoogleUrls() {
+  int testsStarted = 0;
+  int testsFinished = 0;
+  bool allStarted = false;
+  HttpClient client = new HttpClient();
+
+  Future testUrl(String url) {
+    testsStarted++;
+    var requestUri = Uri.parse(url);
+    return client.getUrl(requestUri)
+        .then((HttpClientRequest request) => request.close())
+        .then((HttpClientResponse response) {
+          Expect.isTrue(response.statusCode < 500);
+          if (requestUri.path.length == 0) {
+            Expect.isTrue(response.statusCode != 404);
+          }
+          return response.reduce(null, (previous, element) => null);
+        })
+        .catchError((error) => Expect.fail("Unexpected IO error: $error"));
+  }
+
+  // TODO(3593): Use a Dart HTTP server for this test.
+  testUrl('http://www.google.dk')
+    .then((_) => testUrl('http://www.google.dk'))
+    .then((_) => testUrl('http://www.google.dk/#q=foo'))
+    .then((_) => testUrl('http://www.google.dk/#hl=da&q=foo'))
+    .then((_) { client.close(); });
+}
+
+void main() {
+  testGoogleUrls();
+}
diff --git a/tests/standalone/io/http_client_test.dart b/tests/standalone/io/http_client_test.dart
index 698090a..c3e7db1 100644
--- a/tests/standalone/io/http_client_test.dart
+++ b/tests/standalone/io/http_client_test.dart
@@ -1,6 +1,11 @@
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
 
 import "dart:io";
 import "dart:uri";
@@ -8,21 +13,13 @@
 
 void testGoogle() {
   HttpClient client = new HttpClient();
-  var conn = client.get('www.google.com', 80, '/');
-
-  conn.onRequest = (HttpClientRequest request) {
-    request.outputStream.close();
-  };
-  conn.onResponse = (HttpClientResponse response) {
-    Expect.isTrue(response.statusCode < 500);
-    response.inputStream.onData = () {
-      response.inputStream.read();
-    };
-    response.inputStream.onClosed = () {
-      client.shutdown();
-    };
-  };
-  conn.onError = (error) => Expect.fail("Unexpected IO error $error");
+  client.get('www.google.com', 80, '/')
+      .then((request) => request.close())
+      .then((response) {
+        Expect.isTrue(response.statusCode < 500);
+        response.listen((data) {}, onDone: client.close);
+      })
+      .catchError((error) => Expect.fail("Unexpected IO error: $error"));
 }
 
 int testGoogleUrlCount = 0;
@@ -31,25 +28,19 @@
 
   void testUrl(String url) {
     var requestUri = Uri.parse(url);
-    var conn = client.getUrl(requestUri);
-
-    conn.onRequest = (HttpClientRequest request) {
-      request.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      testGoogleUrlCount++;
-      Expect.isTrue(response.statusCode < 500);
-      if (requestUri.path.length == 0) {
-        Expect.isTrue(response.statusCode != 404);
-      }
-      response.inputStream.onData = () {
-        response.inputStream.read();
-      };
-      response.inputStream.onClosed = () {
-        if (testGoogleUrlCount == 5) client.shutdown();
-      };
-    };
-    conn.onError = (error) => Expect.fail("Unexpected IO error $error");
+    client.getUrl(requestUri)
+        .then((request) => request.close())
+        .then((response) {
+          testGoogleUrlCount++;
+          Expect.isTrue(response.statusCode < 500);
+          if (requestUri.path.length == 0) {
+            Expect.isTrue(response.statusCode != 404);
+          }
+          response.listen((data) {}, onDone: () {
+            if (testGoogleUrlCount == 5) client.close();
+          });
+        })
+        .catchError((error) => Expect.fail("Unexpected IO error: $error"));
   }
 
   testUrl('http://www.google.com');
@@ -67,15 +58,13 @@
 
 void testBadHostName() {
   HttpClient client = new HttpClient();
-  HttpClientConnection connection =
-      client.get("some.bad.host.name.7654321", 0, "/");
-  connection.onRequest = (HttpClientRequest request) {
-    Expect.fail("Should not open a request on bad hostname");
-  };
   ReceivePort port = new ReceivePort();
-  connection.onError = (Exception error) {
-    port.close();  // We expect onError to be called, due to bad host name.
-  };
+  client.get("some.bad.host.name.7654321", 0, "/")
+    .then((request) {
+      Expect.fail("Should not open a request on bad hostname");
+    }).catchError((error) {
+      port.close();  // We expect onError to be called, due to bad host name.
+    }, test: (error) => error is! String);
 }
 
 void main() {
diff --git a/tests/standalone/io/http_connection_close_test.dart b/tests/standalone/io/http_connection_close_test.dart
index 75f3b98..e8f3609 100644
--- a/tests/standalone/io/http_connection_close_test.dart
+++ b/tests/standalone/io/http_connection_close_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
@@ -8,74 +8,73 @@
 import "dart:uri";
 
 void testHttp10Close(bool closeRequest) {
-  HttpServer server = new HttpServer();
-  server.listen("127.0.0.1", 0, backlog: 5);
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+      request.response.close();
+    });
 
-  Socket socket = new Socket("127.0.0.1", server.port);
-  socket.onConnect = () {
-    List<int> buffer = new List<int>.fixedLength(1024);
-    socket.outputStream.writeString("GET / HTTP/1.0\r\n\r\n");
-    if (closeRequest) socket.outputStream.close();
-    socket.onData = () => socket.readList(buffer, 0, buffer.length);
-    socket.onClosed = () {
-      if (!closeRequest) socket.close(true);
-      server.close();
-    };
-  };
+    Socket.connect("127.0.0.1", server.port)
+      .then((socket) {
+        socket.addString("GET / HTTP/1.0\r\n\r\n");
+        socket.listen(
+          (data) {},
+          onDone: () {
+           if (!closeRequest) socket.destroy();
+            server.close();
+          });
+        if (closeRequest) socket.close();
+      });
+  });
 }
 
 void testHttp11Close(bool closeRequest) {
-  HttpServer server = new HttpServer();
-  server.listen("127.0.0.1", 0, backlog: 5);
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+     request.response.close();
+    });
 
-  Socket socket = new Socket("127.0.0.1", server.port);
-  socket.onConnect = () {
-    List<int> buffer = new List<int>.fixedLength(1024);
-    socket.outputStream.writeString(
-        "GET / HTTP/1.1\r\nConnection: close\r\n\r\n");
-    if (closeRequest) socket.outputStream.close();
-    socket.onData = () => socket.readList(buffer, 0, buffer.length);
-    socket.onClosed = () {
-      if (!closeRequest) socket.close(true);
-      server.close();
-    };
-  };
+    Socket.connect("127.0.0.1", server.port)
+      .then((socket) {
+        List<int> buffer = new List<int>.fixedLength(1024);
+        socket.addString("GET / HTTP/1.1\r\nConnection: close\r\n\r\n");
+        socket.listen(
+          (data) {},
+          onDone: () {
+            if (!closeRequest) socket.destroy();
+            server.close();
+          });
+        if (closeRequest) socket.close();
+      });
+  });
 }
 
 void testStreamResponse() {
-  Timer timer;
-  var server = new HttpServer();
-  server.onError = (e) {
-    server.close();
-    timer.cancel();
-  };
-  server.listen("127.0.0.1", 0, backlog: 5);
-  server.defaultRequestHandler = (var request, var response) {
-    timer = new Timer.repeating(new Duration(milliseconds: 10), (_) {
-      DateTime now = new DateTime.now();
-      try {
-        response.outputStream.writeString(
-            'data:${now.millisecondsSinceEpoch}\n\n');
-      } catch (e) {
-        timer.cancel();
-        server.close();
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+      // TODO(ajohnsen): Use timer (see old version).
+      for (int i = 0; i < 10; i++) {
+        request.response.addString(
+            'data:${new DateTime.now().millisecondsSinceEpoch}\n\n');
       }
     });
-  };
 
-  var client = new HttpClient();
-  var connection =
-      client.getUrl(Uri.parse("http://127.0.0.1:${server.port}"));
-  connection.onResponse = (resp) {
-    int bytes = 0;
-    resp.inputStream.onData = () {
-      bytes += resp.inputStream.read().length;
-      if (bytes > 100) {
-        client.shutdown(force: true);
-      }
-    };
-  };
-  connection.onError = (e) => Expect.isTrue(e is HttpException);
+    var client = new HttpClient();
+    client.getUrl(Uri.parse("http://127.0.0.1:${server.port}"))
+      .then((request) => request.close())
+      .then((response) {
+        int bytes = 0;
+        response.listen(
+            (data) {
+              bytes += data.length;
+              if (bytes > 100) {
+                client.close(force: true);
+              }
+            },
+            onError: (error) {
+              server.close();
+            });
+      });
+  });
 }
 
 main() {
diff --git a/tests/standalone/io/http_connection_header_test.dart b/tests/standalone/io/http_connection_header_test.dart
index 77cf976..b7966a2 100644
--- a/tests/standalone/io/http_connection_header_test.dart
+++ b/tests/standalone/io/http_connection_header_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
@@ -31,48 +31,47 @@
 }
 
 void test(int totalConnections, bool clientPersistentConnection) {
-  HttpServer server = new HttpServer();
-  server.onError = (e) => Expect.fail("Unexpected error $e");
-  server.listen("127.0.0.1", 0, backlog: totalConnections);
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    // Check expected request.
-    Expect.equals(clientPersistentConnection, request.persistentConnection);
-    Expect.equals(clientPersistentConnection, response.persistentConnection);
-    checkExpectedConnectionHeaders(request.headers,
-                                   request.persistentConnection);
+  HttpServer.bind().then((server) {
+    server.listen((HttpRequest request) {
+      // Check expected request.
+      Expect.equals(clientPersistentConnection, request.persistentConnection);
+      Expect.equals(clientPersistentConnection,
+                    request.response.persistentConnection);
+      checkExpectedConnectionHeaders(request.headers,
+                                     request.persistentConnection);
 
-    // Generate response. If the client signaled non-persistent
-    // connection the server should not need to set it.
-    if (request.persistentConnection) {
-      response.persistentConnection = false;
+      // Generate response. If the client signaled non-persistent
+      // connection the server should not need to set it.
+      if (request.persistentConnection) {
+        request.response.persistentConnection = false;
+      }
+      setConnectionHeaders(request.response.headers);
+      request.response.close();
+    });
+
+    int count = 0;
+    HttpClient client = new HttpClient();
+    for (int i = 0; i < totalConnections; i++) {
+      client.get("127.0.0.1", server.port, "/")
+        .then((HttpClientRequest request) {
+          setConnectionHeaders(request.headers);
+          request.persistentConnection = clientPersistentConnection;
+          return request.close();
+        })
+        .then((HttpClientResponse response) {
+          Expect.isFalse(response.persistentConnection);
+          checkExpectedConnectionHeaders(response.headers,
+                                         response.persistentConnection);
+          response.listen((_) {}, onDone: () {
+            count++;
+            if (count == totalConnections) {
+              client.close();
+              server.close();
+            }
+          });
+        });
     }
-    setConnectionHeaders(response.headers);
-    response.outputStream.close();
-  };
-
-  int count = 0;
-  HttpClient client = new HttpClient();
-  for (int i = 0; i < totalConnections; i++) {
-    HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-    conn.onError = (e) => Expect.fail("Unexpected error $e");
-    conn.onRequest = (HttpClientRequest request) {
-      setConnectionHeaders(request.headers);
-      request.persistentConnection = clientPersistentConnection;
-      request.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.isFalse(response.persistentConnection);
-      checkExpectedConnectionHeaders(response.headers,
-                                     response.persistentConnection);
-      response.inputStream.onClosed = () {
-        count++;
-        if (count == totalConnections) {
-          client.shutdown();
-          server.close();
-        }
-      };
-    };
-  }
+  });
 }
 
 
diff --git a/tests/standalone/io/http_connection_info_test.dart b/tests/standalone/io/http_connection_info_test.dart
index 627d0fc..54c0628 100644
--- a/tests/standalone/io/http_connection_info_test.dart
+++ b/tests/standalone/io/http_connection_info_test.dart
@@ -1,44 +1,46 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:io";
 
 void testHttpConnectionInfo() {
-  HttpServer server = new HttpServer();
-  server.listen("0.0.0.0", 0);
-  int clientPort;
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    Expect.isTrue(request.connectionInfo.remoteHost is String);
-    Expect.equals(request.connectionInfo.localPort, server.port);
-    Expect.isNotNull(clientPort);
-    Expect.equals(request.connectionInfo.remotePort, clientPort);
-    request.inputStream.onClosed = () {
-      response.outputStream.close();
-    };
-  };
-  server.onError = (Exception e) {
-    Expect.fail("Unexpected error: $e");
-  };
+  HttpServer.bind("0.0.0.0", 0).then((server) {
+    int clientPort;
 
+    server.listen((request) {
+      var response = request.response;
+      Expect.isTrue(request.connectionInfo.remoteHost is String);
+      Expect.isTrue(response.connectionInfo.remoteHost is String);
+      Expect.equals(request.connectionInfo.localPort, server.port);
+      Expect.equals(response.connectionInfo.localPort, server.port);
+      Expect.isNotNull(clientPort);
+      Expect.equals(request.connectionInfo.remotePort, clientPort);
+      Expect.equals(response.connectionInfo.remotePort, clientPort);
+      request.listen(
+          (_) { },
+          onDone: ()  { request.response.close(); });
+    });
 
-  HttpClient client = new HttpClient();
-  HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-  conn.onRequest = (HttpClientRequest request) {
-    Expect.isTrue(conn.connectionInfo.remoteHost is String);
-    Expect.equals(conn.connectionInfo.remotePort, server.port);
-    clientPort = conn.connectionInfo.localPort;
-    request.outputStream.close();
-  };
-  conn.onResponse = (HttpClientResponse response) {
-    response.inputStream.onClosed = () {
-      client.shutdown();
-      server.close();
-    };
-  };
-  conn.onError = (Exception e) {
-    Expect.fail("Unexpected error: $e");
-  };
+    HttpClient client = new HttpClient();
+    client.get("127.0.0.1", server.port, "/")
+        .then((request) {
+          Expect.isTrue(request.connectionInfo.remoteHost is String);
+          Expect.equals(request.connectionInfo.remotePort, server.port);
+          clientPort = request.connectionInfo.localPort;
+          return request.close();
+        })
+        .then((response) {
+            Expect.equals(server.port, response.connectionInfo.remotePort);
+            Expect.equals(clientPort, response.connectionInfo.localPort);
+            response.listen(
+                (_) { },
+                onDone: () {
+                  client.close();
+                  server.close();
+                });
+        });
+    });
 }
 
 void main() {
diff --git a/tests/standalone/io/http_content_length_test.dart b/tests/standalone/io/http_content_length_test.dart
index 6290218..14d4000 100644
--- a/tests/standalone/io/http_content_length_test.dart
+++ b/tests/standalone/io/http_content_length_test.dart
@@ -6,192 +6,229 @@
 import "dart:io";
 
 void testNoBody(int totalConnections, bool explicitContentLength) {
-  HttpServer server = new HttpServer();
-  server.onError = (e) => Expect.fail("Unexpected error $e");
-  server.listen("127.0.0.1", 0, backlog: totalConnections);
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    Expect.equals("0", request.headers.value('content-length'));
-    Expect.equals(0, request.contentLength);
-    response.contentLength = 0;
-    OutputStream stream = response.outputStream;
-    Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-    stream.close();
-    Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-  };
+  var errors = 0;
+  HttpServer.bind("127.0.0.1", 0, totalConnections).then((server) {
+    server.listen(
+        (HttpRequest request) {
+          Expect.equals("0", request.headers.value('content-length'));
+          Expect.equals(0, request.contentLength);
+          var response = request.response;
+          response.contentLength = 0;
+          response.done
+            .then((_) {
+              Expect.fail("Unexpected successful response completion");
+            })
+            .catchError((e) {
+              Expect.isTrue(e.error is HttpException);
+            });
+          // addString with content length 0 closes the connection and
+          // reports an error.
+          response.addString("x");
+          // Subsequent addString are ignored as there is already an
+          // error.
+          response.addString("x");
+          // After an explicit close, addString becomes a state error
+          // because we have said we will not add more.
+          response.close();
+          Expect.throws(() => response.addString("x"),
+                        (e) => e is StateError);
+        },
+        onError: (e) {
+          Expect.fail("Unexpected server error $e");
+        });
 
-  int count = 0;
-  HttpClient client = new HttpClient();
-  for (int i = 0; i < totalConnections; i++) {
-    HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-    conn.onError = (e) => Expect.fail("Unexpected error $e");
-    conn.onRequest = (HttpClientRequest request) {
-      OutputStream stream = request.outputStream;
-      if (explicitContentLength) {
-        request.contentLength = 0;
-        Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-      }
-      stream.close();
-      Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals("0", response.headers.value('content-length'));
-      Expect.equals(0, response.contentLength);
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () {
-        if (++count == totalConnections) {
-          client.shutdown();
-          server.close();
-        }
-      };
-    };
-  }
+    int count = 0;
+    HttpClient client = new HttpClient();
+    for (int i = 0; i < totalConnections; i++) {
+      client.get("127.0.0.1", server.port, "/")
+          .then((request) {
+            if (explicitContentLength) {
+              request.contentLength = 0;
+            }
+            return request.close();
+          })
+          .then((response) {
+            Expect.equals("0", response.headers.value('content-length'));
+            Expect.equals(0, response.contentLength);
+            response.listen(
+                (d) {},
+                onDone: () {
+                  if (++count == totalConnections) {
+                    client.close();
+                    server.close();
+                  }
+                });
+          })
+          .catchError((e) {
+            Expect.fail("Unexpected error $e");
+          });
+    }
+  });
 }
 
 void testBody(int totalConnections, bool useHeader) {
-  HttpServer server = new HttpServer();
-  server.onError = (e) => Expect.fail("Unexpected error $e");
-  server.listen("127.0.0.1", 0, backlog: totalConnections);
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    Expect.equals("2", request.headers.value('content-length'));
-    Expect.equals(2, request.contentLength);
-    if (useHeader) {
-      response.contentLength = 2;
-    } else {
-      response.headers.set("content-length", 2);
-    }
-    request.inputStream.onData = request.inputStream.read;
-    request.inputStream.onClosed = () {
-      OutputStream stream = response.outputStream;
-      stream.writeString("x");
-      Expect.throws(() => response.contentLength = 3, (e) => e is HttpException);
-      stream.writeString("x");
-      Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-      stream.close();
-      Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-    };
-  };
+  HttpServer.bind("127.0.0.1", 0, totalConnections).then((server) {
+    server.listen(
+        (HttpRequest request) {
+          Expect.equals("2", request.headers.value('content-length'));
+          Expect.equals(2, request.contentLength);
+          var response = request.response;
+          if (useHeader) {
+            response.contentLength = 2;
+          } else {
+            response.headers.set("content-length", 2);
+          }
+          request.listen(
+              (d) {},
+              onDone: () {
+                response.addString("x");
+                Expect.throws(() => response.contentLength = 3,
+                              (e) => e is HttpException);
+                response.addString("x");
+                response.addString("x");
+                response.done
+                    .then((_) {
+                      Expect.fail("Unexpected successful response completion");
+                    })
+                    .catchError((e) {
+                      Expect.isTrue(e.error is HttpException);
+                    });
+                response.close();
+                Expect.throws(() => response.addString("x"),
+                              (e) => e is StateError);
+              });
+        },
+        onError: (e) => Expect.fail("Unexpected error $e"));
 
-  int count = 0;
-  HttpClient client = new HttpClient();
-  for (int i = 0; i < totalConnections; i++) {
-    HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-    conn.onError = (e) => Expect.fail("Unexpected error $e");
-    conn.onRequest = (HttpClientRequest request) {
-      if (useHeader) {
-        request.contentLength = 2;
-      } else {
-        request.headers.add(HttpHeaders.CONTENT_LENGTH, "7");
-        request.headers.add(HttpHeaders.CONTENT_LENGTH, "2");
-      }
-      OutputStream stream = request.outputStream;
-      stream.writeString("x");
-      Expect.throws(() => request.contentLength = 3, (e) => e is HttpException);
-      stream.writeString("x");
-      Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-      stream.close();
-      Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals("2", response.headers.value('content-length'));
-      Expect.equals(2, response.contentLength);
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () {
-        if (++count == totalConnections) {
-          client.shutdown();
-          server.close();
-        }
-      };
-    };
-  }
+    int count = 0;
+    HttpClient client = new HttpClient();
+    for (int i = 0; i < totalConnections; i++) {
+      client.get("127.0.0.1", server.port, "/")
+          .then((request) {
+            if (useHeader) {
+              request.contentLength = 2;
+            } else {
+              request.headers.add(HttpHeaders.CONTENT_LENGTH, "7");
+              request.headers.add(HttpHeaders.CONTENT_LENGTH, "2");
+            }
+            request.addString("x");
+            Expect.throws(() => request.contentLength = 3,
+                          (e) => e is HttpException);
+            request.addString("x");
+            return request.close();
+          })
+          .then((response) {
+            Expect.equals("2", response.headers.value('content-length'));
+            Expect.equals(2, response.contentLength);
+            response.listen(
+                (d) {},
+                onDone: () {
+                  if (++count == totalConnections) {
+                    client.close();
+                    server.close();
+                  }
+                });
+          });
+    }
+  });
 }
 
 void testBodyChunked(int totalConnections, bool useHeader) {
-  HttpServer server = new HttpServer();
-  server.onError = (e) => Expect.fail("Unexpected error $e");
-  server.listen("127.0.0.1", 0, backlog: totalConnections);
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    Expect.isNull(request.headers.value('content-length'));
-    Expect.equals(-1, request.contentLength);
-    if (useHeader) {
-      response.contentLength = 2;
-      response.headers.chunkedTransferEncoding = true;
-    } else {
-      response.headers.set("content-length", 2);
-      response.headers.set("transfer-encoding", "chunked");
-    }
-    request.inputStream.onData = request.inputStream.read;
-    request.inputStream.onClosed = () {
-      OutputStream stream = response.outputStream;
-      stream.writeString("x");
-      Expect.throws(() => response.headers.chunkedTransferEncoding = false,
+  HttpServer.bind("127.0.0.1", 0, totalConnections).then((server) {
+    server.listen(
+        (HttpRequest request) {
+          Expect.isNull(request.headers.value('content-length'));
+          Expect.equals(-1, request.contentLength);
+          var response = request.response;
+          if (useHeader) {
+            response.contentLength = 2;
+            response.headers.chunkedTransferEncoding = true;
+          } else {
+            response.headers.set("content-length", 2);
+            response.headers.set("transfer-encoding", "chunked");
+          }
+          request.listen(
+              (d) {},
+              onDone: () {
+                response.addString("x");
+                Expect.throws(
+                    () => response.headers.chunkedTransferEncoding = false,
                     (e) => e is HttpException);
-      stream.writeString("x");
-      stream.writeString("x");
-      stream.close();
-      Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-    };
-  };
+                response.addString("x");
+                response.addString("x");
+                response.close();
+                Expect.throws(() => response.addString("x"),
+                              (e) => e is StateError);
+              });
+        },
+        onError: (e) => Expect.fail("Unexpected error $e"));
 
-  int count = 0;
-  HttpClient client = new HttpClient();
-  for (int i = 0; i < totalConnections; i++) {
-    HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-    conn.onError = (e) => Expect.fail("Unexpected error $e");
-    conn.onRequest = (HttpClientRequest request) {
-      if (useHeader) {
-        request.contentLength = 2;
-        request.headers.chunkedTransferEncoding = true;
-      } else {
-        request.headers.add(HttpHeaders.CONTENT_LENGTH, "2");
-        request.headers.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
-      }
-      OutputStream stream = request.outputStream;
-      stream.writeString("x");
-      Expect.throws(() => request.headers.chunkedTransferEncoding = false,
-                    (e) => e is HttpException);
-      stream.writeString("x");
-      stream.writeString("x");
-      stream.close();
-      Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.isNull(response.headers.value('content-length'));
-      Expect.equals(-1, response.contentLength);
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () {
-        if (++count == totalConnections) {
-          client.shutdown();
-          server.close();
-        }
-      };
-    };
-  }
+    int count = 0;
+    HttpClient client = new HttpClient();
+    for (int i = 0; i < totalConnections; i++) {
+      client.get("127.0.0.1", server.port, "/")
+          .then((request) {
+            if (useHeader) {
+              request.contentLength = 2;
+              request.headers.chunkedTransferEncoding = true;
+            } else {
+              request.headers.add(HttpHeaders.CONTENT_LENGTH, "2");
+              request.headers.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
+            }
+            request.addString("x");
+            Expect.throws(() => request.headers.chunkedTransferEncoding = false,
+                          (e) => e is HttpException);
+            request.addString("x");
+            request.addString("x");
+            return request.close();
+          })
+          .then((response) {
+            Expect.isNull(response.headers.value('content-length'));
+            Expect.equals(-1, response.contentLength);
+            response.listen(
+                (d) {},
+                onDone: () {
+                  if (++count == totalConnections) {
+                    client.close();
+                    server.close();
+                  }
+                });
+          })
+          .catchError((e) => Expect.fail("Unexpected error $e"));
+    }
+  });
 }
 
 void testHttp10() {
-  HttpServer server = new HttpServer();
-  server.onError = (e) => Expect.fail("Unexpected error $e");
-  server.listen("127.0.0.1", 0, backlog: 5);
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    Expect.isNull(request.headers.value('content-length'));
-    Expect.equals(-1, request.contentLength);
-    response.contentLength = 0;
-    OutputStream stream = response.outputStream;
-    Expect.equals("1.0", request.protocolVersion);
-    Expect.throws(() => stream.writeString("x"), (e) => e is HttpException);
-    stream.close();
-  };
+  HttpServer.bind("127.0.0.1", 0, 5).then((server) {
+    server.listen(
+        (HttpRequest request) {
+          Expect.isNull(request.headers.value('content-length'));
+          Expect.equals(-1, request.contentLength);
+          var response = request.response;
+          response.contentLength = 0;
+          Expect.equals("1.0", request.protocolVersion);
+          response.done
+              .then((_) => Expect.fail("Unexpected response completion"))
+              .catchError((e) => Expect.isTrue(e.error is HttpException));
+          response.addString("x");
+          response.close();
+          Expect.throws(() => response.addString("x"),
+                        (e) => e is StateError);
+        },
+        onError: (e) => Expect.fail("Unexpected error $e"));
 
-  Socket socket = new Socket("127.0.0.1", server.port);
-  socket.onConnect = () {
-    List<int> buffer = new List<int>.fixedLength(1024);
-    socket.outputStream.writeString("GET / HTTP/1.0\r\n\r\n");
-    socket.onData = () => socket.readList(buffer, 0, buffer.length);
-    socket.onClosed = () {
-      socket.close(true);
-      server.close();
-    };
-  };
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+      socket.addString("GET / HTTP/1.0\r\n\r\n");
+      socket.close();
+      socket.listen(
+          (d) { },
+          onDone: () {
+            socket.destroy();
+            server.close();
+          });
+    });
+  });
 }
 
 void main() {
diff --git a/tests/standalone/io/http_date_test.dart b/tests/standalone/io/http_date_test.dart
index c5b36e2..5821e05 100644
--- a/tests/standalone/io/http_date_test.dart
+++ b/tests/standalone/io/http_date_test.dart
@@ -5,15 +5,12 @@
 import "dart:async";
 import "dart:math";
 
-part "../../../sdk/lib/io/input_stream.dart";
-part "../../../sdk/lib/io/output_stream.dart";
-part "../../../sdk/lib/io/chunked_stream.dart";
-part "../../../sdk/lib/io/string_stream.dart";
-part "../../../sdk/lib/io/stream_util.dart";
+part "../../../sdk/lib/io/io_stream_consumer.dart";
 part "../../../sdk/lib/io/http.dart";
 part "../../../sdk/lib/io/http_impl.dart";
 part "../../../sdk/lib/io/http_parser.dart";
 part "../../../sdk/lib/io/http_utils.dart";
+part "../../../sdk/lib/io/socket.dart";
 
 void testParseHttpDate() {
   DateTime date;
diff --git a/tests/standalone/io/http_detach_socket_test.dart b/tests/standalone/io/http_detach_socket_test.dart
new file mode 100644
index 0000000..e3a5ad5
--- /dev/null
+++ b/tests/standalone/io/http_detach_socket_test.dart
@@ -0,0 +1,113 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:io";
+import "dart:isolate";
+
+void testServerDetachSocket() {
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+      var response = request.response;
+      response.contentLength = 0;
+      response.detachSocket().then((socket) {
+        Expect.isNotNull(socket);
+        var body = new StringBuffer();
+        socket.listen(
+          (data) => body.add(new String.fromCharCodes(data)),
+          onDone: () => Expect.equals("Some data", body.toString()));
+        socket.addString("Test!");
+        socket.close();
+      });
+      server.close();
+    });
+
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+      socket.addString("GET / HTTP/1.1\r\n"
+                       "content-length: 0\r\n\r\n"
+                       "Some data");
+      var body = new StringBuffer();
+      socket.listen(
+        (data) => body.add(new String.fromCharCodes(data)),
+        onDone: () {
+          Expect.equals("HTTP/1.1 200 OK\r\n"
+                        "content-length: 0\r\n"
+                        "\r\n"
+                        "Test!",
+                        body.toString());
+          socket.close();
+        });
+    });
+  });
+}
+
+void testBadServerDetachSocket() {
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+      var response = request.response;
+      response.contentLength = 0;
+      response.close();
+      Expect.throws(response.detachSocket);
+      server.close();
+    });
+
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+      socket.addString("GET / HTTP/1.1\r\n"
+                       "content-length: 0\r\n\r\n");
+      socket.listen((_) {}, onDone: () {
+          socket.close();
+        });
+    });
+  });
+}
+
+void testClientDetachSocket() {
+  ServerSocket.bind().then((server) {
+    server.listen((socket) {
+      socket.addString("HTTP/1.1 200 OK\r\n"
+                       "\r\n"
+                       "Test!");
+      var body = new StringBuffer();
+      socket.listen(
+        (data) => body.add(new String.fromCharCodes(data)),
+        onDone: () {
+          Expect.equals("GET / HTTP/1.1\r\n"
+                        "content-length: 0\r\n"
+                        "host: 127.0.0.1:${server.port}\r\n\r\n"
+                        "Some data",
+                        body.toString());
+          socket.close();
+        });
+      server.close();
+    });
+
+    var client = new HttpClient();
+    client.get("127.0.0.1", server.port, "/")
+      .then((request) => request.close())
+      .then((response) {
+        response.detachSocket().then((socket) {
+          var body = new StringBuffer();
+          socket.listen(
+            (data) => body.add(new String.fromCharCodes(data)),
+            onDone: () {
+              Expect.equals("Test!",
+                            body.toString());
+              client.close();
+            });
+          socket.addString("Some data");
+          socket.close();
+        });
+      });
+  });
+}
+
+void main() {
+  testServerDetachSocket();
+  testBadServerDetachSocket();
+  testClientDetachSocket();
+}
diff --git a/tests/standalone/io/http_head_test.dart b/tests/standalone/io/http_head_test.dart
index 7880e2d..215872c 100644
--- a/tests/standalone/io/http_head_test.dart
+++ b/tests/standalone/io/http_head_test.dart
@@ -1,52 +1,47 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:io";
 
 void testHEAD(int totalConnections) {
-  HttpServer server = new HttpServer();
-  server.onError = (e) => Expect.fail("Unexpected error $e");
-  server.listen("127.0.0.1", 0, backlog: totalConnections);
-  server.addRequestHandler(
-      (request) => request.path == "/test100",
-      (HttpRequest request, HttpResponse response) {
-        response.contentLength = 100;
-        response.outputStream.close();
-      });
-  server.addRequestHandler(
-      (request) => request.path == "/test200",
-      (HttpRequest request, HttpResponse response) {
-        response.contentLength = 200;
-        List<int> data = new List<int>.fixedLength(200);
-        response.outputStream.write(data);
-        response.outputStream.close();
-      });
-
-  HttpClient client = new HttpClient();
-
-  int count = 0;
-  for (int i = 0; i < totalConnections; i++) {
-    HttpClientConnection conn;
-    int len = (i % 2 == 0) ? 100 : 200;
-    if (i % 2 == 0) {
-      conn = client.open("HEAD", "127.0.0.1", server.port, "/test$len");
-    } else {
-      conn = client.open("HEAD", "127.0.0.1", server.port, "/test$len");
-    }
-    conn.onError = (e) => Expect.fail("Unexpected error $e");
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(len, response.contentLength);
-      response.inputStream.onData = () => Expect.fail("Data from HEAD request");
-      response.inputStream.onClosed = () {
-        count++;
-        if (count == totalConnections) {
-          client.shutdown();
-          server.close();
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+        var response = request.response;
+        if (request.uri.path == "/test100") {
+          response.contentLength = 100;
+          response.close();
+        } else if (request.uri.path == "/test200") {
+          response.contentLength = 200;
+          List<int> data = new List<int>.fixedLength(200, fill: 0);
+          response.add(data);
+          response.close();
+        } else {
+          assert(false);
         }
-      };
-    };
-  }
+      });
+
+    HttpClient client = new HttpClient();
+
+    int count = 0;
+    for (int i = 0; i < totalConnections; i++) {
+      int len = (i % 2 == 0) ? 100 : 200;
+      client.open("HEAD", "127.0.0.1", server.port, "/test$len")
+        .then((request) => request.close())
+        .then((HttpClientResponse response) {
+          Expect.equals(len, response.contentLength);
+          response.listen(
+            (_) => Expect.fail("Data from HEAD request"),
+            onDone: () {
+              count++;
+              if (count == totalConnections) {
+                client.close();
+                server.close();
+              }
+            });
+        });
+    }
+  });
 }
 
 void main() {
diff --git a/tests/standalone/io/http_headers_state_test.dart b/tests/standalone/io/http_headers_state_test.dart
index 72e1ddd..73754c7 100644
--- a/tests/standalone/io/http_headers_state_test.dart
+++ b/tests/standalone/io/http_headers_state_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
@@ -7,71 +7,71 @@
 import "dart:io";
 
 void test(int totalConnections, [String body]) {
-  HttpServer server = new HttpServer();
-  server.onError = (e) => Expect.fail("Unexpected error $e");
-  server.listen("127.0.0.1", 0, backlog: totalConnections);
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    // Cannot mutate request headers.
-    Expect.throws(() => request.headers.add("X-Request-Header", "value"),
-                  (e) => e is HttpException);
-    Expect.equals("value", request.headers.value("X-Request-Header"));
-    request.inputStream.onData = request.inputStream.read;
-    request.inputStream.onClosed = () {
-      OutputStream stream = response.outputStream;
-      // Can still mutate response headers as long as no data has been sent.
-      response.headers.add("X-Response-Header", "value");
-      if (body != null) {
-        stream.writeString(body);
-        // Cannot mutate response headers when data has been sent.
-        Expect.throws(() => request.headers.add("X-Request-Header", "value2"),
-                      (e) => e is HttpException);
-      }
-      stream.close();
-      // Cannot mutate response headers when data has been sent.
-      Expect.throws(() => request.headers.add("X-Request-Header", "value3"),
-                    (e) => e is HttpException);
-    };
-  };
+  HttpServer.bind().then((server) {
 
-  int count = 0;
-  HttpClient client = new HttpClient();
-  for (int i = 0; i < totalConnections; i++) {
-    HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-    conn.onError = (e) => Expect.fail("Unexpected error $e");
-    conn.onRequest = (HttpClientRequest request) {
-      if (body != null) {
-        request.contentLength = -1;
-      }
-      OutputStream stream = request.outputStream;
-      // Can still mutate request headers as long as no data has been sent.
-      request.headers.add("X-Request-Header", "value");
-      if (body != null) {
-        stream.writeString(body);
-        // Cannot mutate request headers when data has been sent.
-        Expect.throws(() => request.headers.add("X-Request-Header", "value2"),
-                      (e) => e is HttpException);
-      }
-      stream.close();
-      // Cannot mutate request headers when data has been sent.
-      Expect.throws(() => request.headers.add("X-Request-Header", "value3"),
+    server.listen((HttpRequest request) {
+      HttpResponse response = request.response;
+      // Cannot mutate request headers.
+      Expect.throws(() => request.headers.add("X-Request-Header", "value"),
                     (e) => e is HttpException);
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      // Cannot mutate response headers.
-      Expect.throws(() => response.headers.add("X-Response-Header", "value"),
-                   (e) => e is HttpException);
-      Expect.equals("value", response.headers.value("X-Response-Header"));
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () {
-        // Do not close the connections before we have read the full response
-        // bodies for all connections.
-        if (++count == totalConnections) {
-          client.shutdown();
-          server.close();
+      Expect.equals("value", request.headers.value("X-Request-Header"));
+      request.listen((_) {}, onDone: () {
+        // Can still mutate response headers as long as no data has been sent.
+        response.headers.add("X-Response-Header", "value");
+        if (body != null) {
+          response.addString(body);
+          // Cannot mutate response headers when data has been sent.
+          Expect.throws(() => request.headers.add("X-Request-Header", "value2"),
+                        (e) => e is HttpException);
         }
-      };
-    };
-  }
+        response..close();
+        // Cannot mutate response headers when data has been sent.
+        Expect.throws(() => request.headers.add("X-Request-Header", "value3"),
+                      (e) => e is HttpException);
+      });
+    });
+
+    int count = 0;
+    HttpClient client = new HttpClient();
+    for (int i = 0; i < totalConnections; i++) {
+      client.get("127.0.0.1", server.port, "/")
+        .then((HttpClientRequest request) {
+          if (body != null) {
+            request.contentLength = -1;
+          }
+          // Can still mutate request headers as long as no data has been sent.
+          request.headers.add("X-Request-Header", "value");
+          if (body != null) {
+            request.addString(body);
+            // Cannot mutate request headers when data has been sent.
+            Expect.throws(
+                () => request.headers.add("X-Request-Header", "value2"),
+                (e) => e is HttpException);
+          }
+          request.close();
+          // Cannot mutate request headers when data has been sent.
+          Expect.throws(() => request.headers.add("X-Request-Header", "value3"),
+                        (e) => e is HttpException);
+          return request.response;
+        })
+        .then((HttpClientResponse response) {
+          // Cannot mutate response headers.
+          Expect.throws(
+              () => response.headers.add("X-Response-Header", "value"),
+              (e) => e is HttpException);
+          Expect.equals("value", response.headers.value("X-Response-Header"));
+          response.listen((_) {}, onDone: () {
+            // Do not close the connections before we have read the
+            // full response bodies for all connections.
+            if (++count == totalConnections) {
+              client.close();
+              server.close();
+            }
+          });
+        });
+    }
+
+  });
 }
 
 void main() {
diff --git a/tests/standalone/io/http_headers_test.dart b/tests/standalone/io/http_headers_test.dart
index 826bd81..fca7a49 100644
--- a/tests/standalone/io/http_headers_test.dart
+++ b/tests/standalone/io/http_headers_test.dart
@@ -5,19 +5,16 @@
 import 'dart:async';
 import 'dart:math';
 
-part "../../../sdk/lib/io/input_stream.dart";
-part "../../../sdk/lib/io/output_stream.dart";
-part "../../../sdk/lib/io/chunked_stream.dart";
-part "../../../sdk/lib/io/string_stream.dart";
-part "../../../sdk/lib/io/stream_util.dart";
+part "../../../sdk/lib/io/io_stream_consumer.dart";
 part "../../../sdk/lib/io/http.dart";
 part "../../../sdk/lib/io/http_headers.dart";
 part "../../../sdk/lib/io/http_impl.dart";
 part "../../../sdk/lib/io/http_parser.dart";
 part "../../../sdk/lib/io/http_utils.dart";
+part "../../../sdk/lib/io/socket.dart";
 
 void testMultiValue() {
-  _HttpHeaders headers = new _HttpHeaders();
+  _HttpHeaders headers = new _HttpHeaders("1.1");
   Expect.isNull(headers[HttpHeaders.PRAGMA]);
   headers.add(HttpHeaders.PRAGMA, "pragma1");
   Expect.equals(1, headers[HttpHeaders.PRAGMA].length);
@@ -59,7 +56,7 @@
   DateTime date2 = new DateTime.utc(2000, DateTime.AUG, 16, 12, 34, 56, 0);
   String httpDate2 = "Wed, 16 Aug 2000 12:34:56 GMT";
 
-  _HttpHeaders headers = new _HttpHeaders();
+  _HttpHeaders headers = new _HttpHeaders("1.1");
   Expect.isNull(headers.date);
   headers.date = date1;
   Expect.equals(date1, headers.date);
@@ -85,7 +82,7 @@
   DateTime date2 = new DateTime.utc(2000, DateTime.AUG, 16, 12, 34, 56, 0);
   String httpDate2 = "Wed, 16 Aug 2000 12:34:56 GMT";
 
-  _HttpHeaders headers = new _HttpHeaders();
+  _HttpHeaders headers = new _HttpHeaders("1.1");
   Expect.isNull(headers.expires);
   headers.expires = date1;
   Expect.equals(date1, headers.expires);
@@ -111,7 +108,7 @@
   DateTime date2 = new DateTime.utc(2000, DateTime.AUG, 16, 12, 34, 56, 0);
   String httpDate2 = "Wed, 16 Aug 2000 12:34:56 GMT";
 
-  _HttpHeaders headers = new _HttpHeaders();
+  _HttpHeaders headers = new _HttpHeaders("1.1");
   Expect.isNull(headers.ifModifiedSince);
   headers.ifModifiedSince = date1;
   Expect.equals(date1, headers.ifModifiedSince);
@@ -133,7 +130,7 @@
 
 void testHost() {
   String host = "www.google.com";
-  _HttpHeaders headers = new _HttpHeaders();
+  _HttpHeaders headers = new _HttpHeaders("1.1");
   Expect.isNull(headers.host);
   Expect.isNull(headers.port);
   headers.host = host;
@@ -143,7 +140,7 @@
   headers.port = HttpClient.DEFAULT_HTTP_PORT;
   Expect.equals(host, headers.value(HttpHeaders.HOST));
 
-  headers = new _HttpHeaders();
+  headers = new _HttpHeaders("1.1");
   headers.add(HttpHeaders.HOST, host);
   Expect.equals(host, headers.host);
   Expect.equals(HttpClient.DEFAULT_HTTP_PORT, headers.port);
@@ -152,13 +149,13 @@
   Expect.equals(host, headers.host);
   Expect.equals(4567, headers.port);
 
-  headers = new _HttpHeaders();
+  headers = new _HttpHeaders("1.1");
   headers.add(HttpHeaders.HOST, "$host:xxx");
   Expect.equals("$host:xxx", headers.value(HttpHeaders.HOST));
   Expect.equals(host, headers.host);
   Expect.isNull(headers.port);
 
-  headers = new _HttpHeaders();
+  headers = new _HttpHeaders("1.1");
   headers.add(HttpHeaders.HOST, ":1234");
   Expect.equals(":1234", headers.value(HttpHeaders.HOST));
   Expect.isNull(headers.host);
@@ -166,7 +163,7 @@
 }
 
 void testEnumeration() {
-  _HttpHeaders headers = new _HttpHeaders();
+  _HttpHeaders headers = new _HttpHeaders("1.1");
   Expect.isNull(headers[HttpHeaders.PRAGMA]);
   headers.add("My-Header-1", "value 1");
   headers.add("My-Header-2", "value 2");
@@ -287,7 +284,7 @@
 }
 
 void testContentTypeCache() {
-  _HttpHeaders headers = new _HttpHeaders();
+  _HttpHeaders headers = new _HttpHeaders("1.1");
   headers.set(HttpHeaders.CONTENT_TYPE, "text/html");
   Expect.equals("text", headers.contentType.primaryType);
   Expect.equals("html", headers.contentType.subType);
diff --git a/tests/standalone/io/http_keep_alive_test.dart b/tests/standalone/io/http_keep_alive_test.dart
new file mode 100644
index 0000000..70b9021
--- /dev/null
+++ b/tests/standalone/io/http_keep_alive_test.dart
@@ -0,0 +1,96 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+
+Future getData(HttpClient client, int port, bool chunked, int length) {
+  return client.get("localhost", port, "/?chunked=$chunked&length=$length")
+      .then((request) => request.close())
+      .then((response) {
+        return response.reduce(0, (bytes, data) => bytes + data.length)
+            .then((bytes) {
+              Expect.equals(length, bytes);
+            });
+      });
+}
+
+Future<HttpServer> startServer() {
+  return HttpServer.bind("127.0.0.1", 0).then((server) {
+    server.listen((request) {
+      bool chunked = request.queryParameters["chunked"] == "true";
+      int length = int.parse(request.queryParameters["length"]);
+      var buffer = new List.fixedLength(length, fill: 0);
+      if (!chunked) request.response.contentLength = length;
+      request.response.add(buffer);
+      request.response.close();
+    });
+    return server;
+  });
+}
+
+testKeepAliveNonChunked() {
+  startServer().then((server) {
+    var client = new HttpClient();
+
+    getData(client, server.port, false, 100)
+        .then((_) => getData(client, server.port, false, 100))
+        .then((_) => getData(client, server.port, false, 100))
+        .then((_) => getData(client, server.port, false, 100))
+        .then((_) => getData(client, server.port, false, 100))
+        .then((_) {
+          server.close();
+          client.close();
+        });
+
+  });
+}
+
+testKeepAliveChunked() {
+  startServer().then((server) {
+    var client = new HttpClient();
+
+    getData(client, server.port, true, 100)
+        .then((_) => getData(client, server.port, true, 100))
+        .then((_) => getData(client, server.port, true, 100))
+        .then((_) => getData(client, server.port, true, 100))
+        .then((_) => getData(client, server.port, true, 100))
+        .then((_) {
+          server.close();
+          client.close();
+        });
+
+  });
+}
+
+testKeepAliveMixed() {
+  startServer().then((server) {
+    var client = new HttpClient();
+
+    getData(client, server.port, true, 100)
+        .then((_) => getData(client, server.port, false, 100))
+        .then((_) => getData(client, server.port, true, 100))
+        .then((_) => getData(client, server.port, false, 100))
+        .then((_) => getData(client, server.port, true, 100))
+        .then((_) => getData(client, server.port, false, 100))
+        .then((_) => getData(client, server.port, true, 100))
+        .then((_) => getData(client, server.port, false, 100))
+        .then((_) {
+          server.close();
+          client.close();
+        });
+
+  });
+}
+
+void main() {
+  testKeepAliveNonChunked();
+  testKeepAliveChunked();
+  testKeepAliveMixed();
+}
diff --git a/tests/standalone/io/http_parser_test.dart b/tests/standalone/io/http_parser_test.dart
index fe4018a..173fec4 100644
--- a/tests/standalone/io/http_parser_test.dart
+++ b/tests/standalone/io/http_parser_test.dart
@@ -1,14 +1,19 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
 import 'dart:math';
 import 'dart:scalarlist';
+import 'dart:isolate';
+import 'dart:uri';
 
+part '../../../sdk/lib/io/io_stream_consumer.dart';
 part '../../../sdk/lib/io/http.dart';
+part '../../../sdk/lib/io/http_impl.dart';
 part '../../../sdk/lib/io/http_headers.dart';
 part '../../../sdk/lib/io/http_parser.dart';
+part '../../../sdk/lib/io/socket.dart';
 
 class HttpParserTest {
   static void runAllTests() {
@@ -21,7 +26,7 @@
   static void _testParseRequest(String request,
                                 String expectedMethod,
                                 String expectedUri,
-                                {int expectedContentLength: 0,
+                                {int expectedTransferLength: 0,
                                  int expectedBytesReceived: 0,
                                  Map expectedHeaders: null,
                                  bool chunked: false,
@@ -29,88 +34,93 @@
                                  int unparsedLength: 0,
                                  bool connectionClose: false,
                                  String expectedVersion: "1.1"}) {
-    _HttpParser httpParser;
-    bool headersCompleteCalled;
-    bool dataEndCalled;
-    String method;
-    String uri;
-    String version;
-    HttpHeaders headers;
-    int contentLength;
-    int bytesReceived;
-
+    StreamController controller;
     void reset() {
-      httpParser = new _HttpParser.requestParser();
-      httpParser.requestStart = (m, u, v, h, b) {
-        method = m;
-        uri = u;
-        version = v;
-        headers = h;
-        headersCompleteCalled = true;
+      _HttpParser httpParser = new _HttpParser.requestParser();
+      controller = new StreamController();
+      var port1 = new ReceivePort();
+      var port2 = new ReceivePort();
+
+      String method;
+      Uri uri;
+      HttpHeaders headers;
+      int contentLength;
+      int bytesReceived;
+      int unparsedBytesReceived;
+      bool upgraded;
+
+      controller.stream.pipe(httpParser);
+      var subscription = httpParser.listen((incoming) {
+        method = incoming.method;
+        uri = incoming.uri;
+        headers = incoming.headers;
+        upgraded = incoming.upgraded;
+        Expect.equals(upgrade, upgraded);
+
         if (!chunked) {
-          Expect.equals(expectedContentLength, httpParser.contentLength);
+          Expect.equals(expectedTransferLength, incoming.transferLength);
         } else {
-          Expect.equals(-1, httpParser.contentLength);
+          Expect.equals(-1, incoming.transferLength);
         }
         if (expectedHeaders != null) {
           expectedHeaders.forEach(
               (String name, String value) =>
               Expect.equals(value, headers[name][0]));
         }
-        Expect.equals(upgrade, httpParser.upgrade);
-        Expect.equals(connectionClose, !httpParser.persistentConnection);
-        headersCompleteCalled = true;
-      };
-      httpParser.responseStart = (s, r, v, h, b) {
-        Expect.fail("Expected request");
-      };
-      httpParser.dataReceived = (List<int> data) {
-        Expect.isTrue(headersCompleteCalled);
-        bytesReceived += data.length;
-      };
-      httpParser.dataEnd = (close) {
-        Expect.isFalse(close);
-        dataEndCalled = true;
-      };
-      httpParser.closed = () { };
+        incoming.listen(
+            (List<int> data) {
+              Expect.isFalse(upgraded);
+              bytesReceived += data.length;
+            },
+            onDone: () {
+              Expect.isFalse(upgraded);
+              port2.close();
+            });
 
-      headersCompleteCalled = false;
-      dataEndCalled = false;
+        if (upgraded) {
+          port1.close();
+          httpParser.detachIncoming().listen(
+              (List<int> data) {
+                unparsedBytesReceived += data.length;
+              },
+              onDone: () {
+                Expect.equals(unparsedLength, unparsedBytesReceived);
+                port2.close();
+              });
+        }
+
+        incoming.dataDone.then((_) {
+          port1.close();
+          Expect.isFalse(upgraded);
+          Expect.equals(expectedMethod, method);
+          Expect.stringEquals(expectedUri, uri.toString());
+          Expect.equals(expectedVersion, headers.protocolVersion);
+          if (upgrade) {
+            Expect.equals(0, bytesReceived);
+            // port1 is closed by the listener on the detached data.
+          } else {
+            Expect.equals(expectedBytesReceived, bytesReceived);
+          }
+        });
+      });
+
       method = null;
       uri = null;
       headers = null;
       bytesReceived = 0;
+      unparsedBytesReceived = 0;
+      upgraded = false;
     }
 
     void testWrite(List<int> requestData, [int chunkSize = -1]) {
       if (chunkSize == -1) chunkSize = requestData.length;
       reset();
-      int written = 0;
-      int unparsed;
       for (int pos = 0; pos < requestData.length; pos += chunkSize) {
         int remaining = requestData.length - pos;
         int writeLength = min(chunkSize, remaining);
-        written += writeLength;
-        httpParser.streamData(requestData.getRange(pos, writeLength));
-        unparsed = httpParser.readUnparsedData().length;
-        if (httpParser.upgrade) {
-          unparsed += requestData.length - written;
-          break;
-        } else {
-          Expect.equals(0, unparsed);
-        }
+        controller.add(requestData.getRange(pos, writeLength));
       }
-      Expect.equals(expectedMethod, method);
-      Expect.equals(expectedUri, uri);
-      Expect.equals(expectedVersion, version);
-      Expect.isTrue(headersCompleteCalled);
-      Expect.equals(expectedBytesReceived, bytesReceived);
-      if (!upgrade) Expect.isTrue(dataEndCalled);
-      if (unparsedLength == 0) {
-        Expect.equals(0, unparsed);
-      } else {
-        Expect.equals(unparsedLength, unparsed);
-      }
+      controller.close();
     }
 
     // Test parsing the request three times delivering the data in
@@ -124,17 +134,23 @@
   static void _testParseInvalidRequest(String request) {
     _HttpParser httpParser;
     bool errorCalled;
+    StreamController controller;
 
     void reset() {
       httpParser = new _HttpParser.requestParser();
-      httpParser.responseStart = (s, r, v, h, b) {
+      controller = new StreamController();
+      var port = new ReceivePort();
+      controller.stream.pipe(httpParser);
+      var subscription = httpParser.listen((incoming) {
         Expect.fail("Expected request");
-      };
-      httpParser.error = (e) {
+      });
+      subscription.onError((e) {
         errorCalled = true;
-      };
-      httpParser.closed = () { };
-
+      });
+      subscription.onDone(() {
+        port.close();
+        Expect.isTrue(errorCalled);
+      });
       errorCalled = false;
     }
 
@@ -146,9 +162,9 @@
            pos += chunkSize) {
         int remaining = requestData.length - pos;
         int writeLength = min(chunkSize, remaining);
-        httpParser.streamData(requestData.getRange(pos, writeLength));
+        controller.add(requestData.getRange(pos, writeLength));
       }
-      Expect.isTrue(errorCalled);
+      controller.close();
     }
 
     // Test parsing the request three times delivering the data in
@@ -162,7 +178,7 @@
   static void _testParseResponse(String response,
                                  int expectedStatusCode,
                                  String expectedReasonPhrase,
-                                 {int expectedContentLength: -1,
+                                 {int expectedTransferLength: 0,
                                   int expectedBytesReceived: 0,
                                   Map expectedHeaders: null,
                                   bool chunked: false,
@@ -178,29 +194,27 @@
     bool dataEndClose;
     int statusCode;
     String reasonPhrase;
-    String version;
     HttpHeaders headers;
     int contentLength;
     int bytesReceived;
+    StreamController controller;
+    bool upgraded;
 
     void reset() {
       httpParser = new _HttpParser.responseParser();
-      if (responseToMethod != null) {
-        httpParser.responseToMethod = responseToMethod;
-      }
-      httpParser.requestStart = (m, u, v, h, b) {
-        Expect.fail("Expected response");
-      };
-      httpParser.responseStart = (s, r, v, h, b) {
-        statusCode = s;
-        reasonPhrase = r;
-        version = v;
-        headers = h;
+      controller = new StreamController();
+      var port = new ReceivePort();
+      controller.stream.pipe(httpParser);
+      var subscription = httpParser.listen((incoming) {
+        port.close();
+        statusCode = incoming.statusCode;
+        reasonPhrase = incoming.reasonPhrase;
+        headers = incoming.headers;
         Expect.isFalse(headersCompleteCalled);
         if (!chunked && !close) {
-          Expect.equals(expectedContentLength, httpParser.contentLength);
+          Expect.equals(expectedTransferLength, incoming.transferLength);
         } else {
-          Expect.equals(-1, httpParser.contentLength);
+          Expect.equals(-1, incoming.transferLength);
         }
         if (expectedHeaders != null) {
           expectedHeaders.forEach((String name, String value) {
@@ -209,16 +223,29 @@
         }
         Expect.equals(upgrade, httpParser.upgrade);
         headersCompleteCalled = true;
-      };
-      httpParser.dataReceived = (List<int> data) {
+        incoming.listen(
+            (List<int> data) {
+              Expect.isTrue(headersCompleteCalled);
+              bytesReceived += data.length;
+            },
+            onDone: () {
+              dataEndCalled = true;
+              dataEndClose = close;
+            });
+      });
+
+      subscription.onDone(() {
+        Expect.equals(expectedVersion, headers.protocolVersion);
+        Expect.equals(expectedStatusCode, statusCode);
+        Expect.equals(expectedReasonPhrase, reasonPhrase);
         Expect.isTrue(headersCompleteCalled);
-        bytesReceived += data.length;
-      };
-      httpParser.dataEnd = (close) {
-        dataEndCalled = true;
-        dataEndClose = close;
-      };
-      httpParser.closed = () { };
+        Expect.equals(expectedBytesReceived, bytesReceived);
+        if (!upgrade) {
+          Expect.isTrue(dataEndCalled);
+          if (close) Expect.isTrue(dataEndClose);
+          Expect.equals(dataEndClose, connectionClose);
+        }
+      });
 
       headersCompleteCalled = false;
       dataEndCalled = false;
@@ -232,37 +259,13 @@
     void testWrite(List<int> requestData, [int chunkSize = -1]) {
       if (chunkSize == -1) chunkSize = requestData.length;
       reset();
-      int written = 0;
-      int unparsed;
       for (int pos = 0; pos < requestData.length; pos += chunkSize) {
         int remaining = requestData.length - pos;
         int writeLength = min(chunkSize, remaining);
-        written += writeLength;
-        httpParser.streamData(requestData.getRange(pos, writeLength));
-        unparsed = httpParser.readUnparsedData().length;
-        if (httpParser.upgrade) {
-          unparsed += requestData.length - written;
-          break;
-        } else {
-          Expect.equals(0, unparsed);
-        }
+        controller.add(requestData.getRange(pos, writeLength));
+
       }
-      if (close) httpParser.streamDone();
-      Expect.equals(expectedVersion, version);
-      Expect.equals(expectedStatusCode, statusCode);
-      Expect.equals(expectedReasonPhrase, reasonPhrase);
-      Expect.isTrue(headersCompleteCalled);
-      Expect.equals(expectedBytesReceived, bytesReceived);
-      if (!upgrade) {
-        Expect.isTrue(dataEndCalled);
-        if (close) Expect.isTrue(dataEndClose);
-        Expect.equals(dataEndClose, connectionClose);
-      }
-      if (unparsedLength == 0) {
-        Expect.equals(0, unparsed);
-      } else {
-        Expect.equals(unparsedLength, unparsed);
-      }
+      if (close) controller.close();
     }
 
     // Test parsing the request three times delivering the data in
@@ -276,15 +279,29 @@
   static void _testParseInvalidResponse(String response, [bool close = false]) {
     _HttpParser httpParser;
     bool errorCalled;
+    StreamController controller;
 
     void reset() {
       httpParser = new _HttpParser.responseParser();
-      httpParser.requestStart = (m, u, v, h, b) {
-        Expect.fail("Expected response");
-      };
-      httpParser.error = (e) => errorCalled = true;
-      httpParser.closed = () { };
-
+      controller = new StreamController();
+      var port = new ReceivePort();
+      controller.stream.pipe(httpParser);
+      var subscription = httpParser.listen((incoming) {
+        incoming.listen(
+          (data) {},
+          onError: (e) {
+            Expect.isFalse(errorCalled);
+            errorCalled = true;
+          });
+      });
+      subscription.onError((e) {
+        Expect.isFalse(errorCalled);
+        errorCalled = true;
+      });
+      subscription.onDone(() {
+        port.close();
+        Expect.isTrue(errorCalled);
+      });
       errorCalled = false;
     }
 
@@ -296,10 +313,9 @@
            pos += chunkSize) {
         int remaining = requestData.length - pos;
         int writeLength = min(chunkSize, remaining);
-        httpParser.streamData(requestData.getRange(pos, writeLength));
+        controller.add(requestData.getRange(pos, writeLength));
       }
-      if (close) httpParser.streamDone();
-      Expect.isTrue(errorCalled);
+      controller.close();
     }
 
     // Test parsing the request three times delivering the data in
@@ -329,6 +345,7 @@
       _testParseRequest(request, method, "/index.html");
     });
 
+
     request = "GET / HTTP/1.0\r\n\r\n";
     _testParseRequest(request, "GET", "/",
                       expectedVersion: "1.0",
@@ -406,7 +423,7 @@
     _testParseRequest(request,
                       "POST",
                       "/test",
-                      expectedContentLength: 10,
+                      expectedTransferLength: 10,
                       expectedBytesReceived: 10);
 
     // Test connection close header.
@@ -426,7 +443,7 @@
     _testParseRequest(request,
                       "POST",
                       "/test",
-                      expectedContentLength: -1,
+                      expectedTransferLength: -1,
                       expectedBytesReceived: 10,
                       chunked: true);
 
@@ -445,7 +462,7 @@
     _testParseRequest(request,
                       "POST",
                       "/test",
-                      expectedContentLength: -1,
+                      expectedTransferLength: -1,
                       expectedBytesReceived: 10,
                       chunked: true);
 
@@ -464,7 +481,7 @@
     _testParseRequest(request,
                       "POST",
                       "/test",
-                      expectedContentLength: -1,
+                      expectedTransferLength: -1,
                       expectedBytesReceived: 10,
                       chunked: true);
 
@@ -481,7 +498,7 @@
     _testParseRequest(request,
                       "POST",
                       "/test",
-                      expectedContentLength: -1,
+                      expectedTransferLength: -1,
                       expectedBytesReceived: 60,
                       chunked: true);
 
@@ -498,7 +515,7 @@
     _testParseRequest(request,
                       "POST",
                       "/test",
-                      expectedContentLength: -1,
+                      expectedTransferLength: -1,
                       expectedBytesReceived: 60,
                       chunked: true);
 
@@ -586,13 +603,16 @@
     String response;
     Map headers;
     response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n";
-    _testParseResponse(response, 100, "Continue", expectedContentLength: 0);
+    _testParseResponse(response, 100, "Continue");
+
+    response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n";
+    _testParseResponse(response, 100, "Continue");
 
     response = "HTTP/1.1 100 Continue\r\nContent-Length: 10\r\n\r\n";
     _testParseResponse(response,
                        100,
                        "Continue",
-                       expectedContentLength: 10,
+                       expectedTransferLength: 10,
                        expectedBytesReceived: 0);
 
     response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n"
@@ -600,14 +620,12 @@
     _testParseResponse(response,
                        200,
                        "OK",
-                       expectedContentLength: 0,
                        connectionClose: true);
 
     response = "HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n";
     _testParseResponse(response,
                        200,
                        "OK",
-                       expectedContentLength: 0,
                        expectedVersion: "1.0",
                        connectionClose: true);
 
@@ -616,31 +634,30 @@
     _testParseResponse(response,
                        200,
                        "OK",
-                       expectedContentLength: 0,
                        expectedVersion: "1.0");
 
     response = "HTTP/1.1 204 No Content\r\nContent-Length: 11\r\n\r\n";
     _testParseResponse(response,
                        204,
                        "No Content",
-                       expectedContentLength: 11,
+                       expectedTransferLength: 11,
                        expectedBytesReceived: 0);
 
     response = "HTTP/1.1 304 Not Modified\r\nContent-Length: 12\r\n\r\n";
     _testParseResponse(response,
                        304,
                        "Not Modified",
-                       expectedContentLength: 12,
+                       expectedTransferLength: 12,
                        expectedBytesReceived: 0);
 
     response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n";
-    _testParseResponse(response, 200, "OK", expectedContentLength: 0);
+    _testParseResponse(response, 200, "OK");
 
     response = "HTTP/1.1 404 Not found\r\nContent-Length: 0\r\n\r\n";
-    _testParseResponse(response, 404, "Not found", expectedContentLength: 0);
+    _testParseResponse(response, 404, "Not found");
 
     response = "HTTP/1.1 500 Server error\r\nContent-Length: 0\r\n\r\n";
-    _testParseResponse(response, 500, "Server error", expectedContentLength: 0);
+    _testParseResponse(response, 500, "Server error");
 
     // Test response to HEAD request.
     response = """
@@ -655,7 +672,7 @@
                        200,
                        "OK",
                        responseToMethod: "HEAD",
-                       expectedContentLength: 20,
+                       expectedTransferLength: 20,
                        expectedBytesReceived: 0,
                        expectedHeaders: headers);
 
@@ -668,7 +685,7 @@
     _testParseResponse(response,
                        200,
                        "OK",
-                       expectedContentLength: 20,
+                       expectedTransferLength: 20,
                        expectedBytesReceived: 20);
 
     // Test upper and lower case hex digits in chunked encoding.
@@ -684,7 +701,7 @@
     _testParseResponse(response,
                        200,
                        "OK",
-                       expectedContentLength: -1,
+                       expectedTransferLength: -1,
                        expectedBytesReceived: 57,
                        chunked: true);
 
@@ -697,7 +714,6 @@
     _testParseResponse(response,
                        200,
                        "OK",
-                       expectedContentLength: 0,
                        connectionClose: true);
 
     // Test HTTP response without any transfer length indications
@@ -711,7 +727,7 @@
     _testParseResponse(response,
                        200,
                        "OK",
-                       expectedContentLength: -1,
+                       expectedTransferLength: -1,
                        expectedBytesReceived: 59,
                        close: true,
                        connectionClose: true);
diff --git a/tests/standalone/io/http_proxy_test.dart b/tests/standalone/io/http_proxy_test.dart
index 9d3190c..24a2f84 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.dart
@@ -1,47 +1,60 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:async";
 import "dart:io";
 import "dart:uri";
 
 class Server {
   HttpServer server;
+  bool secure;
   int proxyHops;
   List<String> directRequestPaths;
   int requestCount = 0;
 
-  Server(this.proxyHops, this.directRequestPaths) : server = new HttpServer();
+  Server(this.proxyHops, this.directRequestPaths, this.secure);
 
-  void start() {
-    server.listen("127.0.0.1", 0);
-    server.defaultRequestHandler =
-        (HttpRequest request, HttpResponse response) {
-          requestCount++;
-          // Check whether a proxy or direct connection is expected.
-          bool direct = directRequestPaths.reduce(
-              false,
-              (prev, path) => prev ? prev : path == request.path);
-          if (!direct && proxyHops > 0) {
-            Expect.isNotNull(request.headers[HttpHeaders.VIA]);
-            Expect.equals(1, request.headers[HttpHeaders.VIA].length);
-            Expect.equals(
-                proxyHops,
-                request.headers[HttpHeaders.VIA][0].split(",").length);
-          } else {
-            Expect.isNull(request.headers[HttpHeaders.VIA]);
-          }
-          StringInputStream stream = new StringInputStream(request.inputStream);
-          StringBuffer body = new StringBuffer();
-          stream.onData = () => body.add(stream.read());
-          stream.onClosed = () {
-            String path = request.path.substring(1);
-            String content = "$path$path$path";
-            Expect.equals(content, body.toString());
-            response.outputStream.writeString(request.path);
-            response.outputStream.close();
-          };
-        };
+  Future<Server> start() {
+    var x = new Completer();
+    Future f = secure
+        ? HttpServer.bindSecure(
+            "127.0.0.1", 0, certificateName: 'localhost_cert')
+        : HttpServer.bind();
+    return f.then((s) {
+      server = s;
+      x.complete(this);
+      server.listen((request) {
+        var response = request.response;
+        requestCount++;
+        // Check whether a proxy or direct connection is expected.
+        bool direct = directRequestPaths.reduce(
+            false,
+            (prev, path) => prev ? prev : path == request.uri.path);
+        if (!direct && proxyHops > 0) {
+          Expect.isNotNull(request.headers[HttpHeaders.VIA]);
+          Expect.equals(1, request.headers[HttpHeaders.VIA].length);
+          Expect.equals(
+              proxyHops,
+              request.headers[HttpHeaders.VIA][0].split(",").length);
+        } else {
+          Expect.isNull(request.headers[HttpHeaders.VIA]);
+        }
+        var body = new StringBuffer();
+        request.listen(
+            (data) {
+              body.add(new String.fromCharCodes(data));
+            },
+            onDone: () {
+              String path = request.uri.path.substring(1);
+              String content = "$path$path$path";
+              Expect.equals(content, body.toString());
+              response.addString(request.uri.path);
+              response.close();
+            });
+      });
+      return x.future;
+    });
   }
 
   void shutdown() {
@@ -51,11 +64,11 @@
   int get port => server.port;
 }
 
-Server setupServer(int proxyHops,
-                   [List<String> directRequestPaths = const <String>[]]) {
-  Server server = new Server(proxyHops, directRequestPaths);
-  server.start();
-  return server;
+Future<Server> setupServer(int proxyHops,
+                   {List<String> directRequestPaths: const <String>[],
+                    secure: false}) {
+  Server server = new Server(proxyHops, directRequestPaths, secure);
+  return server.start();
 }
 
 class ProxyServer {
@@ -63,17 +76,18 @@
   HttpClient client;
   int requestCount = 0;
 
-  ProxyServer() : server = new HttpServer(), client = new HttpClient();
+  ProxyServer() : client = new HttpClient();
 
-  void start() {
-    server.listen("127.0.0.1", 0);
-    server.defaultRequestHandler =
-        (HttpRequest request, HttpResponse response) {
-          requestCount++;
-          // Open the connection from the proxy.
-          HttpClientConnection conn =
-              client.openUrl(request.method, Uri.parse(request.path));
-          conn.onRequest = (HttpClientRequest clientRequest) {
+  Future<ProxyServer> start() {
+    var x = new Completer();
+    HttpServer.bind().then((s) {
+      server = s;
+      x.complete(this);
+      server.listen((HttpRequest request) {
+        requestCount++;
+        // Open the connection from the proxy.
+        client.openUrl(request.method, request.uri)
+          .then((HttpClientRequest clientRequest) {
             // Forward all headers.
             request.headers.forEach((String name, List<String> values) {
               values.forEach((String value) {
@@ -89,224 +103,244 @@
             clientRequest.headers.add(
                 HttpHeaders.VIA, "${viaPrefix}1.1 localhost:$port");
             // Copy all content.
-            request.inputStream.pipe(clientRequest.outputStream);
-          };
-          conn.onResponse = (HttpClientResponse clientResponse) {
-            clientResponse.inputStream.pipe(response.outputStream);
-          };
-        };
+            request.pipe(clientRequest);
+            return clientRequest.response;
+          })
+          .then((HttpClientResponse clientResponse) {
+            clientResponse.pipe(request.response);
+          });
+      });
+    });
+    return x.future;
   }
 
   void shutdown() {
     server.close();
-    client.shutdown();
+    client.close();
   }
 
   int get port => server.port;
 }
 
-ProxyServer setupProxyServer() {
+Future<ProxyServer> setupProxyServer() {
   ProxyServer proxyServer = new ProxyServer();
-  proxyServer.start();
-  return proxyServer;
+  return proxyServer.start();
 }
 
 testInvalidProxy() {
   HttpClient client = new HttpClient();
 
-  // TODO(sgjesse): This should not throw errors, but call
-  // HttpClientConnection onError.
+  client.findProxy = (Uri uri) => "";
+  client.getUrl(Uri.parse("http://www.google.com/test"))
+    .catchError((error) {}, test: (e) => e is HttpException);
+
   client.findProxy = (Uri uri) => "XXX";
-  Expect.throws(
-      () => client.getUrl(Uri.parse("http://www.google.com/test")),
-      (e) => e is HttpException);
+  client.getUrl(Uri.parse("http://www.google.com/test"))
+    .catchError((error) {}, test: (e) => e is HttpException);
 
   client.findProxy = (Uri uri) => "PROXY www.google.com";
-  Expect.throws(
-      () => client.getUrl(Uri.parse("http://www.google.com/test")),
-      (e) => e is HttpException);
+  client.getUrl(Uri.parse("http://www.google.com/test"))
+    .catchError((error) {}, test: (e) => e is HttpException);
 
   client.findProxy = (Uri uri) => "PROXY www.google.com:http";
-  Expect.throws(
-      () => client.getUrl(Uri.parse("http://www.google.com/test")),
-      (e) => e is HttpException);
+  client.getUrl(Uri.parse("http://www.google.com/test"))
+    .catchError((error) {}, test: (e) => e is HttpException);
 }
 
 int testDirectDoneCount = 0;
 void testDirectProxy() {
-  Server server = setupServer(0);
-  HttpClient client = new HttpClient();
-  List<String> proxy =
-      ["DIRECT", " DIRECT ", "DIRECT ;", " DIRECT ; ",
-       ";DIRECT", " ; DIRECT ", ";;DIRECT;;"];
+  setupServer(0).then((server) {
+    HttpClient client = new HttpClient();
+    List<String> proxy =
+        ["DIRECT", " DIRECT ", "DIRECT ;", " DIRECT ; ",
+         ";DIRECT", " ; DIRECT ", ";;DIRECT;;"];
 
-  client.findProxy = (Uri uri) {
-    int index = int.parse(uri.path.substring(1));
-    return proxy[index];
-  };
+    client.findProxy = (Uri uri) {
+      int index = int.parse(uri.path.substring(1));
+      return proxy[index];
+    };
 
-  for (int i = 0; i < proxy.length; i++) {
-    HttpClientConnection conn =
-        client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/$i"));
-    conn.onRequest = (HttpClientRequest clientRequest) {
-      String content = "$i$i$i";
-      clientRequest.contentLength = content.length;
-      clientRequest.outputStream.writeString(content);
-      clientRequest.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      response.inputStream.onData = () => response.inputStream.read();
-      response.inputStream.onClosed = () {
-        testDirectDoneCount++;
-        if (testDirectDoneCount == proxy.length) {
-          Expect.equals(proxy.length, server.requestCount);
-          server.shutdown();
-          client.shutdown();
-        }
-      };
-    };
-  }
+    for (int i = 0; i < proxy.length; i++) {
+      client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/$i"))
+        .then((HttpClientRequest clientRequest) {
+          String content = "$i$i$i";
+          clientRequest.contentLength = content.length;
+          clientRequest.addString(content);
+          return clientRequest.close();
+        })
+       .then((HttpClientResponse response) {
+          response.listen((_) {}, onDone: () {
+            testDirectDoneCount++;
+            if (testDirectDoneCount == proxy.length) {
+              Expect.equals(proxy.length, server.requestCount);
+              server.shutdown();
+              client.close();
+            }
+          });
+        });
+    }
+  });
 }
 
 int testProxyDoneCount = 0;
 void testProxy() {
-  ProxyServer proxyServer = setupProxyServer();
-  Server server = setupServer(1, ["/4"]);
-  HttpClient client = new HttpClient();
+  setupProxyServer().then((proxyServer) {
+  setupServer(1, directRequestPaths: ["/4"]).then((server) {
+  setupServer(1, directRequestPaths: ["/4"], secure: true).then((secureServer) {
+    HttpClient client = new HttpClient();
 
-  List<String> proxy =
-      ["PROXY localhost:${proxyServer.port}",
-       "PROXY localhost:${proxyServer.port}; PROXY hede.hule.hest:8080",
-       "PROXY hede.hule.hest:8080; PROXY localhost:${proxyServer.port}",
-       "PROXY hede.hule.hest:8080; PROXY hede.hule.hest:8181; PROXY localhost:${proxyServer.port}",
-       "PROXY hede.hule.hest:8080; PROXY hede.hule.hest:8181; DIRECT",
-       "PROXY localhost:${proxyServer.port}; DIRECT"];
+    List<String> proxy =
+        ["PROXY localhost:${proxyServer.port}",
+         "PROXY localhost:${proxyServer.port}; PROXY hede.hule.hest:8080",
+         "PROXY hede.hule.hest:8080; PROXY localhost:${proxyServer.port}",
+         "PROXY hede.hule.hest:8080; PROXY hede.hule.hest:8181;"
+             " PROXY localhost:${proxyServer.port}",
+         "PROXY hede.hule.hest:8080; PROXY hede.hule.hest:8181; DIRECT",
+         "PROXY localhost:${proxyServer.port}; DIRECT"];
 
-  client.findProxy = (Uri uri) {
-    // Pick the proxy configuration based on the request path.
-    int index = int.parse(uri.path.substring(1));
-    return proxy[index];
-  };
-
-  for (int i = 0; i < proxy.length; i++) {
-    HttpClientConnection conn =
-        client.postUrl(
-            Uri.parse("http://127.0.0.1:${server.port}/$i"));
-    conn.onRequest = (HttpClientRequest clientRequest) {
-      String content = "$i$i$i";
-      clientRequest.outputStream.writeString(content);
-      clientRequest.outputStream.close();
+    client.findProxy = (Uri uri) {
+      // Pick the proxy configuration based on the request path.
+      int index = int.parse(uri.path.substring(1));
+      return proxy[index];
     };
-    conn.onResponse = (HttpClientResponse response) {
-      response.inputStream.onData = () => response.inputStream.read();
-      response.inputStream.onClosed = () {
-        testProxyDoneCount++;
-        if (testProxyDoneCount == proxy.length) {
-          Expect.equals(proxy.length, server.requestCount);
-          proxyServer.shutdown();
-          server.shutdown();
-          client.shutdown();
-        }
-      };
-    };
-  }
+
+    for (int i = 0; i < proxy.length; i++) {
+      test(bool secure) {
+        String url = secure
+            ? "https://localhost:${secureServer.port}/$i"
+            : "http://127.0.0.1:${server.port}/$i";
+
+        client.postUrl(Uri.parse(url))
+          .then((HttpClientRequest clientRequest) {
+            String content = "$i$i$i";
+            clientRequest.addString(content);
+            return clientRequest.close();
+          })
+          .then((HttpClientResponse response) {
+            response.listen((_) {}, onDone: () {
+              testProxyDoneCount++;
+              if (testProxyDoneCount == proxy.length * 2) {
+                Expect.equals(proxy.length, server.requestCount);
+                proxyServer.shutdown();
+                server.shutdown();
+                secureServer.shutdown();
+                client.close();
+              }
+            });
+          });
+      }
+
+      test(false);
+      test(true);
+    }
+  });
+  });
+  });
 }
 
 int testProxyChainDoneCount = 0;
 void testProxyChain() {
   // Setup two proxy servers having the first using the second as its proxy.
-  ProxyServer proxyServer1 = setupProxyServer();
-  ProxyServer proxyServer2 = setupProxyServer();
+  setupProxyServer().then((proxyServer1) {
+  setupProxyServer().then((proxyServer2) {
   proxyServer1.client.findProxy = (_) => "PROXY 127.0.0.1:${proxyServer2.port}";
 
-  Server server = setupServer(2, ["/4"]);
-  HttpClient client = new HttpClient();
+  setupServer(2, directRequestPaths: ["/4"]).then((server) {
+    HttpClient client = new HttpClient();
 
-  List<String> proxy =
-      ["PROXY localhost:${proxyServer1.port}",
-       "PROXY localhost:${proxyServer1.port}; PROXY hede.hule.hest:8080",
-       "PROXY hede.hule.hest:8080; PROXY localhost:${proxyServer1.port}",
-       "PROXY hede.hule.hest:8080; PROXY hede.hule.hest:8181; PROXY localhost:${proxyServer1.port}",
-       "PROXY hede.hule.hest:8080; PROXY hede.hule.hest:8181; DIRECT",
-       "PROXY localhost:${proxyServer1.port}; DIRECT"];
+    List<String> proxy =
+        ["PROXY localhost:${proxyServer1.port}",
+         "PROXY localhost:${proxyServer1.port}; PROXY hede.hule.hest:8080",
+         "PROXY hede.hule.hest:8080; PROXY localhost:${proxyServer1.port}",
+         "PROXY hede.hule.hest:8080; PROXY hede.hule.hest:8181; PROXY localhost:${proxyServer1.port}",
+         "PROXY hede.hule.hest:8080; PROXY hede.hule.hest:8181; DIRECT",
+         "PROXY localhost:${proxyServer1.port}; DIRECT"];
 
-  client.findProxy = (Uri uri) {
-    // Pick the proxy configuration based on the request path.
-    int index = int.parse(uri.path.substring(1));
-    return proxy[index];
-  };
-
-  for (int i = 0; i < proxy.length; i++) {
-    HttpClientConnection conn =
-        client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/$i"));
-    conn.onRequest = (HttpClientRequest clientRequest) {
-      String content = "$i$i$i";
-      clientRequest.contentLength = content.length;
-      clientRequest.outputStream.writeString(content);
-      clientRequest.outputStream.close();
+    client.findProxy = (Uri uri) {
+      // Pick the proxy configuration based on the request path.
+      int index = int.parse(uri.path.substring(1));
+      return proxy[index];
     };
-    conn.onResponse = (HttpClientResponse response) {
-      response.inputStream.onData = () => response.inputStream.read();
-      response.inputStream.onClosed = () {
-        testProxyChainDoneCount++;
-        if (testProxyChainDoneCount == proxy.length) {
-          Expect.equals(proxy.length, server.requestCount);
-          proxyServer1.shutdown();
-          proxyServer2.shutdown();
-          server.shutdown();
-          client.shutdown();
-        }
-      };
-    };
-  }
+
+    for (int i = 0; i < proxy.length; i++) {
+      client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/$i"))
+        .then((HttpClientRequest clientRequest) {
+          String content = "$i$i$i";
+          clientRequest.contentLength = content.length;
+          clientRequest.addString(content);
+          return clientRequest.close();
+        })
+        .then((HttpClientResponse response) {
+          response.listen((_) {}, onDone: () {
+            testProxyChainDoneCount++;
+            if (testProxyChainDoneCount == proxy.length) {
+              Expect.equals(proxy.length, server.requestCount);
+              proxyServer1.shutdown();
+              proxyServer2.shutdown();
+              server.shutdown();
+              client.close();
+            }
+          });
+        });
+    }
+  });
+  });
+  });
 }
 
 int testRealProxyDoneCount = 0;
 void testRealProxy() {
-  Server server = setupServer(1);
-  HttpClient client = new HttpClient();
+  setupServer(1).then((server) {
+    HttpClient client = new HttpClient();
 
-  List<String> proxy =
-      ["PROXY localhost:8080",
-       "PROXY localhost:8080; PROXY hede.hule.hest:8080",
-       "PROXY hede.hule.hest:8080; PROXY localhost:8080",
-       "PROXY localhost:8080; DIRECT"];
+    List<String> proxy =
+        ["PROXY localhost:8080",
+         "PROXY localhost:8080; PROXY hede.hule.hest:8080",
+         "PROXY hede.hule.hest:8080; PROXY localhost:8080",
+         "PROXY localhost:8080; DIRECT"];
 
-  client.findProxy = (Uri uri) {
-    // Pick the proxy configuration based on the request path.
-    int index = int.parse(uri.path.substring(1));
-    return proxy[index];
-  };
-
-  for (int i = 0; i < proxy.length; i++) {
-    HttpClientConnection conn =
-       client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/$i"));
-    conn.onRequest = (HttpClientRequest clientRequest) {
-      String content = "$i$i$i";
-      clientRequest.contentLength = content.length;
-      clientRequest.outputStream.writeString(content);
-      clientRequest.outputStream.close();
+    client.findProxy = (Uri uri) {
+      // Pick the proxy configuration based on the request path.
+      int index = int.parse(uri.path.substring(1));
+      return proxy[index];
     };
-    conn.onResponse = (HttpClientResponse response) {
-      response.inputStream.onData = () => response.inputStream.read();
-      response.inputStream.onClosed = () {
-        testRealProxyDoneCount++;
-        if (testRealProxyDoneCount == proxy.length) {
-          Expect.equals(proxy.length, server.requestCount);
-          server.shutdown();
-          client.shutdown();
-        }
-      };
-    };
-  }
+
+    for (int i = 0; i < proxy.length; i++) {
+      client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/$i"))
+        .then((HttpClientRequest clientRequest) {
+          String content = "$i$i$i";
+          clientRequest.contentLength = content.length;
+          clientRequest.addString(content);
+          return clientRequest.close();
+        })
+        .then((HttpClientResponse response) {
+          response.listen((_) {}, onDone: () {
+            testRealProxyDoneCount++;
+            if (testRealProxyDoneCount == proxy.length) {
+              Expect.equals(proxy.length, server.requestCount);
+              server.shutdown();
+              client.close();
+            }
+          });
+        });
+    }
+  });
+}
+
+void InitializeSSL() {
+  var testPkcertDatabase =
+      new Path(new Options().script).directoryPath.append('pkcert/');
+  SecureSocket.initialize(database: testPkcertDatabase.toNativePath(),
+                          password: 'dartdart');
 }
 
 main() {
+  InitializeSSL();
   testInvalidProxy();
   testDirectProxy();
   testProxy();
   testProxyChain();
   // This test is not normally run. It can be used for locally testing
   // with a real proxy server (e.g. Apache).
-  // testRealProxy();
+  //testRealProxy();
 }
diff --git a/tests/standalone/io/http_read_test.dart b/tests/standalone/io/http_read_test.dart
index bb8a87a..dfef4e4 100644
--- a/tests/standalone/io/http_read_test.dart
+++ b/tests/standalone/io/http_read_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
@@ -10,11 +10,11 @@
 import "dart:isolate";
 import "dart:io";
 
-class TestServerMain {
-  TestServerMain()
+class IsolatedHttpServer {
+  IsolatedHttpServer()
       : _statusPort = new ReceivePort(),
         _serverPort = null {
-    _serverPort = spawnFunction(startTestServer);
+    _serverPort = spawnFunction(startIsolatedHttpServer);
   }
 
   void setServerStartedHandler(void startedCallback(int port)) {
@@ -30,20 +30,22 @@
     });
 
     // Send server start message to the server.
-    var command = new TestServerCommand.start();
+    var command = new IsolatedHttpServerCommand.start();
     _serverPort.send(command, _statusPort.toSendPort());
   }
 
   void shutdown() {
     // Send server stop message to the server.
-    _serverPort.send(new TestServerCommand.stop(), _statusPort.toSendPort());
+    _serverPort.send(new IsolatedHttpServerCommand.stop(),
+                     _statusPort.toSendPort());
     _statusPort.close();
   }
 
   void chunkedEncoding() {
     // Send chunked encoding message to the server.
     _serverPort.send(
-        new TestServerCommand.chunkedEncoding(), _statusPort.toSendPort());
+        new IsolatedHttpServerCommand.chunkedEncoding(),
+        _statusPort.toSendPort());
   }
 
   ReceivePort _statusPort;  // Port for receiving messages from the server.
@@ -52,14 +54,14 @@
 }
 
 
-class TestServerCommand {
+class IsolatedHttpServerCommand {
   static const START = 0;
   static const STOP = 1;
   static const CHUNKED_ENCODING = 2;
 
-  TestServerCommand.start() : _command = START;
-  TestServerCommand.stop() : _command = STOP;
-  TestServerCommand.chunkedEncoding() : _command = CHUNKED_ENCODING;
+  IsolatedHttpServerCommand.start() : _command = START;
+  IsolatedHttpServerCommand.stop() : _command = STOP;
+  IsolatedHttpServerCommand.chunkedEncoding() : _command = CHUNKED_ENCODING;
 
   bool get isStart => _command == START;
   bool get isStop => _command == STOP;
@@ -69,14 +71,14 @@
 }
 
 
-class TestServerStatus {
+class IsolatedHttpServerStatus {
   static const STARTED = 0;
   static const STOPPED = 1;
   static const ERROR = 2;
 
-  TestServerStatus.started(this._port) : _state = STARTED;
-  TestServerStatus.stopped() : _state = STOPPED;
-  TestServerStatus.error() : _state = ERROR;
+  IsolatedHttpServerStatus.started(this._port) : _state = STARTED;
+  IsolatedHttpServerStatus.stopped() : _state = STOPPED;
+  IsolatedHttpServerStatus.error() : _state = ERROR;
 
   bool get isStarted => _state == STARTED;
   bool get isStopped => _state == STOPPED;
@@ -89,7 +91,7 @@
 }
 
 
-void startTestServer() {
+void startIsolatedHttpServer() {
   var server = new TestServer();
   server.init();
   port.receive(server.dispatch);
@@ -97,56 +99,56 @@
 
 class TestServer {
   // Echo the request content back to the response.
-  void _echoHandler(HttpRequest request, HttpResponse response) {
+  void _echoHandler(HttpRequest request) {
+    var response = request.response;
     Expect.equals("POST", request.method);
     response.contentLength = request.contentLength;
-    request.inputStream.pipe(response.outputStream);
+    request.pipe(response);
   }
 
   // Return a 404.
-  void _notFoundHandler(HttpRequest request, HttpResponse response) {
+  void _notFoundHandler(HttpRequest request) {
+    var response = request.response;
     response.statusCode = HttpStatus.NOT_FOUND;
     response.headers.set("Content-Type", "text/html; charset=UTF-8");
-    response.outputStream.writeString("Page not found");
-    response.outputStream.close();
+    response.addString("Page not found");
+    response.close();
   }
 
 
   void init() {
     // Setup request handlers.
     _requestHandlers = new Map();
-    _requestHandlers["/echo"] = (HttpRequest request, HttpResponse response) {
-      _echoHandler(request, response);
-    };
+    _requestHandlers["/echo"] = _echoHandler;
   }
 
   void dispatch(message, SendPort replyTo) {
     if (message.isStart) {
-      _server = new HttpServer();
       try {
-        _server.listen("127.0.0.1", 0);
-        _server.defaultRequestHandler = (HttpRequest req, HttpResponse rsp) {
-          _requestReceivedHandler(req, rsp);
-        };
-        replyTo.send(new TestServerStatus.started(_server.port), null);
+        HttpServer.bind().then((server) {
+          _server = server;
+          _server.listen(_requestReceivedHandler);
+          replyTo.send(
+              new IsolatedHttpServerStatus.started(_server.port), null);
+        });
       } catch (e) {
-        replyTo.send(new TestServerStatus.error(), null);
+        replyTo.send(new IsolatedHttpServerStatus.error(), null);
       }
     } else if (message.isStop) {
       _server.close();
       port.close();
-      replyTo.send(new TestServerStatus.stopped(), null);
+      replyTo.send(new IsolatedHttpServerStatus.stopped(), null);
     } else if (message.isChunkedEncoding) {
       _chunkedEncoding = true;
     }
   }
 
-  void _requestReceivedHandler(HttpRequest request, HttpResponse response) {
-    var requestHandler =_requestHandlers[request.path];
+  void _requestReceivedHandler(HttpRequest request) {
+    var requestHandler =_requestHandlers[request.uri.path];
     if (requestHandler != null) {
-      requestHandler(request, response);
+      requestHandler(request);
     } else {
-      _notFoundHandler(request, response);
+      _notFoundHandler(request);
     }
   }
 
@@ -155,116 +157,55 @@
   bool _chunkedEncoding = false;
 }
 
-void testReadInto(bool chunkedEncoding) {
+void testRead(bool chunkedEncoding) {
   String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   final int kMessageCount = 10;
 
-  TestServerMain testServerMain = new TestServerMain();
+  IsolatedHttpServer server = new IsolatedHttpServer();
 
   void runTest(int port) {
     int count = 0;
     HttpClient httpClient = new HttpClient();
     void sendRequest() {
-      HttpClientConnection conn =
-          httpClient.post("127.0.0.1", port, "/echo");
-      conn.onRequest = (HttpClientRequest request) {
-        if (chunkedEncoding) {
-          request.outputStream.writeString(data.substring(0, 10));
-          request.outputStream.writeString(data.substring(10, data.length));
-        } else {
-          request.contentLength = data.length;
-          request.outputStream.write(data.charCodes);
-        }
-        request.outputStream.close();
-      };
-      conn.onResponse = (HttpClientResponse response) {
-        Expect.equals(HttpStatus.OK, response.statusCode);
-        InputStream stream = response.inputStream;
-        List<int> body = new List<int>();
-        stream.onData = () {
-          List tmp = new List.fixedLength(3);
-          int bytes = stream.readInto(tmp);
-          body.addAll(tmp.getRange(0, bytes));
-        };
-        stream.onClosed = () {
-          Expect.equals(data, new String.fromCharCodes(body));
-          count++;
-          if (count < kMessageCount) {
-            sendRequest();
-          } else {
-            httpClient.shutdown();
-            testServerMain.shutdown();
-          }
-        };
-      };
+      httpClient.post("127.0.0.1", port, "/echo")
+          .then((request) {
+            if (chunkedEncoding) {
+              request.addString(data.substring(0, 10));
+              request.addString(data.substring(10, data.length));
+            } else {
+              request.contentLength = data.length;
+              request.add(data.charCodes);
+            }
+            return request.close();
+          })
+          .then((response) {
+            Expect.equals(HttpStatus.OK, response.statusCode);
+            List<int> body = new List<int>();
+            response.listen(
+                body.addAll,
+                onDone: () {
+                  Expect.equals(data, new String.fromCharCodes(body));
+                  count++;
+                  if (count < kMessageCount) {
+                    sendRequest();
+                  } else {
+                    httpClient.close();
+                    server.shutdown();
+                  }
+                });
+          });
     }
-
     sendRequest();
   }
 
-  testServerMain.setServerStartedHandler(runTest);
+  server.setServerStartedHandler(runTest);
   if (chunkedEncoding) {
-    testServerMain.chunkedEncoding();
+    server.chunkedEncoding();
   }
-  testServerMain.start();
-}
-
-void testReadShort(bool chunkedEncoding) {
-  String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-  final int kMessageCount = 10;
-
-  TestServerMain testServerMain = new TestServerMain();
-
-  void runTest(int port) {
-    int count = 0;
-    HttpClient httpClient = new HttpClient();
-    void sendRequest() {
-      HttpClientConnection conn =
-          httpClient.post("127.0.0.1", port, "/echo");
-      conn.onRequest = (HttpClientRequest request) {
-        if (chunkedEncoding) {
-          request.outputStream.writeString(data.substring(0, 10));
-          request.outputStream.writeString(data.substring(10, data.length));
-        } else {
-          request.contentLength = data.length;
-          request.outputStream.write(data.charCodes);
-        }
-        request.outputStream.close();
-      };
-      conn.onResponse = (HttpClientResponse response) {
-        Expect.equals(HttpStatus.OK, response.statusCode);
-        InputStream stream = response.inputStream;
-        List<int> body = new List<int>();
-        stream.onData = () {
-          List tmp = stream.read(2);
-          body.addAll(tmp);
-        };
-        stream.onClosed = () {
-          Expect.equals(data, new String.fromCharCodes(body));
-          count++;
-          if (count < kMessageCount) {
-            sendRequest();
-          } else {
-            httpClient.shutdown();
-            testServerMain.shutdown();
-          }
-        };
-      };
-    }
-
-    sendRequest();
-  }
-
-  testServerMain.setServerStartedHandler(runTest);
-  if (chunkedEncoding) {
-    testServerMain.chunkedEncoding();
-  }
-  testServerMain.start();
+  server.start();
 }
 
 void main() {
-  testReadInto(true);
-  testReadInto(false);
-  testReadShort(true);
-  testReadShort(false);
+  testRead(true);
+  testRead(false);
 }
diff --git a/tests/standalone/io/http_redirect_test.dart b/tests/standalone/io/http_redirect_test.dart
index 4df9782..3209496 100644
--- a/tests/standalone/io/http_redirect_test.dart
+++ b/tests/standalone/io/http_redirect_test.dart
@@ -3,386 +3,370 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 
+import "dart:async";
 import "dart:io";
 import "dart:uri";
 
-HttpServer setupServer() {
-  HttpServer server = new HttpServer();
-  server.listen("127.0.0.1", 0, backlog: 5);
+Future<HttpServer> setupServer() {
+  Completer completer = new Completer();
+  HttpServer.bind().then((server) {
 
-  void addRedirectHandler(int number, int statusCode) {
-    server.addRequestHandler(
-       (HttpRequest request) => request.path == "/$number",
-       (HttpRequest request, HttpResponse response) {
-       response.headers.set(HttpHeaders.LOCATION,
-                            "http://127.0.0.1:${server.port}/${number + 1}");
-       response.statusCode = statusCode;
-       response.outputStream.close();
-     });
-  }
+    var handlers = new Map<String, Function>();
+    addRequestHandler(String path, void handler(HttpRequest request,
+                                                HttpResponse response)) {
+      handlers[path] = handler;
+    }
 
-  // Setup simple redirect.
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/redirect",
-     (HttpRequest request, HttpResponse response) {
-       response.headers.set(HttpHeaders.LOCATION,
-                            "http://127.0.0.1:${server.port}/location");
-       response.statusCode = HttpStatus.MOVED_PERMANENTLY;
-       response.outputStream.close();
-     }
-  );
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/location",
-     (HttpRequest request, HttpResponse response) {
-       response.outputStream.close();
-     }
-  );
+    server.listen((HttpRequest request) {
+      if (handlers.containsKey(request.uri.path)) {
+        handlers[request.uri.path](request, request.response);
+      } else {
+        request.listen((_) {}, onDone: () {
+          request.response.statusCode = 404;
+          request.response.close();
+        });
+      }
+    });
 
-  // Setup redirect chain.
-  int n = 1;
-  addRedirectHandler(n++, HttpStatus.MOVED_PERMANENTLY);
-  addRedirectHandler(n++, HttpStatus.MOVED_TEMPORARILY);
-  addRedirectHandler(n++, HttpStatus.SEE_OTHER);
-  addRedirectHandler(n++, HttpStatus.TEMPORARY_REDIRECT);
-  for (int i = n; i < 10; i++) {
-    addRedirectHandler(i, HttpStatus.MOVED_PERMANENTLY);
-  }
-
-  // Setup redirect loop.
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/A",
-     (HttpRequest request, HttpResponse response) {
-       response.headers.set(HttpHeaders.LOCATION,
-                            "http://127.0.0.1:${server.port}/B");
-       response.statusCode = HttpStatus.MOVED_PERMANENTLY;
-       response.outputStream.close();
-     }
-  );
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/B",
-     (HttpRequest request, HttpResponse response) {
-       response.headers.set(HttpHeaders.LOCATION,
-                            "http://127.0.0.1:${server.port}/A");
-       response.statusCode = HttpStatus.MOVED_TEMPORARILY;
-       response.outputStream.close();
-     }
-  );
-
-  // Setup redirect checking headers.
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/src",
-     (HttpRequest request, HttpResponse response) {
-       Expect.equals("value", request.headers.value("X-Request-Header"));
-       response.headers.set(HttpHeaders.LOCATION,
-                            "http://127.0.0.1:${server.port}/target");
-       response.statusCode = HttpStatus.MOVED_PERMANENTLY;
-       response.outputStream.close();
-     }
-  );
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/target",
-     (HttpRequest request, HttpResponse response) {
-       Expect.equals("value", request.headers.value("X-Request-Header"));
-       response.outputStream.close();
-     }
-  );
-
-  // Setup redirect for 301 where POST should not redirect.
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/301src",
-     (HttpRequest request, HttpResponse response) {
-       Expect.equals("POST", request.method);
-       response.headers.set(HttpHeaders.LOCATION,
-                            "http://127.0.0.1:${server.port}/301target");
-       response.statusCode = HttpStatus.MOVED_PERMANENTLY;
-       response.outputStream.close();
-     }
-  );
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/301target",
-     (HttpRequest request, HttpResponse response) {
-       Expect.fail("Redirect of POST should not happen");
-     }
-  );
-
-  // Setup redirect for 303 where POST should turn into GET.
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/303src",
-     (HttpRequest request, HttpResponse response) {
-       Expect.equals("POST", request.method);
-       Expect.equals(10, request.contentLength);
-       request.inputStream.onData = request.inputStream.read;
-       request.inputStream.onClosed = () {
+    void addRedirectHandler(int number, int statusCode) {
+      addRequestHandler(
+         "/$number",
+         (HttpRequest request, HttpResponse response) {
          response.headers.set(HttpHeaders.LOCATION,
-                              "http://127.0.0.1:${server.port}/303target");
-         response.statusCode = HttpStatus.SEE_OTHER;
-         response.outputStream.close();
-       };
-     }
-  );
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/303target",
-     (HttpRequest request, HttpResponse response) {
-       Expect.equals("GET", request.method);
-       response.outputStream.close();
-     }
-  );
+                              "http://127.0.0.1:${server.port}/${number + 1}");
+         response.statusCode = statusCode;
+         response.close();
+       });
+    }
 
-  // Setup redirect where we close the connection.
-  server.addRequestHandler(
-     (HttpRequest request) => request.path == "/closing",
-     (HttpRequest request, HttpResponse response) {
-       response.headers.set(HttpHeaders.LOCATION,
-                            "http://127.0.0.1:${server.port}/");
-       response.statusCode = HttpStatus.FOUND;
-       response.persistentConnection = false;
-       response.outputStream.close();
-     }
-  );
+    // Setup simple redirect.
+    addRequestHandler(
+       "/redirect",
+       (HttpRequest request, HttpResponse response) {
+         response.headers.set(HttpHeaders.LOCATION,
+                              "http://127.0.0.1:${server.port}/location");
+         response.statusCode = HttpStatus.MOVED_PERMANENTLY;
+         response.close();
+       }
+    );
+    addRequestHandler(
+       "/location",
+       (HttpRequest request, HttpResponse response) {
+         response.close();
+       }
+    );
 
-  return server;
+    // Setup redirect chain.
+    int n = 1;
+    addRedirectHandler(n++, HttpStatus.MOVED_PERMANENTLY);
+    addRedirectHandler(n++, HttpStatus.MOVED_TEMPORARILY);
+    addRedirectHandler(n++, HttpStatus.SEE_OTHER);
+    addRedirectHandler(n++, HttpStatus.TEMPORARY_REDIRECT);
+    for (int i = n; i < 10; i++) {
+      addRedirectHandler(i, HttpStatus.MOVED_PERMANENTLY);
+    }
+
+    // Setup redirect loop.
+    addRequestHandler(
+       "/A",
+       (HttpRequest request, HttpResponse response) {
+         response.headers.set(HttpHeaders.LOCATION,
+                              "http://127.0.0.1:${server.port}/B");
+         response.statusCode = HttpStatus.MOVED_PERMANENTLY;
+         response.close();
+       }
+    );
+    addRequestHandler(
+       "/B",
+       (HttpRequest request, HttpResponse response) {
+         response.headers.set(HttpHeaders.LOCATION,
+                              "http://127.0.0.1:${server.port}/A");
+         response.statusCode = HttpStatus.MOVED_TEMPORARILY;
+         response.close();
+       }
+    );
+
+    // Setup redirect checking headers.
+    addRequestHandler(
+       "/src",
+       (HttpRequest request, HttpResponse response) {
+         Expect.equals("value", request.headers.value("X-Request-Header"));
+         response.headers.set(HttpHeaders.LOCATION,
+                              "http://127.0.0.1:${server.port}/target");
+         response.statusCode = HttpStatus.MOVED_PERMANENTLY;
+         response.close();
+       }
+    );
+    addRequestHandler(
+       "/target",
+       (HttpRequest request, HttpResponse response) {
+         Expect.equals("value", request.headers.value("X-Request-Header"));
+         response.close();
+       }
+    );
+
+    // Setup redirect for 301 where POST should not redirect.
+    addRequestHandler(
+        "/301src",
+        (HttpRequest request, HttpResponse response) {
+          Expect.equals("POST", request.method);
+          request.listen(
+              (_) {},
+              onDone: () {
+                response.headers.set(
+                    HttpHeaders.LOCATION,
+                    "http://127.0.0.1:${server.port}/301target");
+                response.statusCode = HttpStatus.MOVED_PERMANENTLY;
+                response.close();
+              });
+        });
+    addRequestHandler(
+       "/301target",
+       (HttpRequest request, HttpResponse response) {
+         Expect.fail("Redirect of POST should not happen");
+       }
+    );
+
+    // Setup redirect for 303 where POST should turn into GET.
+    addRequestHandler(
+        "/303src",
+        (HttpRequest request, HttpResponse response) {
+          request.listen((_) {}, onDone: () {
+            Expect.equals("POST", request.method);
+            request.listen(
+                (_) {},
+                onDone: () {
+                  response.headers.set(
+                      HttpHeaders.LOCATION,
+                      "http://127.0.0.1:${server.port}/303target");
+                  response.statusCode = HttpStatus.SEE_OTHER;
+                  response.close();
+                });
+          });
+        });
+    addRequestHandler(
+       "/303target",
+       (HttpRequest request, HttpResponse response) {
+         Expect.equals("GET", request.method);
+         response.close();
+       });
+
+    // Setup redirect where we close the connection.
+    addRequestHandler(
+       "/closing",
+       (HttpRequest request, HttpResponse response) {
+         response.headers.set(HttpHeaders.LOCATION,
+                              "http://127.0.0.1:${server.port}/");
+         response.statusCode = HttpStatus.FOUND;
+         response.persistentConnection = false;
+         response.close();
+       });
+
+    completer.complete(server);
+  });
+  return completer.future;
 }
 
-void checkRedirects(int redirectCount, HttpClientConnection conn) {
+void checkRedirects(int redirectCount, HttpClientResponse response) {
   if (redirectCount < 2) {
-    Expect.isNull(conn.redirects);
+    Expect.isTrue(response.redirects.isEmpty);
   } else {
-    Expect.equals(redirectCount - 1, conn.redirects.length);
+    Expect.equals(redirectCount - 1, response.redirects.length);
     for (int i = 0; i < redirectCount - 2; i++) {
-      Expect.equals(conn.redirects[i].location.path, "/${i + 2}");
+      Expect.equals(response.redirects[i].location.path, "/${i + 2}");
     }
   }
 }
 
 void testManualRedirect() {
-  HttpServer server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  int redirectCount = 0;
-  HttpClientConnection conn =
-     client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/1"));
-  conn.followRedirects = false;
-  conn.onResponse = (HttpClientResponse response) {
-    response.inputStream.onData = response.inputStream.read;
-    response.inputStream.onClosed = () {
-      redirectCount++;
-      if (redirectCount < 10) {
-        Expect.isTrue(response.isRedirect);
-        checkRedirects(redirectCount, conn);
-        conn.redirect();
-      } else {
-        Expect.equals(HttpStatus.NOT_FOUND, response.statusCode);
-        server.close();
-        client.shutdown();
-      }
-    };
-  };
+    int redirectCount = 0;
+    handleResponse(HttpClientResponse response) {
+      response.listen(
+          (_) => Expect.fail("Response data not expected"),
+          onDone: () {
+            redirectCount++;
+            if (redirectCount < 10) {
+              Expect.isTrue(response.isRedirect);
+              checkRedirects(redirectCount, response);
+              response.redirect().then(handleResponse);
+            } else {
+              Expect.equals(HttpStatus.NOT_FOUND, response.statusCode);
+              server.close();
+              client.close();
+            }
+          });
+    }
+    client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/1"))
+      .then((HttpClientRequest request) {
+        request.followRedirects = false;
+        return request.close();
+      })
+      .then(handleResponse);
+  });
 }
 
 void testManualRedirectWithHeaders() {
-  HttpServer server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  int redirectCount = 0;
-  HttpClientConnection conn =
-     client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/src"));
-  conn.followRedirects = false;
-  conn.onRequest = (HttpClientRequest request) {
-    request.headers.add("X-Request-Header", "value");
-    request.outputStream.close();
-  };
-  conn.onResponse = (HttpClientResponse response) {
-    response.inputStream.onData = response.inputStream.read;
-    response.inputStream.onClosed = () {
-      redirectCount++;
-      if (redirectCount < 2) {
-        Expect.isTrue(response.isRedirect);
-        conn.redirect();
-      } else {
-        Expect.equals(HttpStatus.OK, response.statusCode);
-        server.close();
-        client.shutdown();
-      }
-    };
-  };
+    int redirectCount = 0;
+
+    handleResponse(HttpClientResponse response) {
+      response.listen(
+          (_) => Expect.fail("Response data not expected"),
+          onDone: () {
+            redirectCount++;
+            if (redirectCount < 2) {
+              Expect.isTrue(response.isRedirect);
+              response.redirect().then(handleResponse);
+            } else {
+              Expect.equals(HttpStatus.OK, response.statusCode);
+              server.close();
+              client.close();
+            }
+          });
+    }
+
+    client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/src"))
+      .then((HttpClientRequest request) {
+        request.followRedirects = false;
+        request.headers.add("X-Request-Header", "value");
+        return request.close();
+      }).then(handleResponse);
+  });
 }
 
 void testAutoRedirect() {
-  HttpServer server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  var requestCount = 0;
-
-  void onRequest(HttpClientRequest request) {
-    requestCount++;
-    request.outputStream.close();
-  }
-
-  void onResponse(HttpClientResponse response) {
-    response.inputStream.onData =
-        () => Expect.fail("Response data not expected");
-    response.inputStream.onClosed = () {
-      Expect.equals(1, requestCount);
-      server.close();
-      client.shutdown();
-    };
-  };
-
-  HttpClientConnection conn =
-      client.getUrl(
-          Uri.parse("http://127.0.0.1:${server.port}/redirect"));
-  conn.onRequest = onRequest;
-  conn.onResponse = onResponse;
-  conn.onError = (e) => Expect.fail("Error not expected ($e)");
+    client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/redirect"))
+      .then((HttpClientRequest request) {
+        return request.close();
+      })
+      .then((HttpClientResponse response) {
+        response.listen(
+            (_) => Expect.fail("Response data not expected"),
+            onDone: () {
+              Expect.equals(1, response.redirects.length);
+              server.close();
+              client.close();
+            });
+      });
+  });
 }
 
 void testAutoRedirectWithHeaders() {
-  HttpServer server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  var requestCount = 0;
-
-  void onRequest(HttpClientRequest request) {
-    requestCount++;
-    request.headers.add("X-Request-Header", "value");
-    request.outputStream.close();
-  };
-
-  void onResponse(HttpClientResponse response) {
-    response.inputStream.onData =
-        () => Expect.fail("Response data not expected");
-    response.inputStream.onClosed = () {
-      Expect.equals(1, requestCount);
-      server.close();
-      client.shutdown();
-    };
-  };
-
-  HttpClientConnection conn =
-      client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/src"));
-  conn.onRequest = onRequest;
-  conn.onResponse = onResponse;
-  conn.onError = (e) => Expect.fail("Error not expected ($e)");
+    client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/src"))
+      .then((HttpClientRequest request) {
+        request.headers.add("X-Request-Header", "value");
+        return request.close();
+      })
+      .then((HttpClientResponse response) {
+        response.listen(
+            (_) => Expect.fail("Response data not expected"),
+            onDone: () {
+              Expect.equals(1, response.redirects.length);
+              server.close();
+              client.close();
+            });
+      });
+  });
 }
 
 void testAutoRedirect301POST() {
-  HttpServer server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  var requestCount = 0;
-
-  void onRequest(HttpClientRequest request) {
-    requestCount++;
-    request.outputStream.close();
-  };
-
-  void onResponse(HttpClientResponse response) {
-    Expect.equals(HttpStatus.MOVED_PERMANENTLY, response.statusCode);
-    response.inputStream.onData =
-        () => Expect.fail("Response data not expected");
-    response.inputStream.onClosed = () {
-      Expect.equals(1, requestCount);
-      server.close();
-      client.shutdown();
-    };
-  };
-
-  HttpClientConnection conn =
-      client.postUrl(
-          Uri.parse("http://127.0.0.1:${server.port}/301src"));
-  conn.onRequest = onRequest;
-  conn.onResponse = onResponse;
-  conn.onError = (e) => Expect.fail("Error not expected ($e)");
+    client.postUrl(Uri.parse("http://127.0.0.1:${server.port}/301src"))
+      .then((HttpClientRequest request) {
+        return request.close();
+      })
+      .then((HttpClientResponse response) {
+        Expect.equals(HttpStatus.MOVED_PERMANENTLY, response.statusCode);
+        response.listen(
+            (_) => Expect.fail("Response data not expected"),
+            onDone: () {
+              Expect.equals(0, response.redirects.length);
+              server.close();
+              client.close();
+            });
+      });
+  });
 }
 
 void testAutoRedirect303POST() {
-  HttpServer server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  var requestCount = 0;
-
-  void onRequest(HttpClientRequest request) {
-    requestCount++;
-    request.contentLength = 10;
-    request.outputStream.write(new List<int>.fixedLength(10, fill: 0));
-    request.outputStream.close();
-  };
-
-  void onResponse(HttpClientResponse response) {
-    Expect.equals(HttpStatus.OK, response.statusCode);
-    response.inputStream.onData =
-        () => Expect.fail("Response data not expected");
-    response.inputStream.onClosed = () {
-      Expect.equals(1, requestCount);
-      server.close();
-      client.shutdown();
-    };
-  };
-
-  HttpClientConnection conn =
-      client.postUrl(
-          Uri.parse("http://127.0.0.1:${server.port}/303src"));
-  conn.onRequest = onRequest;
-  conn.onResponse = onResponse;
-  conn.onError = (e) => Expect.fail("Error not expected ($e)");
+    client.postUrl(Uri.parse("http://127.0.0.1:${server.port}/303src"))
+      .then((HttpClientRequest request) {
+        return request.close();
+      })
+      .then((HttpClientResponse response) {
+        Expect.equals(HttpStatus.OK, response.statusCode);
+        response.listen(
+            (_) => Expect.fail("Response data not expected"),
+            onDone: () {
+              Expect.equals(1, response.redirects.length);
+              server.close();
+              client.close();
+            });
+      });
+  });
 }
 
 void testAutoRedirectLimit() {
-  HttpServer server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  HttpClientConnection conn =
-      client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/1"));
-  conn.onResponse = (HttpClientResponse response) {
-    response.inputStream.onData = () => Expect.fail("Response not expected");
-    response.inputStream.onClosed = () => Expect.fail("Response not expected");
-  };
-  conn.onError = (e) {
-    Expect.isTrue(e is RedirectLimitExceededException);
-    Expect.equals(5, e.redirects.length);
-    server.close();
-    client.shutdown();
-  };
+    client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/1"))
+      .then((HttpClientRequest request) => request.close())
+      .catchError((e) {
+        Expect.equals(5, e.error.redirects.length);
+        server.close();
+        client.close();
+      }, test: (e) => e is RedirectLimitExceededException);
+  });
 }
 
 void testRedirectLoop() {
-  HttpServer server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  int redirectCount = 0;
-  HttpClientConnection conn =
-      client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/A"));
-  conn.onResponse = (HttpClientResponse response) {
-    response.inputStream.onData = () => Expect.fail("Response not expected");
-    response.inputStream.onClosed = () => Expect.fail("Response not expected");
-  };
-  conn.onError = (e) {
-    Expect.isTrue(e is RedirectLoopException);
-    Expect.equals(2, e.redirects.length);
-    server.close();
-    client.shutdown();
-  };
+    int redirectCount = 0;
+    client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/A"))
+      .then((HttpClientRequest request) => request.close())
+      .catchError((e) {
+        Expect.equals(2, e.error.redirects.length);
+        server.close();
+        client.close();
+      }, test: (e) => e is RedirectLoopException);
+  });
 }
 
 void testRedirectClosingConnection() {
-  HttpServer server = setupServer();
-  HttpClient client = new HttpClient();
+  setupServer().then((server) {
+    HttpClient client = new HttpClient();
 
-  int redirectCount = 0;
-  HttpClientConnection conn =
-      client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/closing"));
-
-  conn.followRedirects = true;
-  conn.onResponse = (HttpClientResponse response) {
-    response.inputStream.onData = () => Expect.fail("Response not expected");
-    response.inputStream.onClosed = () => Expect.fail("Response not expected");
-  };
-  conn.onError = (e) {
-    Expect.isTrue(e is RedirectException);
-    Expect.isNull(e.redirects);
-    server.close();
-    client.shutdown();
-  };
+    client.getUrl(Uri.parse("http://127.0.0.1:${server.port}/closing"))
+        .then((request) => request.close())
+        .then((response) {
+          response.listen(
+              (_) {},
+              onDone: () {
+                Expect.equals(1, response.redirects.length);
+                server.close();
+                client.close();
+              });
+          });
+  });
 }
 
 main() {
diff --git a/tests/standalone/io/http_server_early_client_close_test.dart b/tests/standalone/io/http_server_early_client_close_test.dart
index 624442f..b59857e 100644
--- a/tests/standalone/io/http_server_early_client_close_test.dart
+++ b/tests/standalone/io/http_server_early_client_close_test.dart
@@ -7,16 +7,16 @@
 import "dart:isolate";
 
 void sendData(List<int> data, int port) {
-  Socket socket = new Socket("127.0.0.1", port);
-  socket.onConnect = () {
-    socket.onData = () {
-      Expect.fail("No data response was expected");
-    };
-    socket.outputStream.onNoPendingWrites = () {
-      socket.close(true);
-    };
-    socket.outputStream.write(data);
-  };
+  Socket.connect("127.0.0.1", port).then((socket) {
+    socket.listen((data) {
+        Expect.fail("No data response was expected");
+      });
+    socket.add(data);
+    socket.close();
+    socket.done.then((_) {
+      socket.destroy();
+    });
+  });
 }
 
 class EarlyCloseTest {
@@ -29,22 +29,31 @@
 
     bool calledOnRequest = false;
     bool calledOnError = false;
-    server.defaultRequestHandler =
-        (HttpRequest request, HttpResponse response) {
+    ReceivePort port = new ReceivePort();
+    server.listen(
+        (request) {
           Expect.isTrue(expectRequest);
           Expect.isFalse(calledOnError);
           Expect.isFalse(calledOnRequest, "onRequest called multiple times");
           calledOnRequest = true;
-        };
-    ReceivePort port = new ReceivePort();
-    server.onError = (error) {
-      Expect.isFalse(calledOnError);
-      Expect.equals(exception, error.message);
-      Expect.equals(expectRequest, calledOnRequest);
-      calledOnError = true;
-      port.close();
-      c.complete(null);
-    };
+          request.listen(
+              (_) {},
+              onError: (e) {
+                Expect.isFalse(calledOnError);
+                Expect.equals(exception, e.error.message);
+                calledOnError = true;
+                port.close();
+                c.complete(null);
+              });
+        },
+        onError: (e) {
+          Expect.isFalse(calledOnError);
+          Expect.equals(exception, e.error.message);
+          Expect.equals(expectRequest, calledOnRequest);
+          calledOnError = true;
+          port.close();
+          c.complete(null);
+        });
 
     List<int> d;
     if (data is List<int>) d = data;
@@ -68,7 +77,7 @@
   // The empty packet is valid.
 
   // Close while sending header
-  String message = "Connection closed before full request header was received";
+  String message = "Connection closed before full header was received";
   add("G", message);
   add("GET /", message);
   add("GET / HTTP/1.1", message);
@@ -76,54 +85,55 @@
 
   // Close while sending content
   add("GET / HTTP/1.1\r\nContent-Length: 100\r\n\r\n",
-      "Connection closed before full request body was received",
+      "Connection closed while receiving data",
       expectRequest: true);
   add("GET / HTTP/1.1\r\nContent-Length: 100\r\n\r\n1",
-      "Connection closed before full request body was received",
+      "Connection closed while receiving data",
       expectRequest: true);
 
-
-  HttpServer server = new HttpServer();
-  server.listen("127.0.0.1", 0);
   void runTest(Iterator it) {
     if (it.moveNext()) {
-      it.current.execute(server).then((_) => runTest(it));
-    } else {
-      server.close();
+      HttpServer.bind("127.0.0.1", 0).then((server) {
+        it.current.execute(server).then((_) {
+          runTest(it);
+          server.close();
+        });
+      });
     }
   }
   runTest(tests.iterator);
 }
 
 testEarlyClose2() {
-  var server = new HttpServer();
-  server.listen("127.0.0.1", 0);
-  server.onError = (e) { /* ignore */ };
-  server.defaultRequestHandler = (request, response) {
-    String name = new Options().script;
-    new File(name).openInputStream().pipe(response.outputStream);
-  };
+  HttpServer.bind("127.0.0.1", 0).then((server) {
+    server.listen(
+      (request) {
+        String name = new Options().script;
+        new File(name).openRead().pipe(request.response);
+      },
+      onError: (e) { /* ignore */ });
 
-  var count = 0;
-  var makeRequest;
-  makeRequest = () {
-    Socket socket = new Socket("127.0.0.1", server.port);
-    socket.onConnect = () {
-      var data = "GET / HTTP/1.1\r\nContent-Length: 0\r\n\r\n".charCodes;
-      socket.writeList(data, 0, data.length);
-      socket.close();
-      if (++count < 10) {
-        makeRequest();
-      } else {
-        server.close();
-      }
-    };
-  };
-
-  makeRequest();
+    var count = 0;
+    makeRequest() {
+      Socket.connect("127.0.0.1", server.port).then((socket) {
+        var data = "GET / HTTP/1.1\r\nContent-Length: 0\r\n\r\n".charCodes;
+        socket.add(data);
+        socket.close();
+        socket.done.then((_) {
+          socket.destroy();
+          if (++count < 10) {
+            makeRequest();
+          } else {
+            server.close();
+          }
+        });
+      });
+    }
+    makeRequest();
+  });
 }
 
 void main() {
   testEarlyClose1();
-  testEarlyClose2();
+//  testEarlyClose2();
 }
diff --git a/tests/standalone/io/http_server_early_server_close_test.dart b/tests/standalone/io/http_server_early_server_close_test.dart
index 7609257..79f1254 100644
--- a/tests/standalone/io/http_server_early_server_close_test.dart
+++ b/tests/standalone/io/http_server_early_server_close_test.dart
@@ -7,39 +7,38 @@
 import "dart:isolate";
 
 class Server {
-  Server() {
-    HttpServer server = new HttpServer();
-    server.listen("127.0.0.1", 0);
-    port = server.port;
-    server.defaultRequestHandler =
-        (HttpRequest request, HttpResponse response) {
-          Timer.run(server.close);
-        };
-    server.onError = (e) {
-      Expect.fail("No server errors expected: $e");
-    };
+  static Future<int> start() {
+    return HttpServer.bind("127.0.0.1", 0).then((server) {
+      server.listen((HttpRequest request) {
+            Timer.run(server.close);
+          }, onError: (e) {
+            Expect.fail("No server errors expected: $e");
+          });
+      return server.port;
+    });
   }
-  int port;
 }
 
 class Client {
   Client(int port) {
     ReceivePort r = new ReceivePort();
     HttpClient client = new HttpClient();
-    HttpClientConnection c = client.get("127.0.0.1", port, "/");
-    c.onRequest = (HttpClientRequest request) {
-      request.outputStream.close();
-    };
-    c.onResponse = (HttpClientResponse response) {
-      Expect.fail("Response should not be given, as not data was returned.");
-    };
-    c.onError = (e) {
-      r.close();
-    };
+    client.get("127.0.0.1", port, "/")
+        .then((HttpClientRequest request) {
+          return request.close();
+        })
+        .then((HttpClientResponse response) {
+          Expect.fail(
+              "Response should not be given, as not data was returned.");
+        })
+        .catchError((e) {
+          r.close();
+        });
   }
 }
 
 main() {
-  Server server = new Server();
-  new Client(server.port);
+  Server.start().then((port) {
+    new Client(port);
+  });
 }
diff --git a/tests/standalone/io/http_server_handler_test.dart b/tests/standalone/io/http_server_handler_test.dart
deleted file mode 100644
index 62d77ed..0000000
--- a/tests/standalone/io/http_server_handler_test.dart
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-//
-
-import 'dart:io';
-import 'dart:isolate';
-
-class Handler1 {
-  void onRequest(HttpRequest request, HttpResponse response) {
-    response.outputStream.writeString("Handler 1");
-    response.outputStream.close();
-  }
-}
-
-class Handler2 {
-  void onRequest(HttpRequest request, HttpResponse response) {
-    response.outputStream.writeString("Handler 2");
-    response.outputStream.close();
-  }
-}
-
-class French404Handler {
-  void onRequest(HttpRequest request, HttpResponse response) {
-    response.statusCode = HttpStatus.NOT_FOUND;
-    response.reasonPhrase = "Non Trouvé";
-    response.outputStream.close();
-  }
-}
-
-class Server {
-  Server() {
-    server = new HttpServer();
-    server.listen("127.0.0.1", 0);
-    port = server.port;
-    server.onError = (e) {
-      Expect.fail("No server errors expected: $e");
-    };
-  }
-
-  void addHandler(Function matcher, handler) {
-    if (handler is Function) {
-      server.addRequestHandler(matcher, handler);
-    } else {
-      server.addRequestHandler(matcher, handler.onRequest);
-    }
-  }
-
-  void set defaultHandler(handler) {
-    if (handler is Function) {
-      server.defaultRequestHandler = handler;
-    } else {
-      server.defaultRequestHandler = handler.onRequest;
-    }
-  }
-
-  void close() {
-    server.close();
-  }
-
-  int port;
-  HttpServer server;
-}
-
-void testDefaultHandler() {
-  Server server = new Server();
-  HttpClient client = new HttpClient();
-
-  void done() {
-    server.close();
-    client.shutdown();
-  }
-
-  void error(e) {
-    Expect.fail("No client error expected $e");
-    done();
-  };
-
-  void german404(HttpRequest request, HttpResponse response) {
-    response.statusCode = HttpStatus.NOT_FOUND;
-    response.reasonPhrase = "Nicht Gefunden";
-    response.outputStream.close();
-  }
-
-  // Test the standard default handler.
-  HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-  conn.onResponse = (HttpClientResponse response) {
-    Expect.equals(HttpStatus.NOT_FOUND, response.statusCode);
-    Expect.equals("Not Found", response.reasonPhrase);
-
-    // Install a default handler.
-    server.defaultHandler = german404;
-    HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(HttpStatus.NOT_FOUND, response.statusCode);
-      Expect.equals("Nicht Gefunden", response.reasonPhrase);
-
-      // Install another default handler.
-      server.defaultHandler = new French404Handler();
-      HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-      conn.onResponse = (HttpClientResponse response) {
-        Expect.equals(HttpStatus.NOT_FOUND, response.statusCode);
-        Expect.equals("Non Trouvé", response.reasonPhrase);
-        response.inputStream.onClosed = done;
-      };
-      conn.onError = error;
-    };
-    conn.onError = error;
-  };
-  conn.onError = error;
-}
-
-void testHandlers() {
-  Server server = new Server();
-  HttpClient client = new HttpClient();
-  int requests = 0;
-  int doneCount = 0;
-
-  void done() {
-    doneCount++;
-    if (doneCount == requests) {
-      server.close();
-      client.shutdown();
-    }
-  }
-
-  void error(e) {
-    Expect.fail("No client error expected $e");
-    done();
-  };
-
-  void handler3(HttpRequest request, HttpResponse response) {
-    response.statusCode = HttpStatus.OK;
-    response.outputStream.writeString("Handler 3");
-    response.outputStream.close();
-  }
-
-  void handler4(HttpRequest request, HttpResponse response) {
-    response.statusCode = HttpStatus.OK;
-    response.outputStream.writeString("Handler 4");
-    response.outputStream.close();
-  }
-
-  void checkBody(HttpClientResponse response, String expected) {
-    StringBuffer sb = new StringBuffer();
-    StringInputStream stream = new StringInputStream(response.inputStream);
-    stream.onData = () {
-      sb.add(stream.read());
-    };
-    stream.onClosed = () {
-      Expect.equals(expected, sb.toString());
-      done();
-    };
-  }
-
-  server.addHandler(
-      (request) => request.path.startsWith("/xxx/yyy/"), new Handler1());
-  server.addHandler(
-      (request) => new RegExp("^/xxx").hasMatch(request.path), new Handler2());
-  server.addHandler(
-      (request) => request.path == "/yyy.dat", handler3);
-  server.addHandler(
-      (request) => request.path.endsWith(".dat"), handler4);
-
-  void testRequest(String path, int expectedStatus, String expectedBody) {
-    HttpClientConnection conn =
-        client.get("127.0.0.1", server.port, path);
-    requests++;
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.equals(expectedStatus, response.statusCode);
-      checkBody(response, expectedBody);
-    };
-    conn.onError = error;
-  }
-
-  testRequest("/xxx/yyy/zzz", HttpStatus.OK, "Handler 1");
-  testRequest("/xxx/zzz", HttpStatus.OK, "Handler 2");
-  testRequest("/yyy.dat", HttpStatus.OK, "Handler 3");
-  testRequest("/abc.dat", HttpStatus.OK, "Handler 4");
-  testRequest("/abcdat", HttpStatus.NOT_FOUND, "");
-  testRequest("/xxx.dat", HttpStatus.OK, "Handler 2");
-}
-
-main() {
-  testDefaultHandler();
-  testHandlers();
-}
diff --git a/tests/standalone/io/http_server_response_test.dart b/tests/standalone/io/http_server_response_test.dart
new file mode 100644
index 0000000..674c901
--- /dev/null
+++ b/tests/standalone/io/http_server_response_test.dart
@@ -0,0 +1,100 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:io";
+import "dart:scalarlist";
+
+void testServerRequest(void handler(server, request)) {
+  HttpServer.bind().then((server) {
+    server.listen((request) {
+      handler(server, request);
+    });
+
+    var client = new HttpClient();
+    // We only close the client on either
+    // - Bad response headers
+    // - Response done (with optional errors in between).
+    client.get("127.0.0.1", server.port, "/")
+      .then((request) => request.close())
+      .then((response) {
+        response.listen((_) {}, onDone: () {
+          client.close();
+        }, onError: (error) {
+          Expect.isTrue(error.error is HttpParserException);
+        });
+      })
+      .catchError((error) {
+         client.close();
+      }, test: (e) => e is HttpParserException);
+  });
+}
+
+void testResponseDone() {
+  testServerRequest((server, request) {
+    request.response.close();
+    request.response.done.then((response) {
+      Expect.equals(request.response, response);
+      server.close();
+    });
+  });
+}
+
+void testBadResponseAdd() {
+  testServerRequest((server, request) {
+    request.response.contentLength = 0;
+    request.response.add([0]);
+    request.response.done.catchError((error) {
+      server.close();
+    }, test: (e) => e is HttpException);
+  });
+
+  testServerRequest((server, request) {
+    request.response.contentLength = 5;
+    request.response.add([0, 0, 0]);
+    request.response.add([0, 0, 0]);
+    request.response.done.catchError((error) {
+      server.close();
+    }, test: (e) => e is HttpException);
+  });
+
+  testServerRequest((server, request) {
+    request.response.contentLength = 0;
+    request.response.add(new Uint8List(64 * 1024));
+    request.response.add(new Uint8List(64 * 1024));
+    request.response.add(new Uint8List(64 * 1024));
+    request.response.done.catchError((error) {
+      server.close();
+    }, test: (e) => e is HttpException);
+  });
+}
+
+void testBadResponseClose() {
+  testServerRequest((server, request) {
+    request.response.contentLength = 5;
+    request.response.close();
+    request.response.done.catchError((error) {
+      server.close();
+    }, test: (e) => e is HttpException);
+  });
+
+  testServerRequest((server, request) {
+    request.response.contentLength = 5;
+    request.response.add([0]);
+    request.response.close();
+    request.response.done.catchError((error) {
+      server.close();
+    }, test: (e) => e is HttpException);
+  });
+}
+
+void main() {
+  testResponseDone();
+  testBadResponseAdd();
+  testBadResponseClose();
+}
diff --git a/tests/standalone/io/http_server_socket_test.dart b/tests/standalone/io/http_server_socket_test.dart
deleted file mode 100644
index 13b92d8..0000000
--- a/tests/standalone/io/http_server_socket_test.dart
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-import "dart:isolate";
-import "dart:math";
-
-class ExpectedDataOutputStream implements OutputStream {
-  ExpectedDataOutputStream(List<int> this._data,
-                           int this._cutoff,
-                           bool this._closeAsError,
-                           SocketMock this._socket);
-
-  void set onNoPendingWrites(void callback()) {
-    _onNoPendingWrites = callback;
-  }
-
-  void set onClosed(void callback()) {
-    // Not used in test.
-  }
-
-  void set onError(void callback(e)) {
-    _onError = callback;
-  }
-
-  bool write(List data, [bool copyBuffer = true]) {
-    _onData(data);
-    return true;
-  }
-
-  bool writeFrom(List data, [int offset = 0, int len]) {
-    if (len == null) len = data.length - offset;
-    _onData(data.getRange(offset, len));
-    return true;
-  }
-
-  void close() {
-    _socket.close(true);
-  }
-
-  void _onData(List<int> data) {
-    // TODO(ajohnsen): To be removed, since the socket should not be written to
-    //                 after close.
-    if (_socket._closed) return;
-    Expect.isFalse(_written > _cutoff);
-    Expect.listEquals(data, _data.getRange(0, data.length));
-    _data = _data.getRange(data.length, _data.length - data.length);
-    _written += data.length;
-    if (_written >= _cutoff) {
-      // Tell HttpServer that the socket have closed.
-      _socket._closeInternal(_closeAsError);
-    }
-  }
-
-  Function _onNoPendingWrites;
-  Function _onError;
-  List<int> _data;
-  int _written = 0;
-  int _cutoff;
-  bool _closeAsError;
-  SocketMock _socket;
-}
-
-class SocketMock implements Socket {
-  SocketMock(List<int> this._data,
-             List<int> expected,
-             int cutoff,
-             bool closeAsError) :
-      _hashCode = new Random().nextInt(1<< 32),
-      _read = [] {
-    _outputStream =
-        new ExpectedDataOutputStream(expected, cutoff, closeAsError, this);
-  }
-
-  int available() {
-    return _data.length;
-  }
-
-  void _closeInternal([bool asError = false]) {
-    Expect.isFalse(_closed);
-    _closed = true;
-    _onClosedInternal();
-    if (asError) {
-      _onError(new Exception("Socket closed unexpected"));
-    } else {
-      _onClosed();
-    }
-  }
-
-  List<int> read([int len]) {
-    var result;
-    if (len == null) {
-      result = _data;
-      _data = [];
-    } else {
-      result = new Uint8List(len);
-      readList(result, 0, len);
-    }
-    return result;
-  }
-
-  int readList(List<int> buffer, int offset, int count) {
-    int max = min(count, _data.length);
-    buffer.setRange(offset, max, _data);
-    _data = _data.getRange(max, _data.length - max);
-    return max;
-  }
-
-  void close([bool halfClose = false]) {
-    if (!halfClose && !_closed) _closeInternal();
-  }
-
-  void set onData(void callback()) {
-    _onData = callback;
-  }
-
-  void set onClosed(void callback()) {
-    _onClosed = callback;
-  }
-
-  void set onError(void callback(e)) {
-    _onError = callback;
-  }
-
-  OutputStream get outputStream => _outputStream;
-
-  int get hashCode => _hashCode;
-
-  List<int> _read;
-  bool _closed = false;
-  int _hashCode;
-  Function _onData;
-  Function _onClosed;
-  Function _onError;
-  Function _onClosedInternal;
-  List<int> _data;
-  ExpectedDataOutputStream _outputStream;
-}
-
-class ServerSocketMock implements ServerSocket {
-  ServerSocketMock(String addr, int this._port, int backlog) :
-      _sockets = new Set<Socket>();
-
-  void spawnSocket(var data, String response, int cutOff, bool closeAsError) {
-    if (data is String) data = data.charCodes;
-    SocketMock socket = new SocketMock(data,
-                                       response.charCodes,
-                                       cutOff,
-                                       closeAsError);
-    _sockets.add(socket);
-    ReceivePort port = new ReceivePort();
-    socket._onClosedInternal = () {
-      // The server should always close the connection.
-      _sockets.remove(socket);
-      port.close();
-    };
-    // Tell HttpServer that a connection have come to life.
-    _onConnection(socket);
-    // Start 'sending' data.
-    socket._onData();
-  }
-
-  void close() {
-    Expect.fail("Don't close the connection, we attach to this socket");
-  }
-
-  void set onConnection(void callback(Socket connection)) {
-    _onConnection = callback;
-  }
-
-  void set onError(void callback(e)) {
-    _onError = callback;
-  }
-
-  int get port => _port;
-
-  int _port;
-  Function _onConnection;
-  Function _onError;
-  Set<Socket> _sockets;
-}
-
-void testSocketClose() {
-  ServerSocketMock serverSocket = new ServerSocketMock("0.0.0.0", 5432, 5);
-
-  HttpServer server = new HttpServer();
-  server.listenOn(serverSocket);
-  void testContent(String requestString,
-                   String responseString,
-                   [int okayFrom = 0,
-                    bool expectError = true]) {
-    // Inner callback to actually run a given setting.
-    void runSettings(int cutoff,
-                     bool closeAsError,
-                     bool expectError) {
-      server.defaultRequestHandler =
-          (HttpRequest request, HttpResponse response) {
-            request.inputStream.onData = () {
-            };
-            request.inputStream.onClosed = () {
-              response.outputStream.close();
-            };
-          };
-
-      if (expectError) {
-        ReceivePort port = new ReceivePort();
-        server.onError = (var error) {
-          port.close();
-        };
-      } else {
-        server.onError = (var error) {
-          Expect.fail("An error was not expected: $error");
-        };
-      }
-
-      serverSocket.spawnSocket(requestString, responseString,
-                               cutoff, closeAsError);
-      // TODO(ajohnsen): Validate HttpServers number of connections.
-    }
-    for (int i = 1; i < responseString.length; i++) {
-      bool _expectError = expectError && i < responseString.length - okayFrom;
-      runSettings(i, false, _expectError);
-      runSettings(i, true, _expectError);
-    }
-  }
-  testContent(
-      "GET / HTTP/1.1\r\nKeep-Alive: False\r\n\r\n",
-      "HTTP/1.1 200 OK\r\ntransfer-encoding: chunked\r\nconnection: close"
-      "\r\n\r\n0\r\n\r\n");
-
-  server.close();
-}
-
-void main() {
-  testSocketClose();
-}
diff --git a/tests/standalone/io/http_server_test.dart b/tests/standalone/io/http_server_test.dart
index 8e7424e..dd6eeac 100644
--- a/tests/standalone/io/http_server_test.dart
+++ b/tests/standalone/io/http_server_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -6,56 +6,53 @@
 import "dart:isolate";
 
 void testListenOn() {
-  ServerSocket socket = new ServerSocket("127.0.0.1", 0, 5);
-
-  socket.onError = (Exception e) {
-    Expect.fail("ServerSocket closed unexpected");
-  };
+  ServerSocket socket;
+  HttpServer server;
 
   void test(void onDone()) {
-    HttpServer server = new HttpServer();
-    Expect.throws(() => server.port);
 
-    ReceivePort serverPort = new ReceivePort();
-    server.defaultRequestHandler =
-        (HttpRequest request, HttpResponse response) {
-          request.inputStream.onClosed = () {
-            response.outputStream.close();
-            serverPort.close();
-          };
-        };
-
-    server.onError = (Exception e) {
-      Expect.fail("Unexpected error in Http Server: $e");
-    };
-
-    server.listenOn(socket);
     Expect.equals(socket.port, server.port);
 
-    HttpClient client = new HttpClient();
-    HttpClientConnection conn = client.get("127.0.0.1", socket.port, "/");
-    conn.onRequest = (HttpClientRequest request) {
-      request.outputStream.close();
-    };
     ReceivePort clientPort = new ReceivePort();
-    conn.onResponse = (HttpClientResponse response) {
-      response.inputStream.onClosed = () {
-        client.shutdown();
-        clientPort.close();
-        server.close();
-        Expect.throws(() => server.port);
-        onDone();
-      };
-    };
-    conn.onError = (Exception e) {
-      Expect.fail("Unexpected error in Http Client: $e");
-    };
-  };
+    HttpClient client = new HttpClient();
+    client.get("127.0.0.1", socket.port, "/")
+      .then((request) {
+        return request.close();
+      })
+      .then((response) {
+        response.listen(
+          (_) {},
+          onDone: () {
+            client.close();
+            clientPort.close();
+            onDone();
+          });
+      })
+      .catchError((error) {
+        Expect.fail("Unexpected error in Http Client: $error");
+      });
+  }
 
   // Test two connection after each other.
-  test(() {
+  ServerSocket.bind().then((s) {
+    socket = s;
+    server = new HttpServer.listenOn(socket);
+    ReceivePort serverPort = new ReceivePort();
+    server.listen((HttpRequest request) {
+      request.listen(
+        (_) {},
+        onDone: () {
+          request.response.close();
+          serverPort.close();
+        });
+    });
+
     test(() {
-      socket.close();
+      test(() {
+        server.close();
+        Expect.throws(() => server.port);
+        socket.close();
+      });
     });
   });
 }
diff --git a/tests/standalone/io/http_session_test.dart b/tests/standalone/io/http_session_test.dart
index 796408f..69f6a6b 100644
--- a/tests/standalone/io/http_session_test.dart
+++ b/tests/standalone/io/http_session_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -20,89 +20,137 @@
   return id;
 }
 
-Future<String> connectGetSession(int port, [String session]) {
-  var c = new Completer();
-  var client = new HttpClient();
-  var conn = client.get("127.0.0.1", port, "/");
-  conn.onRequest = (request) {
-    if (session != null) {
-      request.cookies.add(new Cookie(SESSION_ID, session));
-    }
-    request.outputStream.close();
-  };
-  conn.onResponse = (response) {
-    response.inputStream.onData = response.inputStream.read;
-    response.inputStream.onClosed = () {
-      client.shutdown();
-      c.complete(getSessionId(response.cookies));
-    };
-  };
-  return c.future;
+Future<String> connectGetSession(
+    HttpClient client, int port, [String session]) {
+  return client.get("127.0.0.1", port, "/")
+    .then((request) {
+      if (session != null) {
+        request.cookies.add(new Cookie(SESSION_ID, session));
+      }
+      return request.close();
+    })
+    .then((response) {
+      return response.reduce(getSessionId(response.cookies), (v, _) => v);
+    });
 }
 
 void testSessions(int sessionCount) {
-  HttpServer server = new HttpServer();
-  server.listen("127.0.0.1", 0);
-  var sessions = new Set();
-  server.defaultRequestHandler = (request, response) {
-    sessions.add(request.session().id);
-    response.outputStream.close();
-  };
+  var client = new HttpClient();
+  HttpServer.bind().then((server) {
+    var sessions = new Set();
+    server.listen((request) {
+      sessions.add(request.session.id);
+      request.response.close();
+    });
 
-  var futures = [];
-  for (int i = 0; i < sessionCount; i++) {
-    futures.add(connectGetSession(server.port).then((session) {
-      Expect.isNotNull(session);
-      Expect.isTrue(sessions.contains(session));
-      return connectGetSession(server.port, session).then((session2) {
-        Expect.equals(session2, session);
-        Expect.isTrue(sessions.contains(session2));
-        return session2;
+    var futures = [];
+    for (int i = 0; i < sessionCount; i++) {
+      futures.add(connectGetSession(client, server.port).then((session) {
+        Expect.isNotNull(session);
+        Expect.isTrue(sessions.contains(session));
+        return connectGetSession(client, server.port, session).then((session2) {
+          Expect.equals(session2, session);
+          Expect.isTrue(sessions.contains(session2));
+          return session2;
         });
-    }));
-  }
-  Future.wait(futures).then((clientSessions) {
-    Expect.equals(sessions.length, sessionCount);
-    Expect.setEquals(new Set.from(clientSessions), sessions);
-    server.close();
+      }));
+    }
+    Future.wait(futures).then((clientSessions) {
+      Expect.equals(sessions.length, sessionCount);
+      Expect.setEquals(new Set.from(clientSessions), sessions);
+      server.close();
+      client.close();
+    });
   });
 }
 
 void testTimeout(int sessionCount) {
-  HttpServer server = new HttpServer();
-  server.sessionTimeout = 0;
-  server.listen("127.0.0.1", 0);
-  var timeouts = [];
-  server.defaultRequestHandler = (request, response) {
-    var c = new Completer();
-    timeouts.add(c.future);
-    request.session().onTimeout = () {
-      c.complete(null);
-    };
-    response.outputStream.close();
-  };
+  var client = new HttpClient();
+  HttpServer.bind().then((server) {
+    server.sessionTimeout = 0;
+    var timeouts = [];
+    server.listen((request) {
+      var c = new Completer();
+      timeouts.add(c.future);
+      request.session.onTimeout = () {
+        c.complete(null);
+      };
+      request.response.close();
+    });
 
-  var futures = [];
-  for (int i = 0; i < sessionCount; i++) {
-    futures.add(connectGetSession(server.port));
-  }
-  Future.wait(futures).then((clientSessions) {
-    Future.wait(timeouts).then((_) {
-      futures = [];
-      for (var id in clientSessions) {
-        futures.add(connectGetSession(server.port, id).then((session) {
-          Expect.isNotNull(session);
-          Expect.notEquals(id, session);
-        }));
-      }
-      Future.wait(futures).then((_) {
-        server.close();
+    var futures = [];
+    for (int i = 0; i < sessionCount; i++) {
+      futures.add(connectGetSession(client, server.port));
+    }
+    Future.wait(futures).then((clientSessions) {
+      Future.wait(timeouts).then((_) {
+        futures = [];
+        for (var id in clientSessions) {
+          futures.add(connectGetSession(
+              client, server.port, id).then((session) {
+            Expect.isNotNull(session);
+            Expect.notEquals(id, session);
+          }));
+        }
+        Future.wait(futures).then((_) {
+          server.close();
+          client.close();
+        });
       });
     });
   });
 }
 
+void testSessionsData() {
+  HttpServer.bind().then((server) {
+    bool firstHit = false;
+    bool secondHit = false;
+    server.listen((request) {
+      var c = new Completer();
+      var session = request.session;
+      if (session.isNew) {
+        Expect.isFalse(firstHit);
+        Expect.isFalse(secondHit);
+        firstHit = true;
+        session["data"] = "some data";
+      } else {
+        Expect.isTrue(firstHit);
+        Expect.isFalse(secondHit);
+        secondHit = true;
+        Expect.isTrue(session.containsKey("data"));
+        Expect.equals("some data", session["data"]);
+      };
+      request.response.close();
+    });
+
+    var client = new HttpClient();
+    client.get("127.0.0.1", server.port, "/")
+      .then((request) => request.close())
+      .then((response) {
+        response.listen((_) {}, onDone: () {
+          var id = getSessionId(response.cookies);
+          Expect.isNotNull(id);
+          client.get("127.0.0.1", server.port, "/")
+            .then((request) {
+              request.cookies.add(new Cookie(SESSION_ID, id));
+              return request.close();
+            })
+            .then((response) {
+              response.listen((_) {}, onDone: () {
+                Expect.isTrue(firstHit);
+                Expect.isTrue(secondHit);
+                Expect.equals(id, getSessionId(response.cookies));
+                server.close();
+                client.close();
+              });
+            });
+        });
+      });
+  });
+}
+
 void main() {
-  testSessions(5);
+  testSessions(1);
   testTimeout(5);
+  testSessionsData();
 }
diff --git a/tests/standalone/io/http_shutdown_test.dart b/tests/standalone/io/http_shutdown_test.dart
index c296be5..c7bcc16 100644
--- a/tests/standalone/io/http_shutdown_test.dart
+++ b/tests/standalone/io/http_shutdown_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
@@ -8,167 +8,179 @@
 
 void test1(int totalConnections) {
   // Server which just closes immediately.
-  HttpServer server = new HttpServer();
-  server.listen("127.0.0.1", 0, backlog: totalConnections);
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    response.outputStream.close();
-  };
+  HttpServer.bind().then((server) {
+    server.listen((HttpRequest request) {
+      request.response.close();
+    });
 
-  int count = 0;
-  HttpClient client = new HttpClient();
-  for (int i = 0; i < totalConnections; i++) {
-    HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-    conn.onRequest = (HttpClientRequest request) {
-      request.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      response.inputStream.onClosed = () {
-        count++;
-        if (count == totalConnections) {
-          client.shutdown();
-          server.close();
-        }
-      };
-    };
-  }
+    int count = 0;
+    HttpClient client = new HttpClient();
+    for (int i = 0; i < totalConnections; i++) {
+      client.get("127.0.0.1", server.port, "/")
+        .then((HttpClientRequest request) => request.close())
+        .then((HttpClientResponse response) {
+          response.listen((_) {}, onDone: () {
+            count++;
+            if (count == totalConnections) {
+              client.close();
+              server.close();
+            }
+          });
+        });
+    }
+  });
 }
 
 
 void test2(int totalConnections, int outputStreamWrites) {
   // Server which responds without waiting for request body.
-  HttpServer server = new HttpServer();
-  server.listen("127.0.0.1", 0, backlog: totalConnections);
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    response.outputStream.writeString("!dlrow ,olleH");
-    response.outputStream.close();
-  };
+  HttpServer.bind().then((server) {
+    server.listen((HttpRequest request) {
+      request.response.addString("!dlrow ,olleH");
+      request.response.close();
+    });
 
-  int count = 0;
-  HttpClient client = new HttpClient();
-  for (int i = 0; i < totalConnections; i++) {
-    HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-    conn.onRequest = (HttpClientRequest request) {
-      request.contentLength = -1;
-      for (int i = 0; i < outputStreamWrites; i++)
-        request.outputStream.writeString("Hello, world!");
-      request.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () {
-        count++;
-        if (count == totalConnections) {
-          client.shutdown();
-          server.close();
-        }
-      };
-    };
-    conn.onError = (e) {
-      count++;
-      if (count == totalConnections) {
-        client.shutdown();
-        server.close();
-      }
-    };
-  }
+    int count = 0;
+    HttpClient client = new HttpClient();
+    for (int i = 0; i < totalConnections; i++) {
+      client.get("127.0.0.1", server.port, "/")
+        .then((HttpClientRequest request) {
+          request.contentLength = -1;
+          for (int i = 0; i < outputStreamWrites; i++) {
+            request.addString("Hello, world!");
+          }
+          return request.close();
+        })
+        .then((HttpClientResponse response) {
+          response.listen(
+            (_) {},
+            onDone: () {
+              count++;
+              if (count == totalConnections) {
+                client.close(force: true);
+                server.close();
+              }
+            },
+            onError: (e) {} /* ignore */);
+        })
+        .catchError((error) {
+          count++;
+          if (count == totalConnections) {
+            client.close();
+            server.close();
+          }
+        });
+    }
+  });
 }
 
 
 void test3(int totalConnections) {
   // Server which responds when request body has been received.
-  HttpServer server = new HttpServer();
-  server.listen("127.0.0.1", 0, backlog: totalConnections);
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    request.inputStream.onData = () {
-      request.inputStream.read();
-    };
-    request.inputStream.onClosed = () {
-      response.outputStream.writeString("!dlrow ,olleH");
-      response.outputStream.close();
-    };
-  };
+  HttpServer.bind().then((server) {
+
+  server.listen((HttpRequest request) {
+    request.listen((_) {}, onDone: () {
+      request.response.addString("!dlrow ,olleH");
+      request.response.close();
+    });
+  });
 
   int count = 0;
   HttpClient client = new HttpClient();
   for (int i = 0; i < totalConnections; i++) {
-    HttpClientConnection conn = client.get("127.0.0.1", server.port, "/");
-    conn.onRequest = (HttpClientRequest request) {
-      request.contentLength = -1;
-      request.outputStream.writeString("Hello, world!");
-      request.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      response.inputStream.onData = response.inputStream.read;
-      response.inputStream.onClosed = () {
-        count++;
-        if (count == totalConnections) {
-          client.shutdown();
-          server.close();
-        }
-      };
-    };
+    client.get("127.0.0.1", server.port, "/")
+      .then((HttpClientRequest request) {
+        request.contentLength = -1;
+        request.addString("Hello, world!");
+        return request.close();
+      })
+      .then((HttpClientResponse response) {
+        response.listen((_) {}, onDone: () {
+          count++;
+          if (count == totalConnections) {
+            client.close();
+            server.close();
+          }
+        });
+      });
   }
+
+  });
 }
 
 
 void test4() {
-  var server = new HttpServer();
-  server.listen("127.0.0.1", 0);
-  server.defaultRequestHandler = (var request, var response) {
-    request.inputStream.onClosed = () {
+  HttpServer.bind().then((server) {
+
+  server.listen((var request) {
+    request.listen((_) {}, onDone: () {
       new Timer.repeating(new Duration(milliseconds: 100), (timer) {
         if (server.connectionsInfo().total == 0) {
           server.close();
           timer.cancel();
         }
       });
-      response.outputStream.close();
-    };
-  };
+      request.response.close();
+    });
+  });
 
   var client= new HttpClient();
-  var conn = client.get("127.0.0.1", server.port, "/");
-  conn.onResponse = (var response) {
-    response.inputStream.onData = response.inputStream.read;
-    response.inputStream.onClosed = () {
-      client.shutdown();
-    };
-  };
+  client.get("127.0.0.1", server.port, "/")
+    .then((request) => request.close())
+    .then((response) {
+      response.listen((_) {}, onDone: () {
+        client.close();
+      });
+    });
+
+  });
 }
 
 
 void test5(int totalConnections) {
-  var server = new HttpServer();
-  server.listen("127.0.0.1", 0, backlog: totalConnections);
-  server.defaultRequestHandler = (var request, var response) {
-    request.inputStream.onClosed = () {
-      response.outputStream.close();
-    };
-  };
-  server.onError = (e) => { };
+  HttpServer.bind().then((server) {
+    server.listen(
+        (request) {
+          request.listen(
+              (_) { },
+              onDone: () {
+                request.response.close();
+              },
+              onError: (error) { });
+        },
+        onError: (error) { });
 
-  // Create a number of client requests and keep then active. Then
-  // close the client and wait for the server to lose all active
-  // connections.
-  var client= new HttpClient();
-  for (int i = 0; i < totalConnections; i++) {
-    var conn = client.post("127.0.0.1", server.port, "/");
-    conn.onRequest = (req) { req.outputStream.write([0]); };
-    conn.onError = (e) => Expect.isTrue(e is HttpException);
-  }
-  bool clientClosed = false;
-  new Timer.repeating(new Duration(milliseconds: 100), (timer) {
-    if (!clientClosed) {
-      if (server.connectionsInfo().total == totalConnections) {
-        clientClosed = true;
-        client.shutdown(force: true);
-      }
-    } else {
-      if (server.connectionsInfo().total == 0) {
-        server.close();
-        timer.cancel();
-      }
+    // Create a number of client requests and keep then active. Then
+    // close the client and wait for the server to lose all active
+    // connections.
+    var client= new HttpClient();
+    for (int i = 0; i < totalConnections; i++) {
+      client.post("127.0.0.1", server.port, "/")
+        .then((request) {
+            request.add([0]);
+            // TODO(sgjesse): Make this test work with
+            //request.response instead of request.close() return
+            //return request.response;
+            return request.close();
+          })
+        .then((response) { })
+        .catchError((e) { }, test: (e) => e is HttpParserException);
     }
+    bool clientClosed = false;
+    new Timer.repeating(new Duration(milliseconds: 100), (timer) {
+      if (!clientClosed) {
+        if (server.connectionsInfo().total == totalConnections) {
+          clientClosed = true;
+          client.close(force: true);
+        }
+      } else {
+        if (server.connectionsInfo().total == 0) {
+          server.close();
+          timer.cancel();
+        }
+      }
+    });
   });
 }
 
diff --git a/tests/standalone/io/http_stream_close_test.dart b/tests/standalone/io/http_stream_close_test.dart
index 9f444a6..6cf73d6 100644
--- a/tests/standalone/io/http_stream_close_test.dart
+++ b/tests/standalone/io/http_stream_close_test.dart
@@ -11,47 +11,46 @@
   bool clientOnClosed = false;
   bool requestOnClosed = false;
 
-  var server = new HttpServer();
-  var client = new HttpClient();
+  HttpServer.bind("127.0.0.1", 0).then((server) {
+    var client = new HttpClient();
 
-  checkDone() {
-    if (serverOnClosed && clientOnClosed && requestOnClosed) {
-      server.close();
-      client.shutdown();
+    checkDone() {
+      if (serverOnClosed && clientOnClosed && requestOnClosed) {
+        server.close();
+        client.close();
+      }
     }
-  }
 
-  server.listen("127.0.0.1", 0);
-  server.defaultRequestHandler = (request, response) {
-    request.inputStream.onData = request.inputStream.read;
-    request.inputStream.onClosed = () {
-      response.outputStream.onClosed = () {
-        serverOnClosed = true;
-        checkDone();
-      };
-      response.outputStream.writeString("hello!");
-      response.outputStream.close();
-    };
-  };
+    server.listen((request) {
+      request.listen(
+          (_) {},
+          onDone: () {
+            request.response.done.then((_) {
+              serverOnClosed = true;
+              checkDone();
+            });
+            request.response.addString("hello!");
+            request.response.close();
+          });
+      });
 
-  var connection = client.postUrl(
-      Uri.parse("http://127.0.0.1:${server.port}"));
-  connection.onError = (e) { throw e; };
-  connection.onRequest = (request) {
-    request.contentLength = "hello!".length;
-    request.outputStream.onError = (e) { throw e; };
-    request.outputStream.onClosed = () {
-      clientOnClosed = true;
-      checkDone();
-    };
-    request.outputStream.writeString("hello!");
-    request.outputStream.close();
-  };
-  connection.onResponse = (response) {
-    response.inputStream.onData = response.inputStream.read;
-    response.inputStream.onClosed = () {
-      requestOnClosed = true;
-      checkDone();
-    };
-  };
+    client.postUrl(Uri.parse("http://127.0.0.1:${server.port}"))
+        .then((request) {
+          request.contentLength = "hello!".length;
+          request.done.then((_) {
+            clientOnClosed = true;
+            checkDone();
+          });
+          request.addString("hello!");
+          return request.close();
+        })
+        .then((response) {
+          response.listen(
+              (_) {},
+              onDone: () {
+                requestOnClosed = true;
+                checkDone();
+              });
+        });
+  });
 }
diff --git a/tests/standalone/io/https_client_certificate_test.dart b/tests/standalone/io/https_client_certificate_test.dart
index 67162a5..1d9b0e4 100644
--- a/tests/standalone/io/https_client_certificate_test.dart
+++ b/tests/standalone/io/https_client_certificate_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -10,71 +10,34 @@
 const SERVER_ADDRESS = "127.0.0.1";
 const HOST_NAME = "localhost";
 
-int numClientCertificatesReceived = 0;
 
-Function test(Map options) {
-  Future runTest([var unused]) {
-    var completer = new Completer();
-    HttpsServer server = new HttpsServer();
-    Expect.throws(() => server.port);
-
-    server.defaultRequestHandler =
-        (HttpRequest request, HttpResponse response) {
-      if (request.path == '/true') {
-        // Client certificate sent
-        numClientCertificatesReceived++;
-        Expect.isNotNull(request.certificate);
-        Expect.equals('CN=localhost', request.certificate.subject);
-      } else {
-        Expect.equals('/false', request.path);
-        Expect.isNull(request.certificate);
-      }
-
-      request.inputStream.onClosed = () {
-        response.outputStream.close();
-      };
-    };
-
-    server.listen(SERVER_ADDRESS,
-                  0,
-                  backlog: 5,
-                  certificate_name: 'CN=$HOST_NAME',
-                  requestClientCertificate: true);
+Function test() {
+  var keepAlive = new ReceivePort();
+  HttpServer.bindSecure(SERVER_ADDRESS,
+                        0,
+                        backlog: 5,
+                        certificateName: 'localhost_cert',
+                        requestClientCertificate: true).then((server) {
+    server.listen((HttpRequest request) {
+      Expect.isNotNull(request.certificate);
+      Expect.equals('CN=localhost', request.certificate.subject);
+      request.response.addString("Hello");
+      request.response.close();
+    });
 
     HttpClient client = new HttpClient();
-    Future testConnect(bool sendCertificate) {
-      client.sendClientCertificate = sendCertificate;
-      client.clientCertificate = options['certificateName'];
-      var completer = new Completer();
-      HttpClientConnection conn =
-          client.getUrl(Uri.parse(
-              "https://$HOST_NAME:${server.port}/$sendCertificate"));
-      conn.onRequest = (HttpClientRequest request) {
-        request.outputStream.close();
-      };
-      conn.onResponse = (HttpClientResponse response) {
-        Expect.isNotNull(response.certificate);
-        Expect.equals('CN=myauthority', response.certificate.issuer);
-        response.inputStream.onClosed = () {
-          completer.complete(false);  // Chained call will not send cert.
-        };
-      };
-      conn.onError = (Exception e) {
-        Expect.fail("Unexpected error in Https Client: $e");
-      };
-      return completer.future;
-    }
-
-    testConnect(true).then(testConnect).then((_) {
-        client.shutdown();
-        server.close();
-        Expect.throws(() => server.port);
-        // Run second test with a certificate name.
-        completer.complete(null);
-      });
-    return completer.future;
-  }
-  return runTest;
+    client.getUrl(Uri.parse("https://$HOST_NAME:${server.port}/"))
+        .then((request) => request.close())
+        .then((response) =>
+            response.reduce(<int>[], (message, data) => message..addAll(data)))
+        .then((message) {
+          String received = new String.fromCharCodes(message);
+          Expect.equals(received, "Hello");
+          client.close();
+          server.close();
+          keepAlive.close();
+        });
+  });
 }
 
 void InitializeSSL() {
@@ -85,13 +48,6 @@
 }
 
 void main() {
-  var keepAlive = new ReceivePort();
   InitializeSSL();
-  // Test two connections in sequence.
-  test({'certificateName': null})()
-      .then((_) => test({'certificateName': 'localhost_cert'})())
-      .then((_) {
-    Expect.equals(2, numClientCertificatesReceived);
-    keepAlive.close();
-  });
+  test();
 }
diff --git a/tests/standalone/io/https_client_socket_reuse_test.dart b/tests/standalone/io/https_client_socket_reuse_test.dart
new file mode 100644
index 0000000..5b4244b
--- /dev/null
+++ b/tests/standalone/io/https_client_socket_reuse_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+import "dart:io";
+import "dart:uri";
+import "dart:isolate";
+
+// By running tests sequentially, we cover the socket reuse code in HttpClient.
+
+void testGoogleUrls() {
+  int testsStarted = 0;
+  int testsFinished = 0;
+  bool allStarted = false;
+  HttpClient client = new HttpClient();
+
+  Future testUrl(String url) {
+    testsStarted++;
+    var requestUri = Uri.parse(url);
+    return client.getUrl(requestUri)
+        .then((HttpClientRequest request) => request.close())
+        .then((HttpClientResponse response) {
+          Expect.isTrue(response.statusCode < 500);
+          if (requestUri.path.length == 0) {
+            Expect.isTrue(response.statusCode != 404);
+          }
+          return response.reduce(null, (previous, element) => null);
+        })
+        .catchError((error) => Expect.fail("Unexpected IO error: $error"));
+  }
+
+  // TODO(3593): Use a Dart HTTPS server for this test.
+  testUrl('https://www.google.dk')
+    .then((_) => testUrl('https://www.google.dk'))
+    .then((_) => testUrl('https://www.google.dk/#q=foo'))
+    .then((_) => testUrl('https://www.google.dk/#hl=da&q=foo'))
+    .then((_) { client.close(); });
+}
+
+void main() {
+  testGoogleUrls();
+}
diff --git a/tests/standalone/io/https_client_test.dart b/tests/standalone/io/https_client_test.dart
index 847249f..37b3d4f 100644
--- a/tests/standalone/io/https_client_test.dart
+++ b/tests/standalone/io/https_client_test.dart
@@ -7,50 +7,46 @@
 import "dart:isolate";
 
 
-int testGoogleUrlCount = 0;
 void testGoogleUrl() {
+  int testsStarted = 0;
+  int testsFinished = 0;
+  bool allStarted = false;
   HttpClient client = new HttpClient();
 
   void testUrl(String url) {
+    testsStarted++;
     var requestUri = Uri.parse(url);
-    var conn = client.getUrl(requestUri);
-
-    conn.onRequest = (HttpClientRequest request) {
-      request.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      testGoogleUrlCount++;
-      Expect.isTrue(response.statusCode < 500);
-      if (requestUri.path.length == 0) {
-        Expect.isTrue(response.statusCode != 404);
-      }
-      response.inputStream.onData = () {
-        response.inputStream.read();
-      };
-      response.inputStream.onClosed = () {
-        if (testGoogleUrlCount == 4) client.shutdown();
-      };
-    };
-    conn.onError = (error) => Expect.fail("Unexpected IO error $error");
+    client.getUrl(requestUri)
+        .then((HttpClientRequest request) => request.close())
+        .then((HttpClientResponse response) {
+          Expect.isTrue(response.statusCode < 500);
+          if (requestUri.path.length == 0) {
+            Expect.isTrue(response.statusCode != 404);
+          }
+          response.listen((data) { }, onDone: () {
+            if (++testsFinished == testsStarted && allStarted) client.close();
+          });
+        })
+        .catchError((error) => Expect.fail("Unexpected IO error: $error"));
   }
 
   testUrl('https://www.google.dk');
   testUrl('https://www.google.dk');
   testUrl('https://www.google.dk/#q=foo');
   testUrl('https://www.google.dk/#hl=da&q=foo');
+  allStarted = true;
 }
 
 void testBadHostName() {
   HttpClient client = new HttpClient();
-  HttpClientConnection connection = client.getUrl(
-      Uri.parse("https://some.bad.host.name.7654321/"));
-  connection.onRequest = (HttpClientRequest request) {
-    Expect.fail("Should not open a request on bad hostname");
-  };
   ReceivePort port = new ReceivePort();
-  connection.onError = (Exception error) {
-    port.close();  // We expect onError to be called, due to bad host name.
-  };
+  client.getUrl(Uri.parse("https://some.bad.host.name.7654321/"))
+      .then((HttpClientRequest request) {
+        Expect.fail("Should not open a request on bad hostname");
+      })
+      .catchError((error) {
+        port.close();  // Should throw an error on bad hostname.
+      });
 }
 
 void InitializeSSL() {
diff --git a/tests/standalone/io/https_server_test.dart b/tests/standalone/io/https_server_test.dart
index 1da8854..e4e86e8 100644
--- a/tests/standalone/io/https_server_test.dart
+++ b/tests/standalone/io/https_server_test.dart
@@ -11,52 +11,46 @@
 
 void testListenOn() {
   void test(void onDone()) {
-    HttpsServer server = new HttpsServer();
-    Expect.throws(() => server.port);
-
-    ReceivePort serverPort = new ReceivePort();
-    server.defaultRequestHandler =
-        (HttpRequest request, HttpResponse response) {
-          request.inputStream.onClosed = () {
-            response.outputStream.close();
+    HttpServer.bindSecure(SERVER_ADDRESS,
+                          0,
+                          backlog: 5,
+                          certificateName: 'localhost_cert').then((server) {
+      ReceivePort serverPort = new ReceivePort();
+      server.listen((HttpRequest request) {
+        request.listen(
+          (_) { },
+          onDone: () {
+            request.response.close();
             serverPort.close();
-          };
-        };
+          });
+      });
 
-    server.onError = (Exception e) {
-      Expect.fail("Unexpected error in Https Server: $e");
-    };
-
-    server.listen(SERVER_ADDRESS,
-                  0,
-                  backlog: 5,
-                  certificate_name: 'CN=$HOST_NAME');
-
-    HttpClient client = new HttpClient();
-    HttpClientConnection conn =
-        client.getUrl(Uri.parse("https://$HOST_NAME:${server.port}/"));
-    conn.onRequest = (HttpClientRequest request) {
-      request.outputStream.close();
-    };
-    ReceivePort clientPort = new ReceivePort();
-    conn.onResponse = (HttpClientResponse response) {
-      response.inputStream.onClosed = () {
-        client.shutdown();
-        clientPort.close();
-        server.close();
-        Expect.throws(() => server.port);
-        onDone();
-      };
-    };
-    conn.onError = (Exception e) {
-      Expect.fail("Unexpected error in Https Client: $e");
-    };
-  };
-
-  // Test two connection after each other.
-  test(() {
-    test(() {
+      HttpClient client = new HttpClient();
+      ReceivePort clientPort = new ReceivePort();
+      client.getUrl(Uri.parse("https://$HOST_NAME:${server.port}/"))
+        .then((HttpClientRequest request) {
+          return request.close();
+        })
+        .then((HttpClientResponse response) {
+            response.listen(
+              (_) { },
+              onDone: () {
+                client.close();
+                clientPort.close();
+                server.close();
+                Expect.throws(() => server.port);
+                onDone();
+              });
+        })
+        .catchError((error) {
+          Expect.fail("Unexpected error in Https client: $error");
+        });
     });
+  }
+
+  // Test two servers in succession.
+  test(() {
+    test(() { });
   });
 }
 
diff --git a/tests/standalone/io/list_input_stream_test.dart b/tests/standalone/io/list_input_stream_test.dart
deleted file mode 100644
index cebf50d..0000000
--- a/tests/standalone/io/list_input_stream_test.dart
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-import "dart:isolate";
-
-void testEmptyListInputStream() {
-  ListInputStream stream = new ListInputStream();
-  stream.write([]);
-  stream.markEndOfStream();
-  ReceivePort donePort = new ReceivePort();
-
-  void onData() {
-    throw "No data expected";
-  }
-
-  void onClosed() {
-    donePort.toSendPort().send(null);
-  }
-
-  stream.onData = onData;
-  stream.onClosed = onClosed;
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testEmptyDynamicListInputStream() {
-  ListInputStream stream = new ListInputStream();
-  ReceivePort donePort = new ReceivePort();
-
-  void onData() {
-    throw "No data expected";
-  }
-
-  void onClosed() {
-    donePort.toSendPort().send(null);
-  }
-
-  stream.onData = onData;
-  stream.onClosed = onClosed;
-  stream.markEndOfStream();
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testListInputStream1() {
-  List<int> data = [0x00, 0x01, 0x10, 0x11, 0x7e, 0x7f, 0x80, 0x81, 0xfe, 0xff];
-  ListInputStream stream = new ListInputStream();
-  stream.write(data);
-  stream.markEndOfStream();
-  int count = 0;
-  ReceivePort donePort = new ReceivePort();
-
-  void onData() {
-    List<int> x = stream.read(1);
-    Expect.equals(1, x.length);
-    Expect.equals(data[count++], x[0]);
-  }
-
-  void onClosed() {
-    Expect.equals(data.length, count);
-    donePort.toSendPort().send(count);
-  }
-
-  stream.onData = onData;
-  stream.onClosed = onClosed;
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testListInputStream2() {
-  List<int> data = [0x00, 0x01, 0x10, 0x11, 0x7e, 0x7f, 0x80, 0x81, 0xfe, 0xff];
-  ListInputStream stream = new ListInputStream();
-  stream.write(data);
-  stream.markEndOfStream();
-  int count = 0;
-  ReceivePort donePort = new ReceivePort();
-
-  void onData() {
-    List<int> x = new List<int>.fixedLength(2);
-    var bytesRead = stream.readInto(x);
-    Expect.equals(2, bytesRead);
-    Expect.equals(data[count++], x[0]);
-    Expect.equals(data[count++], x[1]);
-  }
-
-  void onClosed() {
-    Expect.equals(data.length, count);
-    donePort.toSendPort().send(count);
-  }
-
-  stream.onData = onData;
-  stream.onClosed = onClosed;
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testListInputStreamPipe1() {
-  List<int> data = [0x00, 0x01, 0x10, 0x11, 0x7e, 0x7f, 0x80, 0x81, 0xfe, 0xff];
-  ListInputStream input = new ListInputStream();
-  input.write(data);
-  input.markEndOfStream();
-  ListOutputStream output = new ListOutputStream();
-  ReceivePort donePort = new ReceivePort();
-
-  void onClosed() {
-    var contents = output.read();
-    Expect.equals(data.length, contents.length);
-    donePort.toSendPort().send(null);
-  }
-
-  input.onClosed = onClosed;
-  input.pipe(output);
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testListInputStreamPipe2() {
-  List<int> data = [0x00, 0x01, 0x10, 0x11, 0x7e, 0x7f, 0x80, 0x81, 0xfe, 0xff];
-  ListOutputStream output = new ListOutputStream();
-  ReceivePort donePort = new ReceivePort();
-  int count = 0;
-
-  void onClosed() {
-    if (count < 10) {
-      ListInputStream input = new ListInputStream();
-      input.write(data);
-      input.markEndOfStream();
-      input.onClosed = onClosed;
-      if (count < 9) {
-        input.pipe(output, close: false);
-      } else {
-        input.pipe(output);
-      }
-      count++;
-    } else {
-      var contents = output.read();
-      Expect.equals(data.length * 10, contents.length);
-      donePort.toSendPort().send(null);
-    }
-  }
-
-  ListInputStream input = new ListInputStream();
-  input.write(data);
-  input.markEndOfStream();
-  input.onClosed = onClosed;
-  input.pipe(output, close: false);
-  count++;
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testListInputClose1() {
-  List<int> data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
-  ListInputStream stream = new ListInputStream();
-  stream.write(data);
-  stream.markEndOfStream();
-  ReceivePort donePort = new ReceivePort();
-
-  void onData() {
-    throw "No data expected";
-  }
-
-  void onClosed() {
-    donePort.toSendPort().send(null);
-  }
-
-  stream.onData = onData;
-  stream.onClosed = onClosed;
-  stream.close();
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testListInputClose2() {
-  List<int> data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
-  ListInputStream stream = new ListInputStream();
-  stream.write(data);
-  stream.markEndOfStream();
-  ReceivePort donePort = new ReceivePort();
-  int count = 0;
-
-  void onData() {
-    count += stream.read(2).length;
-    stream.close();
-  }
-
-  void onClosed() {
-    Expect.equals(2, count);
-    donePort.toSendPort().send(count);
-  }
-
-  stream.onData = onData;
-  stream.onClosed = onClosed;
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testDynamicListInputStream() {
-  List<int> data = [0x00, 0x01, 0x10, 0x11, 0x7e, 0x7f, 0x80, 0x81, 0xfe, 0xff];
-  ListInputStream stream = new ListInputStream();
-  int count = 0;
-  ReceivePort donePort = new ReceivePort();
-
-  void onData() {
-    List<int> x = stream.read(1);
-    Expect.equals(1, x.length);
-    x = stream.read();
-    Expect.equals(9, x.length);
-    count++;
-    if (count < 10) {
-      stream.write(data);
-    } else {
-      stream.markEndOfStream();
-    }
-  }
-
-  void onClosed() {
-    Expect.equals(data.length, count);
-    donePort.toSendPort().send(count);
-  }
-
-  stream.write(data);
-  stream.onData = onData;
-  stream.onClosed = onClosed;
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testDynamicListInputClose1() {
-  List<int> data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
-  ListInputStream stream = new ListInputStream();
-  ReceivePort donePort = new ReceivePort();
-
-  void onData() {
-    throw "No data expected";
-  }
-
-  void onClosed() {
-    donePort.toSendPort().send(null);
-  }
-
-  stream.write(data);
-  stream.onData = onData;
-  stream.onClosed = onClosed;
-  stream.close();
-  Expect.throws(() => stream.write(data), (e) => e is StreamException);
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testDynamicListInputClose2() {
-  List<int> data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
-  ListInputStream stream = new ListInputStream();
-  ReceivePort donePort = new ReceivePort();
-  int count = 0;
-
-  void onData() {
-    count += stream.read(15).length;
-    stream.close();
-    Expect.throws(() => stream.write(data), (e) => e is StreamException);
-  }
-
-  void onClosed() {
-    Expect.equals(15, count);
-    donePort.toSendPort().send(null);
-  }
-
-  stream.write(data);
-  stream.write(data);
-  stream.write(data);
-  stream.onData = onData;
-  stream.onClosed = onClosed;
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-main() {
-  testEmptyListInputStream();
-  testEmptyDynamicListInputStream();
-  testListInputStream1();
-  testListInputStream2();
-  testListInputStreamPipe1();
-  testListInputStreamPipe2();
-  testListInputClose1();
-  testListInputClose2();
-  testDynamicListInputStream();
-  testDynamicListInputClose1();
-  testDynamicListInputClose2();
-}
diff --git a/tests/standalone/io/list_output_stream_test.dart b/tests/standalone/io/list_output_stream_test.dart
deleted file mode 100644
index ad3b029..0000000
--- a/tests/standalone/io/list_output_stream_test.dart
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:io';
-import 'dart:isolate';
-
-void testEmptyListOutputStream1() {
-  ListOutputStream stream = new ListOutputStream();
-  Expect.equals(null, stream.read());
-  stream.close();
-  Expect.equals(null, stream.read());
-  Expect.throws(() { stream.write([0]); });
-}
-
-
-void testEmptyListOutputStream2() {
-  ListOutputStream stream = new ListOutputStream();
-  ReceivePort donePort = new ReceivePort();
-
-  void onNoPendingWrites() {
-    stream.close();
-  }
-
-  void onClosed() {
-    Expect.equals(null, stream.read());
-    donePort.toSendPort().send(null);
-  }
-
-  stream.onNoPendingWrites = onNoPendingWrites;
-  stream.onClosed = onClosed;
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-
-void testListOutputStream1() {
-  ListOutputStream stream = new ListOutputStream();
-  Expect.equals(null, stream.read());
-  stream.write([1, 2]);
-  stream.writeFrom([1, 2, 3, 4, 5], 2, 2);
-  stream.write([5]);
-  stream.close();
-  var contents = stream.read();
-  Expect.equals(5, contents.length);
-  for (var i = 0; i < contents.length; i++) Expect.equals(i + 1, contents[i]);
-  Expect.equals(null, stream.read());
-}
-
-
-void testListOutputStream2() {
-  ListOutputStream stream = new ListOutputStream();
-  ReceivePort donePort = new ReceivePort();
-  int stage = 0;
-  void onNoPendingWrites() {
-    switch (stage) {
-      case 0:
-        stream.write([1, 2]);
-        break;
-      case 1:
-        stream.writeFrom([1, 2, 3, 4, 5], 2, 2);
-        break;
-      case 2:
-        stream.write([5]);
-        break;
-      case 3:
-        stream.close();
-        break;
-    }
-    stage++;
-  }
-
-  void onClosed() {
-    Expect.equals(4, stage);
-    var contents = stream.read();
-    Expect.equals(5, contents.length);
-    for (var i = 0; i < contents.length; i++) Expect.equals(i + 1, contents[i]);
-    Expect.equals(null, stream.read());
-    donePort.toSendPort().send(null);
-  }
-
-  stream.onNoPendingWrites = onNoPendingWrites;
-  stream.onClosed = onClosed;
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testListOutputStream3() {
-  ListOutputStream stream = new ListOutputStream();
-  ReceivePort donePort = new ReceivePort();
-  void onNoPendingWrites() {
-    stream.writeString("abcdABCD");
-    stream.writeString("abcdABCD", Encoding.UTF_8);
-    stream.writeString("abcdABCD", Encoding.ISO_8859_1);
-    stream.writeString("abcdABCD", Encoding.ASCII);
-    stream.writeString("æøå", Encoding.UTF_8);
-    stream.close();
-  }
-
-  void onClosed() {
-    var contents = stream.read();
-    Expect.equals(38, contents.length);
-    donePort.toSendPort().send(null);
-  }
-
-  stream.onNoPendingWrites = onNoPendingWrites;
-  stream.onClosed = onClosed;
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testListOutputStream4() {
-  ListOutputStream stream = new ListOutputStream();
-  ReceivePort donePort = new ReceivePort();
-  List result = <int>[];
-
-  void onData() => result.addAll(stream.read());
-
-  void onClosed() {
-    Expect.equals(4, result.length);
-    for (var i = 0; i < result.length; i++) Expect.equals(i + 1, result[i]);
-    donePort.toSendPort().send(null);
-  }
-
-  stream.onData = onData;
-  stream.onClosed = onClosed;
-
-  Timer.run(() {
-    result.add(1);
-    stream.write([2]);
-
-    Timer.run(() {
-      result.add(3);
-      stream.write([4]);
-      stream.close();
-    });
-  });
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-void testListOutputStream5() {
-  ListOutputStream stream = new ListOutputStream();
-  ReceivePort donePort = new ReceivePort();
-
-  stream.onClosed = () {
-    Expect.isTrue(stream.closed);
-    var contents = stream.read();
-    Expect.equals(3, contents.length);
-    for (var i = 0; i < contents.length; i++) Expect.equals(i + 1, contents[i]);
-    donePort.toSendPort().send(null);
-  };
-
-  Expect.isFalse(stream.closed);
-  stream.write([1, 2, 3]);
-  Expect.isFalse(stream.closed);
-  stream.close();
-  Expect.isTrue(stream.closed);
-  Expect.throws(() => stream.write([4, 5, 6]));
-
-  donePort.receive((x,y) => donePort.close());
-}
-
-main() {
-  testEmptyListOutputStream1();
-  testEmptyListOutputStream2();
-  testListOutputStream1();
-  testListOutputStream2();
-  testListOutputStream3();
-  testListOutputStream4();
-  testListOutputStream5();
-}
diff --git a/tests/standalone/io/mime_multipart_parser_test.dart b/tests/standalone/io/mime_multipart_parser_test.dart
index 122e075..adccecb 100644
--- a/tests/standalone/io/mime_multipart_parser_test.dart
+++ b/tests/standalone/io/mime_multipart_parser_test.dart
@@ -1,11 +1,16 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:async';
 import 'dart:math';
 
+part '../../../sdk/lib/io/io_stream_consumer.dart';
+part "../../../sdk/lib/io/http.dart";
+part "../../../sdk/lib/io/http_impl.dart";
 part "../../../sdk/lib/io/http_parser.dart";
 part "../../../sdk/lib/io/mime_multipart_parser.dart";
+part '../../../sdk/lib/io/socket.dart';
 
 void testParse(String message,
                String boundary,
diff --git a/tests/standalone/io/pipe_server_test.dart b/tests/standalone/io/pipe_server_test.dart
new file mode 100644
index 0000000..2e7c0ea
--- /dev/null
+++ b/tests/standalone/io/pipe_server_test.dart
@@ -0,0 +1,123 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+library ServerTest;
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+part "testing_server.dart";
+
+
+String getDataFilename(String path) =>
+    new File(path).existsSync() ? path : '../$path';
+
+
+bool compareFileContent(String fileName1, String fileName2) {
+  var contents1 = new File(fileName1).readAsStringSync();
+  var contents2 = new File(fileName2).readAsStringSync();
+  return contents1 == contents2;
+}
+
+
+// This test does:
+//  1. Opens a socket to the testing server.
+//  2. Pipes the content of a file to that sockets input stream.
+//  3. Creates a temp file.
+//  4. Pipes the socket output stream to the temp file.
+//  5. Expects the original file and the temp file to be equal.
+class PipeServerGame {
+
+  int count = 0;
+
+  PipeServerGame.start()
+      : _receivePort = new ReceivePort(),
+        _sendPort = null,
+        _messages = 0 {
+    _sendPort = spawnFunction(startPipeServer);
+    initialize();
+  }
+
+  void runTest() {
+
+    void connectHandler() {
+      String srcFileName =
+          getDataFilename("tests/standalone/io/readline_test1.dat");
+      Stream fileInput = new File(srcFileName).openRead();
+
+      fileInput.pipe(_socket).then((_) {
+        var tempDir = new Directory('').createTempSync();
+        var dstFileName = tempDir.path.concat("/readline_test1.dat");
+        var dstFile = new File(dstFileName);
+        dstFile.createSync();
+        var fileOutput = dstFile.openWrite();
+        _socket.pipe(fileOutput).then((_) {
+          // Check that the resulting file is equal to the initial
+          // file.
+          bool result = compareFileContent(srcFileName, dstFileName);
+          new File(dstFileName).deleteSync();
+          tempDir.deleteSync();
+          Expect.isTrue(result);
+
+          // Run this twice.
+          if (count++ < 2) {
+            runTest();
+          } else {
+            shutdown();
+          }
+        });
+      });
+    }
+
+    // Connect to the server.
+    Socket.connect(TestingServer.HOST, _port).then((s) {
+      _socket = s;
+      connectHandler();
+    });
+  }
+
+  void initialize() {
+    _receivePort.receive((var message, SendPort replyTo) {
+      _port = message;
+      runTest();
+    });
+    _sendPort.send(TestingServer.INIT, _receivePort.toSendPort());
+  }
+
+  void shutdown() {
+    _sendPort.send(TestingServer.SHUTDOWN, _receivePort.toSendPort());
+    _receivePort.close();
+  }
+
+  int _port;
+  ReceivePort _receivePort;
+  SendPort _sendPort;
+  Socket _socket;
+  int _messages;
+}
+
+
+void startPipeServer() {
+  var server = new PipeServer();
+  port.receive(server.dispatch);
+}
+
+
+// The testing server will simply pipe each connecting sockets input
+// stream to its output stream.
+class PipeServer extends TestingServer {
+  void onConnection(Socket connection) {
+    connection.pipe(connection);
+  }
+}
+
+
+main() {
+  PipeServerGame echoServerGame = new PipeServerGame.start();
+}
diff --git a/tests/standalone/io/process_broken_pipe_test.dart b/tests/standalone/io/process_broken_pipe_test.dart
index 1f42789..3833158 100644
--- a/tests/standalone/io/process_broken_pipe_test.dart
+++ b/tests/standalone/io/process_broken_pipe_test.dart
@@ -5,6 +5,7 @@
 // Process test program to test closed stdin from child process.
 
 import "dart:io";
+import "dart:isolate";
 
 import "process_test_util.dart";
 
@@ -12,17 +13,18 @@
   // Running dart without arguments makes it close right away.
   var future = Process.start(new Options().executable, []);
   future.then((process) {
-    // Ignore error on stdin.
-    process.stdin.onError = (e) => null;
+    process.stdin.done.catchError((e) {
+      // Accept errors on stdin.
+    });
 
     // Drain stdout and stderr.
-    process.stdout.onData = () => process.stdout.read();
-    process.stderr.onData = () => process.stderr.read();
+    process.stdout.listen((_) {});
+    process.stderr.listen((_) {});
 
     // Write to the stdin after the process is terminated to test
     // writing to a broken pipe.
-    process.onExit = (code) {
-      Expect.isFalse(process.stdin.write([0]));
-    };
+    process.exitCode.then((code) {
+      process.stdin.add([0]);
+    });
   });
 }
diff --git a/tests/standalone/io/process_check_arguments_test.dart b/tests/standalone/io/process_check_arguments_test.dart
index 23ee444..46b1cb4 100644
--- a/tests/standalone/io/process_check_arguments_test.dart
+++ b/tests/standalone/io/process_check_arguments_test.dart
@@ -8,12 +8,12 @@
 test(args) {
   var future = Process.start(new Options().executable, args);
   future.then((process) {
-    process.onExit = (exitCode) {
+    process.exitCode.then((exitCode) {
       Expect.equals(0, exitCode);
-    };
+    });
     // Drain stdout and stderr.
-    process.stdout.onData = process.stdout.read;
-    process.stderr.onData = process.stderr.read;
+    process.stdout.listen((_) {});
+    process.stderr.listen((_) {});
   });
 }
 
diff --git a/tests/standalone/io/process_exit_test.dart b/tests/standalone/io/process_exit_test.dart
index f4f9100..060bb14 100644
--- a/tests/standalone/io/process_exit_test.dart
+++ b/tests/standalone/io/process_exit_test.dart
@@ -12,11 +12,11 @@
   var future = Process.start(getProcessTestFileName(),
                              const ["0", "0", "99", "0"]);
   future.then((process) {
-    process.onExit = (int exitCode) {
+    process.exitCode.then((int exitCode) {
       Expect.equals(exitCode, 99);
-    };
-    process.stdout.onData = process.stdout.read;
-    process.stderr.onData = process.stderr.read;
+    });
+    process.stdout.listen((_) {});
+    process.stderr.listen((_) {});
   });
 }
 
diff --git a/tests/standalone/io/process_kill_test.dart b/tests/standalone/io/process_kill_test.dart
index 8571952..733724f 100644
--- a/tests/standalone/io/process_kill_test.dart
+++ b/tests/standalone/io/process_kill_test.dart
@@ -11,12 +11,12 @@
 testKill() {
   // Start a process that will hang waiting for input until killed.
   Process.start(getProcessTestFileName(), const ["0", "1", "0", "0"]).then((p) {
-    p.onExit = (exitCode) {
+    p.exitCode.then((exitCode) {
       // Process killed from the side so exit code is not 0.
       Expect.isTrue(exitCode != 0);
       // Killing a process that is already dead returns false.
       Expect.isFalse(p.kill());
-    };
+    });
     Expect.isTrue(p.kill());
   });
 }
diff --git a/tests/standalone/io/process_segfault_test.dart b/tests/standalone/io/process_segfault_test.dart
index 10d7572..5c278d2 100644
--- a/tests/standalone/io/process_segfault_test.dart
+++ b/tests/standalone/io/process_segfault_test.dart
@@ -12,11 +12,11 @@
   var future = Process.start(getProcessTestFileName(),
                              const ["0", "0", "1", "1"]);
   future.then((process) {
-    process.onExit = (int exitCode) {
+    process.exitCode.then((int exitCode) {
       Expect.isTrue(exitCode != 0);
-    };
-    process.stdout.onData = process.stdout.read;
-    process.stderr.onData = process.stderr.read;
+    });
+    process.stdout.listen((_) {});
+    process.stderr.listen((_) {});
   });
 }
 
diff --git a/tests/standalone/io/process_set_exit_code_script.dart b/tests/standalone/io/process_set_exit_code_script.dart
index 6a78429..f247963 100644
--- a/tests/standalone/io/process_set_exit_code_script.dart
+++ b/tests/standalone/io/process_set_exit_code_script.dart
@@ -5,7 +5,7 @@
 import "dart:io";
 
 main() {
-  stdout.writeString("standard out");
-  stderr.writeString("standard error");
+  stdout.addString("standard out");
+  stderr.addString("standard error");
   exitCode = 25;
-}
\ No newline at end of file
+}
diff --git a/tests/standalone/io/process_std_io_script.dart b/tests/standalone/io/process_std_io_script.dart
index bc8b240..06ee29a 100644
--- a/tests/standalone/io/process_std_io_script.dart
+++ b/tests/standalone/io/process_std_io_script.dart
@@ -10,15 +10,14 @@
   var options = new Options();
   if (options.arguments.length > 0) {
     if (options.arguments[0] == "0") {
-      stdin.onData = () => stdout.write(stdin.read());
+      stdin.pipe(stdout);
     } else if (options.arguments[0] == "1") {
-      stdin.onData = () => stderr.write(stdin.read());
+      stdin.pipe(stderr);
     } else if (options.arguments[0] == "2") {
-      stdin.onData = () {
-        var data = stdin.read();
-        stdout.write(data);
-        stderr.write(data);
-      };
+      stdin.listen((data) {
+        stdout.add(data);
+        stderr.add(data);
+      });
     }
   }
 }
diff --git a/tests/standalone/io/process_std_io_script2.dart b/tests/standalone/io/process_std_io_script2.dart
index 96d9739..5c0501f 100644
--- a/tests/standalone/io/process_std_io_script2.dart
+++ b/tests/standalone/io/process_std_io_script2.dart
@@ -9,9 +9,9 @@
 
 writeData(data, encoding, stream) {
   if (stream == "stdout") {
-    stdout.writeString(data, encoding);
+    stdout.addString(data, encoding);
   } else if (stream == "stderr") {
-    stderr.writeString(data, encoding);
+    stderr.addString(data, encoding);
   }
 }
 
diff --git a/tests/standalone/io/process_stderr_test.dart b/tests/standalone/io/process_stderr_test.dart
index b84d81c..858bb9a 100644
--- a/tests/standalone/io/process_stderr_test.dart
+++ b/tests/standalone/io/process_stderr_test.dart
@@ -17,20 +17,18 @@
 
 void test(Future<Process> future, int expectedExitCode) {
   future.then((process) {
-    process.onExit = (exitCode) {
+    process.exitCode.then((exitCode) {
       Expect.equals(expectedExitCode, exitCode);
-    };
+    });
 
     List<int> data = "ABCDEFGHI\n".charCodes;
     final int dataSize = data.length;
 
-    InputStream err = process.stderr;
-
     int received = 0;
     List<int> buffer = [];
 
-    void readData() {
-      buffer.addAll(err.read());
+    void readData(data) {
+      buffer.addAll(data);
       for (int i = received;
            i < min(data.length, buffer.length) - 1;
            i++) {
@@ -47,10 +45,10 @@
       }
     }
 
-    process.stdout.onData = process.stdout.read;
-    process.stdin.write(data);
+    process.stdout.listen((_) {});
+    process.stdin.add(data);
     process.stdin.close();
-    err.onData = readData;
+    process.stderr.listen(readData);
   });
 }
 
diff --git a/tests/standalone/io/process_stdout_test.dart b/tests/standalone/io/process_stdout_test.dart
index 200faf0..698ab57 100644
--- a/tests/standalone/io/process_stdout_test.dart
+++ b/tests/standalone/io/process_stdout_test.dart
@@ -17,20 +17,18 @@
 
 void test(Future<Process> future, int expectedExitCode) {
   future.then((process) {
-    process.onExit = (exitCode) {
+    process.exitCode.then((exitCode) {
       Expect.equals(expectedExitCode, exitCode);
-    };
+    });
 
     List<int> data = "ABCDEFGHI\n".charCodes;
     final int dataSize = data.length;
 
-    InputStream out = process.stdout;
-
     int received = 0;
     List<int> buffer = [];
 
-    void readData() {
-      buffer.addAll(out.read());
+    void readData(data) {
+      buffer.addAll(data);
       for (int i = received;
            i < min(data.length, buffer.length) - 1;
            i++) {
@@ -47,10 +45,10 @@
       }
     }
 
-    process.stdin.write(data);
+    process.stderr.listen((_) {});
+    process.stdin.add(data);
     process.stdin.close();
-    out.onData = readData;
-    process.stderr.onData = process.stderr.read;
+    process.stdout.listen(readData);
   });
 }
 
diff --git a/tests/standalone/io/process_working_directory_test.dart b/tests/standalone/io/process_working_directory_test.dart
index 3240cb9..1529a13 100644
--- a/tests/standalone/io/process_working_directory_test.dart
+++ b/tests/standalone/io/process_working_directory_test.dart
@@ -25,12 +25,12 @@
     var processFuture =
         Process.start(fullTestFilePath, const ["0", "0", "99", "0"], options);
     processFuture.then((process) {
-      process.onExit = (int exitCode) {
+      process.exitCode.then((int exitCode) {
         Expect.equals(exitCode, 99);
         directory.deleteSync();
-      };
-      process.stdout.onData = process.stdout.read;
-      process.stderr.onData = process.stderr.read;
+      });
+      process.stdout.listen((_) {});
+      process.stderr.listen((_) {});
     }).catchError((error) {
       directory.deleteSync();
       Expect.fail("Couldn't start process");
diff --git a/tests/standalone/io/raw_secure_server_closing_test.dart b/tests/standalone/io/raw_secure_server_closing_test.dart
new file mode 100644
index 0000000..1f8116d4
--- /dev/null
+++ b/tests/standalone/io/raw_secure_server_closing_test.dart
@@ -0,0 +1,159 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+const SERVER_ADDRESS = "127.0.0.1";
+const HOST_NAME = "localhost";
+const CERTIFICATE = "localhost_cert";
+
+void testCloseOneEnd(String toClose) {
+  ReceivePort port = new ReceivePort();
+  Completer serverDone = new Completer();
+  Completer serverEndDone = new Completer();
+  Completer clientEndDone = new Completer();
+  Future.wait([serverDone.future, serverEndDone.future, clientEndDone.future])
+      .then((_) {
+        port.close();
+      });
+  RawSecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((server) {
+    server.listen((serverConnection) {
+      serverConnection.listen((event) {
+        if (toClose == "server" || event == RawSocketEvent.READ_CLOSED) {
+          serverConnection.shutdown(SocketDirection.SEND);
+        }
+      },
+      onDone: () {
+        serverEndDone.complete(null);
+      });
+    },
+    onDone: () {
+      serverDone.complete(null);
+    });
+    RawSecureSocket.connect(HOST_NAME, server.port).then((clientConnection) {
+      clientConnection.listen((event){
+        if (toClose == "client" || event == RawSocketEvent.READ_CLOSED) {
+          clientConnection.shutdown(SocketDirection.SEND);
+        }
+      },
+      onDone: () {
+        clientEndDone.complete(null);
+        server.close();
+      });
+    });
+  });
+}
+
+void testCloseBothEnds() {
+  ReceivePort port = new ReceivePort();
+  RawSecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((server) {
+    var clientEndFuture = RawSecureSocket.connect(HOST_NAME, server.port);
+    server.listen((serverEnd) {
+      clientEndFuture.then((clientEnd) {
+        clientEnd.close();
+        serverEnd.close();
+        server.close();
+        port.close();
+      });
+    });
+  });
+}
+
+testPauseServerSocket() {
+  const int socketCount = 10;
+  var acceptCount = 0;
+  var resumed = false;
+
+  ReceivePort port = new ReceivePort();
+
+  RawSecureServerSocket.bind(SERVER_ADDRESS,
+                             0,
+                             2 * socketCount,
+                             CERTIFICATE).then((server) {
+    Expect.isTrue(server.port > 0);
+    var subscription;
+    subscription = server.listen((connection) {
+      Expect.isTrue(resumed);
+      connection.shutdown(SocketDirection.SEND);
+      if (++acceptCount == 2 * socketCount) {
+        server.close();
+        port.close();
+      }
+    });
+
+    // Pause the server socket subscription and resume it after having
+    // connected a number client sockets. Then connect more client
+    // sockets.
+    subscription.pause();
+    var connectCount = 0;
+    for (int i = 0; i < socketCount; i++) {
+      RawSecureSocket.connect(HOST_NAME, server.port).then((connection) {
+        connection.shutdown(SocketDirection.SEND);
+      });
+    }
+    new Timer(500, (_) {
+      subscription.resume();
+      resumed = true;
+      for (int i = 0; i < socketCount; i++) {
+        RawSecureSocket.connect(HOST_NAME, server.port).then((connection) {
+          connection.shutdown(SocketDirection.SEND);
+        });
+      }
+    });
+  });
+}
+
+testCloseServer() {
+  const int socketCount = 3;
+  ReceivePort port = new ReceivePort();
+  List ends = [];
+
+  RawSecureServerSocket.bind(SERVER_ADDRESS, 0, 15, CERTIFICATE).then((server) {
+    Expect.isTrue(server.port > 0);
+    void checkDone() {
+      if (ends.length < 2 * socketCount) return;
+      for (var end in ends) {
+        end.close();
+      }
+      server.close();
+      port.close();
+    }
+
+    server.listen((connection) {
+      ends.add(connection);
+      checkDone();
+    });
+
+    for (int i = 0; i < socketCount; i++) {
+      RawSecureSocket.connect(HOST_NAME, server.port).then((connection) {
+        ends.add(connection);
+        checkDone();
+      });
+    }
+  });
+}
+
+
+main() {
+  Path scriptDir = new Path(new Options().script).directoryPath;
+  Path certificateDatabase = scriptDir.append('pkcert');
+  SecureSocket.initialize(database: certificateDatabase.toNativePath(),
+                          password: 'dartdart',
+                          useBuiltinRoots: false);
+
+  testCloseOneEnd("client");
+  testCloseOneEnd("server");
+  testCloseBothEnds();
+  testCloseServer();
+  testPauseServerSocket();
+  // TODO(whesse): Add testPauseSocket from raw_socket_test.dart.
+  // TODO(whesse): Add testCancelResubscribeSocket from raw_socket_test.dart.
+}
diff --git a/tests/standalone/io/raw_secure_server_socket_test.dart b/tests/standalone/io/raw_secure_server_socket_test.dart
new file mode 100644
index 0000000..73609ae
--- /dev/null
+++ b/tests/standalone/io/raw_secure_server_socket_test.dart
@@ -0,0 +1,262 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+const SERVER_ADDRESS = "127.0.0.1";
+const HOST_NAME = "localhost";
+const CERTIFICATE = "localhost_cert";
+
+void testArguments() {
+  Expect.throws(() =>
+      RawSecureServerSocket.bind(SERVER_ADDRESS, 65536, 5, CERTIFICATE));
+  Expect.throws(() =>
+      RawSecureServerSocket.bind(SERVER_ADDRESS, -1, CERTIFICATE));
+  Expect.throws(() =>
+      RawSecureServerSocket.bind(SERVER_ADDRESS, 0, -1, CERTIFICATE));
+}
+
+void testSimpleBind() {
+  ReceivePort port = new ReceivePort();
+  RawSecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((s) {
+    Expect.isTrue(s.port > 0);
+    s.close();
+    port.close();
+  });
+}
+
+void testInvalidBind() {
+  int count = 0;
+  ReceivePort port = new ReceivePort();
+  port.receive((_, __) { count++; if (count == 3) port.close(); });
+
+  // Bind to a unknown DNS name.
+  RawSecureServerSocket.bind("ko.faar.__hest__", 0, 5, CERTIFICATE).then((_) {
+    Expect.fail("Failure expected");
+  }).catchError((e) {
+    Expect.isTrue(e.error is SocketIOException);
+    port.toSendPort().send(1);
+  });
+
+  // Bind to an unavaliable IP-address.
+  RawSecureServerSocket.bind("8.8.8.8", 0, 5, CERTIFICATE).then((_) {
+    Expect.fail("Failure expected");
+  }).catchError((e) {
+    Expect.isTrue(e.error is SocketIOException);
+    port.toSendPort().send(1);
+  });
+
+  // Bind to a port already in use.
+  // Either an error or a successful bind is allowed.
+  // Windows platforms allow multiple binding to the same socket, with
+  // unpredictable results.
+  RawSecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((s) {
+    RawSecureServerSocket.bind(SERVER_ADDRESS,
+                               s.port,
+                               5,
+                               CERTIFICATE).then((t) {
+      Expect.equals('windows', Platform.operatingSystem);
+      Expect.equals(s.port, t.port);
+      s.close();
+      t.close();
+      port.toSendPort().send(1);
+    })
+    .catchError((e) {
+      Expect.notEquals('windows', Platform.operatingSystem);
+      Expect.isTrue(e.error is SocketIOException);
+      s.close();
+      port.toSendPort().send(1);
+    });
+  });
+}
+
+void testSimpleConnect(String certificate) {
+  ReceivePort port = new ReceivePort();
+  RawSecureServerSocket.bind(SERVER_ADDRESS, 0, 5, certificate).then((server) {
+    var clientEndFuture = RawSecureSocket.connect(HOST_NAME, server.port);
+    server.listen((serverEnd) {
+      clientEndFuture.then((clientEnd) {
+        clientEnd.shutdown(SocketDirection.SEND);
+        serverEnd.shutdown(SocketDirection.SEND);
+        server.close();
+        port.close();
+      });
+    });
+  });
+}
+
+void testSimpleConnectFail(String certificate) {
+  ReceivePort port = new ReceivePort();
+  RawSecureServerSocket.bind(SERVER_ADDRESS, 0, 5, certificate).then((server) {
+    var clientEndFuture = RawSecureSocket.connect(HOST_NAME, server.port)
+      .then((clientEnd) {
+        Expect.fail("No client connection expected.");
+      })
+      .catchError((e) {
+        Expect.isTrue(e is AsyncError);
+        Expect.isTrue(e.error is SocketIOException);
+      });
+    server.listen((serverEnd) {
+      Expect.fail("No server connection expected.");
+    },
+    onError: (e) {
+      Expect.isTrue(e is AsyncError);
+      Expect.isTrue(e.error is SocketIOException);
+      clientEndFuture.then((_) => port.close());
+    });
+  });
+}
+
+void testServerListenAfterConnect() {
+  ReceivePort port = new ReceivePort();
+  RawSecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((server) {
+    Expect.isTrue(server.port > 0);
+    var clientEndFuture = RawSecureSocket.connect(HOST_NAME, server.port);
+    new Timer(500, (_) {
+      server.listen((serverEnd) {
+        clientEndFuture.then((clientEnd) {
+          clientEnd.shutdown(SocketDirection.SEND);
+          serverEnd.shutdown(SocketDirection.SEND);
+          server.close();
+          port.close();
+        });
+      });
+    });
+  });
+}
+
+void testSimpleReadWrite() {
+  // This test creates a server and a client connects. The client then
+  // writes and the server echos. When the server has finished its
+  // echo it half-closes. When the client gets the close event is
+  // closes fully.
+  ReceivePort port = new ReceivePort();
+
+  const messageSize = 1000;
+
+  List<int> createTestData() {
+    List<int> data = new List.fixedLength(messageSize);
+    for (int i = 0; i < messageSize; i++) {
+      data[i] = i & 0xff;
+    }
+    return data;
+  }
+
+  void verifyTestData(List<int> data) {
+    Expect.equals(messageSize, data.length);
+    List<int> expected = createTestData();
+    for (int i = 0; i < messageSize; i++) {
+      Expect.equals(expected[i], data[i]);
+    }
+  }
+
+  RawSecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((server) {
+    server.listen((client) {
+      int bytesRead = 0;
+      int bytesWritten = 0;
+      List<int> data = new List.fixedLength(messageSize);
+
+      client.writeEventsEnabled = false;
+      client.listen((event) {
+        switch (event) {
+          case RawSocketEvent.READ:
+            Expect.isTrue(bytesWritten == 0);
+            Expect.isTrue(client.available() > 0);
+            var buffer = client.read();
+            if (buffer != null) {
+              data.setRange(bytesRead, buffer.length, buffer);
+              bytesRead += buffer.length;
+              for (var value in buffer) {
+                Expect.isTrue(value is int);
+                Expect.isTrue(value < 256 && value >= 0);
+              }
+            }
+            if (bytesRead == data.length) {
+              verifyTestData(data);
+              client.writeEventsEnabled = true;
+            }
+            break;
+          case RawSocketEvent.WRITE:
+            Expect.isFalse(client.writeEventsEnabled);
+            Expect.equals(bytesRead, data.length);
+            for (int i = bytesWritten; i < data.length; ++i) {
+              Expect.isTrue(data[i] is int);
+              Expect.isTrue(data[i] < 256 && data[i] >= 0);
+            }
+            bytesWritten += client.write(
+                data, bytesWritten, data.length - bytesWritten);
+            if (bytesWritten < data.length) {
+              client.writeEventsEnabled = true;
+            }
+            if (bytesWritten == data.length) {
+              client.shutdown(SocketDirection.SEND);
+            }
+            break;
+          case RawSocketEvent.READ_CLOSED:
+            server.close();
+            break;
+          default: throw "Unexpected event $event";
+        }
+      });
+    });
+
+    RawSecureSocket.connect(HOST_NAME, server.port).then((socket) {
+      int bytesRead = 0;
+      int bytesWritten = 0;
+      List<int> dataSent = createTestData();
+      List<int> dataReceived = new List<int>.fixedLength(dataSent.length);
+      socket.listen((event) {
+        switch (event) {
+          case RawSocketEvent.READ:
+            Expect.isTrue(socket.available() > 0);
+            var buffer = socket.read();
+            if (buffer != null) {
+              dataReceived.setRange(bytesRead, buffer.length, buffer);
+              bytesRead += buffer.length;
+            }
+            break;
+          case RawSocketEvent.WRITE:
+            Expect.isTrue(bytesRead == 0);
+            Expect.isFalse(socket.writeEventsEnabled);
+            bytesWritten += socket.write(
+                dataSent, bytesWritten, dataSent.length - bytesWritten);
+            if (bytesWritten < dataSent.length) {
+              socket.writeEventsEnabled = true;
+            }
+            break;
+          case RawSocketEvent.READ_CLOSED:
+            verifyTestData(dataReceived);
+            socket.close();
+            port.close();
+            break;
+          default: throw "Unexpected event $event";
+        }
+      });
+    });
+  });
+}
+
+main() {
+  Path scriptDir = new Path(new Options().script).directoryPath;
+  Path certificateDatabase = scriptDir.append('pkcert');
+  SecureSocket.initialize(database: certificateDatabase.toNativePath(),
+                          password: 'dartdart',
+                          useBuiltinRoots: false);
+  testArguments();
+  testSimpleBind();
+  testInvalidBind();
+  testSimpleConnect(CERTIFICATE);
+  testSimpleConnect("CN=localhost");
+  testSimpleConnectFail("not_a_nickname");
+  testSimpleConnectFail("CN=notARealDistinguishedName");
+  testServerListenAfterConnect();
+  testSimpleReadWrite();
+}
diff --git a/tests/standalone/io/raw_secure_socket_pause_test.dart b/tests/standalone/io/raw_secure_socket_pause_test.dart
new file mode 100644
index 0000000..23b2eff
--- /dev/null
+++ b/tests/standalone/io/raw_secure_socket_pause_test.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+
+void main() {
+  List<int> message = "GET / HTTP/1.0\r\nHost: www.google.dk\r\n\r\n".charCodes;
+  int written = 0;
+  List<String> chunks = <String>[];
+  SecureSocket.initialize();
+  // TODO(whesse): Use a Dart HTTPS server for this test.
+  // The Dart HTTPS server works on bleeding-edge, but not on IOv2.
+  // When we use a Dart HTTPS server, allow --short_socket_write. The flag
+  // causes fragmentation of the client hello message, which doesn't seem to
+  // work with www.google.dk.
+  RawSecureSocket.connect("www.google.dk", 443).then((socket) {
+    StreamSubscription subscription;
+    bool paused = false;
+    bool readEventsTested = false;
+    bool readEventsPaused = false;
+
+    void runPauseTest() {
+      subscription.pause();
+      paused = true;
+      new Timer(500, (_) {
+          paused = false;
+          subscription.resume();
+      });
+    }
+
+    void runReadEventTest() {
+      if (readEventsTested) return;
+      readEventsTested = true;
+      socket.readEventsEnabled = false;
+      readEventsPaused = true;
+      new Timer(500, (_) {
+        readEventsPaused = false;
+        socket.readEventsEnabled = true;
+      });
+    }
+
+    subscription = socket.listen((RawSocketEvent event) {
+      Expect.isFalse(paused);
+      switch (event) {
+        case RawSocketEvent.READ:
+          Expect.isFalse(readEventsPaused);
+          runReadEventTest();
+          var data = socket.read();
+          var received = new String.fromCharCodes(data);
+          chunks.add(received);
+          break;
+        case RawSocketEvent.WRITE:
+          written +=
+              socket.write(message, written, message.length - written);
+          if (written < message.length) {
+            socket.writeEventsEnabled = true;
+          } else {
+            socket.shutdown(SocketDirection.SEND);
+            runPauseTest();
+          }
+          break;
+        case RawSocketEvent.READ_CLOSED:
+          String fullPage = chunks.join();
+          Expect.isTrue(fullPage.contains('</body></html>'));
+          break;
+        default: throw "Unexpected event $event";
+      }
+      }, onError: (AsyncError a) {
+        Expect.fail("onError handler of RawSecureSocket stream hit: $a");
+      });
+  });
+}
diff --git a/tests/standalone/io/raw_secure_socket_test.dart b/tests/standalone/io/raw_secure_socket_test.dart
new file mode 100644
index 0000000..b7f7068
--- /dev/null
+++ b/tests/standalone/io/raw_secure_socket_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+
+void main() {
+  List<int> message = "GET / HTTP/1.0\r\nHost: www.google.dk\r\n\r\n".charCodes;
+  int written = 0;
+  List<String> chunks = <String>[];
+  SecureSocket.initialize();
+  // TODO(3593): Use a Dart HTTPS server for this test.
+  RawSecureSocket.connect("www.google.dk", 443).then((socket) {
+    socket.listen((RawSocketEvent event) {
+      switch (event) {
+        case RawSocketEvent.READ:
+          var data = socket.read();
+          var received = new String.fromCharCodes(data);
+          chunks.add(received);
+          break;
+        case RawSocketEvent.WRITE:
+          written +=
+              socket.write(message, written, message.length - written);
+          if (written < message.length) {
+            socket.writeEventsEnabled = true;
+          } else {
+            socket.shutdown(SocketDirection.SEND);
+          }
+          break;
+        case RawSocketEvent.READ_CLOSED:
+          String fullPage = chunks.join();
+          Expect.isTrue(fullPage.contains('</body></html>'));
+          break;
+        default: throw "Unexpected event $event";
+      }
+    }, onError: (AsyncError a) {
+      Expect.fail("onError handler of RawSecureSocket stream hit: $a");
+    });
+  });
+}
diff --git a/tests/standalone/io/raw_socket_test.dart b/tests/standalone/io/raw_socket_test.dart
new file mode 100644
index 0000000..d14dc9e
--- /dev/null
+++ b/tests/standalone/io/raw_socket_test.dart
@@ -0,0 +1,412 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+void testArguments() {
+  Expect.throws(() => RawServerSocket.bind("127.0.0.1", 65536));
+  Expect.throws(() => RawServerSocket.bind("127.0.0.1", -1));
+  Expect.throws(() => RawServerSocket.bind("127.0.0.1", 0, -1));
+}
+
+void testSimpleBind() {
+  ReceivePort port = new ReceivePort();
+  RawServerSocket.bind().then((s) {
+    Expect.isTrue(s.port > 0);
+    port.close();
+  });
+}
+
+void testInvalidBind() {
+  int count = 0;
+  ReceivePort port = new ReceivePort();
+  port.receive((_, __) { count++; if (count == 3) port.close(); });
+
+  // Bind to a unknown DNS name.
+  RawServerSocket.bind("ko.faar.__hest__")
+      .then((_) { Expect.fail("Failure expected"); } )
+      .catchError((e) {
+        Expect.isTrue(e.error is SocketIOException);
+        port.toSendPort().send(1);
+      });
+
+  // Bind to an unavaliable IP-address.
+  RawServerSocket.bind("8.8.8.8")
+      .then((_) { Expect.fail("Failure expected"); } )
+      .catchError((e) {
+        Expect.isTrue(e.error is SocketIOException);
+        port.toSendPort().send(1);
+      });
+
+  // Bind to a port already in use.
+  // Either an error or a successful bind is allowed.
+  // Windows platforms allow multiple binding to the same socket, with
+  // unpredictable results.
+  RawServerSocket.bind("127.0.0.1")
+      .then((s) {
+        RawServerSocket.bind("127.0.0.1", s.port)
+            .then((t) {
+              Expect.equals('windows', Platform.operatingSystem);
+              Expect.equals(s.port, t.port);
+              port.toSendPort().send(1);
+            })
+            .catchError((e) {
+              Expect.notEquals('windows', Platform.operatingSystem);
+              Expect.isTrue(e.error is SocketIOException);
+              port.toSendPort().send(1);
+            });
+      });
+}
+
+void testSimpleConnect() {
+  ReceivePort port = new ReceivePort();
+  RawServerSocket.bind().then((server) {
+    server.listen((_) { });
+    RawSocket.connect("127.0.0.1", server.port).then((_) {
+      server.close();
+      port.close();
+    });
+  });
+}
+
+void testCloseOneEnd(String toClose) {
+  ReceivePort port = new ReceivePort();
+  Completer serverDone = new Completer();
+  Completer serverEndDone = new Completer();
+  Completer clientEndDone = new Completer();
+  Future.wait([serverDone.future, serverEndDone.future, clientEndDone.future])
+      .then((_) {
+        port.close();
+      });
+  RawServerSocket.bind().then((server) {
+    server.listen((serverConnection) {
+      serverConnection.listen((event) {
+        if (toClose == "server" || event == RawSocketEvent.READ_CLOSED) {
+          serverConnection.shutdown(SocketDirection.SEND);
+        }
+      },
+      onDone: () {
+        serverEndDone.complete(null);
+      });
+    },
+    onDone:() {
+      serverDone.complete(null);
+    });
+    RawSocket.connect("127.0.0.1", server.port).then((clientConnection) {
+      clientConnection.listen((event){
+        if (toClose == "client" || event == RawSocketEvent.READ_CLOSED) {
+          clientConnection.shutdown(SocketDirection.SEND);
+        }
+      },
+      onDone: () {
+        clientEndDone.complete(null);
+        server.close();
+      });
+    });
+  });
+}
+
+void testServerListenAfterConnect() {
+  ReceivePort port = new ReceivePort();
+  RawServerSocket.bind().then((server) {
+    Expect.isTrue(server.port > 0);
+    RawSocket.connect("127.0.0.1", server.port).then((_) {
+      server.listen((_) {
+        server.close();
+        port.close();
+      });
+    });
+  });
+}
+
+void testSimpleReadWrite() {
+  // This test creates a server and a client connects. The client then
+  // writes and the server echos. When the server has finished its
+  // echo it half-closes. When the client gets the close event is
+  // closes fully.
+  ReceivePort port = new ReceivePort();
+
+  const messageSize = 1000;
+
+  List<int> createTestData() {
+    List<int> data = new List.fixedLength(messageSize);
+    for (int i = 0; i < messageSize; i++) {
+      data[i] = i & 0xff;
+    }
+    return data;
+  }
+
+  void verifyTestData(List<int> data) {
+    Expect.equals(messageSize, data.length);
+    List<int> expected = createTestData();
+    for (int i = 0; i < messageSize; i++) {
+      Expect.equals(expected[i], data[i]);
+    }
+  }
+
+  RawServerSocket.bind().then((server) {
+    server.listen((client) {
+      int bytesRead = 0;
+      int bytesWritten = 0;
+      List<int> data = new List.fixedLength(messageSize);
+
+      client.writeEventsEnabled = false;
+      client.listen((event) {
+        switch (event) {
+          case RawSocketEvent.READ:
+            Expect.isTrue(bytesWritten == 0);
+            Expect.isTrue(client.available() > 0);
+            var buffer = client.read();
+            data.setRange(bytesRead, buffer.length, buffer);
+            bytesRead += buffer.length;
+            if (bytesRead == data.length) {
+              verifyTestData(data);
+              client.writeEventsEnabled = true;
+            }
+            break;
+          case RawSocketEvent.WRITE:
+            Expect.isFalse(client.writeEventsEnabled);
+            bytesWritten += client.write(
+                data, bytesWritten, data.length - bytesWritten);
+            if (bytesWritten < data.length) {
+              client.writeEventsEnabled = true;
+            }
+            if (bytesWritten == data.length) {
+              client.shutdown(SocketDirection.SEND);
+            }
+            break;
+          case RawSocketEvent.READ_CLOSED:
+            server.close();
+            break;
+          default: throw "Unexpected event $event";
+        }
+      });
+    });
+
+    RawSocket.connect("127.0.0.1", server.port).then((socket) {
+      int bytesRead = 0;
+      int bytesWritten = 0;
+      List<int> data = createTestData();
+
+      socket.listen((event) {
+        switch (event) {
+          case RawSocketEvent.READ:
+            Expect.isTrue(socket.available() > 0);
+            var buffer = socket.read();
+            data.setRange(bytesRead, buffer.length, buffer);
+            bytesRead += buffer.length;
+            break;
+          case RawSocketEvent.WRITE:
+            Expect.isTrue(bytesRead == 0);
+            Expect.isFalse(socket.writeEventsEnabled);
+            bytesWritten += socket.write(
+                data, bytesWritten, data.length - bytesWritten);
+            if (bytesWritten < data.length) {
+              socket.writeEventsEnabled = true;
+            } else {
+              data = new List.fixedLength(messageSize);
+            }
+            break;
+          case RawSocketEvent.READ_CLOSED:
+            verifyTestData(data);
+            socket.close();
+            break;
+          default: throw "Unexpected event $event";
+        }
+      },
+      onDone: () => port.close());
+    });
+  });
+}
+
+testPauseServerSocket() {
+  const int socketCount = 10;
+  var acceptCount = 0;
+  var resumed = false;
+
+  ReceivePort port = new ReceivePort();
+
+  RawServerSocket.bind().then((server) {
+    Expect.isTrue(server.port > 0);
+    var subscription = server.listen((_) {
+      Expect.isTrue(resumed);
+      if (++acceptCount == socketCount) {
+        server.close();
+        port.close();
+      }
+    });
+
+    // Pause the server socket subscription and resume it after having
+    // connected a number client sockets. Then connect more client
+    // sockets.
+    subscription.pause();
+    var connectCount = 0;
+    for (int i = 0; i <= socketCount / 2; i++) {
+      RawSocket.connect("127.0.0.1", server.port).then((_) {
+        if (++connectCount == socketCount / 2) {
+          subscription.resume();
+          resumed = true;
+          for (int i = connectCount; i < socketCount; i++) {
+            RawSocket.connect("127.0.0.1", server.port).then((_) {});
+          }
+        }
+      });
+    }
+  });
+}
+
+testCancelResubscribeServerSocket() {
+  const int socketCount = 10;
+  var acceptCount = 0;
+  var doneCount = 0;
+  var closeCount = 0;
+  var errorCount = 0;
+
+  ReceivePort port = new ReceivePort();
+
+  RawServerSocket.bind().then((server) {
+    Expect.isTrue(server.port > 0);
+
+    void checkDone() {
+      if (doneCount == socketCount &&
+          closeCount + errorCount == socketCount) {
+        port.close();
+      }
+    }
+
+    // Subscribe the server socket. Then cancel subscription and
+    // subscribe again.
+    var subscription;
+    subscription = server.listen((client) {
+      if (++acceptCount == socketCount / 2) {
+        subscription.cancel();
+        new Timer(0, (_) {
+          subscription = server.listen((_) {
+            // Close on cancel, so no more events.
+            Expect.fail("Event after closed through cancel");
+          });
+        });
+      }
+      // Close the client socket.
+      client.close();
+    });
+
+    // Connect a number of sockets.
+    for (int i = 0; i < socketCount; i++) {
+      RawSocket.connect("127.0.0.1", server.port).then((socket) {
+        socket.writeEventsEnabled = false;
+        var subscription;
+        subscription = socket.listen((event) {
+          Expect.equals(RawSocketEvent.READ_CLOSED, event);
+          socket.close();
+          closeCount++;
+          checkDone();
+        },
+        onDone: () { doneCount++; checkDone(); },
+        onError: (e) { errorCount++; checkDone(); });
+      });
+    }
+  });
+}
+
+testPauseSocket() {
+  const messageSize = 1000;
+  const loopCount = 10;
+  Completer connected = new Completer();
+  int pauseResumeCount = 0;
+  int bytesWritten = 0;
+  int bytesRead = 0;
+  var writeSubscription;
+  var readSubscription;
+
+  ReceivePort port = new ReceivePort();
+
+  RawServerSocket.bind().then((server) {
+    Expect.isTrue(server.port > 0);
+    server.listen((client) {
+      List<int> data = new List.fixedLength(messageSize, fill: 0);
+      writeSubscription = client.listen((event) {
+        switch (event) {
+          case RawSocketEvent.READ:
+            throw "Unexpected read event";
+          case RawSocketEvent.WRITE:
+            if (pauseResumeCount == loopCount) return;
+            Expect.isFalse(client.writeEventsEnabled);
+            Expect.equals(0, bytesRead);  // Checks that reader is paused.
+            bytesWritten += client.write(
+                data, bytesWritten, data.length - bytesWritten);
+            // Ensure all data is written. When done disable the write
+            // event and resume the receiver.
+            if (bytesWritten == data.length) {
+              writeSubscription.pause();
+              bytesWritten = 0;
+              connected.future.then((_) { readSubscription.resume(); });
+            }
+            client.writeEventsEnabled = true;
+            break;
+          case RawSocketEvent.READ_CLOSED:
+            client.close();
+            server.close();
+            break;
+          default: throw "Unexpected event $event";
+        }
+      });
+    });
+
+    RawSocket.connect("127.0.0.1", server.port).then((socket) {
+      socket.writeEventsEnabled = false;
+      readSubscription = socket.listen((event) {
+        switch (event) {
+          case RawSocketEvent.READ:
+            Expect.equals(0, bytesWritten);  // Checks that writer is paused.
+            Expect.isTrue(socket.available() > 0);
+            var buffer = socket.read();
+            bytesRead += buffer.length;
+            // Ensure all data is read. When done pause and resume the sender
+            if (bytesRead == messageSize) {
+              if (++pauseResumeCount == loopCount) {
+                socket.close();
+                port.close();
+              } else {
+                readSubscription.pause();
+              }
+              // Always resume writer as it needs the read closed
+              // event when done.
+              bytesRead = 0;
+              writeSubscription.resume();
+            }
+            break;
+          case RawSocketEvent.WRITE:
+            throw "Unexpected write event";
+          case RawSocketEvent.READ_CLOSED:
+            throw "Unexpected close event";
+          default: throw "Unexpected event $event";
+        }
+      });
+      readSubscription.pause();
+      connected.complete(true);
+    });
+  });
+}
+
+main() {
+  testArguments();
+  testSimpleBind();
+  testCloseOneEnd("client");
+  testCloseOneEnd("server");
+  testInvalidBind();
+  testSimpleConnect();
+  testServerListenAfterConnect();
+  testSimpleReadWrite();
+  testPauseServerSocket();
+  testCancelResubscribeServerSocket();
+  testPauseSocket();
+}
diff --git a/tests/standalone/io/raw_socket_write_destroy_test.dart b/tests/standalone/io/raw_socket_write_destroy_test.dart
new file mode 100644
index 0000000..b5e558a8
--- /dev/null
+++ b/tests/standalone/io/raw_socket_write_destroy_test.dart
@@ -0,0 +1,96 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+const SERVER_ADDRESS = "127.0.0.1";
+
+void testWriteDestroyServer() {
+  int WROTE = 100000;
+  RawServerSocket.bind(SERVER_ADDRESS).then((server) {
+    server.listen((socket) {
+      socket.writeEventsEnabled = false;
+
+      var buffer = new List.fixedLength(WROTE, fill: 0);
+      int offset = 0;
+      void write() {
+        int n = socket.write(buffer, offset, buffer.length - offset);
+        offset += n;
+        socket.writeEventsEnabled = true;
+      }
+      socket.listen((e) {
+        if (e == RawSocketEvent.WRITE) {
+          if (offset == buffer.length) {
+            socket.close();
+          } else {
+            write();
+          }
+        }
+      });
+      write();
+    });
+    RawSocket.connect(SERVER_ADDRESS, server.port).then((socket) {
+      var bytes = 0;
+      socket.listen((e) {
+        if (e == RawSocketEvent.READ) {
+          bytes += socket.read().length;
+        } else if (e == RawSocketEvent.READ_CLOSED) {
+          Expect.equals(WROTE, bytes);
+          socket.close();
+          server.close();
+        }
+      });
+    });
+  });
+}
+
+void testWriteDestroyClient() {
+  int WROTE = 100000;
+  RawServerSocket.bind(SERVER_ADDRESS).then((server) {
+    server.listen((socket) {
+      var bytes = 0;
+      socket.listen((e) {
+        if (e == RawSocketEvent.READ) {
+          bytes += socket.read().length;
+        } else if (e == RawSocketEvent.READ_CLOSED) {
+          Expect.equals(WROTE, bytes);
+          socket.close();
+          server.close();
+        }
+      });
+    });
+    RawSocket.connect(SERVER_ADDRESS, server.port).then((socket) {
+      socket.writeEventsEnabled = false;
+
+      var buffer = new List.fixedLength(WROTE, fill: 0);
+      int offset = 0;
+      void write() {
+        int n = socket.write(buffer, offset, buffer.length - offset);
+        offset += n;
+        socket.writeEventsEnabled = true;
+      }
+      socket.listen((e) {
+        if (e == RawSocketEvent.WRITE) {
+          if (offset == buffer.length) {
+            socket.close();
+          } else {
+            write();
+          }
+        }
+      });
+      write();
+    });
+  });
+}
+
+void main() {
+  testWriteDestroyServer();
+  testWriteDestroyClient();
+}
\ No newline at end of file
diff --git a/tests/standalone/io/read_into_const_list_test.dart b/tests/standalone/io/read_into_const_list_test.dart
index 0362f3c..576cc3f 100644
--- a/tests/standalone/io/read_into_const_list_test.dart
+++ b/tests/standalone/io/read_into_const_list_test.dart
@@ -17,13 +17,14 @@
 
   String filename = getFilename("bin/file_test.cc");
   File file = new File(filename);
-  InputStream input = file.openInputStream();
-  try {
-    input.readInto(a, 0, 1);
-    Expect.fail("no exception thrown");
-  } catch (e) {
-    Expect.isTrue(e is UnsupportedError);
-  }
-  Expect.equals(0, a[0]);
-  Expect.equals(0, b[0]);
+  file.open().then((input) {
+      try {
+        input.readListSync(a, 0, 1);
+        Expect.fail("no exception thrown");
+      } catch (e) {
+        Expect.isTrue(e is UnsupportedError);
+      }
+      Expect.equals(0, a[0]);
+      Expect.equals(0, b[0]);
+    });
 }
diff --git a/tests/standalone/io/regress_6521_test.dart b/tests/standalone/io/regress_6521_test.dart
index cd625ee..73eb67a 100644
--- a/tests/standalone/io/regress_6521_test.dart
+++ b/tests/standalone/io/regress_6521_test.dart
@@ -11,29 +11,30 @@
 var clientRequest;
 
 void main() {
-  var server = new HttpServer();
-  server.listen("127.0.0.1", 0);
-  server.defaultRequestHandler = (req, rsp) {
-    req.inputStream.onData = () {
-      req.inputStream.read();
-      rsp.outputStream.close();
-    };
-  };
+  HttpServer.bind("127.0.0.1", 0)
+      .then((server) {
+        server.listen(
+            (req) {
+              req.pipe(req.response);
+            });
 
-  var connection = client.openUrl(
-      "POST",
-      Uri.parse("http://localhost:${server.port}/"));
-  connection.onRequest = (request) {
-    // Keep a reference to the client request object.
-    clientRequest = request;
-    request.outputStream.write([0]);
-  };
-  connection.onResponse = (response) {
-    response.inputStream.onClosed = () {
-      // Wait with closing the client request until the response is done.
-      clientRequest.outputStream.close();
-      client.shutdown();
-      server.close();
-    };
-  };
+        client.openUrl("POST", Uri.parse("http://localhost:${server.port}/"))
+            .then((request) {
+              // Keep a reference to the client request object.
+              clientRequest = request;
+              request.add([0]);
+              return request.response;
+            })
+            .then((response) {
+              // Wait with closing the client request until the response headers
+              // are done.
+              clientRequest.close();
+              response.listen(
+                  (_) {},
+                  onDone: () {
+                    client.close();
+                    server.close();
+                  });
+            });
+      });
 }
diff --git a/tests/standalone/io/regress_7097_test.dart b/tests/standalone/io/regress_7097_test.dart
deleted file mode 100644
index 214f92b..0000000
--- a/tests/standalone/io/regress_7097_test.dart
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:io';
-import 'dart:uri';
-
-void main() {
-  var client = new HttpClient();
-  var server = new HttpServer();
-
-  var count = 0;
-  server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
-    List<int> data = [];
-    request.inputStream.onData = () {
-      data.addAll(request.inputStream.read());
-    };
-    request.inputStream.onClosed = () {
-      count++;
-      Expect.equals(count, data.length);
-      switch (count - 1) {
-        case 0:
-          response.outputStream.writeFrom([65, 66, 67], 1, 1);
-          break;
-        case 1:
-          response.outputStream.writeFrom([65, 66, 67], 1);
-          break;
-        case 2:
-          response.outputStream.writeFrom([65, 66, 67]);
-          break;
-        default:
-          Expect.fail("Unexpected state");
-      }
-      response.outputStream.close();
-    };
-  };
-  server.listen('127.0.0.1', 0);
-
-  Future makeRequest(int n) {
-    var completer = new Completer();
-    var url = Uri.parse("http://localhost:${server.port}");
-    var connection = client.openUrl("POST", url);
-    connection.onRequest = (HttpClientRequest request) {
-      request.contentLength = n + 1;
-      switch (n) {
-        case 0:
-          request.outputStream.writeFrom([65, 66, 67], 1, 1);
-          break;
-        case 1:
-          request.outputStream.writeFrom([65, 66, 67], 1);
-          break;
-        case 2:
-          request.outputStream.writeFrom([65, 66, 67]);
-          break;
-        default:
-          Expect.fail("Unexpected state");
-      }
-      request.outputStream.close();
-    };
-    connection.onResponse = (HttpClientResponse response) {
-      List<int> data = [];
-      response.inputStream.onData = () {
-        data.addAll(response.inputStream.read());
-      };
-      response.inputStream.onClosed = () {
-        Expect.equals(count, data.length);
-        completer.complete(null);
-      };
-    };
-    return completer.future;
-  }
-
-  makeRequest(0).then((_) {
-    makeRequest(1).then((_) {
-      makeRequest(2).then((_) {
-        client.shutdown();
-        server.close();
-      });
-    });
-  });
-}
diff --git a/tests/standalone/io/regress_7191_script.dart b/tests/standalone/io/regress_7191_script.dart
index d90f0b5..1b047f1 100644
--- a/tests/standalone/io/regress_7191_script.dart
+++ b/tests/standalone/io/regress_7191_script.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -9,22 +9,21 @@
   // Open a port to make the script hang.
   var port = new ReceivePort();
   // Start sub-process when receiving data.
-  stdin.onData = () {
-    var data = stdin.read();
+  var subscription;
+  subscription = stdin.listen((data) {
     var options = new Options();
     Process.start(options.executable, [options.script]).then((p) {
-      p.stdout.onData = p.stdout.read;
-      p.stderr.onData = p.stderr.read;
+      p.stdout.listen((_) { });
+      p.stderr.listen((_) { });
       // When receiving data again, kill sub-process and exit.
-      stdin.onData = () {
-        var data = stdin.read();
+      subscription.onData((data) {
         Expect.listEquals([0], data);
         p.kill();
-        p.onExit = exit;
-      };
+        p.exitCode.then(exit);
+      });
       // Close stdout. If handles are incorrectly inherited this will
       // not actually close stdout and the test will hang.
       stdout.close();
     });
-  };
+  });
 }
diff --git a/tests/standalone/io/regress_7191_test.dart b/tests/standalone/io/regress_7191_test.dart
index 4d72e52..fa92538 100644
--- a/tests/standalone/io/regress_7191_test.dart
+++ b/tests/standalone/io/regress_7191_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -19,12 +19,10 @@
   var scriptDir = new Path(options.script).directoryPath;
   var script = scriptDir.append('regress_7191_script.dart').toNativePath();
   Process.start(executable, [script]).then((process) {
-    process.stdin.write([0]);
-    process.stdout.onData = process.stdout.read;
-    process.stderr.onData = process.stderr.read;
-    process.stdout.onClosed = () {
-      process.stdin.write([0]);
-    };
-    process.onExit = (exitCode) => port.close();
+    process.stdin.add([0]);
+      process.stdout.listen((_) { },
+                            onDone: () { process.stdin.add([0]); });
+    process.stderr.listen((_) { });
+    process.exitCode.then((exitCode) => port.close());
   });
 }
diff --git a/tests/standalone/io/secure_builtin_roots_test.dart b/tests/standalone/io/secure_builtin_roots_test.dart
deleted file mode 100644
index 0881ab3..0000000
--- a/tests/standalone/io/secure_builtin_roots_test.dart
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-import "dart:uri";
-import "dart:isolate";
-
-void testGoogleUrl() {
-  ReceivePort keepAlive = new ReceivePort();
-  HttpClient client = new HttpClient();
-
-  void testUrl(String url) {
-    var requestUri = Uri.parse(url);
-    var conn = client.getUrl(requestUri);
-
-    conn.onRequest = (HttpClientRequest request) {
-      request.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.isTrue(response.statusCode < 500);
-      Expect.isTrue(response.statusCode != 404);
-      response.inputStream.onData = () {
-        response.inputStream.read();
-      };
-      response.inputStream.onClosed = () {
-        client.shutdown();
-        keepAlive.close();
-      };
-    };
-    conn.onError = (error) => Expect.fail("Unexpected IO error $error");
-  }
-
-  testUrl('https://www.google.com');
-}
-
-void InitializeSSL() {
-  SecureSocket.initialize();
-}
-
-void main() {
-  InitializeSSL();
-  testGoogleUrl();
-}
diff --git a/tests/standalone/io/secure_client_raw_server_test.dart b/tests/standalone/io/secure_client_raw_server_test.dart
new file mode 100644
index 0000000..331ea6c
--- /dev/null
+++ b/tests/standalone/io/secure_client_raw_server_test.dart
@@ -0,0 +1,91 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+const SERVER_ADDRESS = "127.0.0.1";
+const HOST_NAME = "localhost";
+const CERTIFICATE = "localhost_cert";
+Future<RawSecureServerSocket> startEchoServer() {
+  return RawSecureServerSocket.bind(SERVER_ADDRESS,
+                                    0,
+                                    5,
+                                    CERTIFICATE).then((server) {
+    server.listen((RawSecureSocket client) {
+      List<List<int>> readChunks = <List<int>>[];
+      List<int> dataToWrite = null;
+      int bytesWritten = 0;
+      client.writeEventsEnabled = false;
+      client.listen((event) {
+        switch (event) {
+          case RawSocketEvent.READ:
+            Expect.isTrue(bytesWritten == 0);
+            Expect.isTrue(client.available() > 0);
+            readChunks.add(client.read());
+            break;
+          case RawSocketEvent.WRITE:
+            Expect.isFalse(client.writeEventsEnabled);
+            Expect.isNotNull(dataToWrite);
+            bytesWritten += client.write(
+                dataToWrite, bytesWritten, dataToWrite.length - bytesWritten);
+            if (bytesWritten < dataToWrite.length) {
+              client.writeEventsEnabled = true;
+            }
+            if (bytesWritten == dataToWrite.length) {
+              client.shutdown(SocketDirection.SEND);
+            }
+            break;
+          case RawSocketEvent.READ_CLOSED:
+            dataToWrite = readChunks.reduce(<int>[], (list, x) {
+              list.addAll(x);
+              return list;
+            });
+            client.writeEventsEnabled = true;
+            break;
+        }
+      });
+    });
+    return server;
+  });
+}
+
+Future testClient(server) {
+  Completer success = new Completer();
+  List<String> chunks = <String>[];
+  SecureSocket.connect(HOST_NAME, server.port).then((socket) {
+    socket.add("Hello server.".charCodes);
+    socket.close();
+    socket.listen(
+      (List<int> data) {
+        var received = new String.fromCharCodes(data);
+        chunks.add(received);
+      },
+      onDone: () {
+        String reply = chunks.join();
+        Expect.equals("Hello server.", reply);
+        success.complete(server);
+      });
+  });
+  return success.future;
+}
+
+void main() {
+  Path scriptDir = new Path(new Options().script).directoryPath;
+  Path certificateDatabase = scriptDir.append('pkcert');
+  SecureSocket.initialize(database: certificateDatabase.toNativePath(),
+                          password: 'dartdart');
+
+  startEchoServer()
+      .then(testClient)
+      .then((server) {
+        server.close();
+      });
+}
diff --git a/tests/standalone/io/secure_client_server_test.dart b/tests/standalone/io/secure_client_server_test.dart
new file mode 100644
index 0000000..da48e87
--- /dev/null
+++ b/tests/standalone/io/secure_client_server_test.dart
@@ -0,0 +1,56 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+const SERVER_ADDRESS = "127.0.0.1";
+const HOST_NAME = "localhost";
+const CERTIFICATE = "localhost_cert";
+Future<SecureServerSocket> startEchoServer() {
+  return SecureServerSocket.bind(SERVER_ADDRESS,
+                                 0,
+                                 5,
+                                 CERTIFICATE).then((server) {
+    server.listen((SecureSocket client) {
+      client.reduce(<int>[], (message, data) => message..addAll(data))
+          .then((message) {
+            client.add(message);
+            client.close();
+          });
+    });
+    return server;
+  });
+}
+
+Future testClient(server) {
+  return SecureSocket.connect(HOST_NAME, server.port).then((socket) {
+    socket.add("Hello server.".charCodes);
+    socket.close();
+    return socket.reduce(<int>[], (message, data) => message..addAll(data))
+        .then((message) {
+          Expect.listEquals("Hello server.".charCodes, message);
+          return server;
+        });
+  });
+}
+
+void main() {
+  Path scriptDir = new Path(new Options().script).directoryPath;
+  Path certificateDatabase = scriptDir.append('pkcert');
+  SecureSocket.initialize(database: certificateDatabase.toNativePath(),
+                          password: 'dartdart');
+
+  startEchoServer()
+      .then(testClient)
+      .then((server) {
+        server.close();
+      });
+}
diff --git a/tests/standalone/io/secure_multiple_client_server_test.dart b/tests/standalone/io/secure_multiple_client_server_test.dart
new file mode 100644
index 0000000..52e0b56
--- /dev/null
+++ b/tests/standalone/io/secure_multiple_client_server_test.dart
@@ -0,0 +1,59 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+const SERVER_ADDRESS = "127.0.0.1";
+const HOST_NAME = "localhost";
+const CERTIFICATE = "localhost_cert";
+Future<SecureServerSocket> startServer() {
+  return SecureServerSocket.bind(SERVER_ADDRESS,
+                                 0,
+                                 5,
+                                 CERTIFICATE).then((server) {
+    server.listen((SecureSocket client) {
+      client.reduce(<int>[], (message, data) => message..addAll(data))
+          .then((message) {
+            String received = new String.fromCharCodes(message);
+            Expect.isTrue(received.contains("Hello from client "));
+            String name = received.substring(received.indexOf("client ") + 7);
+            client.add("Welcome, client $name".charCodes);
+            client.close();
+          });
+    });
+    return server;
+  });
+}
+
+Future testClient(server, name) {
+  return SecureSocket.connect(HOST_NAME, server.port).then((socket) {
+    socket.add("Hello from client $name".charCodes);
+    socket.close();
+    return socket.reduce(<int>[], (message, data) => message..addAll(data))
+        .then((message) {
+          Expect.listEquals("Welcome, client $name".charCodes, message);
+          return server;
+        });
+  });
+}
+
+void main() {
+  Path scriptDir = new Path(new Options().script).directoryPath;
+  Path certificateDatabase = scriptDir.append('pkcert');
+  SecureSocket.initialize(database: certificateDatabase.toNativePath(),
+                          password: 'dartdart');
+
+  startServer()
+      .then((server) => Future.wait(
+          ['able', 'baker', 'charlie', 'dozen', 'elapse']
+          .map((name) => testClient(server, name))))
+      .then((servers) => servers.first.close());
+}
diff --git a/tests/standalone/io/secure_no_builtin_roots_test.dart b/tests/standalone/io/secure_no_builtin_roots_test.dart
index 40dbe21..9b6f489 100644
--- a/tests/standalone/io/secure_no_builtin_roots_test.dart
+++ b/tests/standalone/io/secure_no_builtin_roots_test.dart
@@ -5,28 +5,20 @@
 import "dart:io";
 import "dart:uri";
 import "dart:isolate";
+import "dart:async";
 
 void testGoogleUrl() {
-  ReceivePort keepalivePort = new ReceivePort();
+  ReceivePort keepAlive = new ReceivePort();
   HttpClient client = new HttpClient();
-
-  void testUrl(String url) {
-    var requestUri = Uri.parse(url);
-    var conn = client.getUrl(requestUri);
-
-    conn.onRequest = (HttpClientRequest request) {
-      request.outputStream.close();
-    };
-    conn.onResponse = (HttpClientResponse response) {
-      Expect.fail("Https connection unexpectedly succeeded");
-    };
-    conn.onError = (error) {
-      Expect.isTrue(error is SocketIOException);
-      keepalivePort.close();
-    };
-  }
-
-  testUrl('https://www.google.com');
+  client.getUrl(Uri.parse('https://www.google.com'))
+      .then((request) => request.close())
+      .then((response) => Expect.fail("Unexpected successful connection"))
+      .catchError((error) {
+        Expect.isTrue(error is AsyncError);
+        Expect.isTrue(error.error is SocketIOException);
+        keepAlive.close();
+        client.close();
+      });
 }
 
 void InitializeSSL() {
diff --git a/tests/standalone/io/secure_server_client_certificate_test.dart b/tests/standalone/io/secure_server_client_certificate_test.dart
index ad177f7..5d75c6c 100644
--- a/tests/standalone/io/secure_server_client_certificate_test.dart
+++ b/tests/standalone/io/secure_server_client_certificate_test.dart
@@ -48,7 +48,7 @@
     server = new SecureServerSocket(SERVER_ADDRESS,
                                     0,
                                     10,
-                                    "CN=$HOST_NAME",
+                                    "localhost_cert",
                                     requireClientCertificate: true);
     Expect.isNotNull(server);
     server.onConnection = onConnection;
diff --git a/tests/standalone/io/secure_server_closing_test.dart b/tests/standalone/io/secure_server_closing_test.dart
new file mode 100644
index 0000000..794c54f
--- /dev/null
+++ b/tests/standalone/io/secure_server_closing_test.dart
@@ -0,0 +1,167 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+const SERVER_ADDRESS = "127.0.0.1";
+const HOST_NAME = "localhost";
+const CERTIFICATE = "localhost_cert";
+
+void testCloseOneEnd(String toClose) {
+  ReceivePort port = new ReceivePort();
+  Completer serverDone = new Completer();
+  Completer serverEndDone = new Completer();
+  Completer clientEndDone = new Completer();
+  Future.wait([serverDone.future, serverEndDone.future, clientEndDone.future])
+      .then((_) {
+        port.close();
+      });
+  SecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((server) {
+    server.listen((serverConnection) {
+      serverConnection.listen(
+        (data) {
+          Expect.fail("No data should be received by server");
+        },
+        onDone: () {
+          serverConnection.close();
+          serverEndDone.complete(null);
+          server.close();
+        });
+      if (toClose == "server") {
+        serverConnection.close();
+      }
+    },
+    onDone: () {
+      serverDone.complete(null);
+    });
+    SecureSocket.connect(HOST_NAME, server.port).then((clientConnection) {
+      clientConnection.listen(
+        (data) {
+          Expect.fail("No data should be received by client");
+        },
+        onDone: () {
+          clientConnection.close();
+          clientEndDone.complete(null);
+        });
+      if (toClose == "client") {
+        clientConnection.close();
+      }
+    });
+  });
+}
+
+void testCloseBothEnds() {
+  ReceivePort port = new ReceivePort();
+  SecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((server) {
+    var clientEndFuture = SecureSocket.connect(HOST_NAME, server.port);
+    server.listen((serverEnd) {
+      clientEndFuture.then((clientEnd) {
+        clientEnd.destroy();
+        serverEnd.destroy();
+        server.close();
+        port.close();
+      });
+    });
+  });
+}
+
+testPauseServerSocket() {
+  const int socketCount = 10;
+  var acceptCount = 0;
+  var resumed = false;
+
+  ReceivePort port = new ReceivePort();
+
+  SecureServerSocket.bind(SERVER_ADDRESS,
+                          0,
+                          2 * socketCount,
+                          CERTIFICATE).then((server) {
+    Expect.isTrue(server.port > 0);
+    var subscription;
+    subscription = server.listen((connection) {
+      Expect.isTrue(resumed);
+      connection.close();
+      if (++acceptCount == 2 * socketCount) {
+        server.close();
+        port.close();
+      }
+    });
+
+    // Pause the server socket subscription and resume it after having
+    // connected a number client sockets. Then connect more client
+    // sockets.
+    subscription.pause();
+    var connectCount = 0;
+    for (int i = 0; i < socketCount; i++) {
+      SecureSocket.connect(HOST_NAME, server.port).then((connection) {
+        connection.close();
+      });
+    }
+    new Timer(500, (_) {
+      subscription.resume();
+      resumed = true;
+      for (int i = 0; i < socketCount; i++) {
+        SecureSocket.connect(HOST_NAME, server.port).then((connection) {
+          connection.close();
+        });
+      }
+    });
+  });
+}
+
+
+testCloseServer() {
+  const int socketCount = 3;
+  var endCount = 0;
+  ReceivePort port = new ReceivePort();
+  List ends = [];
+
+  SecureServerSocket.bind(SERVER_ADDRESS, 0, 15, CERTIFICATE).then((server) {
+    Expect.isTrue(server.port > 0);
+    void checkDone() {
+      if (ends.length < 2 * socketCount) return;
+      for (var end in ends) {
+        end.destroy();
+      }
+      server.close();
+      port.close();
+    }
+
+    server.listen((connection) {
+      ends.add(connection);
+      checkDone();
+    });
+
+    for (int i = 0; i < socketCount; i++) {
+      SecureSocket.connect(HOST_NAME, server.port).then((connection) {
+        ends.add(connection);
+        checkDone();
+      });
+    }
+  });
+}
+
+
+main() {
+  Path scriptDir = new Path(new Options().script).directoryPath;
+  Path certificateDatabase = scriptDir.append('pkcert');
+  SecureSocket.initialize(database: certificateDatabase.toNativePath(),
+                          password: 'dartdart',
+                          useBuiltinRoots: false);
+
+  testCloseOneEnd("client");
+  testCloseOneEnd("server");
+  testCloseBothEnds();
+  testPauseServerSocket();
+  testCloseServer();
+  // TODO(whesse): Add testPauseSocket from raw_socket_test.dart.
+  // TODO(whesse): Add testCancelResubscribeSocket from raw_socket_test.dart.
+}
diff --git a/tests/standalone/io/secure_server_socket_test.dart b/tests/standalone/io/secure_server_socket_test.dart
new file mode 100644
index 0000000..cadabf3
--- /dev/null
+++ b/tests/standalone/io/secure_server_socket_test.dart
@@ -0,0 +1,218 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+const SERVER_ADDRESS = "127.0.0.1";
+const HOST_NAME = "localhost";
+const CERTIFICATE = "localhost_cert";
+
+void testArguments() {
+  Expect.throws(() =>
+      SecureServerSocket.bind(SERVER_ADDRESS, 65536, 5, CERTIFICATE));
+  Expect.throws(() =>
+      SecureServerSocket.bind(SERVER_ADDRESS, -1, CERTIFICATE));
+  Expect.throws(() =>
+      SecureServerSocket.bind(SERVER_ADDRESS, 0, -1, CERTIFICATE));
+}
+
+void testSimpleBind() {
+  ReceivePort port = new ReceivePort();
+  SecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((s) {
+    Expect.isTrue(s.port > 0);
+    s.close();
+    port.close();
+  });
+}
+
+void testInvalidBind() {
+  int count = 0;
+  ReceivePort port = new ReceivePort();
+  port.receive((_, __) { count++; if (count == 3) port.close(); });
+
+  // Bind to a unknown DNS name.
+  SecureServerSocket.bind("ko.faar.__hest__", 0, 5, CERTIFICATE).then((_) {
+    Expect.fail("Failure expected");
+  }).catchError((e) {
+    Expect.isTrue(e.error is SocketIOException);
+    port.toSendPort().send(1);
+  });
+
+  // Bind to an unavaliable IP-address.
+  SecureServerSocket.bind("8.8.8.8", 0, 5, CERTIFICATE).then((_) {
+    Expect.fail("Failure expected");
+  }).catchError((e) {
+    Expect.isTrue(e.error is SocketIOException);
+    port.toSendPort().send(1);
+  });
+
+  // Bind to a port already in use.
+  // Either an error or a successful bind is allowed.
+  // Windows platforms allow multiple binding to the same socket, with
+  // unpredictable results.
+  SecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((s) {
+    SecureServerSocket.bind(SERVER_ADDRESS,
+                            s.port,
+                            5,
+                            CERTIFICATE).then((t) {
+      Expect.equals('windows', Platform.operatingSystem);
+      Expect.equals(s.port, t.port);
+      s.close();
+      t.close();
+      port.toSendPort().send(1);
+    }).catchError((e) {
+      Expect.notEquals('windows', Platform.operatingSystem);
+      Expect.isTrue(e.error is SocketIOException);
+      s.close();
+      port.toSendPort().send(1);
+    });
+  });
+}
+
+void testSimpleConnect(String certificate) {
+  ReceivePort port = new ReceivePort();
+  SecureServerSocket.bind(SERVER_ADDRESS, 0, 5, certificate).then((server) {
+    var clientEndFuture = SecureSocket.connect(HOST_NAME, server.port);
+    server.listen((serverEnd) {
+      clientEndFuture.then((clientEnd) {
+        clientEnd.close();
+        serverEnd.close();
+        server.close();
+        port.close();
+      });
+    });
+  });
+}
+
+void testSimpleConnectFail(String certificate) {
+  ReceivePort port = new ReceivePort();
+  SecureServerSocket.bind(SERVER_ADDRESS, 0, 5, certificate).then((server) {
+    var clientEndFuture = SecureSocket.connect(HOST_NAME, server.port)
+      .then((clientEnd) {
+        Expect.fail("No client connection expected.");
+      })
+      .catchError((e) {
+        Expect.isTrue(e is AsyncError);
+        Expect.isTrue(e.error is SocketIOException);
+      });
+    server.listen((serverEnd) {
+      Expect.fail("No server connection expected.");
+    },
+    onError: (e) {
+      Expect.isTrue(e is AsyncError);
+      Expect.isTrue(e.error is SocketIOException);
+      clientEndFuture.then((_) => port.close());
+    });
+  });
+}
+
+void testServerListenAfterConnect() {
+  ReceivePort port = new ReceivePort();
+  SecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((server) {
+    Expect.isTrue(server.port > 0);
+    var clientEndFuture = SecureSocket.connect(HOST_NAME, server.port);
+    new Timer(500, (_) {
+      server.listen((serverEnd) {
+        clientEndFuture.then((clientEnd) {
+          clientEnd.close();
+          serverEnd.close();
+          server.close();
+          port.close();
+        });
+      });
+    });
+  });
+}
+
+void testSimpleReadWrite() {
+  // This test creates a server and a client connects. The client then
+  // writes and the server echos. When the server has finished its
+  // echo it half-closes. When the client gets the close event is
+  // closes fully.
+  ReceivePort port = new ReceivePort();
+
+  const messageSize = 1000;
+
+  List<int> createTestData() {
+    List<int> data = new List.fixedLength(messageSize);
+    for (int i = 0; i < messageSize; i++) {
+      data[i] = i & 0xff;
+    }
+    return data;
+  }
+
+  void verifyTestData(List<int> data) {
+    Expect.equals(messageSize, data.length);
+    List<int> expected = createTestData();
+    for (int i = 0; i < messageSize; i++) {
+      Expect.equals(expected[i], data[i]);
+    }
+  }
+
+  SecureServerSocket.bind(SERVER_ADDRESS, 0, 5, CERTIFICATE).then((server) {
+    server.listen((client) {
+      int bytesRead = 0;
+      int bytesWritten = 0;
+      List<int> data = new List.fixedLength(messageSize);
+
+      client.listen(
+        (buffer) {
+          Expect.isTrue(bytesWritten == 0);
+          data.setRange(bytesRead, buffer.length, buffer);
+          bytesRead += buffer.length;
+          if (bytesRead == data.length) {
+            verifyTestData(data);
+            client.add(data);
+            client.close();
+          }
+        },
+        onDone: () {
+          server.close();
+        });
+    });
+
+    SecureSocket.connect(HOST_NAME, server.port).then((socket) {
+      int bytesRead = 0;
+      int bytesWritten = 0;
+      List<int> dataSent = createTestData();
+      List<int> dataReceived = new List<int>.fixedLength(dataSent.length);
+      socket.add(dataSent);
+      socket.close();  // Can also be delayed.
+      socket.listen(
+        (List<int> buffer) {
+          dataReceived.setRange(bytesRead, buffer.length, buffer);
+          bytesRead += buffer.length;
+        },
+        onDone: () {
+          verifyTestData(dataReceived);
+          socket.close();
+          port.close();
+        });
+    });
+  });
+}
+
+main() {
+  Path scriptDir = new Path(new Options().script).directoryPath;
+  Path certificateDatabase = scriptDir.append('pkcert');
+  SecureSocket.initialize(database: certificateDatabase.toNativePath(),
+                          password: 'dartdart',
+                          useBuiltinRoots: false);
+  testArguments();
+  testSimpleBind();
+  testInvalidBind();
+  testSimpleConnect(CERTIFICATE);
+  testSimpleConnect("CN=localhost");
+  testSimpleConnectFail("not_a_nickname");
+  testSimpleConnectFail("CN=notARealDistinguishedName");
+  testServerListenAfterConnect();
+  testSimpleReadWrite();
+}
diff --git a/tests/standalone/io/secure_server_stream_test.dart b/tests/standalone/io/secure_server_stream_test.dart
deleted file mode 100644
index d99e93e..0000000
--- a/tests/standalone/io/secure_server_stream_test.dart
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-import "dart:isolate";
-
-const SERVER_ADDRESS = "127.0.0.1";
-const HOST_NAME = "localhost";
-
-class SecureTestServer {
-  void onConnection(Socket connection) {
-    numConnections++;
-    var input = connection.inputStream;
-    String received = "";
-    input.onData = () {
-      received = received.concat(new String.fromCharCodes(input.read()));
-    };
-    input.onClosed = () {
-      Expect.isTrue(received.contains("Hello from client "));
-      String name = received.substring(received.indexOf("client ") + 7);
-      connection.outputStream.write("Welcome, client $name".charCodes);
-      connection.outputStream.close();
-    };
-  }
-
-  void errorHandlerServer(Exception e) {
-    Expect.fail("Server socket error $e");
-  }
-
-  int start() {
-    server = new SecureServerSocket(SERVER_ADDRESS, 0, 10, "CN=$HOST_NAME");
-    Expect.isNotNull(server);
-    server.onConnection = onConnection;
-    server.onError = errorHandlerServer;
-    return server.port;
-  }
-
-  void stop() {
-    server.close();
-  }
-
-  int numConnections = 0;
-  SecureServerSocket server;
-}
-
-class SecureTestClient {
-  SecureTestClient(int this.port, String this.name) {
-    socket = new SecureSocket(HOST_NAME, port);
-    numRequests++;
-    socket.outputStream.write("Hello from client $name".charCodes);
-    socket.outputStream.close();
-    socket.inputStream.onData = () {
-      reply = reply.concat(new String.fromCharCodes(socket.inputStream.read()));
-    };
-    socket.inputStream.onClosed = this.done;
-    reply = "";
-  }
-
-  void done() {
-    Expect.equals("Welcome, client $name", reply);
-    numReplies++;
-    if (numReplies == CLIENT_NAMES.length) {
-      Expect.equals(numRequests, numReplies);
-      EndTest();
-    }
-  }
-
-  static int numRequests = 0;
-  static int numReplies = 0;
-
-  int port;
-  String name;
-  SecureSocket socket;
-  String reply;
-}
-
-Function EndTest;
-
-const CLIENT_NAMES = const ['able', 'baker', 'camera', 'donut', 'echo'];
-
-void main() {
-  ReceivePort keepAlive = new ReceivePort();
-  Path scriptDir = new Path(new Options().script).directoryPath;
-  Path certificateDatabase = scriptDir.append('pkcert');
-  SecureSocket.initialize(database: certificateDatabase.toNativePath(),
-                          password: 'dartdart');
-
-  var server = new SecureTestServer();
-  int port = server.start();
-
-  EndTest = () {
-    Expect.equals(CLIENT_NAMES.length, server.numConnections);
-    server.stop();
-    keepAlive.close();
-  };
-
-  for (var x in CLIENT_NAMES) {
-    new SecureTestClient(port, x);
-  }
-}
diff --git a/tests/standalone/io/secure_server_test.dart b/tests/standalone/io/secure_server_test.dart
deleted file mode 100644
index f039284..0000000
--- a/tests/standalone/io/secure_server_test.dart
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-import "dart:isolate";
-
-const SERVER_ADDRESS = "127.0.0.1";
-const HOST_NAME = "localhost";
-
-void WriteAndClose(Socket socket, String message) {
-  var data = message.charCodes;
-  int written = 0;
-  void write() {
-    written += socket.writeList(data, written, data.length - written);
-    if (written < data.length) {
-      socket.onWrite = write;
-    } else {
-      socket.close(true);
-    }
-  }
-  write();
-}
-
-class SecureTestServer {
-  void onConnection(Socket connection) {
-    connection.onConnect = () {
-      numConnections++;
-    };
-    String received = "";
-    connection.onData = () {
-      received = received.concat(new String.fromCharCodes(connection.read()));
-    };
-    connection.onClosed = () {
-      Expect.isTrue(received.contains("Hello from client "));
-      String name = received.substring(received.indexOf("client ") + 7);
-      WriteAndClose(connection, "Welcome, client $name");
-    };
-  }
-
-  void errorHandlerServer(Exception e) {
-    Expect.fail("Server socket error $e");
-  }
-
-  int start() {
-    server = new SecureServerSocket(SERVER_ADDRESS, 0, 10, "CN=$HOST_NAME");
-    Expect.isNotNull(server);
-    server.onConnection = onConnection;
-    server.onError = errorHandlerServer;
-    return server.port;
-  }
-
-  void stop() {
-    server.close();
-  }
-
-  int numConnections = 0;
-  SecureServerSocket server;
-}
-
-class SecureTestClient {
-  SecureTestClient(int this.port, String this.name) {
-    socket = new SecureSocket(HOST_NAME, port);
-    socket.onConnect = this.onConnect;
-    socket.onData = () {
-      reply = reply.concat(new String.fromCharCodes(socket.read()));
-    };
-    socket.onClosed = done;
-    reply = "";
-  }
-
-  void onConnect() {
-    numRequests++;
-    WriteAndClose(socket, "Hello from client $name");
-  }
-
-  void done() {
-    Expect.equals("Welcome, client $name", reply);
-    numReplies++;
-    if (numReplies == CLIENT_NAMES.length) {
-      Expect.equals(numRequests, numReplies);
-      EndTest();
-    }
-  }
-
-  static int numRequests = 0;
-  static int numReplies = 0;
-
-  int port;
-  String name;
-  SecureSocket socket;
-  String reply;
-}
-
-Function EndTest;
-
-const CLIENT_NAMES = const ['able', 'baker', 'camera', 'donut', 'echo'];
-
-void main() {
-  ReceivePort keepAlive = new ReceivePort();
-  Path scriptDir = new Path(new Options().script).directoryPath;
-  Path certificateDatabase = scriptDir.append('pkcert');
-  SecureSocket.initialize(database: certificateDatabase.toNativePath(),
-                          password: 'dartdart',
-                          useBuiltinRoots: false);
-
-  var server = new SecureTestServer();
-  int port = server.start();
-
-  EndTest = () {
-    Expect.equals(CLIENT_NAMES.length, server.numConnections);
-    server.stop();
-    keepAlive.close();
-  };
-
-  for (var x in CLIENT_NAMES) {
-    new SecureTestClient(port, x);
-  }
-}
diff --git a/tests/standalone/io/secure_session_resume_test.dart b/tests/standalone/io/secure_session_resume_test.dart
index 76746eb..b1cf5ebf 100644
--- a/tests/standalone/io/secure_session_resume_test.dart
+++ b/tests/standalone/io/secure_session_resume_test.dart
@@ -1,7 +1,7 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
-
+//
 // This test tests TLS session resume, by making multiple client connections
 // on the same port to the same server, with a delay of 200 ms between them.
 // The unmodified secure_server_test creates all sessions simultaneously,
@@ -10,6 +10,11 @@
 //
 // Session resume is currently disabled - see issue
 // https://code.google.com/p/dart/issues/detail?id=7230
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
 
 import "dart:async";
 import "dart:io";
@@ -17,119 +22,54 @@
 
 const SERVER_ADDRESS = "127.0.0.1";
 const HOST_NAME = "localhost";
-
-void WriteAndClose(Socket socket, String message) {
-  var data = message.charCodes;
-  int written = 0;
-  void write() {
-    written += socket.writeList(data, written, data.length - written);
-    if (written < data.length) {
-      socket.onWrite = write;
-    } else {
-      socket.close(true);
-    }
-  }
-  write();
+const CERTIFICATE = "localhost_cert";
+Future<SecureServerSocket> startServer() {
+  return SecureServerSocket.bind(SERVER_ADDRESS,
+                                 0,
+                                 5,
+                                 CERTIFICATE).then((server) {
+    server.listen((SecureSocket client) {
+      client.reduce(<int>[], (message, data) => message..addAll(data))
+          .then((message) {
+            String received = new String.fromCharCodes(message);
+            Expect.isTrue(received.contains("Hello from client "));
+            String name = received.substring(received.indexOf("client ") + 7);
+            client.add("Welcome, client $name".charCodes);
+            client.close();
+          });
+    });
+    return server;
+  });
 }
 
-class SecureTestServer {
-  void onConnection(Socket connection) {
-    connection.onConnect = () {
-      numConnections++;
-    };
-    String received = "";
-    connection.onData = () {
-      received = received.concat(new String.fromCharCodes(connection.read()));
-    };
-    connection.onClosed = () {
-      Expect.isTrue(received.contains("Hello from client "));
-      String name = received.substring(received.indexOf("client ") + 7);
-      WriteAndClose(connection, "Welcome, client $name");
-    };
-  }
-
-  void errorHandlerServer(Exception e) {
-    Expect.fail("Server socket error $e");
-  }
-
-  int start() {
-    server = new SecureServerSocket(SERVER_ADDRESS, 0, 10, "CN=$HOST_NAME");
-    Expect.isNotNull(server);
-    server.onConnection = onConnection;
-    server.onError = errorHandlerServer;
-    return server.port;
-  }
-
-  void stop() {
-    server.close();
-  }
-
-  int numConnections = 0;
-  SecureServerSocket server;
+Future testClient(server, name) {
+  return SecureSocket.connect(HOST_NAME, server.port).then((socket) {
+    socket.add("Hello from client $name".charCodes);
+    socket.close();
+    return socket.reduce(<int>[], (message, data) => message..addAll(data))
+        .then((message) {
+          Expect.listEquals("Welcome, client $name".charCodes, message);
+          return server;
+        });
+  });
 }
 
-class SecureTestClient {
-  SecureTestClient(int this.port, String this.name) {
-    socket = new SecureSocket(HOST_NAME, port);
-    socket.onConnect = this.onConnect;
-    socket.onData = () {
-      reply = reply.concat(new String.fromCharCodes(socket.read()));
-    };
-    socket.onClosed = done;
-    reply = "";
-  }
-
-  void onConnect() {
-    numRequests++;
-    WriteAndClose(socket, "Hello from client $name");
-  }
-
-  void done() {
-    Expect.equals("Welcome, client $name", reply);
-    numReplies++;
-    if (numReplies == CLIENT_NAMES.length) {
-      Expect.equals(numRequests, numReplies);
-      EndTest();
-    }
-  }
-
-  static int numRequests = 0;
-  static int numReplies = 0;
-
-  int port;
-  String name;
-  SecureSocket socket;
-  String reply;
-}
-
-Function EndTest;
-
-const CLIENT_NAMES = const ['able', 'baker'];
-
 void main() {
-  ReceivePort keepAlive = new ReceivePort();
   Path scriptDir = new Path(new Options().script).directoryPath;
   Path certificateDatabase = scriptDir.append('pkcert');
   SecureSocket.initialize(database: certificateDatabase.toNativePath(),
-                          password: 'dartdart',
-                          useBuiltinRoots: false);
-
-  var server = new SecureTestServer();
-  int port = server.start();
-
-  EndTest = () {
-    Expect.equals(CLIENT_NAMES.length, server.numConnections);
-    server.stop();
-    keepAlive.close();
-  };
+                          password: 'dartdart');
 
   Duration delay = const Duration(milliseconds: 0);
   Duration delay_between_connections = const Duration(milliseconds: 300);
 
-  for (var x in CLIENT_NAMES) {
-    new Timer(delay, () {
-      new SecureTestClient(port, x);
-    });
-    delay += delay_between_connections;
-  }
+  startServer()
+      .then((server) => Future.wait(
+          ['able', 'baker', 'charlie', 'dozen', 'elapse']
+          .map((name) {
+            delay += delay_between_connections;
+            return new Future.delayed(delay, () => server)
+            .then((server) => testClient(server, name));
+          })))
+      .then((servers) => servers.first.close());
 }
diff --git a/tests/standalone/io/secure_socket_argument_test.dart b/tests/standalone/io/secure_socket_argument_test.dart
new file mode 100644
index 0000000..7fda4a4
--- /dev/null
+++ b/tests/standalone/io/secure_socket_argument_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:io";
+
+void main() {
+  Expect.throws(() => SecureSocket.initialize(database: "foo.txt"));
+  Expect.throws(() => SecureSocket.initialize(password: false));
+  Expect.throws(() => SecureSocket.initialize(useBuiltinRoots: 7));
+  SecureSocket.initialize();
+}
diff --git a/tests/standalone/io/secure_socket_bad_certificate_test.dart b/tests/standalone/io/secure_socket_bad_certificate_test.dart
index d53dd93..4e8bc0e 100644
--- a/tests/standalone/io/secure_socket_bad_certificate_test.dart
+++ b/tests/standalone/io/secure_socket_bad_certificate_test.dart
@@ -4,6 +4,8 @@
 //
 // VMOptions=
 // VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_write --short_socket_read
 // The --short_socket_write option does not work with external server
 // www.google.dk.  Add this to the test when we have secure server sockets.
 // See TODO below.
@@ -12,26 +14,14 @@
 import "dart:isolate";
 import "dart:io";
 
-void WriteAndClose(Socket socket, String message) {
-  var data = message.charCodes;
-  int written = 0;
-  void write() {
-    written += socket.writeList(data, written, data.length - written);
-    if (written < data.length) {
-      socket.onWrite = write;
-    } else {
-      socket.close(true);
-    }
-  }
-  write();
-}
-
 void main() {
+  ReceivePort keepAlive = new ReceivePort();
   SecureSocket.initialize(useBuiltinRoots: false);
   testCertificateCallback(host: "www.google.dk",
                           acceptCertificate: false).then((_) {
     testCertificateCallback(host: "www.google.dk",
                             acceptCertificate: true).then((_) {
+                                keepAlive.close();
       // TODO(7153): Open a receive port, and close it when we get here.
       // Currently, it can happen that neither onClosed or onError is called.
       // So we never reach this point. Diagnose this and fix.
@@ -40,36 +30,33 @@
 }
 
 Future testCertificateCallback({String host, bool acceptCertificate}) {
-  Completer completer = new Completer();
-  var secure = new SecureSocket(host, 443);
-  List<String> chunks = <String>[];
-  secure.onConnect = () {
-    Expect.isTrue(acceptCertificate);
-    WriteAndClose(secure, "GET / HTTP/1.0\r\nHost: $host\r\n\r\n");
-  };
-  secure.onBadCertificate = (_) { };
-  secure.onBadCertificate = null;
-  Expect.throws(() => secure.onBadCertificate = 7,
-                (e) => e is TypeError || e is SocketIOException);
-  secure.onBadCertificate = (X509Certificate certificate) {
+  Expect.throws(
+      () {
+        var x = 7;
+        SecureSocket.connect(host, 443, onBadCertificate: x);
+      },
+      (e) => e is ArgumentError || e is TypeError);
+
+  bool badCertificateCallback(X509Certificate certificate) {
     Expect.isTrue(certificate.subject.contains("O=Google Inc"));
     Expect.isTrue(certificate.startValidity < new DateTime.now());
     Expect.isTrue(certificate.endValidity > new DateTime.now());
     return acceptCertificate;
   };
-  secure.onData = () {
-    Expect.isTrue(acceptCertificate);
-    chunks.add(new String.fromCharCodes(secure.read()));
-  };
-  secure.onClosed = () {
-    Expect.isTrue(acceptCertificate);
-    String fullPage = chunks.join();
-    Expect.isTrue(fullPage.contains('</body></html>'));
-    completer.complete(null);
-  };
-  secure.onError = (e) {
-    Expect.isFalse(acceptCertificate);
-    completer.complete(null);
-  };
-  return completer.future;
+
+  return SecureSocket.connect(host,
+                              443,
+                              onBadCertificate: badCertificateCallback)
+      .then((socket) {
+        Expect.isTrue(acceptCertificate);
+        socket.add("GET / HTTP/1.0\r\nHost: $host\r\n\r\n".charCodes);
+        socket.close();
+        return socket.reduce(<int>[], (message, data)  => message..addAll(data))
+            .then((message) {
+              String received = new String.fromCharCodes(message);
+              Expect.isTrue(received.contains('</body></html>'));
+            });
+      }).catchError((e) {
+        Expect.isFalse(acceptCertificate);
+      });
 }
diff --git a/tests/standalone/io/secure_socket_test.dart b/tests/standalone/io/secure_socket_test.dart
index f010444..fec1115 100644
--- a/tests/standalone/io/secure_socket_test.dart
+++ b/tests/standalone/io/secure_socket_test.dart
@@ -4,57 +4,29 @@
 //
 // VMOptions=
 // VMOptions=--short_socket_read
-// The --short_socket_write option does not work with external server
-// www.google.dk.  Add this to the test when we have secure server sockets.
-// See TODO below.
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
 
 import "dart:isolate";
 import "dart:io";
 
-void WriteAndClose(Socket socket, String message) {
-  var data = message.charCodes;
-  int written = 0;
-  void write() {
-    written += socket.writeList(data, written, data.length - written);
-    if (written < data.length) {
-      socket.onWrite = write;
-    } else {
-      socket.close(true);
-    }
-  }
-  write();
-}
-
 void main() {
   ReceivePort keepAlive = new ReceivePort();
   SecureSocket.initialize();
-  // TODO(3593): Use a Dart HTTPS server for this test.
-  // When we use a Dart HTTPS server, allow --short_socket_write. The flag
-  // causes fragmentation of the client hello message, which doesn't seem to
-  // work with www.google.dk.
-  var secure = new SecureSocket("www.google.dk", 443);
   List<String> chunks = <String>[];
-  secure.onConnect = () {
-    WriteAndClose(secure, "GET / HTTP/1.0\r\nHost: www.google.dk\r\n\r\n");
-  };
-  var useReadList;  // Mutually recursive onData callbacks.
-  void useRead() {
-    var data = secure.read();
-    var received = new String.fromCharCodes(data);
-    chunks.add(received);
-    secure.onData = useReadList;
-  }
-  useReadList = () {
-    var buffer = new List.fixedLength(2000);
-    int len = secure.readList(buffer, 0, 2000);
-    var received = new String.fromCharCodes(buffer.getRange(0, len));
-    chunks.add(received);
-    secure.onData = useRead;
-  };
-  secure.onData = useRead;
-  secure.onClosed = () {
-    String fullPage = chunks.join();
-    Expect.isTrue(fullPage.contains('</body></html>'));
-    keepAlive.close();
-  };
+  SecureSocket.connect("www.google.dk", 443).then((socket) {
+    socket.add("GET / HTTP/1.0\r\nHost: www.google.dk\r\n\r\n".charCodes);
+    socket.close();
+    socket.listen(
+      (List<int> data) {
+        var received = new String.fromCharCodes(data);
+        chunks.add(received);
+      },
+      onDone: () {
+        String fullPage = chunks.join();
+        Expect.isTrue(fullPage.contains('</body></html>'));
+        keepAlive.close();
+      },
+      onError: (e) => Expect.fail("Unexpected error $e"));
+  });
 }
diff --git a/tests/standalone/io/secure_stream_test.dart b/tests/standalone/io/secure_stream_test.dart
deleted file mode 100644
index 11acb7b..0000000
--- a/tests/standalone/io/secure_stream_test.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-//
-// VMOptions=
-// VMOptions=--short_socket_read
-// The --short_socket_write option does not work with external server
-// www.google.dk.  Add this to the test when we have secure server sockets.
-// See TODO below.
-
-import "dart:isolate";
-import "dart:io";
-
-void main() {
-  ReceivePort keepAlive = new ReceivePort();
-  SecureSocket.initialize();
-  // TODO(3593): Use a Dart HTTPS server for this test.
-  // When we use a Dart HTTPS server, allow --short_socket_write. The flag
-  // causes fragmentation of the client hello message, which doesn't seem to
-  // work with www.google.dk.
-  var secure = new SecureSocket("www.google.dk", 443);
-  List<String> chunks = <String>[];
-  var input = secure.inputStream;
-  var output = secure.outputStream;
-
-  output.write("GET / HTTP/1.0\r\nHost: www.google.dk\r\n\r\n".charCodes);
-  output.close();
-  input.onData = () {
-    chunks.add(new String.fromCharCodes(input.read()));
-  };
-  input.onClosed = () {
-    String fullPage = chunks.join();
-    Expect.isTrue(fullPage.contains('</body></html>'));
-    keepAlive.close();
-  };
-}
diff --git a/tests/standalone/io/socket_close_test.dart b/tests/standalone/io/socket_close_test.dart
index 3dddf4e..dcb90a2 100644
--- a/tests/standalone/io/socket_close_test.dart
+++ b/tests/standalone/io/socket_close_test.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
@@ -41,7 +41,7 @@
 
   void sendData() {
 
-    void dataHandler() {
+    void dataHandler(bytes) {
       switch (_mode) {
         case 0:
         case 1:
@@ -52,8 +52,7 @@
         case 4:
         case 5:
         case 6:
-          List<int> b = new List<int>.fixedLength(5);
-          _readBytes += _socket.readList(b, 0, 5);
+          _readBytes += bytes.length;
           if ((_readBytes % 5) == 0) {
             _dataEvents++;
           }
@@ -63,23 +62,23 @@
       }
     }
 
-    void closeHandler() {
+    void closeHandler(socket) {
       _closeEvents++;
       switch (_mode) {
         case 0:
         case 1:
-          Expect.fail("No close expected");
+          socket.close();
           break;
         case 2:
         case 3:
-          _socket.close();
+          socket.close();
           proceed();
           break;
         case 4:
           proceed();
           break;
         case 5:
-          _socket.close();
+          socket.close();
           proceed();
           break;
         case 6:
@@ -92,32 +91,28 @@
 
     void errorHandler(Exception e) {
       _errorEvents++;
-      _socket.close();
+      socket.close();
     }
 
-    void connectHandler() {
-      _socket.onData = dataHandler;
-      _socket.onClosed = closeHandler;
-      _socket.onError = errorHandler;
+    void connectHandler(socket) {
+      socket.listen(
+          dataHandler,
+          onDone: () => closeHandler(socket),
+          onError: (error) => errorHandler(socket));
 
       void writeHello() {
-        int bytesWritten = 0;
-        while (bytesWritten != 5) {
-          bytesWritten += _socket.writeList("Hello".charCodes,
-                                            bytesWritten,
-                                            5 - bytesWritten);
-        }
+        socket.add("Hello".charCodes);
       }
 
       _iterations++;
       switch (_mode) {
         case 0:
-          _socket.close();
+          socket.destroy();
           proceed();
           break;
         case 1:
           writeHello();
-          _socket.close();
+          socket.destroy();
           proceed();
           break;
         case 2:
@@ -126,23 +121,21 @@
           break;
         case 4:
           writeHello();
-          _socket.close(true);
+          socket.close();  // Half close.
           break;
         case 5:
           writeHello();
           break;
         case 6:
           writeHello();
-          _socket.close(true);
+          socket.close();  // Half close.
           break;
         default:
           Expect.fail("Unknown test mode");
       }
     }
 
-    _socket = new Socket(SocketCloseServer.HOST, _port);
-    Expect.equals(true, _socket != null);
-    _socket.onConnect = connectHandler;
+    Socket.connect(SocketCloseServer.HOST, _port).then(connectHandler);
   }
 
   void initialize() {
@@ -164,7 +157,7 @@
       case 0:
       case 1:
         Expect.equals(0, _dataEvents);
-        Expect.equals(0, _closeEvents);
+        Expect.equals(ITERATIONS, _closeEvents);
         break;
       case 2:
         Expect.equals(0, _dataEvents);
@@ -172,6 +165,10 @@
         break;
       case 3:
       case 4:
+        Expect.isTrue(_dataEvents <= ITERATIONS);
+        Expect.isTrue(_dataEvents >= 0);
+        Expect.equals(ITERATIONS, _closeEvents);
+        break;
       case 5:
       case 6:
         Expect.equals(ITERATIONS, _dataEvents);
@@ -186,7 +183,6 @@
   int _port;
   ReceivePort _receivePort;
   SendPort _sendPort;
-  Socket _socket;
   List<int> _buffer;
   int _readBytes;
   int _dataEvents;
@@ -219,56 +215,51 @@
   void connectionHandler(ConnectionData data) {
     var connection = data.connection;
 
-    void readBytes(whenFiveBytes) {
-      List<int> b = new List<int>.fixedLength(5);
-      data.readBytes += connection.readList(b, 0, 5);
+    void readBytes(bytes, whenFiveBytes) {
+      data.readBytes += bytes.length;
+      Expect.isTrue(data.readBytes <= 5);
       if (data.readBytes == 5) {
         whenFiveBytes();
       }
     }
 
     void writeHello() {
-      int bytesWritten = 0;
-      while (bytesWritten != 5) {
-        bytesWritten += connection.writeList("Hello".charCodes,
-                                             bytesWritten,
-                                             5 - bytesWritten);
-      }
+      connection.add("Hello".charCodes);
     }
 
-    void dataHandler() {
+    void dataHandler(bytes) {
       switch (_mode) {
         case 0:
           Expect.fail("No data expected");
           break;
         case 1:
-          readBytes(() { _dataEvents++; });
+          readBytes(bytes, () { _dataEvents++; });
           break;
         case 2:
-          readBytes(() {
+          readBytes(bytes, () {
             _dataEvents++;
-            connection.close();
+            connection.destroy();
           });
           break;
         case 3:
-          readBytes(() {
+          readBytes(bytes, () {
             _dataEvents++;
             writeHello();
-            connection.close();
+            connection.destroy();
           });
           break;
         case 4:
-          readBytes(() {
+          readBytes(bytes, () {
             _dataEvents++;
             writeHello();
           });
           break;
         case 5:
         case 6:
-          readBytes(() {
+          readBytes(bytes, () {
             _dataEvents++;
             writeHello();
-            connection.close(true);
+            connection.close();  // Half close.
           });
           break;
         default:
@@ -281,18 +272,19 @@
       connection.close();
     }
 
-    void errorHandler(Exception e) {
+    void errorHandler(e) {
       Expect.fail("Socket error $e");
     }
 
     _iterations++;
 
-    connection.onData = dataHandler;
-    connection.onClosed = closeHandler;
-    connection.onError = errorHandler;
+    connection.listen(
+        dataHandler,
+        onDone: closeHandler,
+        onError: errorHandler);
   }
 
-  void errorHandlerServer(Exception e) {
+  void errorHandlerServer(e) {
     Expect.fail("Server socket error");
   }
 
@@ -310,13 +302,14 @@
           Expect.equals(ITERATIONS, _closeEvents);
           break;
         case 1:
-          Expect.equals(ITERATIONS, _dataEvents);
+          Expect.isTrue(_dataEvents <= ITERATIONS);
+          Expect.isTrue(_dataEvents >= 0);
           Expect.equals(ITERATIONS, _closeEvents);
           break;
         case 2:
         case 3:
           Expect.equals(ITERATIONS, _dataEvents);
-          Expect.equals(0, _closeEvents);
+          Expect.equals(ITERATIONS, _closeEvents);
           break;
         case 4:
         case 5:
@@ -345,14 +338,17 @@
       _closeEvents = 0;
       _iterations = 0;
       _mode = message;
-      _server = new ServerSocket(HOST, 0, 10);
-      Expect.equals(true, _server != null);
-      _server.onConnection = (connection) {
-        var data = new ConnectionData(connection);
-        connectionHandler(data);
-      };
-      _server.onError = errorHandlerServer;
-      replyTo.send(_server.port, null);
+      ServerSocket.bind().then((server) {
+        _server = server;
+        _server.listen(
+          (socket) {
+            var data = new ConnectionData(socket);
+            connectionHandler(data);
+          },
+          onError: errorHandlerServer
+        );
+        replyTo.send(_server.port, null);
+      });
     } else {
       Timer.run(waitForResult);
     }
@@ -372,10 +368,10 @@
 main() {
   // Run the close test in these different "modes".
   // 0: Client closes without sending at all.
-  // 1: Client sends and closes.
-  // 2: Client sends. Server closes.
-  // 3: Client sends. Server responds and closes.
-  // 4: Client sends and half-closes. Server responds and closes.
+  // 1: Client sends and destroys.
+  // 2: Client sends. Server destroys.
+  // 3: Client sends. Server responds and destroys.
+  // 4: Client sends and half-closes. Server responds and destroys.
   // 5: Client sends. Server responds and half closes.
   // 6: Client sends and half-closes. Server responds and half closes.
   var tests = 7;
diff --git a/tests/standalone/io/socket_exception_test.dart b/tests/standalone/io/socket_exception_test.dart
index fe5399f..7624ac7 100644
--- a/tests/standalone/io/socket_exception_test.dart
+++ b/tests/standalone/io/socket_exception_test.dart
@@ -1,180 +1,213 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
 // Tests socket exceptions.
 
+import "dart:async";
 import "dart:isolate";
 import "dart:io";
 
 class SocketExceptionTest {
 
-  static const PORT = 0;
-  static const HOST = "127.0.0.1";
-
   static void serverSocketExceptionTest() {
     bool exceptionCaught = false;
     bool wrongExceptionCaught = false;
 
-    ServerSocket server = new ServerSocket(HOST, PORT, 10);
-    Expect.equals(true, server != null);
-    server.close();
-    try {
+    ServerSocket.bind().then((server) {
+      Expect.isNotNull(server);
       server.close();
-    } on SocketIOException catch(ex) {
-      exceptionCaught = true;
-    } on Exception catch (ex) {
-      wrongExceptionCaught = true;
-    }
-    Expect.equals(false, exceptionCaught);
-    Expect.equals(true, !wrongExceptionCaught);
+      try {
+        server.close();
+      } on SocketIOException catch(ex) {
+        exceptionCaught = true;
+      } catch (ex) {
+        wrongExceptionCaught = true;
+      }
+      Expect.equals(false, exceptionCaught);
+      Expect.equals(true, !wrongExceptionCaught);
 
-    // Test invalid host.
-    Expect.throws(() => new ServerSocket("__INVALID_HOST__", PORT, 10),
-                  (e) => e is SocketIOException);
+      // Test invalid host.
+      ServerSocket.bind("__INVALID_HOST__")
+        .then((server) { })
+        .catchError((e) => e is SocketIOException);
+    });
+  }
+
+  static void serverSocketCloseListenTest() {
+    var port = new ReceivePort();
+    ServerSocket.bind().then((server) {
+      Socket.connect("127.0.0.1", server.port).then((socket) {
+        server.close();
+        server.listen(
+          (incoming) => Expect.fail("Unexpected socket"),
+          onDone: port.close);
+      });
+    });
+  }
+
+  static void serverSocketListenCloseTest() {
+    var port = new ReceivePort();
+    ServerSocket.bind().then((server) {
+      Socket.connect("127.0.0.1", server.port).then((socket) {
+        server.listen(
+          (incoming) => server.close(),
+          onDone: port.close());
+      });
+    });
   }
 
   static void clientSocketExceptionTest() {
     bool exceptionCaught = false;
     bool wrongExceptionCaught = false;
 
-    ServerSocket server = new ServerSocket(HOST, PORT, 10);
-    Expect.equals(true, server != null);
-    int port = server.port;
-    Socket client = new Socket(HOST, port);
-    client.onConnect = () {
-      Expect.equals(true, client != null);
-      InputStream input = client.inputStream;
-      OutputStream output = client.outputStream;
-      client.close();
-      try {
+    ServerSocket.bind().then((server) {
+      Expect.isNotNull(server);
+     int port = server.port;
+      Socket.connect("127.0.0.1", port).then((client) {
+       Expect.isNotNull(client);
         client.close();
-      } on SocketIOException catch(ex) {
-        exceptionCaught = true;
-      } on Exception catch (ex) {
-        wrongExceptionCaught = true;
-      }
-      Expect.equals(false, exceptionCaught);
-      Expect.equals(true, !wrongExceptionCaught);
-      exceptionCaught = false;
-      try {
-        client.available();
-      } on SocketIOException catch(ex) {
-        exceptionCaught = true;
-      } on Exception catch (ex) {
-        wrongExceptionCaught = true;
-      }
-      Expect.equals(true, exceptionCaught);
-      Expect.equals(true, !wrongExceptionCaught);
-      exceptionCaught = false;
-      try {
-        List<int> buffer = new List<int>.fixedLength(10);
-        client.readList(buffer, 0 , 10);
-      } on SocketIOException catch(ex) {
-        exceptionCaught = true;
-      } on Exception catch (ex) {
-        wrongExceptionCaught = true;
-      }
-      Expect.equals(true, exceptionCaught);
-      Expect.equals(true, !wrongExceptionCaught);
-      exceptionCaught = false;
-      try {
-        List<int> buffer = new List<int>.fixedLength(10);
-        client.writeList(buffer, 0, 10);
-      } on SocketIOException catch(ex) {
-        exceptionCaught = true;
-      } on Exception catch (ex) {
-        wrongExceptionCaught = true;
-      }
-      Expect.equals(true, exceptionCaught);
-      Expect.equals(true, !wrongExceptionCaught);
-      exceptionCaught = false;
-      try {
-        List<int> buffer = new List<int>.fixedLength(42);
-        input.readInto(buffer, 0, 12);
-      } on SocketIOException catch(ex) {
-        exceptionCaught = true;
-      } on Exception catch (ex) {
-        wrongExceptionCaught = true;
-      }
-      Expect.equals(true, exceptionCaught);
-      Expect.equals(true, !wrongExceptionCaught);
-      exceptionCaught = false;
-      try {
-        List<int> buffer = new List<int>.fixedLength(42);
-        output.writeFrom(buffer, 0, 12);
-      } on SocketIOException catch(ex) {
-        exceptionCaught = true;
-      } on Exception catch (ex) {
-        wrongExceptionCaught = true;
-      }
-      Expect.equals(true, exceptionCaught);
-      Expect.equals(true, !wrongExceptionCaught);
+        try {
+          client.close();
+        } on SocketIOException catch(ex) {
+          exceptionCaught = true;
+        } catch (ex) {
+          wrongExceptionCaught = true;
+        }
+        Expect.isFalse(exceptionCaught);
+        Expect.isFalse(wrongExceptionCaught);
+        try {
+          client.destroy();
+        } on SocketIOException catch(ex) {
+          exceptionCaught = true;
+        } catch (ex) {
+          print(ex);
+          wrongExceptionCaught = true;
+        }
+        Expect.isFalse(exceptionCaught);
+        Expect.isFalse(wrongExceptionCaught);
+        try {
+          List<int> buffer = new List<int>.fixedLength(10);
+          client.add(buffer);
+        } on StateError catch (ex) {
+          exceptionCaught = true;
+        } catch (ex) {
+          wrongExceptionCaught = true;
+        }
+        Expect.isTrue(exceptionCaught);
+        Expect.isFalse(wrongExceptionCaught);
 
-      server.close();
-    };
+        server.close();
+      });
+    });
   }
 
-  static void indexOutOfRangeExceptionTest() {
-    bool exceptionCaught = false;
-    bool wrongExceptionCaught = false;
+  static void clientSocketDestroyNoErrorTest() {
+    ServerSocket.bind().then((server) {
+      server.listen((socket) {
+        socket.pipe(socket);
+      });
+      Socket.connect("127.0.0.1", server.port).then((client) {
+        client.listen((data) {}, onDone: server.close);
+        client.destroy();
+      });
+    });
+  }
 
-    ServerSocket server = new ServerSocket(HOST, PORT, 10);
-    Expect.equals(true, server != null);
-    int port = server.port;
-    Socket client = new Socket(HOST, port);
-    client.onConnect = () {
-      Expect.equals(true, client != null);
-      try {
-        List<int> buffer = new List<int>.fixedLength(10);
-        client.readList(buffer, -1, 1);
-      } on RangeError catch (ex) {
-        exceptionCaught = true;
-      } on Exception catch (ex) {
-        wrongExceptionCaught = true;
-      }
-      Expect.equals(true, exceptionCaught);
-      Expect.equals(true, !wrongExceptionCaught);
-      exceptionCaught = false;
+  static void clientSocketAddDestroyNoErrorTest() {
+    ServerSocket.bind().then((server) {
+      server.listen((socket) {
+        // Passive block data by not sobscribing to socket.
+      });
+      Socket.connect("127.0.0.1", server.port).then((client) {
+        client.listen((data) {}, onDone: server.close);
+        client.add(new List.fixedLength(1024 * 1024, fill: 0));
+        client.destroy();
+      });
+    });
+  }
 
-      try {
-        List<int> buffer = new List<int>.fixedLength(10);
-        client.readList(buffer, 0, -1);
-      } on RangeError catch (ex) {
-        exceptionCaught = true;
-      } on Exception catch (ex) {
-        wrongExceptionCaught = true;
-      }
-      Expect.equals(true, exceptionCaught);
-      Expect.equals(true, !wrongExceptionCaught);
-      exceptionCaught = false;
+  static void clientSocketAddCloseNoErrorTest() {
+    ServerSocket.bind().then((server) {
+      var completer = new Completer();
+      server.listen((socket) {
+        // The socket is 'paused' until the future completes.
+        completer.future.then((_) => socket.pipe(socket));
+      });
+      Socket.connect("127.0.0.1", server.port).then((client) {
+        const int SIZE = 1024 * 1024;
+        int count = 0;
+        client.listen(
+            (data) => count += data.length,
+            onDone: () {
+              Expect.equals(SIZE, count);
+              server.close();
+            });
+        client.add(new List.fixedLength(SIZE, fill: 0));
+        client.close();
+        // Start piping now.
+        completer.complete(null);
+      });
+    });
+  }
 
-      try {
-        List<int> buffer = new List<int>.fixedLength(10);
-        client.writeList(buffer, -1, 1);
-      } on RangeError catch (ex) {
-        exceptionCaught = true;
-      } on Exception catch (ex) {
-        wrongExceptionCaught = true;
-      }
-      Expect.equals(true, exceptionCaught);
-      Expect.equals(true, !wrongExceptionCaught);
-      exceptionCaught = false;
+  static void clientSocketAddCloseErrorTest() {
+    ServerSocket.bind().then((server) {
+      var completer = new Completer();
+      server.listen((socket) {
+        completer.future.then((_) => socket.destroy());
+      });
+      Socket.connect("127.0.0.1", server.port).then((client) {
+        const int SIZE = 1024 * 1024;
+        int errors = 0;
+        client.listen(
+            (data) => Expect.fail("Unexpected data"),
+            onError: (error) {
+              Expect.isTrue(error.error is SocketIOException);
+              errors++;
+            },
+            onDone: () {
+              // We get either a close or an error followed by a close
+              // on the socket.  Whether we get both depends on
+              // whether the system notices the error for the read
+              // event or only for the write event.
+              Expect.isTrue(errors <= 1);
+              server.close();
+            });
+        client.add(new List.fixedLength(SIZE, fill: 0));
+        // Destroy other socket now.
+        completer.complete(null);
+        var port = new ReceivePort();
+        client.done.then(
+            (_) {
+              Expect.fail("Expected error");
+            },
+            onError: (error) {
+              Expect.isTrue(error.error is SocketIOException);
+              port.close();
+            });
+      });
+    });
+  }
 
-      try {
-        List<int> buffer = new List<int>.fixedLength(10);
-        client.writeList(buffer, 0, -1);
-      } on RangeError catch (ex) {
-        exceptionCaught = true;
-      } on Exception catch (ex) {
-        wrongExceptionCaught = true;
-      }
-      Expect.equals(true, exceptionCaught);
-      Expect.equals(true, !wrongExceptionCaught);
-
-      server.close();
-      client.close();
-    };
+  static void clientSocketAddCloseResultErrorTest() {
+    ServerSocket.bind().then((server) {
+      var completer = new Completer();
+      server.listen((socket) {
+        completer.future.then((_) => socket.destroy());
+      });
+      Socket.connect("127.0.0.1", server.port).then((client) {
+        const int SIZE = 1024 * 1024;
+        int errors = 0;
+        client.add(new List.fixedLength(SIZE, fill: 0));
+        client.close();
+        client.done.catchError((error) {
+          server.close();
+        });
+        // Destroy other socket now.
+        completer.complete(null);
+      });
+    });
   }
 
   static void unknownHostTest() {
@@ -182,15 +215,22 @@
     var port = new ReceivePort();
     port.receive((message, replyTo) => null);
 
-    Socket s =  new Socket("hede.hule.hest", 1234);
-    s.onError = (e) => port.close();
-    s.onConnect = () => Expect.fail("Connection completed");
+    Socket.connect("hede.hule.hest", 1234)
+        .then((socket) => Expect.fail("Connection completed"))
+        .catchError((e) => port.close(), test: (e) => e is SocketIOException);
+
   }
 
   static void testMain() {
     serverSocketExceptionTest();
+    serverSocketCloseListenTest();
+    serverSocketListenCloseTest();
     clientSocketExceptionTest();
-    indexOutOfRangeExceptionTest();
+    clientSocketDestroyNoErrorTest();
+    clientSocketAddDestroyNoErrorTest();
+    clientSocketAddCloseNoErrorTest();
+    clientSocketAddCloseErrorTest();
+    clientSocketAddCloseResultErrorTest();
     unknownHostTest();
   }
 }
diff --git a/tests/standalone/io/socket_info_test.dart b/tests/standalone/io/socket_info_test.dart
index e35eab6..f3b675f 100644
--- a/tests/standalone/io/socket_info_test.dart
+++ b/tests/standalone/io/socket_info_test.dart
@@ -1,23 +1,24 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:io";
 
 void testHostAndPort() {
-  ServerSocket server = new ServerSocket("127.0.0.1", 0, 5);
+  ServerSocket.bind().then((server) {
 
-  Socket clientSocket = new Socket("127.0.0.1", server.port);
+    Socket.connect("127.0.0.1", server.port).then((clientSocket) {
+      server.listen((socket) {
+        Expect.equals(socket.port, server.port);
+        Expect.equals(clientSocket.port, socket.remotePort);
+        Expect.equals(clientSocket.remotePort, socket.port);
+        Expect.equals(socket.remoteHost, "127.0.0.1");
+        Expect.equals(clientSocket.remoteHost, "127.0.0.1");
 
-  server.onConnection = (Socket socket) {
-    Expect.equals(socket.port, server.port);
-    Expect.equals(clientSocket.port, socket.remotePort);
-    Expect.equals(clientSocket.remotePort, socket.port);
-    Expect.equals(socket.remoteHost, "127.0.0.1");
-    Expect.equals(clientSocket.remoteHost, "127.0.0.1");
-
-    server.close();
-  };
+        server.close();
+      });
+    });
+  });
 }
 
 void main() {
diff --git a/tests/standalone/io/socket_invalid_arguments_test.dart b/tests/standalone/io/socket_invalid_arguments_test.dart
index 91108b4..7505aaa 100644
--- a/tests/standalone/io/socket_invalid_arguments_test.dart
+++ b/tests/standalone/io/socket_invalid_arguments_test.dart
@@ -1,8 +1,9 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:io";
+import "dart:isolate";
 
 class NotAnInteger {
   operator==(other) => other == 1;
@@ -16,39 +17,41 @@
 }
 
 testSocketCreation(host, port) {
-  var s = new Socket(host, port);
-  s.onError = (e) => null;
-  s.onConnect = () => Expect.fail("Shouldn't get connected");
+  Socket.connect(host, port)
+      .then((socket) => Expect.fail("Shouldn't get connected"))
+      .catchError((e) => null, test: (e) => e is SocketIOException)
+      .catchError((e) => null, test: (e) => e is ArgumentError);
 }
 
-testReadList(buffer, offset, length) {
-  var server = new ServerSocket("127.0.0.1", 0, 5);
-  var s = new Socket("127.0.0.1", server.port);
-  s.onConnect = () {
-    try { s.readList(buffer, offset, length); } catch (e) {}
-    s.close();
-  };
-  s.onError = (e) => null;
-}
-
-testWriteList(buffer, offset, length) {
-  var server = new ServerSocket("127.0.0.1", 0, 5);
-  var s = new Socket("127.0.0.1", server.port);
-  s.onConnect = () {
-    try { s.writeList(buffer, offset, length); } catch (e) {}
-    s.close();
-  };
-  s.onError = (e) => null;
+testAdd(buffer) {
+  ServerSocket.bind("127.0.0.1", 0, 5).then((server) {
+    server.listen((socket) => socket.destroy());
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+      int errors = 0;
+      socket.done.catchError((e) { errors++; });
+      socket.listen(
+          (_) { },
+          onError: (error) {
+            Expect.fail("Error on stream");
+          },
+          onDone: () {
+            Expect.equals(1, errors);
+            socket.destroy();
+            server.close();
+          });
+      socket.add(buffer);
+    });
+  });
 }
 
 testServerSocketCreation(address, port, backlog) {
   var server;
+  var port = new ReceivePort();
   try {
-    server = new ServerSocket(address, port, backlog);
-    server.onError = (e) => null;
-    server.onConnection = (c) => Expect.fail("Shouldn't get connection");
+    ServerSocket.bind(address, port, backlog)
+        .then((_) { Expect.fail("ServerSocket bound"); });
   } catch (e) {
-    // ignore
+    port.close();
   }
 }
 
@@ -56,15 +59,14 @@
   testSocketCreation(123, 123);
   testSocketCreation("string", null);
   testSocketCreation(null, null);
-  testReadList(null, 123, 123);
-  testReadList(new NotAList(), 1, 1);
-  testReadList([1, 2, 3], new NotAnInteger(), new NotAnInteger());
-  testReadList([1, 2, 3], 1, new NotAnInteger());
-  testWriteList(null, 123, 123);
-  testWriteList(new NotAList(), 1, 1);
-  testWriteList([1, 2, 3], new NotAnInteger(), new NotAnInteger());
-  testWriteList([1, 2, 3], 1, new NotAnInteger());
-  testWriteList([1, 2, 3], new NotAnInteger(), 1);
+  testAdd(null);
+  testAdd(new NotAList());
+  testAdd(42);
+  // TODO(8233): Throw ArgumentError from API implementation.
+  // testAdd([-1]);
+  // testAdd([2222222222222222222222222222222]);
+  // testAdd([1, 2, 3, null]);
+  // testAdd([new NotAnInteger()]);
   testServerSocketCreation(123, 123, 123);
   testServerSocketCreation("string", null, null);
   testServerSocketCreation("string", 123, null);
diff --git a/tests/standalone/io/socket_many_connections_test.dart b/tests/standalone/io/socket_many_connections_test.dart
index 3aabf60..c313fe1 100644
--- a/tests/standalone/io/socket_many_connections_test.dart
+++ b/tests/standalone/io/socket_many_connections_test.dart
@@ -28,19 +28,18 @@
       _connections++;
       if (_connections == CONNECTIONS) {
         for (int i = 0; i < CONNECTIONS; i++) {
-          _sockets[i].close();
+          _sockets[i].destroy();
         }
-        shutdown();
+        close();
       }
     }
 
     for (int i = 0; i < CONNECTIONS; i++) {
-      _sockets[i] = new Socket(TestingServer.HOST, _port);
-      if (_sockets[i] != null) {
-        _sockets[i].onConnect = connectHandler;
-      } else {
-        Expect.fail("socket creation failed");
-      }
+      Socket.connect(TestingServer.HOST, _port).then((socket) {
+        Expect.isNotNull(socket);
+        _sockets[i] = socket;
+        connectHandler();
+      });
     }
   }
 
@@ -52,7 +51,7 @@
     _sendPort.send(TestingServer.INIT, _receivePort.toSendPort());
   }
 
-  void shutdown() {
+  void close() {
     _sendPort.send(TestingServer.SHUTDOWN, _receivePort.toSendPort());
     _receivePort.close();
   }
@@ -79,14 +78,16 @@
       connection.close();
     }
 
-    void errorHandler(Exception e) {
+    void errorHandler(e) {
       print("Socket error $e");
       connection.close();
     }
 
     _connections++;
-    connection.onClosed = closeHandler;
-    connection.onError = errorHandler;
+    connection.listen(
+        (data) {},
+        onDone: closeHandler,
+        onError: errorHandler);
   }
 
   int _connections = 0;
diff --git a/tests/standalone/io/socket_port_test.dart b/tests/standalone/io/socket_port_test.dart
index 841e1444..009a522 100644
--- a/tests/standalone/io/socket_port_test.dart
+++ b/tests/standalone/io/socket_port_test.dart
@@ -1,21 +1,20 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:io";
 
 void testPort() {
-  ServerSocket server = new ServerSocket("127.0.0.1", 0, 5);
-
-  Socket clientSocket = new Socket("127.0.0.1", server.port);
-
-  server.onConnection = (Socket socket) {
-    Expect.equals(socket.port, server.port);
-    Expect.equals(clientSocket.port, socket.remotePort);
-    Expect.equals(clientSocket.remotePort, socket.port);
-
-    server.close();
-  };
+  ServerSocket.bind().then((server) {
+    Socket.connect("127.0.0.1", server.port).then((clientSocket) {
+      server.listen((Socket socket) {
+          Expect.equals(socket.port, server.port);
+        Expect.equals(clientSocket.port, socket.remotePort);
+        Expect.equals(clientSocket.remotePort, socket.port);
+        server.close();
+      });
+    });
+  });
 }
 
 void main() {
diff --git a/tests/standalone/io/socket_stream_close_test.dart b/tests/standalone/io/socket_stream_close_test.dart
deleted file mode 100644
index 4082c81..0000000
--- a/tests/standalone/io/socket_stream_close_test.dart
+++ /dev/null
@@ -1,418 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-//
-// VMOptions=
-// VMOptions=--short_socket_read
-// VMOptions=--short_socket_write
-// VMOptions=--short_socket_read --short_socket_write
-//
-// Test socket close events.
-
-import 'dart:async';
-import 'dart:io';
-import 'dart:isolate';
-
-const SERVERSHUTDOWN = -1;
-const ITERATIONS = 10;
-
-
-class SocketClose {
-
-  SocketClose.start(this._mode, this._donePort)
-      : _receivePort = new ReceivePort(),
-        _sendPort = null,
-        _readBytes = 0,
-        _dataEvents = 0,
-        _closeEvents = 0,
-        _errorEvents = 0,
-        _iterations = 0 {
-    _sendPort = spawnFunction(startSocketCloseServer);
-    initialize();
-  }
-
-  void proceed() {
-    if (_iterations < ITERATIONS) {
-      Timer.run(sendData);
-    } else {
-      shutdown();
-    }
-  }
-
-  void sendData() {
-
-    void dataHandler() {
-      switch (_mode) {
-        case 0:
-        case 1:
-        case 2:
-          Expect.fail("No data expected");
-          break;
-        case 3:
-        case 4:
-        case 5:
-        case 6:
-        case 7:
-        case 8:
-          var read = _socket.inputStream.read();
-          _readBytes += read.length;
-          if ((_readBytes % 5) == 0) {
-            _dataEvents++;
-          }
-          break;
-        default:
-          Expect.fail("Unknown test mode");
-      }
-    }
-
-    void closeHandler() {
-      _closeEvents++;
-      switch (_mode) {
-        case 0:
-        case 1:
-          break;
-        case 2:
-        case 3:
-        case 4:
-          _socket.outputStream.close();
-          proceed();
-          break;
-        case 5:
-          proceed();
-          break;
-        case 6:
-          _socket.outputStream.close();
-          proceed();
-          break;
-        case 7:
-        case 8:
-          proceed();
-          break;
-        default:
-          Expect.fail("Unknown test mode");
-      }
-    }
-
-    void errorHandler(Exception e) {
-      _errorEvents++;
-      _socket.close();
-    }
-
-    void connectHandler() {
-      _socket.inputStream.onData = dataHandler;
-      _socket.inputStream.onClosed = closeHandler;
-      _socket.onError = errorHandler;
-
-      _iterations++;
-      switch (_mode) {
-        case 0:
-          _socket.inputStream.close();
-          proceed();
-          break;
-        case 1:
-          _socket.outputStream.write("Hello".charCodes);
-          _socket.outputStream.onNoPendingWrites = () {
-            _socket.inputStream.close();
-            proceed();
-          };
-          break;
-        case 2:
-        case 3:
-        case 4:
-          _socket.outputStream.write("Hello".charCodes);
-          break;
-        case 5:
-          _socket.outputStream.write("Hello".charCodes);
-          _socket.outputStream.onNoPendingWrites = () {
-            _socket.outputStream.close();
-          };
-          break;
-        case 6:
-          _socket.outputStream.write("Hello".charCodes);
-          break;
-        case 7:
-        case 8:
-          _socket.outputStream.write("Hello".charCodes);
-          _socket.outputStream.onNoPendingWrites = () {
-            _socket.outputStream.close();
-          };
-          break;
-        default:
-          Expect.fail("Unknown test mode");
-      }
-    }
-
-    _socket = new Socket(SocketCloseServer.HOST, _port);
-    Expect.equals(true, _socket != null);
-    _socket.onConnect = connectHandler;
-  }
-
-  void initialize() {
-    _receivePort.receive((var message, SendPort replyTo) {
-      _port = message;
-      proceed();
-    });
-    _sendPort.send(_mode, _receivePort.toSendPort());
-  }
-
-  void shutdown() {
-    _sendPort.send(SERVERSHUTDOWN, _receivePort.toSendPort());
-    _receivePort.receive((message, ignore) {
-      _donePort.send(null);
-      _receivePort.close();
-    });
-
-    switch (_mode) {
-      case 0:
-      case 1:
-        Expect.equals(0, _dataEvents);
-        Expect.equals(0, _closeEvents);
-        break;
-      case 2:
-        Expect.equals(0, _dataEvents);
-        Expect.equals(ITERATIONS, _closeEvents);
-        break;
-      case 3:
-        Expect.equals(ITERATIONS, _dataEvents);
-        Expect.equals(ITERATIONS, _closeEvents);
-        break;
-      case 4:
-        Expect.equals(ITERATIONS, _closeEvents);
-        break;
-      case 5:
-      case 6:
-      case 7:
-      case 8:
-        Expect.equals(ITERATIONS, _dataEvents);
-        Expect.equals(ITERATIONS, _closeEvents);
-        break;
-      default:
-        Expect.fail("Unknown test mode");
-    }
-    Expect.equals(0, _errorEvents);
-  }
-
-  int _port;
-  ReceivePort _receivePort;
-  SendPort _sendPort;
-  Socket _socket;
-  List<int> _buffer;
-  int _readBytes;
-  int _dataEvents;
-  int _closeEvents;
-  int _errorEvents;
-  int _iterations;
-  int _mode;
-  SendPort _donePort;
-}
-
-
-class ConnectionData {
-  ConnectionData(Socket this.connection) : readBytes = 0;
-  Socket connection;
-  int readBytes;
-}
-
-
-void startSocketCloseServer() {
-  var server = new SocketCloseServer();
-  port.receive(server.dispatch);
-}
-
-
-class SocketCloseServer {
-
-  static const HOST = "127.0.0.1";
-
-  SocketCloseServer() : super() {}
-
-  void connectionHandler(ConnectionData data) {
-    var connection = data.connection;
-
-    void readBytes(whenFiveBytes) {
-      var read = connection.inputStream.read();
-      data.readBytes += read.length;
-      if (data.readBytes == 5) {
-        whenFiveBytes();
-      }
-    }
-
-    void dataHandler() {
-      switch (_mode) {
-        case 0:
-          Expect.fail("No data expected");
-          break;
-        case 1:
-          readBytes(() {
-            _dataEvents++;
-          });
-          break;
-        case 2:
-          readBytes(() {
-            _dataEvents++;
-            connection.inputStream.close();
-          });
-          break;
-        case 3:
-          readBytes(() {
-            _dataEvents++;
-            connection.outputStream.write("Hello".charCodes);
-            connection.outputStream.onNoPendingWrites = () {
-              connection.inputStream.close();
-            };
-          });
-          break;
-        case 4:
-          readBytes(() {
-            _dataEvents++;
-            connection.outputStream.write("Hello".charCodes);
-            connection.inputStream.close();
-          });
-          break;
-        case 5:
-          readBytes(() {
-            _dataEvents++;
-            connection.outputStream.write("Hello".charCodes);
-          });
-          break;
-        case 6:
-        case 7:
-          readBytes(() {
-            _dataEvents++;
-            connection.outputStream.write("Hello".charCodes);
-            connection.outputStream.onNoPendingWrites = () {
-              connection.outputStream.close();
-            };
-          });
-          break;
-        case 8:
-          readBytes(() {
-            _dataEvents++;
-            connection.outputStream.write("Hello".charCodes);
-            connection.outputStream.close();
-          });
-          break;
-        default:
-          Expect.fail("Unknown test mode");
-      }
-    }
-
-    void closeHandler() {
-      _closeEvents++;
-      connection.outputStream.close();
-    }
-
-    void errorHandler(Exception e) {
-      Expect.fail("Socket error $e");
-    }
-
-    _iterations++;
-
-    connection.inputStream.onData = dataHandler;
-    connection.inputStream.onClosed = closeHandler;
-    connection.onError = errorHandler;
-  }
-
-  void errorHandlerServer(Exception e) {
-    Expect.fail("Server socket error");
-  }
-
-  waitForResult() {
-    // Make sure all iterations have been run. In multiple of these
-    // scenarios it is possible to get the SERVERSHUTDOWN message
-    // before we have received the last close event on the
-    // server. In these cases we wait for the correct number of
-    // close events.
-    if (_iterations == ITERATIONS &&
-        (_closeEvents == ITERATIONS ||
-         (_mode == 2 || _mode == 3 || _mode == 4))) {
-      switch (_mode) {
-        case 0:
-          Expect.equals(0, _dataEvents);
-          Expect.equals(ITERATIONS, _closeEvents);
-          break;
-        case 1:
-          Expect.equals(ITERATIONS, _dataEvents);
-          Expect.equals(ITERATIONS, _closeEvents);
-          break;
-        case 2:
-        case 3:
-        case 4:
-          Expect.equals(ITERATIONS, _dataEvents);
-          Expect.equals(0, _closeEvents);
-          break;
-        case 5:
-        case 6:
-        case 7:
-        case 8:
-          Expect.equals(ITERATIONS, _dataEvents);
-          Expect.equals(ITERATIONS, _closeEvents);
-          break;
-        default:
-          Expect.fail("Unknown test mode");
-      }
-      Expect.equals(0, _errorEvents);
-      _server.close();
-      port.close();
-      _donePort.send(null);
-    } else {
-      new Timer(new Duration(milliseconds: 100), waitForResult);
-    }
-  }
-
-  void dispatch(message, replyTo) {
-    _donePort = replyTo;
-    if (message != SERVERSHUTDOWN) {
-      _readBytes = 0;
-      _errorEvents = 0;
-      _dataEvents = 0;
-      _closeEvents = 0;
-      _iterations = 0;
-      _mode = message;
-      _server = new ServerSocket(HOST, 0, 10);
-      Expect.equals(true, _server != null);
-      _server.onConnection = (connection) {
-        var data = new ConnectionData(connection);
-        connectionHandler(data);
-      };
-      _server.onError = errorHandlerServer;
-      replyTo.send(_server.port, null);
-    } else {
-      Timer.run(waitForResult);
-    }
-  }
-
-  ServerSocket _server;
-  SendPort _donePort;
-  int _readBytes;
-  int _errorEvents;
-  int _dataEvents;
-  int _closeEvents;
-  int _iterations;
-  int _mode;
-}
-
-
-main() {
-  // Run the close test in these different "modes".
-  // 0: Client closes without sending at all.
-  // 1: Client sends and closes.
-  // 2: Client sends. Server closes.
-  // 3: Client sends. Server responds and closes.
-  // 4: Client sends. Server responds and closes without waiting for everything
-  //    being sent.
-  // 5: Client sends and half-closes. Server responds and closes.
-  // 6: Client sends. Server responds and half closes.
-  // 7: Client sends and half-closes. Server responds and half closes.
-  // 8: Client sends and half-closes. Server responds and half closes without
-  //    explicitly waiting for everything being sent.
-  var tests = 9;
-  var port = new ReceivePort();
-  var completed = 0;
-  port.receive((message, ignore) {
-    if (++completed == tests) port.close();
-  });
-  for (var i = 0; i < tests; i++) {
-    new SocketClose.start(i, port.toSendPort());
-  }
-}
diff --git a/tests/standalone/io/socket_test.dart b/tests/standalone/io/socket_test.dart
new file mode 100644
index 0000000..6ce7a75
--- /dev/null
+++ b/tests/standalone/io/socket_test.dart
@@ -0,0 +1,230 @@
+// 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.
+//
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+void testArguments() {
+  Expect.throws(() => ServerSocket.bind("127.0.0.1", 65536));
+  Expect.throws(() => ServerSocket.bind("127.0.0.1", -1));
+  Expect.throws(() => ServerSocket.bind("127.0.0.1", 0, -1));
+}
+
+void testSimpleBind() {
+  ReceivePort port = new ReceivePort();
+  ServerSocket.bind().then((s) {
+    Expect.isTrue(s.port > 0);
+    port.close();
+  });
+}
+
+void testInvalidBind() {
+  int count = 0;
+  ReceivePort port = new ReceivePort();
+  port.receive((_, __) { count++; if (count == 3) port.close(); });
+
+  // Bind to a unknown DNS name.
+  ServerSocket.bind("ko.faar.__hest__")
+      .then((_) { Expect.fail("Failure expected"); } )
+      .catchError((e) {
+        Expect.isTrue(e.error is SocketIOException);
+        port.toSendPort().send(1);
+      });
+
+  // Bind to an unavaliable IP-address.
+  ServerSocket.bind("8.8.8.8")
+      .then((_) { Expect.fail("Failure expected"); } )
+      .catchError((e) {
+        Expect.isTrue(e.error is SocketIOException);
+        port.toSendPort().send(1);
+      });
+
+  // Bind to a port already in use.
+  // Either an error or a successful bind is allowed.
+  // Windows platforms allow multiple binding to the same socket, with
+  // unpredictable results.
+  ServerSocket.bind("127.0.0.1")
+      .then((s) {
+        ServerSocket.bind("127.0.0.1", s.port)
+            .then((t) {
+              Expect.equals('windows', Platform.operatingSystem);
+              Expect.equals(s.port, t.port);
+              port.toSendPort().send(1);
+            })
+            .catchError((e) {
+              Expect.notEquals('windows', Platform.operatingSystem);
+              Expect.isTrue(e.error is SocketIOException);
+              port.toSendPort().send(1);
+            });
+      });
+}
+
+void testConnectNoDestroy() {
+  ReceivePort port = new ReceivePort();
+  ServerSocket.bind().then((server) {
+    server.listen((_) { });
+    Socket.connect("127.0.0.1", server.port).then((_) {
+      server.close();
+      port.close();
+    });
+  });
+}
+
+void testConnectImmediateDestroy() {
+  ReceivePort port = new ReceivePort();
+  ServerSocket.bind().then((server) {
+    server.listen((_) { });
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+      socket.destroy();
+      server.close();
+      port.close();
+    });
+  });
+}
+
+void testConnectConsumerClose() {
+  // Connect socket then immediate close the consumer without
+  // listening on the stream.
+  ReceivePort port = new ReceivePort();
+  ServerSocket.bind().then((server) {
+    server.listen((_) { });
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+      socket.close();
+      socket.done.then((_) {
+        socket.destroy();
+        server.close();
+        port.close();
+      });
+    });
+  });
+}
+
+void testConnectConsumerWriteClose() {
+  // Connect socket write some data immediate close the consumer
+  // without listening on the stream.
+  ReceivePort port = new ReceivePort();
+  ServerSocket.bind().then((server) {
+    server.listen((_) { });
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+      socket.add([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+      socket.close();
+      socket.done.then((_) {
+        socket.destroy();
+        server.close();
+        port.close();
+      });
+    });
+  });
+}
+
+void testConnectStreamClose() {
+  // Connect socket and listen on the stream. The server closes
+  // immediately so only a done event is received.
+  ReceivePort port = new ReceivePort();
+  ServerSocket.bind().then((server) {
+    server.listen((client) {
+                    client.close();
+                    client.done.then((_) => client.destroy());
+                  });
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+        bool onDoneCalled = false;
+        socket.listen((_) { Expect.fail("Unexpected data"); },
+                      onDone: () {
+                        Expect.isFalse(onDoneCalled);
+                        onDoneCalled = true;
+                        socket.close();
+                        server.close();
+                        port.close();
+                      });
+    });
+  });
+}
+
+void testConnectStreamDataClose(bool useDestroy) {
+  // Connect socket and listen on the stream. The server sends data
+  // and then closes so both data and a done event is received.
+  List<int> sendData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+  ReceivePort port = new ReceivePort();
+  ServerSocket.bind().then((server) {
+    server.listen(
+        (client) {
+          client.add(sendData);
+          if (useDestroy) {
+            client.destroy();
+          } else {
+            client.close();
+          }
+          client.done.then((_) { if (!useDestroy) { client.destroy(); } });
+        });
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+        List<int> data = [];
+        bool onDoneCalled = false;
+        socket.listen(data.addAll,
+                      onDone: () {
+                        Expect.isFalse(onDoneCalled);
+                        onDoneCalled = true;
+                        if (!useDestroy) Expect.listEquals(sendData, data);
+                        socket.add([0]);
+                        socket.close();
+                        server.close();
+                        port.close();
+                      });
+    });
+  });
+}
+
+void testConnectStreamDataCloseCancel(bool useDestroy) {
+  List<int> sendData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+  ReceivePort port = new ReceivePort();
+  ServerSocket.bind().then((server) {
+    server.listen(
+        (client) {
+          client.add(sendData);
+          if (useDestroy) {
+            client.destroy();
+          } else {
+            client.close();
+          }
+          client.done
+              .then((_) {
+                if (!useDestroy) client.destroy();
+              })
+              .catchError((e) { /* can happen with short writes */ });
+        });
+    Socket.connect("127.0.0.1", server.port).then((socket) {
+        List<int> data = [];
+        bool onDoneCalled = false;
+        var subscription;
+        subscription = socket.listen(
+            (_) {
+              subscription.cancel();
+              socket.close();
+              server.close();
+              port.close();
+            },
+            onDone: () { Expect.fail("Unexpected pipe completion"); });
+    });
+  });
+}
+
+main() {
+  testArguments();
+  testSimpleBind();
+  testInvalidBind();
+  testConnectNoDestroy();
+  testConnectImmediateDestroy();
+  testConnectConsumerClose();
+  testConnectConsumerWriteClose();
+  testConnectStreamClose();
+  testConnectStreamDataClose(true);
+  testConnectStreamDataClose(false);
+  testConnectStreamDataCloseCancel(true);
+  testConnectStreamDataCloseCancel(false);
+}
diff --git a/tests/standalone/io/stream_pipe_test.dart b/tests/standalone/io/stream_pipe_test.dart
index 8a1b910..f663e81 100644
--- a/tests/standalone/io/stream_pipe_test.dart
+++ b/tests/standalone/io/stream_pipe_test.dart
@@ -10,7 +10,6 @@
 
 import "dart:io";
 import "dart:isolate";
-part "testing_server.dart";
 
 // Helper method to be able to run the test from the runtime
 // directory, or the top directory.
@@ -56,112 +55,6 @@
 }
 
 
-// This test does:
-//  1. Opens a socket to the testing server.
-//  2. Pipes the content of a file to that sockets input stream.
-//  3. Creates a temp file.
-//  4. Pipes the socket output stream to the temp file.
-//  5. Expects the original file and the temp file to be equal.
-class PipeServerGame {
-  int count = 0;
-
-  PipeServerGame.start()
-      : _receivePort = new ReceivePort(),
-        _sendPort = null,
-        _messages = 0 {
-    _sendPort = spawnFunction(startPipeServer);
-    initialize();
-  }
-
-  void runTest() {
-
-    void connectHandler() {
-      String srcFileName =
-          getDataFilename("tests/standalone/io/readline_test1.dat");
-
-      OutputStream socketOutput = _socket.outputStream;
-      InputStream fileInput = new File(srcFileName).openInputStream();
-
-      fileInput.onClosed = () {
-        InputStream socketInput = _socket.inputStream;
-        var tempDir = new Directory('').createTempSync();
-        var dstFileName = tempDir.path.concat("/readline_test1.dat");
-        var dstFile = new File(dstFileName);
-        dstFile.createSync();
-        var fileOutput = dstFile.openOutputStream();
-
-        socketInput.onClosed = () {
-          // Check that the resulting file is equal to the initial
-          // file.
-          fileOutput.onClosed = () {
-            bool result = compareFileContent(srcFileName, dstFileName);
-            new File(dstFileName).deleteSync();
-            tempDir.deleteSync();
-            Expect.isTrue(result);
-
-            _socket.close();
-
-            // Run this twice.
-            if (count++ < 2) {
-              runTest();
-            } else {
-              shutdown();
-            }
-          };
-        };
-
-        socketInput.pipe(fileOutput);
-      };
-
-      fileInput.pipe(socketOutput);
-    }
-
-    // Connect to the server.
-    _socket = new Socket(TestingServer.HOST, _port);
-    if (_socket != null) {
-      _socket.onConnect = connectHandler;
-    } else {
-      Expect.fail("socket creation failed");
-    }
-  }
-
-  void initialize() {
-    _receivePort.receive((var message, SendPort replyTo) {
-      _port = message;
-      runTest();
-    });
-    _sendPort.send(TestingServer.INIT, _receivePort.toSendPort());
-  }
-
-  void shutdown() {
-    _sendPort.send(TestingServer.SHUTDOWN, _receivePort.toSendPort());
-    _receivePort.close();
-  }
-
-  int _port;
-  ReceivePort _receivePort;
-  SendPort _sendPort;
-  Socket _socket;
-  int _messages;
-}
-
-
-void startPipeServer() {
-  var server = new PipeServer();
-  port.receive(server.dispatch);
-}
-
-
-// The testing server will simply pipe each connecting sockets input
-// stream to its output stream.
-class PipeServer extends TestingServer {
-  void onConnection(Socket connection) {
-    connection.onError = (Exception e) { Expect.fail("Socket error $e"); };
-    connection.inputStream.pipe(connection.outputStream);
-  }
-}
-
-
 // Test piping from one file to another and closing both streams
 // after wards.
 testFileToFilePipe1() {
@@ -172,22 +65,19 @@
 
   String srcFileName =
       getDataFilename("tests/standalone/io/readline_test1.dat");
-  var srcStream = new File(srcFileName).openInputStream();
+  var srcStream = new File(srcFileName).openRead();
 
   var tempDir = new Directory('').createTempSync();
   String dstFileName = tempDir.path.concat("/readline_test1.dat");
   new File(dstFileName).createSync();
-  var dstStream = new File(dstFileName).openOutputStream();
-
-  dstStream.onClosed = () {
+  var output = new File(dstFileName).openWrite();
+  srcStream.pipe(output).then((_) {
     bool result = compareFileContent(srcFileName, dstFileName);
     new File(dstFileName).deleteSync();
     tempDir.deleteSync();
     Expect.isTrue(result);
     donePort.toSendPort().send(null);
-  };
-
-  srcStream.pipe(dstStream);
+  });
 }
 
 
@@ -202,18 +92,17 @@
   String srcFileName =
       getDataFilename("tests/standalone/io/readline_test1.dat");
   var srcFile = new File(srcFileName);
-  var srcStream = srcFile.openInputStream();
+  var srcStream = srcFile.openRead();
 
   var tempDir = new Directory('').createTempSync();
   var dstFileName = tempDir.path.concat("/readline_test1.dat");
   var dstFile = new File(dstFileName);
   dstFile.createSync();
-  var dstStream = dstFile.openOutputStream();
-
-  srcStream.onClosed = () {
-    dstStream.write([32]);
-    dstStream.close();
-    dstStream.onClosed = () {
+  var output = dstFile.openWrite();
+  output.addStream(srcStream).then((_) {
+    output.add([32]);
+    output.close();
+    output.done.then((_) {
       var src = srcFile.openSync();
       var dst = dstFile.openSync();
       var srcLength = src.lengthSync();
@@ -231,10 +120,8 @@
       dstFile.deleteSync();
       tempDir.deleteSync();
       donePort.toSendPort().send(null);
-    };
-  };
-
-  srcStream.pipe(dstStream, close: false);
+    });
+  });
 }
 
 
@@ -248,42 +135,38 @@
   String srcFileName =
       getDataFilename("tests/standalone/io/readline_test1.dat");
   var srcFile = new File(srcFileName);
-  var srcStream = srcFile.openInputStream();
+  var srcStream = srcFile.openRead();
 
   var tempDir = new Directory('').createTempSync();
   var dstFileName = tempDir.path.concat("/readline_test1.dat");
   var dstFile = new File(dstFileName);
   dstFile.createSync();
-  var dstStream = dstFile.openOutputStream();
-
-  srcStream.onClosed = () {
-    var srcStream2 = srcFile.openInputStream();
-
-    dstStream.onClosed = () {
-      var src = srcFile.openSync();
-      var dst = dstFile.openSync();
-      var srcLength = src.lengthSync();
-      var dstLength = dst.lengthSync();
-      Expect.equals(srcLength * 2, dstLength);
-      Expect.isTrue(compareFileContent(srcFileName,
-                                       dstFileName,
-                                       count: srcLength));
-      Expect.isTrue(compareFileContent(srcFileName,
-                                       dstFileName,
-                                       file2Offset: srcLength,
-                                       count: srcLength));
-      src.closeSync();
-      dst.closeSync();
-      dstFile.deleteSync();
-      tempDir.deleteSync();
-      donePort.toSendPort().send(null);
-    };
-
-    // Pipe another copy of the source file.
-    srcStream2.pipe(dstStream);
-  };
-
-  srcStream.pipe(dstStream, close: false);
+  var output = dstFile.openWrite();
+  output.addStream(srcStream).then((_) {
+    var srcStream2 = srcFile.openRead();
+    output.addStream(srcStream2).then((_) {
+      output.close();
+      output.done.then((_) {
+        var src = srcFile.openSync();
+        var dst = dstFile.openSync();
+        var srcLength = src.lengthSync();
+        var dstLength = dst.lengthSync();
+        Expect.equals(srcLength * 2, dstLength);
+        Expect.isTrue(compareFileContent(srcFileName,
+                                         dstFileName,
+                                         count: srcLength));
+        Expect.isTrue(compareFileContent(srcFileName,
+                                         dstFileName,
+                                         file2Offset: srcLength,
+                                         count: srcLength));
+        src.closeSync();
+        dst.closeSync();
+        dstFile.deleteSync();
+        tempDir.deleteSync();
+        donePort.toSendPort().send(null);
+      });
+    });
+  });
 }
 
 
@@ -291,5 +174,4 @@
   testFileToFilePipe1();
   testFileToFilePipe2();
   testFileToFilePipe3();
-  PipeServerGame echoServerGame = new PipeServerGame.start();
 }
diff --git a/tests/standalone/io/string_decoder_test.dart b/tests/standalone/io/string_decoder_test.dart
index 879cf8c..6a81f95 100644
--- a/tests/standalone/io/string_decoder_test.dart
+++ b/tests/standalone/io/string_decoder_test.dart
@@ -2,49 +2,60 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:async";
 import "dart:io";
 
 void test() {
   // Code point U+10FFFF is the largest code point supported by Dart.
-  //var decoder = _StringDecoders.decoder(Encoding.UTF_8);
-  ListInputStream lis = new ListInputStream();
-  lis.write([0xf0, 0x90, 0x80, 0x80]);  // U+10000
-  lis.write([0xf4, 0x8f, 0xbf, 0xbf]);  // U+10FFFF
-  lis.write([0xf4, 0x90, 0x80, 0x80]);  // U+110000
-  lis.write([0xfa, 0x80, 0x80, 0x80, 0x80]);  //  U+2000000
-  lis.write([0xfd, 0x80, 0x80, 0x80, 0x80, 0x80]);  // U+40000000
-  lis.markEndOfStream();
+  var controller = new StreamController();
+  controller.add([0xf0, 0x90, 0x80, 0x80]);  // U+10000
+  controller.add([0xf4, 0x8f, 0xbf, 0xbf]);  // U+10FFFF
+  controller.add([0xf4, 0x90, 0x80, 0x80]);  // U+110000
+  controller.add([0xfa, 0x80, 0x80, 0x80, 0x80]);  //  U+2000000
+  controller.add([0xfd, 0x80, 0x80, 0x80, 0x80, 0x80]);  // U+40000000
+  controller.close();
 
-  var sis = new StringInputStream(lis);
-  sis.onData = () {
-    var decoded = sis.read();
-    Expect.equals(7, decoded.length);
+  var decoder = new StringDecoder(Encoding.UTF_8, '?'.charCodeAt(0));
+  var stream = controller.stream.transform(decoder);
+  stream.reduce(
+      new StringBuffer(),
+      (b, e) {
+        b.add(e);
+        return b;
+      })
+      .then((b) => b.toString())
+      .then((decoded) {
+        Expect.equals(7, decoded.length);
 
-    var replacementChar = '?'.charCodeAt(0);
-    Expect.equals(0xd800, decoded.charCodeAt(0));
-    Expect.equals(0xdc00, decoded.charCodeAt(1));
-    Expect.equals(0xdbff, decoded.charCodeAt(2));
-    Expect.equals(0xdfff, decoded.charCodeAt(3));
-    Expect.equals(replacementChar, decoded.charCodeAt(4));
-    Expect.equals(replacementChar, decoded.charCodeAt(5));
-    Expect.equals(replacementChar, decoded.charCodeAt(6));
-  };
+        var replacementChar = '?'.charCodeAt(0);
+        Expect.equals(0xd800, decoded.charCodeAt(0));
+        Expect.equals(0xdc00, decoded.charCodeAt(1));
+        Expect.equals(0xdbff, decoded.charCodeAt(2));
+        Expect.equals(0xdfff, decoded.charCodeAt(3));
+        Expect.equals(replacementChar, decoded.charCodeAt(4));
+        Expect.equals(replacementChar, decoded.charCodeAt(5));
+        Expect.equals(replacementChar, decoded.charCodeAt(6));
+      });
 }
 
 void testInvalid() {
-  void invalid(var bytes) {
-    ListInputStream lis = new ListInputStream();
-    lis.write(bytes);
-    lis.markEndOfStream();
-    var sis = new StringInputStream(lis);
-    sis.onData = () { throw "onData not expected"; };
-    sis.onError = (e) { Expect.isTrue(e is DecoderException); };
-    sis.onClosed = () { throw "onClosed not expected"; };
+  void invalid(var bytes, var outputLength) {
+    var controller = new StreamController();
+    controller.add(bytes);
+    controller.close();
+    controller.stream.transform(new StringDecoder()).listen((string) {
+      Expect.equals(outputLength, string.length);
+      for (var i = 0; i < outputLength; i++) {
+        Expect.equals(0xFFFD, string.charCodeAt(i));
+      }
+    });
   }
 
-  invalid([0x80]);
-  invalid([0xff]);
-  invalid([0xf0, 0xc0]);
+  invalid([0x80], 1);
+  invalid([0xff], 1);
+  invalid([0xf0, 0xc0], 1);
+  invalid([0xc0, 0x80], 1);
+  invalid([0xfd, 0x80, 0x80], 3); // Unfinished encoding.
 }
 
 void main() {
diff --git a/tests/standalone/io/string_stream_test.dart b/tests/standalone/io/string_stream_test.dart
deleted file mode 100644
index 4ef0534..0000000
--- a/tests/standalone/io/string_stream_test.dart
+++ /dev/null
@@ -1,335 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-import "dart:isolate";
-
-void testUtf8() {
-  List<int> data = [0x01,
-                    0x7f,
-                    0xc2, 0x80,
-                    0xdf, 0xbf,
-                    0xe0, 0xa0, 0x80,
-                    0xef, 0xbf, 0xbf,
-                    0xf0, 0x9d, 0x84, 0x9e];
-  ListInputStream s = new ListInputStream();
-  s.write(data);
-  s.markEndOfStream();
-  StringInputStream stream = new StringInputStream(s);
-  void stringData() {
-    String s = stream.read();
-    Expect.equals(8, s.length);
-    Expect.equals(new String.fromCharCodes([0x01]), s[0]);
-    Expect.equals(new String.fromCharCodes([0x7f]), s[1]);
-    Expect.equals(new String.fromCharCodes([0x80]), s[2]);
-    Expect.equals(new String.fromCharCodes([0x7ff]), s[3]);
-    Expect.equals(new String.fromCharCodes([0x800]), s[4]);
-    Expect.equals(new String.fromCharCodes([0xffff]), s[5]);
-    Expect.equals(new String.fromCharCodes([0xffff]), s[5]);
-
-    // Surrogate pair for U+1D11E.
-    Expect.equals(new String.fromCharCodes([0xd834, 0xdd1e]),
-                  s.substring(6, 8));
-  }
-  stream.onData = stringData;
-}
-
-void testLatin1() {
-  List<int> data = [0x01,
-                    0x7f,
-                    0x44, 0x61, 0x72, 0x74,
-                    0x80,
-                    0xff];
-  ListInputStream s = new ListInputStream();
-  s.write(data);
-  s.markEndOfStream();
-  StringInputStream stream = new StringInputStream(s, Encoding.ISO_8859_1);
-  void stringData() {
-    String s = stream.read();
-    Expect.equals(8, s.length);
-    Expect.equals(new String.fromCharCodes([0x01]), s[0]);
-    Expect.equals(new String.fromCharCodes([0x7f]), s[1]);
-    Expect.equals("Dart", s.substring(2, 6));
-    Expect.equals(new String.fromCharCodes([0x80]), s[6]);
-    Expect.equals(new String.fromCharCodes([0xff]), s[7]);
-  }
-  stream.onData = stringData;
-}
-
-void testAscii() {
-  List<int> data = [0x01,
-                    0x44, 0x61, 0x72, 0x74,
-                    0x7f];
-  ListInputStream s = new ListInputStream();
-  s.write(data);
-  s.markEndOfStream();
-  StringInputStream stream =
-      new StringInputStream(s, Encoding.ASCII);
-  void stringData() {
-    String s = stream.read();
-    Expect.equals(6, s.length);
-    Expect.equals(new String.fromCharCodes([0x01]), s[0]);
-    Expect.equals("Dart", s.substring(1, 5));
-    Expect.equals(new String.fromCharCodes([0x7f]), s[5]);
-  }
-  stream.onData = stringData;
-}
-
-void testReadLine1() {
-  ListInputStream s = new ListInputStream();
-  StringInputStream stream = new StringInputStream(s);
-  var stage = 0;
-
-  void stringData() {
-    var line;
-    if (stage == 0) {
-      line = stream.readLine();
-      Expect.equals(null, line);
-      stage++;
-      s.markEndOfStream();
-    } else if (stage == 1) {
-      line = stream.readLine();
-      Expect.equals("Line", line);
-      line = stream.readLine();
-      Expect.equals(null, line);
-      stage++;
-    }
-  }
-
-  void streamClosed() {
-    Expect.equals(true, stream.closed);
-    Expect.equals(2, stage);
-  }
-
-  stream.onData = stringData;
-  stream.onClosed = streamClosed;
-  s.write("Line".charCodes);
-}
-
-void testReadLine2() {
-  ListInputStream s = new ListInputStream();
-  StringInputStream stream = new StringInputStream(s);
-  var stage = 0;
-
-  void stringData() {
-    var line;
-    if (stage == 0) {
-      Expect.equals(21, stream.available());
-      line = stream.readLine();
-      Expect.equals("Line1", line);
-      Expect.equals(15, stream.available());
-      line = stream.readLine();
-      Expect.equals("Line2", line);
-      Expect.equals(8, stream.available());
-      line = stream.readLine();
-      Expect.equals("Line3", line);
-      line = stream.readLine();
-      Expect.equals(2, stream.available());
-      Expect.equals(null, line);
-      stage++;
-      s.write("ne4\n".charCodes);
-    } else if (stage == 1) {
-      Expect.equals(6, stream.available());
-      line = stream.readLine();
-      Expect.equals("Line4", line);
-      Expect.equals(0, stream.available());
-      line = stream.readLine();
-      Expect.equals(null, line);
-      stage++;
-      s.write("\n\n\r\n\r\n\r\r".charCodes);
-    } else if (stage == 2) {
-      // Expect 5 empty lines. As long as the stream is not closed the
-      // final \r cannot be interpreted as a end of line.
-      Expect.equals(8, stream.available());
-      for (int i = 0; i < 5; i++) {
-        line = stream.readLine();
-        Expect.equals("", line);
-      }
-      Expect.equals(1, stream.available());
-      line = stream.readLine();
-      Expect.equals(null, line);
-      stage++;
-      s.markEndOfStream();
-    } else if (stage == 3) {
-      // The final \r can now be interpreted as an end of line.
-      Expect.equals(1, stream.available());
-      line = stream.readLine();
-      Expect.equals("", line);
-      line = stream.readLine();
-      Expect.equals(null, line);
-      stage++;
-    }
-  }
-
-  void streamClosed() {
-    Expect.equals(4, stage);
-    Expect.equals(true, stream.closed);
-  }
-
-  stream.onLine = stringData;
-  stream.onClosed = streamClosed;
-  s.write("Line1\nLine2\r\nLine3\rLi".charCodes);
-}
-
-void testReadChunks() {
-  ListInputStream s = new ListInputStream();
-  StringInputStream stream = new StringInputStream(s);
-
-  void stringData() {
-    var data;
-    Expect.equals(8, stream.available());
-    data = stream.read(1);
-    Expect.equals("A", data);
-    Expect.equals(7, stream.available());
-    data = stream.read(2);
-    Expect.equals("BC", data);
-    Expect.equals(5, stream.available());
-    data = stream.read(3);
-    Expect.equals("D12", data);
-    Expect.equals(2, stream.available());
-    data = stream.read();
-    Expect.equals("34", data);
-    Expect.equals(0, stream.available());
-    data = stream.read(1);
-    Expect.equals(null, data);
-    Expect.equals(0, stream.available());
-    data = stream.read(2);
-    Expect.equals(null, data);
-    Expect.equals(0, stream.available());
-    data = stream.read(3);
-    Expect.equals(null, data);
-    Expect.equals(0, stream.available());
-    data = stream.read();
-    Expect.equals(null, data);
-    Expect.equals(0, stream.available());
-  }
-
-  s.write("ABCD1234".charCodes);
-  stream.onData = stringData;
-}
-
-void testReadMixed() {
-  ListInputStream s = new ListInputStream();
-  StringInputStream stream = new StringInputStream(s);
-  var stage = 0;
-
-  void stringData() {
-    var data;
-    if (stage == 0) {
-      Expect.equals(11, stream.available());
-      data = stream.read(2);
-      Expect.equals("A\r", data);
-      Expect.equals(9, stream.available());
-      data = stream.readLine();
-      Expect.equals("", data);
-      Expect.equals(8, stream.available());
-      data = stream.read(4);
-      Expect.equals("BCD\n", data);
-      Expect.equals(4, stream.available());
-      data = stream.readLine();
-      Expect.equals(null, data);
-      data = stream.read(4);
-      Expect.equals("1234", data);
-      s.write("A\r\nBCD\n1234".charCodes);
-      stage++;
-    } else if (stage == 1) {
-      Expect.equals(11, stream.available());
-      data = stream.read(1);
-      Expect.equals("A", data);
-      Expect.equals(10, stream.available());
-      data = stream.read(1);
-      Expect.equals("\r", data);
-      Expect.equals(9, stream.available());
-      data = stream.read(1);
-      Expect.equals("\n", data);
-      Expect.equals(8, stream.available());
-      data = stream.readLine();
-      Expect.equals("BCD", data);
-      data = stream.readLine();
-      Expect.equals(null, data);
-      data = stream.read(4);
-      Expect.equals("1234", data);
-      s.write("A\r\nBCD\n1234".charCodes);
-      stage++;
-    } else if (stage == 2) {
-      Expect.equals(11, stream.available());
-      data = stream.read(7);
-      Expect.equals("A\r\nBCD\n", data);
-      Expect.equals(4, stream.available());
-      data = stream.readLine();
-      Expect.equals(null, data);
-      data = stream.read();
-      Expect.equals("1234", data);
-      stage++;
-      s.markEndOfStream();
-    }
-  }
-
-  void streamClosed() {
-    Expect.equals(3, stage);
-    Expect.equals(true, stream.closed);
-  }
-
-  s.write("A\r\nBCD\n1234".charCodes);
-  stream.onData = stringData;
-  stream.onClosed = streamClosed;
-}
-
-class TestException implements Exception {
-  TestException();
-}
-
-class ErrorInputStream implements InputStream {
-  ErrorInputStream();
-  List<int> read([int len]) => null;
-  int readInto(List<int> buffer, [int offset, int len]) => 0;
-  int available() => 0;
-  void pipe(OutputStream output, {bool close: true}){ }
-  void close() { }
-  bool get closed => true;
-  void set onData(void callback()) { }
-  void set onClosed(void callback()) { }
-  void set onError(void callback(Exception e)) {
-    callback(new TestException());
-  }
-}
-
-testErrorHandler() {
-  var errors = 0;
-  var stream = new StringInputStream(new ErrorInputStream());
-  stream.onError = (e) {
-    errors++;
-    Expect.isTrue(e is TestException);
-  };
-  Expect.equals(1, errors);
-}
-
-testEncodingErrorWithHandler() {
-  var port = new ReceivePort();
-  var errors = 0;
-  var expected = [206, 187, 120, 46, 32, 120, 10];
-  ListInputStream input = new ListInputStream();
-  input.write(expected);
-  var stringStream = new StringInputStream(input, Encoding.ASCII);
-  stringStream.onData = () {
-    Expect.fail("We should not get any data");
-  };
-  stringStream.onError = (e) {
-    port.close();
-    Expect.isTrue(e is Exception);
-  };
-}
-
-
-main() {
-  testUtf8();
-  testLatin1();
-  testAscii();
-  testReadLine1();
-  testReadLine2();
-  testReadChunks();
-  testReadMixed();
-  testErrorHandler();
-  testEncodingErrorWithHandler();
-}
diff --git a/tests/standalone/io/string_transformer_test.dart b/tests/standalone/io/string_transformer_test.dart
new file mode 100644
index 0000000..16b1b3f
--- /dev/null
+++ b/tests/standalone/io/string_transformer_test.dart
@@ -0,0 +1,238 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+import "dart:utf";
+
+void testUtf8() {
+  List<int> data = [0x01,
+                    0x7f,
+                    0xc2, 0x80,
+                    0xdf, 0xbf,
+                    0xe0, 0xa0, 0x80,
+                    0xef, 0xbf, 0xbf,
+                    0xf0, 0x9d, 0x84, 0x9e,
+                    0x100, -0x1, -0xFF];
+  var controller = new StreamController();
+  controller.add(data);
+  controller.close();
+  var stringStream = controller.stream
+    .transform(new StringDecoder(Encoding.UTF_8));
+  stringStream.listen(
+    (s) {
+      Expect.equals(11, s.length);
+      Expect.equals(new String.fromCharCodes([0x01]), s[0]);
+      Expect.equals(new String.fromCharCodes([0x7f]), s[1]);
+      Expect.equals(new String.fromCharCodes([0x80]), s[2]);
+      Expect.equals(new String.fromCharCodes([0x7ff]), s[3]);
+      Expect.equals(new String.fromCharCodes([0x800]), s[4]);
+      Expect.equals(new String.fromCharCodes([0xffff]), s[5]);
+      Expect.equals(new String.fromCharCodes([0xffff]), s[5]);
+
+      // Surrogate pair for U+1D11E.
+      Expect.equals(new String.fromCharCodes([0xd834, 0xdd1e]),
+                    s.substring(6, 8));
+
+      Expect.equals(new String.fromCharCodes(
+          [UNICODE_REPLACEMENT_CHARACTER_CODEPOINT,
+           UNICODE_REPLACEMENT_CHARACTER_CODEPOINT,
+           UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]),
+          s.substring(8, 11));
+    });
+}
+
+void testLatin1() {
+  List<int> data = [0x01,
+                    0x7f,
+                    0x44, 0x61, 0x72, 0x74,
+                    0x80,
+                    0xff,
+                    0x100, -0x1, -0xff];
+  var controller = new StreamController();
+  controller.add(data);
+  controller.close();
+  var stream = controller.stream
+    .transform(new StringDecoder(Encoding.ISO_8859_1));
+  stream.listen((s) {
+    Expect.equals(11, s.length);
+    Expect.equals(new String.fromCharCodes([0x01]), s[0]);
+    Expect.equals(new String.fromCharCodes([0x7f]), s[1]);
+    Expect.equals("Dart", s.substring(2, 6));
+    Expect.equals(new String.fromCharCodes([0x80]), s[6]);
+    Expect.equals(new String.fromCharCodes([0xff]), s[7]);
+    Expect.equals('???', s.substring(8, 11));
+  });
+}
+
+void testAscii() {
+  List<int> data = [0x01,
+                    0x44, 0x61, 0x72, 0x74,
+                    0x7f,
+                    0xf4, 0x100, -0x1, -0xff];
+  var controller = new StreamController();
+  controller.add(data);
+  controller.close();
+  var stream = controller.stream
+    .transform(new StringDecoder(Encoding.ASCII));
+  stream.listen((s) {
+    Expect.equals(10, s.length);
+    Expect.equals(new String.fromCharCodes([0x01]), s[0]);
+    Expect.equals("Dart", s.substring(1, 5));
+    Expect.equals(new String.fromCharCodes([0x7f]), s[5]);
+    Expect.equals('????', s.substring(6, 10));
+  });
+}
+
+void testReadLine1() {
+  var controller = new StreamController();
+  var stream = controller.stream
+      .transform(new StringDecoder())
+      .transform(new LineTransformer());
+
+  var stage = 0;
+
+  void stringData(line) {
+    var line;
+    if (stage == 0) {
+      Expect.equals(null, line);
+      stage++;
+      controller.close();
+    } else if (stage == 1) {
+      Expect.equals("Line", line);
+      stage++;
+    }
+  }
+
+  void streamClosed() {
+    Expect.equals(2, stage);
+  }
+
+  stream.listen(
+      stringData,
+      onDone: streamClosed);
+
+  controller.add("Line".charCodes);
+}
+
+void testReadLine2() {
+  var controller = new StreamController();
+
+  var stream = controller.stream
+    .transform(new StringDecoder())
+    .transform(new LineTransformer());
+
+  var stage = 0;
+  var subStage = 0;
+  stream.listen((line) {
+      if (stage == 0) {
+        if (subStage == 0) {
+          Expect.equals("Line1", line);
+          subStage++;
+        } else if (subStage == 1) {
+          Expect.equals("Line2", line);
+          subStage++;
+        } else if (subStage == 2) {
+          Expect.equals("Line3", line);
+          subStage = 0;
+          stage++;
+          controller.add("ne4\n".charCodes);
+        } else {
+          Expect.fail("Stage 0 failed");
+        }
+      } else if (stage == 1) {
+        if (subStage == 0) {
+          Expect.equals("Line4", line);
+          subStage = 0;
+          stage++;
+          controller.add("\n\n\r\n\r\n\r\r".charCodes);
+        } else {
+          Expect.fail("Stage 1 failed");
+        }
+      } else if (stage == 2) {
+        if (subStage < 4) {
+          // Expect 5 empty lines. As long as the stream is not closed the
+          // final \r cannot be interpreted as a end of line.
+          Expect.equals("", line);
+          subStage++;
+        } else if (subStage == 4) {
+          Expect.equals("", line);
+          subStage = 0;
+          stage++;
+          controller.close();
+        } else {
+          Expect.fail("Stage 2 failed");
+        }
+      } else if (stage == 3) {
+        if (subStage == 0) {
+          Expect.equals("", line);
+          stage++;
+        } else {
+          Expect.fail("Stage 3 failed");
+        }
+      }
+    }, onDone: () {
+      Expect.equals(4, stage);
+      Expect.equals(0, subStage);
+    });
+
+  controller.add("Line1\nLine2\r\nLine3\rLi".charCodes);
+}
+
+class TestException implements Exception {
+  TestException();
+}
+
+testErrorHandler() {
+  var controller = new StreamController();
+  var errors = 0;
+  var stream = controller.stream
+    .transform(new StringDecoder())
+    .transform(new LineTransformer());
+  stream.listen(
+      (_) {},
+      onDone: () {
+        Expect.equals(1, errors);
+      },
+      onError: (e) {
+        errors++;
+        Expect.isTrue(e.error is TestException);
+      });
+  controller.signalError(new TestException());
+  controller.close();
+}
+
+testLatin1EncoderError() {
+  List<int> data = [0x01,
+                    0x7f,
+                    0x44, 0x61, 0x72, 0x74,
+                    0x80,
+                    0xff,
+                    0x100];
+  var controller = new StreamController();
+  controller.add(new String.fromCharCodes(data));
+  controller.close();
+  var stream = controller.stream
+    .transform(new StringEncoder(Encoding.ISO_8859_1));
+  stream.listen(
+    (s) {
+      Expect.fail("data not expected");
+    },
+    onError: (error) {
+    print(error);
+      Expect.isTrue(error.error is FormatException);
+    });
+
+}
+
+main() {
+  testUtf8();
+  testLatin1();
+  testAscii();
+  testReadLine1();
+  testReadLine2();
+  testErrorHandler();
+  testLatin1EncoderError();
+}
diff --git a/tests/standalone/io/testing_server.dart b/tests/standalone/io/testing_server.dart
index e37a989..79ab136 100644
--- a/tests/standalone/io/testing_server.dart
+++ b/tests/standalone/io/testing_server.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
@@ -12,17 +12,19 @@
 
   void onConnection(Socket connection);  // Abstract.
 
-  void errorHandlerServer(Exception e) {
+  void errorHandlerServer(e) {
     Expect.fail("Server socket error $e");
   }
 
   void dispatch(message, SendPort replyTo) {
     if (message == INIT) {
-      _server = new ServerSocket(HOST, 0, 10);
-      Expect.equals(true, _server != null);
-      _server.onConnection = onConnection;
-      _server.onError = errorHandlerServer;
-      replyTo.send(_server.port, null);
+      ServerSocket.bind(HOST, 0, 10).then((server) {
+        _server = server;
+        _server.listen(
+            onConnection,
+            onError: errorHandlerServer);
+        replyTo.send(_server.port, null);
+      });
     } else if (message == SHUTDOWN) {
       _server.close();
       port.close();
diff --git a/tests/standalone/io/url_encoding_test.dart b/tests/standalone/io/url_encoding_test.dart
index cee5022..cfeefe5 100644
--- a/tests/standalone/io/url_encoding_test.dart
+++ b/tests/standalone/io/url_encoding_test.dart
@@ -1,18 +1,16 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:async";
 import "dart:utf";
-part "../../../sdk/lib/io/input_stream.dart";
-part "../../../sdk/lib/io/output_stream.dart";
-part "../../../sdk/lib/io/chunked_stream.dart";
-part "../../../sdk/lib/io/string_stream.dart";
-part "../../../sdk/lib/io/stream_util.dart";
+
+part '../../../sdk/lib/io/io_stream_consumer.dart';
 part "../../../sdk/lib/io/http.dart";
 part "../../../sdk/lib/io/http_impl.dart";
 part "../../../sdk/lib/io/http_parser.dart";
 part "../../../sdk/lib/io/http_utils.dart";
+part "../../../sdk/lib/io/socket.dart";
 
 void testParseEncodedString() {
   String encodedString = 'foo+bar%20foobar%25%26';
diff --git a/tests/standalone/io/web_socket_no_secure_test.dart b/tests/standalone/io/web_socket_no_secure_test.dart
index 7aae7a3..46e1d03 100644
--- a/tests/standalone/io/web_socket_no_secure_test.dart
+++ b/tests/standalone/io/web_socket_no_secure_test.dart
@@ -1,19 +1,191 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
 
 // TODO(7157): Remove this test once the bug is fixed.
 // This is a copy of web_socket_test.dart with the secure connection
 // tests disabled, so it does not crash on Windows.
-import "dart:async";
 import "dart:io";
 import "dart:isolate";
 import "dart:scalarlist";
-import "dart:uri";
 
-const SERVER_ADDRESS = "127.0.0.1";
-const HOST_NAME = "localhost";
+void testRequestResponseClientCloses(
+    int totalConnections, int closeStatus, String closeReason) {
+  HttpServer.bind().then((server) {
+
+    server.transform(new WebSocketTransformer()).listen((webSocket) {
+      webSocket.listen((event) {
+        if (event is MessageEvent) {
+          webSocket.send(event.data);
+        } else if (event is CloseEvent) {
+          Expect.equals(closeStatus == null
+                        ? WebSocketStatus.NO_STATUS_RECEIVED
+                        : closeStatus, event.code);
+          Expect.equals(closeReason == null ? "" : closeReason, event.reason);
+        }
+      });
+    });
+
+    int closeCount = 0;
+    String messageText = "Hello, world!";
+    for (int i = 0; i < totalConnections; i++) {
+      int messageCount = 0;
+       WebSocket.connect("ws://127.0.0.1:${server.port}/")
+        .then((webSocket) {
+          webSocket.send(messageText);
+          webSocket.listen((event) {
+            if (event is MessageEvent) {
+              messageCount++;
+              if (messageCount < 1 ) {
+                Expect.equals(messageText, event.data);
+                webSocket.send(event.data);
+              } else {
+                webSocket.close(closeStatus, closeReason);
+              }
+            } else if (event is CloseEvent) {
+              Expect.equals(closeStatus == null
+                            ? WebSocketStatus.NO_STATUS_RECEIVED
+                            : closeStatus, event.code);
+              Expect.equals("", event.reason);
+              closeCount++;
+              if (closeCount == totalConnections) {
+                server.close();
+              }
+            }
+          });
+        });
+    }
+
+  });
+}
+
+
+void testRequestResponseServerCloses(
+    int totalConnections, int closeStatus, String closeReason) {
+  HttpServer.bind().then((server) {
+
+    int closeCount = 0;
+    server.transform(new WebSocketTransformer()).listen((webSocket) {
+      String messageText = "Hello, world!";
+      int messageCount = 0;
+      webSocket.listen((event) {
+        if (event is MessageEvent) {
+          messageCount++;
+          if (messageCount < 10) {
+            Expect.equals(messageText, event.data);
+            webSocket.send(event.data);
+          } else {
+            webSocket.close(closeStatus, closeReason);
+          }
+        } else if (event is CloseEvent) {
+          Expect.equals(closeStatus == null
+                        ? WebSocketStatus.NO_STATUS_RECEIVED
+                        : closeStatus, event.code);
+          Expect.equals("", event.reason);
+          closeCount++;
+          if (closeCount == totalConnections) {
+            server.close();
+          }
+        }
+      });
+      webSocket.send(messageText);
+    });
+
+    for (int i = 0; i < totalConnections; i++) {
+      WebSocket.connect("ws://127.0.0.1:${server.port}/")
+        .then((webSocket) {
+          webSocket.listen((event) {
+            if (event is MessageEvent) {
+              webSocket.send(event.data);
+            } else if (event is CloseEvent) {
+              Expect.equals(closeStatus == null
+                            ? WebSocketStatus.NO_STATUS_RECEIVED
+                            : closeStatus, event.code);
+              Expect.equals(
+                  closeReason == null ? "" : closeReason, event.reason);
+            }
+          });
+        });
+    }
+
+  });
+}
+
+
+void testMessageLength(int messageLength) {
+  HttpServer.bind().then((server) {
+
+    Uint8List originalMessage = new Uint8List(messageLength);
+    server.transform(new WebSocketTransformer()).listen((webSocket) {
+      webSocket.listen((event) {
+        if (event is MessageEvent) {
+          Expect.listEquals(originalMessage, event.data);
+          webSocket.send(event.data);
+        } else if (event is CloseEvent) {
+        }
+      });
+    });
+
+    WebSocket.connect("ws://127.0.0.1:${server.port}/")
+      .then((webSocket) {
+        webSocket.listen((event) {
+          if (event is MessageEvent) {
+            Expect.listEquals(originalMessage, event.data);
+            webSocket.close();
+          } else if (event is CloseEvent) {
+            server.close();
+          }
+        });
+        webSocket.send(originalMessage);
+      });
+
+  });
+}
+
+
+void testNoUpgrade() {
+  HttpServer.bind().then((server) {
+
+    // Create a server which always responds with NOT_FOUND.
+    server.listen((request) {
+      request.response.statusCode = HttpStatus.NOT_FOUND;
+      request.response.close();
+    });
+
+    WebSocket.connect("ws://127.0.0.1:${server.port}/").catchError((error) {
+      server.close();
+    });
+
+  });
+}
+
+
+void testUsePOST() {
+  HttpServer.bind().then((server) {
+
+    var errorPort = new ReceivePort();
+    server.transform(new WebSocketTransformer()).listen((webSocket) {
+      Expect.fail("No connection expected");
+    }, onError: (e) {
+      errorPort.close();
+    });
+
+    HttpClient client = new HttpClient();
+    client.post("127.0.0.1", server.port, "/")
+      .then((request) => request.close())
+      .then((response) {
+        Expect.equals(HttpStatus.BAD_REQUEST, response.statusCode);
+        client.close();
+        server.close();
+      });
+
+  });
+}
 
 
 class WebSocketInfo {
@@ -21,360 +193,89 @@
 }
 
 
-/**
- * A SecurityConfiguration lets us run the tests over HTTP or HTTPS.
- */
-class SecurityConfiguration {
-  final bool secure;
-  HttpClient client;
-
-  SecurityConfiguration({bool this.secure}) : client = new HttpClient();
-
-  HttpServer createServer({int backlog}) {
-    HttpServer server = secure ? new HttpsServer() : new HttpServer();
-    server.listen(SERVER_ADDRESS,
-                  0,
-                  backlog: backlog,
-                  certificate_name: "CN=$HOST_NAME");
-    return server;
-  }
-
-  WebSocketClientConnection createClient(int port,
-                                         {bool followRedirects,
-                                          String method: "GET"}) {
-    HttpClientConnection conn = client.openUrl(method, Uri.parse(
-        '${secure ? "https" : "http"}://$HOST_NAME:$port/'));
-    if (followRedirects != null) {
-      conn.followRedirects = followRedirects;
-    }
-    return new WebSocketClientConnection(conn);
-  }
-
-  void testRequestResponseClientCloses(
-      int totalConnections, int closeStatus, String closeReason) {
-    HttpServer server = createServer(backlog: totalConnections);
-    HttpClient client = new HttpClient();
-
-    // Make a web socket handler and set it as the HTTP server default handler.
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
-      var count = 0;
-      conn.onMessage = (Object message) => conn.send(message);
-      conn.onClosed = (status, reason) {
-        Expect.equals(closeStatus == null
-                      ? WebSocketStatus.NO_STATUS_RECEIVED
-                      : closeStatus, status);
-        Expect.equals(closeReason == null ? "" : closeReason, reason);
-      };
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
+void testW3CInterface(
+    int totalConnections, int closeStatus, String closeReason) {
+  HttpServer.bind().then((server) {
 
     int closeCount = 0;
-    String messageText = "Hello, world!";
-    for (int i = 0; i < totalConnections; i++) {
-      int messageCount = 0;
-      WebSocketClientConnection wsconn = createClient(server.port);
-      wsconn.onOpen = () => wsconn.send(messageText);
-      wsconn.onMessage = (message) {
-        messageCount++;
-        if (messageCount < 10) {
-          Expect.equals(messageText, message);
-          wsconn.send(message);
-        } else {
-          wsconn.close(closeStatus, closeReason);
-        }
-      };
-      wsconn.onClosed = (status, reason) {
-        Expect.equals(closeStatus == null
-                      ? WebSocketStatus.NO_STATUS_RECEIVED
-                      : closeStatus, status);
-        Expect.equals("", reason);
-        closeCount++;
-        if (closeCount == totalConnections) {
-          client.shutdown();
-          server.close();
-        }
-      };
-    }
-  }
-
-
-  void testRequestResponseServerCloses(
-      int totalConnections, int closeStatus, String closeReason) {
-    ReceivePort keepAlive = new ReceivePort();
-    HttpServer server = createServer(backlog: totalConnections);
-
-    // Create a web socket handler and set is as the HTTP server default
-    // handler.
-    int closeCount = 0;
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
+    server.transform(new WebSocketTransformer()).listen((webSocket) {
       String messageText = "Hello, world!";
       int messageCount = 0;
-      conn.onMessage = (Object message) {
-        messageCount++;
-        if (messageCount < 10) {
-          Expect.equals(messageText, message);
-          conn.send(message);
-        } else {
-        conn.close(closeStatus, closeReason);
+      webSocket.listen((event) {
+        if (event is MessageEvent) {
+          messageCount++;
+          if (messageCount < 10) {
+            Expect.equals(messageText, event.data);
+            webSocket.send(event.data);
+          } else {
+            webSocket.close(closeStatus, closeReason);
+          }
+        } else if (event is CloseEvent) {
+          Expect.equals(closeStatus, event.code);
+          Expect.equals("", event.reason);
+          closeCount++;
+          if (closeCount == totalConnections) {
+            server.close();
+          }
         }
-      };
-      conn.onClosed = (status, reason) {
-        Expect.equals(closeStatus == null
-                      ? WebSocketStatus.NO_STATUS_RECEIVED
-                      : closeStatus, status);
-        Expect.equals("", reason);
-        closeCount++;
-        if (closeCount == totalConnections) {
-          client.shutdown();
-          server.close();
-          keepAlive.close();
-      }
-      };
-      conn.send(messageText);
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
-
-    for (int i = 0; i < totalConnections; i++) {
-      WebSocketClientConnection wsconn = createClient(server.port);
-      wsconn.onMessage = (message) => wsconn.send(message);
-      wsconn.onClosed = (status, reason) {
-        Expect.equals(closeStatus == null
-                      ? WebSocketStatus.NO_STATUS_RECEIVED
-                      : closeStatus, status);
-        Expect.equals(closeReason == null ? "" : closeReason, reason);
-      };
-    }
-  }
-
-
-  void testMessageLength(int messageLength) {
-    HttpServer server = createServer(backlog: 1);
-    bool serverReceivedMessage = false;
-    bool clientReceivedMessage = false;
-
-    // Create a web socket handler and set is as the HTTP server default
-    // handler.
-    Uint8List originalMessage = new Uint8List(messageLength);
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
-      conn.onMessage = (Object message) {
-        serverReceivedMessage = true;
-        Expect.listEquals(originalMessage, message);
-        conn.send(message);
-      };
-      conn.onClosed = (status, reason) {
-      };
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
-
-    WebSocketClientConnection wsconn = createClient(server.port);
-    wsconn.onMessage = (message) {
-      clientReceivedMessage = true;
-      Expect.listEquals(originalMessage, message);
-      wsconn.close();
-    };
-    wsconn.onClosed = (status, reason) {
-      Expect.isTrue(serverReceivedMessage);
-      Expect.isTrue(clientReceivedMessage);
-      client.shutdown();
-      server.close();
-    };
-    wsconn.onOpen = () {
-      wsconn.send(originalMessage);
-    };
-  }
-
-
-  void testNoUpgrade() {
-    HttpServer server = createServer(backlog: 5);
-
-    // Create a server which always responds with a redirect.
-    server.defaultRequestHandler = (request, response) {
-      response.statusCode = HttpStatus.MOVED_PERMANENTLY;
-      response.outputStream.close();
-    };
-
-    WebSocketClientConnection wsconn = createClient(server.port,
-                                                    followRedirects: false);
-    wsconn.onNoUpgrade = (response) {
-      Expect.equals(HttpStatus.MOVED_PERMANENTLY, response.statusCode);
-      client.shutdown();
-      server.close();
-    };
-  }
-
-
-  void testUsePOST() {
-    HttpServer server = createServer(backlog: 5);
-
-    // Create a web socket handler and set is as the HTTP server default
-    // handler.
-    int closeCount = 0;
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
-      Expect.fail("No connection expected");
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
-
-    WebSocketClientConnection wsconn = createClient(server.port,
-                                                    method: "POST");
-    wsconn.onNoUpgrade = (response) {
-      Expect.equals(HttpStatus.BAD_REQUEST, response.statusCode);
-      client.shutdown();
-      server.close();
-    };
-  }
-
-
-  void testHashCode(int totalConnections) {
-    ReceivePort keepAlive = new ReceivePort();
-    HttpServer server = createServer(backlog: totalConnections);
-    Map connections = new Map();
-
-    void handleMessage(conn, message) {
-      var info = connections[conn];
-      Expect.isNotNull(info);
-      info.messageCount++;
-      if (info.messageCount < 10) {
-        conn.send(message);
-      } else {
-        conn.close();
-      }
-    }
-
-    // Create a web socket handler and set is as the HTTP server default
-    // handler.
-    int closeCount = 0;
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
-      connections[conn] = new WebSocketInfo();
-      String messageText = "Hello, world!";
-      conn.onMessage = (Object message) {
-        handleMessage(conn, message);
-      };
-      conn.onClosed = (status, reason) {
-        closeCount++;
-        var info = connections[conn];
-        Expect.equals(10, info.messageCount);
-        if (closeCount == totalConnections) {
-          client.shutdown();
-          server.close();
-          keepAlive.close();
-        }
-      };
-      conn.send(messageText);
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
-
-    for (int i = 0; i < totalConnections; i++) {
-      WebSocketClientConnection wsconn = createClient(server.port);
-      wsconn.onMessage = (message) => wsconn.send(message);
-    }
-  }
-
-
-  void testW3CInterface(
-      int totalConnections, int closeStatus, String closeReason) {
-    HttpServer server = createServer(backlog: totalConnections);
-
-    // Create a web socket handler and set is as the HTTP server default
-    // handler.
-    int closeCount = 0;
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
-      String messageText = "Hello, world!";
-      int messageCount = 0;
-      conn.onMessage = (Object message) {
-        messageCount++;
-        if (messageCount < 10) {
-          Expect.equals(messageText, message);
-          conn.send(message);
-        } else {
-          conn.close(closeStatus, closeReason);
-        }
-      };
-      conn.onClosed = (status, reason) {
-        Expect.equals(closeStatus, status);
-        Expect.equals("", reason);
-        closeCount++;
-        if (closeCount == totalConnections) {
-          server.close();
-        }
-      };
-      conn.send(messageText);
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
+      });
+      webSocket.send(messageText);
+    });
 
     void webSocketConnection() {
       bool onopenCalled = false;
       int onmessageCalled = 0;
       bool oncloseCalled = false;
 
-      var websocket =
-          new WebSocket('${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}');
-      Expect.equals(WebSocket.CONNECTING, websocket.readyState);
-      websocket.onopen = () {
+      WebSocket.connect("ws://127.0.0.1:${server.port}").then((webSocket) {
         Expect.isFalse(onopenCalled);
         Expect.equals(0, onmessageCalled);
         Expect.isFalse(oncloseCalled);
         onopenCalled = true;
-        Expect.equals(WebSocket.OPEN, websocket.readyState);
-      };
-      websocket.onmessage = (event) {
-        onmessageCalled++;
-        Expect.isTrue(onopenCalled);
-        Expect.isFalse(oncloseCalled);
-        Expect.equals(WebSocket.OPEN, websocket.readyState);
-        websocket.send(event.data);
-      };
-      websocket.onclose = (event) {
-        Expect.isTrue(onopenCalled);
-        Expect.equals(10, onmessageCalled);
-        Expect.isFalse(oncloseCalled);
-        oncloseCalled = true;
-        Expect.isTrue(event.wasClean);
-        Expect.equals(3002, event.code);
-        Expect.equals("Got tired", event.reason);
-        Expect.equals(WebSocket.CLOSED, websocket.readyState);
-      };
+        Expect.equals(WebSocket.OPEN, webSocket.readyState);
+        webSocket.listen((event) {
+         if (event is MessageEvent) {
+            onmessageCalled++;
+            Expect.isTrue(onopenCalled);
+            Expect.isFalse(oncloseCalled);
+            Expect.equals(WebSocket.OPEN, webSocket.readyState);
+            webSocket.send(event.data);
+          } else if (event is CloseEvent) {
+            Expect.isTrue(onopenCalled);
+            Expect.equals(10, onmessageCalled);
+            Expect.isFalse(oncloseCalled);
+            oncloseCalled = true;
+            Expect.isTrue(event.wasClean);
+            Expect.equals(3002, event.code);
+            Expect.equals("Got tired", event.reason);
+            Expect.equals(WebSocket.CLOSED, webSocket.readyState);
+          }
+        });
+      });
     }
 
     for (int i = 0; i < totalConnections; i++) {
       webSocketConnection();
     }
-  }
 
-
-  runTests() {
-    testRequestResponseClientCloses(2, null, null);
-    testRequestResponseClientCloses(2, 3001, null);
-    testRequestResponseClientCloses(2, 3002, "Got tired");
-    testRequestResponseServerCloses(2, null, null);
-    testRequestResponseServerCloses(2, 3001, null);
-    testRequestResponseServerCloses(2, 3002, "Got tired");
-    testMessageLength(125);
-    testMessageLength(126);
-    testMessageLength(127);
-    testMessageLength(65535);
-    testMessageLength(65536);
-    testNoUpgrade();
-    testUsePOST();
-    testHashCode(2);
-    testW3CInterface(2, 3002, "Got tired");
-  }
-}
-
-
-void initializeSSL() {
-  var testPkcertDatabase =
-      new Path(new Options().script).directoryPath.append("pkcert/");
-  SecureSocket.initialize(database: testPkcertDatabase.toNativePath(),
-                          password: "dartdart");
+  });
 }
 
 
 main() {
-  new SecurityConfiguration(secure: false).runTests();
+  testRequestResponseClientCloses(2, null, null);
+  testRequestResponseClientCloses(2, 3001, null);
+  testRequestResponseClientCloses(2, 3002, "Got tired");
+  testRequestResponseServerCloses(2, null, null);
+  testRequestResponseServerCloses(2, 3001, null);
+  testRequestResponseServerCloses(2, 3002, "Got tired");
+  testMessageLength(125);
+  testMessageLength(126);
+  testMessageLength(127);
+  testMessageLength(65535);
+  testMessageLength(65536);
+  testNoUpgrade();
+  testUsePOST();
+
+  testW3CInterface(2, 3002, "Got tired");
 }
diff --git a/tests/standalone/io/web_socket_protocol_processor_test.dart b/tests/standalone/io/web_socket_protocol_processor_test.dart
index 763a8bf..6ab0da9 100644
--- a/tests/standalone/io/web_socket_protocol_processor_test.dart
+++ b/tests/standalone/io/web_socket_protocol_processor_test.dart
@@ -1,9 +1,12 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:math";
+import "dart:async";
 
+part "../../../sdk/lib/io/http.dart";
+part "../../../sdk/lib/io/io_stream_consumer.dart";
 part "../../../sdk/lib/io/websocket.dart";
 part "../../../sdk/lib/io/websocket_impl.dart";
 
@@ -107,7 +110,7 @@
 
     // Update the processor with one big chunk.
     messageCount++;
-    processor.update(frame);
+    processor.update(frame, 0, frame.length);
     Expect.isNull(mc.data);
     Expect.equals(0, processor._state);
 
@@ -116,7 +119,7 @@
       // Update the processor one byte at the time.
       messageCount++;
       for (int i = 0; i < frame.length; i++) {
-        processor.update(frame.getRange(i, 1));
+        processor.update(frame, i, 1);
       }
       Expect.equals(0, processor._state);
       Expect.isNull(mc.data);
@@ -124,7 +127,7 @@
       // Update the processor two bytes at the time.
       messageCount++;
       for (int i = 0; i < frame.length; i += 2) {
-        processor.update(frame.getRange(i, i + 1 < frame.length ? 2 : 1));
+        processor.update(frame, i, i + 1 < frame.length ? 2 : 1);
       }
       Expect.equals(0, processor._state);
       Expect.isNull(mc.data);
@@ -177,7 +180,7 @@
                                     payloadSize);
       frameCount++;
       messageIndex += payloadSize;
-      processor.update(frame);
+      processor.update(frame, 0, frame.length);
       remaining -= payloadSize;
       firstFrame = false;
     }
diff --git a/tests/standalone/io/web_socket_secure_test.dart b/tests/standalone/io/web_socket_secure_test.dart
deleted file mode 100644
index cb78bd3..0000000
--- a/tests/standalone/io/web_socket_secure_test.dart
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-import "dart:uri";
-import "dart:isolate";
-
-const SERVER_ADDRESS = "127.0.0.1";
-const HOST_NAME = "localhost";
-
-void test() {
-  HttpsServer server = new HttpsServer();
-  var client = new HttpClient();
-
-  // Create a web socket handler and set it as the HTTP server default
-  // handler.
-  WebSocketHandler wsHandler = new WebSocketHandler();
-  wsHandler.onOpen = (WebSocketConnection conn) {
-    conn.onMessage = (Object message) => conn.send(message);
-    conn.onClosed = (status, reason) {
-      conn.close();
-      server.close();
-      client.shutdown();
-    };
-  };
-  server.defaultRequestHandler = wsHandler.onRequest;
-
-  server.onError = (Exception e) {
-    Expect.fail("Unexpected error in Https Server: $e");
-  };
-
-  server.listen(SERVER_ADDRESS,
-                0,
-                backlog: 5,
-                certificate_name: "CN=$HOST_NAME");
-
-  // Connect web socket over HTTPS.
-  var conn = new WebSocketClientConnection(
-      client.getUrl(
-          Uri.parse("https://$HOST_NAME:${server.port}/")));
-  conn.onOpen = () {
-    conn.send("hello");
-  };
-  conn.onMessage = (msg) {
-    Expect.equals("hello", msg);
-    print(msg);
-    conn.close();
-  };
-
-}
-
-void InitializeSSL() {
-  var testPkcertDatabase =
-      new Path(new Options().script).directoryPath.append("pkcert/");
-  SecureSocket.initialize(database: testPkcertDatabase.toNativePath(),
-                          password: "dartdart");
-}
-
-void main() {
-  InitializeSSL();
-  test();
-}
diff --git a/tests/standalone/io/web_socket_test.dart b/tests/standalone/io/web_socket_test.dart
index 2520992c..baa6ddd 100644
--- a/tests/standalone/io/web_socket_test.dart
+++ b/tests/standalone/io/web_socket_test.dart
@@ -1,16 +1,188 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
 //
+// VMOptions=
+// VMOptions=--short_socket_read
+// VMOptions=--short_socket_write
+// VMOptions=--short_socket_read --short_socket_write
 
-import "dart:async";
 import "dart:io";
 import "dart:isolate";
 import "dart:scalarlist";
-import "dart:uri";
 
-const SERVER_ADDRESS = "127.0.0.1";
-const HOST_NAME = "localhost";
+void testRequestResponseClientCloses(
+    int totalConnections, int closeStatus, String closeReason) {
+  HttpServer.bind().then((server) {
+
+    server.transform(new WebSocketTransformer()).listen((webSocket) {
+      webSocket.listen((event) {
+        if (event is MessageEvent) {
+          webSocket.send(event.data);
+        } else if (event is CloseEvent) {
+          Expect.equals(closeStatus == null
+                        ? WebSocketStatus.NO_STATUS_RECEIVED
+                        : closeStatus, event.code);
+          Expect.equals(closeReason == null ? "" : closeReason, event.reason);
+        }
+      });
+    });
+
+    int closeCount = 0;
+    String messageText = "Hello, world!";
+    for (int i = 0; i < totalConnections; i++) {
+      int messageCount = 0;
+       WebSocket.connect("ws://127.0.0.1:${server.port}/")
+        .then((webSocket) {
+          webSocket.send(messageText);
+          webSocket.listen((event) {
+            if (event is MessageEvent) {
+              messageCount++;
+              if (messageCount < 1 ) {
+                Expect.equals(messageText, event.data);
+                webSocket.send(event.data);
+              } else {
+                webSocket.close(closeStatus, closeReason);
+              }
+            } else if (event is CloseEvent) {
+              Expect.equals(closeStatus == null
+                            ? WebSocketStatus.NO_STATUS_RECEIVED
+                            : closeStatus, event.code);
+              Expect.equals("", event.reason);
+              closeCount++;
+              if (closeCount == totalConnections) {
+                server.close();
+              }
+            }
+          });
+        });
+    }
+
+  });
+}
+
+
+void testRequestResponseServerCloses(
+    int totalConnections, int closeStatus, String closeReason) {
+  HttpServer.bind().then((server) {
+
+    int closeCount = 0;
+    server.transform(new WebSocketTransformer()).listen((webSocket) {
+      String messageText = "Hello, world!";
+      int messageCount = 0;
+      webSocket.listen((event) {
+        if (event is MessageEvent) {
+          messageCount++;
+          if (messageCount < 10) {
+            Expect.equals(messageText, event.data);
+            webSocket.send(event.data);
+          } else {
+            webSocket.close(closeStatus, closeReason);
+          }
+        } else if (event is CloseEvent) {
+          Expect.equals(closeStatus == null
+                        ? WebSocketStatus.NO_STATUS_RECEIVED
+                        : closeStatus, event.code);
+          Expect.equals("", event.reason);
+          closeCount++;
+          if (closeCount == totalConnections) {
+            server.close();
+          }
+        }
+      });
+      webSocket.send(messageText);
+    });
+
+    for (int i = 0; i < totalConnections; i++) {
+      WebSocket.connect("ws://127.0.0.1:${server.port}/")
+        .then((webSocket) {
+          webSocket.listen((event) {
+            if (event is MessageEvent) {
+              webSocket.send(event.data);
+            } else if (event is CloseEvent) {
+              Expect.equals(closeStatus == null
+                            ? WebSocketStatus.NO_STATUS_RECEIVED
+                            : closeStatus, event.code);
+              Expect.equals(
+                  closeReason == null ? "" : closeReason, event.reason);
+            }
+          });
+        });
+    }
+
+  });
+}
+
+
+void testMessageLength(int messageLength) {
+  HttpServer.bind().then((server) {
+
+    Uint8List originalMessage = new Uint8List(messageLength);
+    server.transform(new WebSocketTransformer()).listen((webSocket) {
+      webSocket.listen((event) {
+        if (event is MessageEvent) {
+          Expect.listEquals(originalMessage, event.data);
+          webSocket.send(event.data);
+        } else if (event is CloseEvent) {
+        }
+      });
+    });
+
+    WebSocket.connect("ws://127.0.0.1:${server.port}/")
+      .then((webSocket) {
+        webSocket.listen((event) {
+          if (event is MessageEvent) {
+            Expect.listEquals(originalMessage, event.data);
+            webSocket.close();
+          } else if (event is CloseEvent) {
+            server.close();
+          }
+        });
+        webSocket.send(originalMessage);
+      });
+
+  });
+}
+
+
+void testNoUpgrade() {
+  HttpServer.bind().then((server) {
+
+    // Create a server which always responds with NOT_FOUND.
+    server.listen((request) {
+      request.response.statusCode = HttpStatus.NOT_FOUND;
+      request.response.close();
+    });
+
+    WebSocket.connect("ws://127.0.0.1:${server.port}/").catchError((error) {
+      server.close();
+    });
+
+  });
+}
+
+
+void testUsePOST() {
+  HttpServer.bind().then((server) {
+
+    var errorPort = new ReceivePort();
+    server.transform(new WebSocketTransformer()).listen((webSocket) {
+      Expect.fail("No connection expected");
+    }, onError: (e) {
+      errorPort.close();
+    });
+
+    HttpClient client = new HttpClient();
+    client.post("127.0.0.1", server.port, "/")
+      .then((request) => request.close())
+      .then((response) {
+        Expect.equals(HttpStatus.BAD_REQUEST, response.statusCode);
+        client.close();
+        server.close();
+      });
+
+  });
+}
 
 
 class WebSocketInfo {
@@ -18,362 +190,89 @@
 }
 
 
-/**
- * A SecurityConfiguration lets us run the tests over HTTP or HTTPS.
- */
-class SecurityConfiguration {
-  final bool secure;
-  HttpClient client;
-
-  SecurityConfiguration({bool this.secure}) : client = new HttpClient();
-
-  HttpServer createServer({int backlog}) {
-    HttpServer server = secure ? new HttpsServer() : new HttpServer();
-    server.listen(SERVER_ADDRESS,
-                  0,
-                  backlog: backlog,
-                  certificate_name: "CN=$HOST_NAME");
-    return server;
-  }
-
-  WebSocketClientConnection createClient(int port,
-                                         {bool followRedirects,
-                                          String method: "GET"}) {
-    HttpClientConnection conn = client.openUrl(method, Uri.parse(
-        '${secure ? "https" : "http"}://$HOST_NAME:$port/'));
-    if (followRedirects != null) {
-      conn.followRedirects = followRedirects;
-    }
-    return new WebSocketClientConnection(conn);
-  }
-
-  void testRequestResponseClientCloses(
-      int totalConnections, int closeStatus, String closeReason) {
-    HttpServer server = createServer(backlog: totalConnections);
-    HttpClient client = new HttpClient();
-
-    // Make a web socket handler and set it as the HTTP server default handler.
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
-      var count = 0;
-      conn.onMessage = (Object message) => conn.send(message);
-      conn.onClosed = (status, reason) {
-        Expect.equals(closeStatus == null
-                      ? WebSocketStatus.NO_STATUS_RECEIVED
-                      : closeStatus, status);
-        Expect.equals(closeReason == null ? "" : closeReason, reason);
-      };
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
+void testW3CInterface(
+    int totalConnections, int closeStatus, String closeReason) {
+  HttpServer.bind().then((server) {
 
     int closeCount = 0;
-    String messageText = "Hello, world!";
-    for (int i = 0; i < totalConnections; i++) {
-      int messageCount = 0;
-      WebSocketClientConnection wsconn = createClient(server.port);
-      wsconn.onOpen = () => wsconn.send(messageText);
-      wsconn.onMessage = (message) {
-        messageCount++;
-        if (messageCount < 10) {
-          Expect.equals(messageText, message);
-          wsconn.send(message);
-        } else {
-          wsconn.close(closeStatus, closeReason);
-        }
-      };
-      wsconn.onClosed = (status, reason) {
-        Expect.equals(closeStatus == null
-                      ? WebSocketStatus.NO_STATUS_RECEIVED
-                      : closeStatus, status);
-        Expect.equals("", reason);
-        closeCount++;
-        if (closeCount == totalConnections) {
-          client.shutdown();
-          server.close();
-        }
-      };
-    }
-  }
-
-
-  void testRequestResponseServerCloses(
-      int totalConnections, int closeStatus, String closeReason) {
-    ReceivePort keepAlive = new ReceivePort();
-    HttpServer server = createServer(backlog: totalConnections);
-
-    // Create a web socket handler and set is as the HTTP server default
-    // handler.
-    int closeCount = 0;
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
+    server.transform(new WebSocketTransformer()).listen((webSocket) {
       String messageText = "Hello, world!";
       int messageCount = 0;
-      conn.onMessage = (Object message) {
-        messageCount++;
-        if (messageCount < 10) {
-          Expect.equals(messageText, message);
-          conn.send(message);
-        } else {
-        conn.close(closeStatus, closeReason);
+      webSocket.listen((event) {
+        if (event is MessageEvent) {
+          messageCount++;
+          if (messageCount < 10) {
+            Expect.equals(messageText, event.data);
+            webSocket.send(event.data);
+          } else {
+            webSocket.close(closeStatus, closeReason);
+          }
+        } else if (event is CloseEvent) {
+          Expect.equals(closeStatus, event.code);
+          Expect.equals("", event.reason);
+          closeCount++;
+          if (closeCount == totalConnections) {
+            server.close();
+          }
         }
-      };
-      conn.onClosed = (status, reason) {
-        Expect.equals(closeStatus == null
-                      ? WebSocketStatus.NO_STATUS_RECEIVED
-                      : closeStatus, status);
-        Expect.equals("", reason);
-        closeCount++;
-        if (closeCount == totalConnections) {
-          client.shutdown();
-          server.close();
-          keepAlive.close();
-      }
-      };
-      conn.send(messageText);
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
-
-    for (int i = 0; i < totalConnections; i++) {
-      WebSocketClientConnection wsconn = createClient(server.port);
-      wsconn.onMessage = (message) => wsconn.send(message);
-      wsconn.onClosed = (status, reason) {
-        Expect.equals(closeStatus == null
-                      ? WebSocketStatus.NO_STATUS_RECEIVED
-                      : closeStatus, status);
-        Expect.equals(closeReason == null ? "" : closeReason, reason);
-      };
-    }
-  }
-
-
-  void testMessageLength(int messageLength) {
-    HttpServer server = createServer(backlog: 1);
-    bool serverReceivedMessage = false;
-    bool clientReceivedMessage = false;
-
-    // Create a web socket handler and set is as the HTTP server default
-    // handler.
-    Uint8List originalMessage = new Uint8List(messageLength);
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
-      conn.onMessage = (Object message) {
-        serverReceivedMessage = true;
-        Expect.listEquals(originalMessage, message);
-        conn.send(message);
-      };
-      conn.onClosed = (status, reason) {
-      };
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
-
-    WebSocketClientConnection wsconn = createClient(server.port);
-    wsconn.onMessage = (message) {
-      clientReceivedMessage = true;
-      Expect.listEquals(originalMessage, message);
-      wsconn.close();
-    };
-    wsconn.onClosed = (status, reason) {
-      Expect.isTrue(serverReceivedMessage);
-      Expect.isTrue(clientReceivedMessage);
-      client.shutdown();
-      server.close();
-    };
-    wsconn.onOpen = () {
-      wsconn.send(originalMessage);
-    };
-  }
-
-
-  void testNoUpgrade() {
-    HttpServer server = createServer(backlog: 5);
-
-    // Create a server which always responds with a redirect.
-    server.defaultRequestHandler = (request, response) {
-      response.statusCode = HttpStatus.MOVED_PERMANENTLY;
-      response.outputStream.close();
-    };
-
-    WebSocketClientConnection wsconn = createClient(server.port,
-                                                    followRedirects: false);
-    wsconn.onNoUpgrade = (response) {
-      Expect.equals(HttpStatus.MOVED_PERMANENTLY, response.statusCode);
-      client.shutdown();
-      server.close();
-    };
-  }
-
-
-  void testUsePOST() {
-    HttpServer server = createServer(backlog: 5);
-
-    // Create a web socket handler and set is as the HTTP server default
-    // handler.
-    int closeCount = 0;
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
-      Expect.fail("No connection expected");
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
-
-    WebSocketClientConnection wsconn = createClient(server.port,
-                                                    method: "POST");
-    wsconn.onNoUpgrade = (response) {
-      Expect.equals(HttpStatus.BAD_REQUEST, response.statusCode);
-      client.shutdown();
-      server.close();
-    };
-  }
-
-
-  void testHashCode(int totalConnections) {
-    ReceivePort keepAlive = new ReceivePort();
-    HttpServer server = createServer(backlog: totalConnections);
-    Map connections = new Map();
-
-    void handleMessage(conn, message) {
-      var info = connections[conn];
-      Expect.isNotNull(info);
-      info.messageCount++;
-      if (info.messageCount < 10) {
-        conn.send(message);
-      } else {
-        conn.close();
-      }
-    }
-
-    // Create a web socket handler and set is as the HTTP server default
-    // handler.
-    int closeCount = 0;
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
-      connections[conn] = new WebSocketInfo();
-      String messageText = "Hello, world!";
-      conn.onMessage = (Object message) {
-        handleMessage(conn, message);
-      };
-      conn.onClosed = (status, reason) {
-        closeCount++;
-        var info = connections[conn];
-        Expect.equals(10, info.messageCount);
-        if (closeCount == totalConnections) {
-          client.shutdown();
-          server.close();
-          keepAlive.close();
-        }
-      };
-      conn.send(messageText);
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
-
-    for (int i = 0; i < totalConnections; i++) {
-      WebSocketClientConnection wsconn = createClient(server.port);
-      wsconn.onMessage = (message) => wsconn.send(message);
-    }
-  }
-
-
-  void testW3CInterface(
-      int totalConnections, int closeStatus, String closeReason) {
-    HttpServer server = createServer(backlog: totalConnections);
-
-    // Create a web socket handler and set is as the HTTP server default
-    // handler.
-    int closeCount = 0;
-    WebSocketHandler wsHandler = new WebSocketHandler();
-    wsHandler.onOpen = (WebSocketConnection conn) {
-      String messageText = "Hello, world!";
-      int messageCount = 0;
-      conn.onMessage = (Object message) {
-        messageCount++;
-        if (messageCount < 10) {
-          Expect.equals(messageText, message);
-          conn.send(message);
-        } else {
-          conn.close(closeStatus, closeReason);
-        }
-      };
-      conn.onClosed = (status, reason) {
-        Expect.equals(closeStatus, status);
-        Expect.equals("", reason);
-        closeCount++;
-        if (closeCount == totalConnections) {
-          server.close();
-        }
-      };
-      conn.send(messageText);
-    };
-    server.defaultRequestHandler = wsHandler.onRequest;
+      });
+      webSocket.send(messageText);
+    });
 
     void webSocketConnection() {
       bool onopenCalled = false;
       int onmessageCalled = 0;
       bool oncloseCalled = false;
 
-      var websocket =
-          new WebSocket('${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}');
-      Expect.equals(WebSocket.CONNECTING, websocket.readyState);
-      websocket.onopen = () {
+      WebSocket.connect("ws://127.0.0.1:${server.port}").then((webSocket) {
         Expect.isFalse(onopenCalled);
         Expect.equals(0, onmessageCalled);
         Expect.isFalse(oncloseCalled);
         onopenCalled = true;
-        Expect.equals(WebSocket.OPEN, websocket.readyState);
-      };
-      websocket.onmessage = (event) {
-        onmessageCalled++;
-        Expect.isTrue(onopenCalled);
-        Expect.isFalse(oncloseCalled);
-        Expect.equals(WebSocket.OPEN, websocket.readyState);
-        websocket.send(event.data);
-      };
-      websocket.onclose = (event) {
-        Expect.isTrue(onopenCalled);
-        Expect.equals(10, onmessageCalled);
-        Expect.isFalse(oncloseCalled);
-        oncloseCalled = true;
-        Expect.isTrue(event.wasClean);
-        Expect.equals(3002, event.code);
-        Expect.equals("Got tired", event.reason);
-        Expect.equals(WebSocket.CLOSED, websocket.readyState);
-      };
+        Expect.equals(WebSocket.OPEN, webSocket.readyState);
+        webSocket.listen((event) {
+         if (event is MessageEvent) {
+            onmessageCalled++;
+            Expect.isTrue(onopenCalled);
+            Expect.isFalse(oncloseCalled);
+            Expect.equals(WebSocket.OPEN, webSocket.readyState);
+            webSocket.send(event.data);
+          } else if (event is CloseEvent) {
+            Expect.isTrue(onopenCalled);
+            Expect.equals(10, onmessageCalled);
+            Expect.isFalse(oncloseCalled);
+            oncloseCalled = true;
+            Expect.isTrue(event.wasClean);
+            Expect.equals(3002, event.code);
+            Expect.equals("Got tired", event.reason);
+            Expect.equals(WebSocket.CLOSED, webSocket.readyState);
+          }
+        });
+      });
     }
 
     for (int i = 0; i < totalConnections; i++) {
       webSocketConnection();
     }
-  }
 
-
-  runTests() {
-    testRequestResponseClientCloses(2, null, null);
-    testRequestResponseClientCloses(2, 3001, null);
-    testRequestResponseClientCloses(2, 3002, "Got tired");
-    testRequestResponseServerCloses(2, null, null);
-    testRequestResponseServerCloses(2, 3001, null);
-    testRequestResponseServerCloses(2, 3002, "Got tired");
-    testMessageLength(125);
-    testMessageLength(126);
-    testMessageLength(127);
-    testMessageLength(65535);
-    testMessageLength(65536);
-    testNoUpgrade();
-    testUsePOST();
-    testHashCode(2);
-    testW3CInterface(2, 3002, "Got tired");
-  }
-}
-
-
-void initializeSSL() {
-  var testPkcertDatabase =
-      new Path(new Options().script).directoryPath.append("pkcert/");
-  SecureSocket.initialize(database: testPkcertDatabase.toNativePath(),
-                          password: "dartdart");
+  });
 }
 
 
 main() {
-  new SecurityConfiguration(secure: false).runTests();
-  initializeSSL();
-  new SecurityConfiguration(secure: true).runTests();
+  testRequestResponseClientCloses(2, null, null);
+  testRequestResponseClientCloses(2, 3001, null);
+  testRequestResponseClientCloses(2, 3002, "Got tired");
+  testRequestResponseServerCloses(2, null, null);
+  testRequestResponseServerCloses(2, 3001, null);
+  testRequestResponseServerCloses(2, 3002, "Got tired");
+  testMessageLength(125);
+  testMessageLength(126);
+  testMessageLength(127);
+  testMessageLength(65535);
+  testMessageLength(65536);
+  testNoUpgrade();
+  testUsePOST();
+
+  testW3CInterface(2, 3002, "Got tired");
 }
diff --git a/tests/standalone/left_shift_bit_and_op_test.dart b/tests/standalone/left_shift_bit_and_op_test.dart
new file mode 100644
index 0000000..c9e142a
--- /dev/null
+++ b/tests/standalone/left_shift_bit_and_op_test.dart
@@ -0,0 +1,75 @@
+// 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.
+//
+// Tests optimizing (a << b) & c if c is a Smi constant.
+
+main() {
+  checkshiftAnd32();
+  checkShiftAnd64();
+  // Optimize shiftAnd32.
+  for (int i = 0; i < 10000; i++) {
+    A.shiftAnd32(12, 17);
+    A.shiftAnd64(12, 17);
+    Expect.equals(72, A.multipleConstantUses(3, 4));
+    Expect.equals(34493956096, A.multipleShiftUse(134742016, 8));
+  }
+  checkshiftAnd32();
+  checkShiftAnd64();
+
+  Expect.throws(() => A.shiftAnd32(12, -5));
+
+  // Check environment dependency.
+  final a = new A(), b = new B();
+  for (var i = 0; i < 10000; i++) {
+    Expect.equals(0, bar(a));
+  }
+  Expect.equals(4294967296, bar(b));
+}
+
+
+checkshiftAnd32() {
+  Expect.equals(1572864, A.shiftAnd32(12, 17));
+  Expect.equals(12, A.shiftAnd32(12, 0));
+  Expect.equals(285212672, A.shiftAnd32(16779392, 17));
+}
+
+
+checkShiftAnd64() {
+  Expect.equals(1125936481173504, A.shiftAnd64(4611694814806147072, 7));
+}
+
+
+class A {
+  static const int MASK_32 = (1 << 30) - 1;
+  static const int MASK_64 = (1 << 62) - 1;
+
+  static shiftAnd32(a, c) {
+    return (a << c) & MASK_32;
+  }
+
+  static shiftAnd64(a, c) {
+    return (a << c) & MASK_64;
+  }
+
+  static multipleConstantUses(a, c) {
+    var j = (a << c) & 0xFF;
+    var k = (a << 3) & 0xFF;
+    return j + k;
+  }
+
+  // Make sure that left shift is nor marked as truncating.
+  static multipleShiftUse(a, c) {
+    var y = (a << c);
+    var x = y & 0x7F;
+    return y + x;
+  }
+
+  foo(x) { return x & 0xf; }
+}
+
+class B { foo(x) { return x; } }
+
+bar (o) {
+  return o.foo(1 << 32);
+}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index cbaa158..0bedddf 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -5,8 +5,30 @@
 package/invalid_uri_test: Fail, OK # Fails intentionally
 
 [ $runtime == vm ]
-package/package_isolate_test: Fail # Issue 7520.
+# Temporarily disabled until the test scripts are rewritten for
+# dart:io v2.
+io/skipping_dart2js_compilations_test: skip # Non-fatal process error.
+io/status_file_parser_test: fail
+io/test_runner_exit_code_test: fail
+io/test_runner_test: fail
+
+[ $runtime == vm ]
+io/secure_server_client_certificate_test: fail
+
+[ $runtime == vm && ( $system == windows ) ]
 io/web_socket_test: Fail, Pass # Issue 8495.
+io/https_client_certificate_test: Pass, Timeout # Issue 8674
+io/raw_socket_test: Pass, Timeout # Issue 8675
+io/socket_test: Pass, Timeout # Issue 8676
+io/socket_exception_test: Pass, Timeout # Issue 8677
+io/https_client_test: Pass, Timeout # Issue 8674
+io/https_server_test: Pass, Timeout # Issue 8674
+io/https_client_socket_reuse_test: Pass, Timeout # Issue 8674
+io/http_client_request_test: Pass, Fail # Issue 8681
+io/http_proxy_test: Pass, Timeout # Issue 7773
+
+[ $runtime == vm ]
+package/package_isolate_test: Fail # http://dartbug.com/7520.
 
 [ $runtime == vm && $checked ]
 # These tests have type errors on purpose.
@@ -19,7 +41,7 @@
 io/file_fuzz_test: Skip
 io/directory_fuzz_test: Skip
 
-[ $runtime == vm && $system == macos && $arch == x64 ]
+[ $runtime == vm && $system == macos ]
 io/regress_7191_test: Pass, Timeout # http://dartbug.com/8091
 
 [ $runtime == vm ]
@@ -45,7 +67,6 @@
 
 [ $runtime == vm && $system == windows ]
 io/file_system_links_test: Skip  # No links on Windows.
-io/socket_stream_close_test: Fail, Pass # Issue 8556.
 
 [ $compiler == none && $runtime == drt ]
 io/*: Skip # Don't run tests using dart:io in the browser
@@ -88,6 +109,7 @@
 io/process_exit_negative_test: Fail, OK # relies on a static error that is a warning now.
 package/package_isolate_test: Skip # spawnUri does not work in dart2js. See issue 3051
 debugger/*: Skip # Do not run standalone vm debugger tests with dart2js.
+left_shift_bit_and_op_test: Skip # Integers exceed dart2js precision.
 
 [ $compiler == dart2js && $jscl ]
 assert_test: Fail, OK # Assumes unspecified fields on the AssertionError.
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index bea35e0..4d6e186 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -24,8 +24,6 @@
 # Skip until we stabilize language tests.
 *: Skip
 
-[ $compiler == dartc ]
-
 [ $arch == arm ]
 *: Skip
 
diff --git a/tools/VERSION b/tools/VERSION
index f532fc3..2288fc6 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
-MINOR 3
-BUILD 7
-PATCH 6
+MINOR 4
+BUILD 0
+PATCH 0
diff --git a/tools/build.py b/tools/build.py
index 84aa62b..b60579c 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -40,13 +40,14 @@
       help='The number of parallel jobs to run.',
       metavar=HOST_CPUS,
       default=str(HOST_CPUS))
+  (vs_directory, vs_executable) = utils.GuessVisualStudioPath()
   result.add_option("--devenv",
       help='Path containing devenv.com on Windows',
-      default='C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\Common7'
-      '\\IDE')
+      default=vs_directory)
   result.add_option("--executable",
       help='Name of the devenv.com/msbuild executable on Windows (varies for '
-      'different versions of Visual Studio)', default='devenv.com')
+           'different versions of Visual Studio)',
+      default=vs_executable)
   return result
 
 
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index a8df879..4e87ffb 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -208,7 +208,8 @@
                   'json', 'math', 'mirrors', 'scalarlist',
                   join('svg', 'dart2js'), join('svg', 'dartium'),
                   'uri', 'utf',
-                  join('web_audio', 'dart2js'), join('web_audio', 'dartium')]:
+                  join('web_audio', 'dart2js'), join('web_audio', 'dartium'),
+                  join('web_sql', 'dart2js'), join('web_sql', 'dartium')]:
     copytree(join(HOME, 'sdk', 'lib', library), join(LIB, library),
              ignore=ignore_patterns('*.svn', 'doc', '*.py', '*.gypi', '*.sh'))
 
diff --git a/tools/dom/scripts/dartdomgenerator.py b/tools/dom/scripts/dartdomgenerator.py
index 9007790..b5f63cc 100755
--- a/tools/dom/scripts/dartdomgenerator.py
+++ b/tools/dom/scripts/dartdomgenerator.py
@@ -29,7 +29,7 @@
 
 _logger = logging.getLogger('dartdomgenerator')
 
-_libraries = ['chrome', 'html', 'indexed_db', 'svg', 'web_audio']
+_libraries = ['chrome', 'html', 'indexed_db', 'svg', 'web_audio', 'web_sql']
 
 class GeneratorOptions(object):
   def __init__(self, templates, database, type_registry, renamer):
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 0fc3789..fa6fcac 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -541,8 +541,8 @@
     ],
 
     'DOMWindow.openDatabase': [
-      "@Creates('Database')",
-      "@Creates('DatabaseSync')",
+      "@Creates('SqlDatabase')",
+      "@Creates('SqlDatabaseSync')",
     ],
 
     # To be in callback with the browser-created Event, we had to have called
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 32bb712..c312a9f 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -9,6 +9,8 @@
 html_interface_renames = monitored.Dict('htmlrenamer.html_interface_renames', {
     'CDATASection': 'CDataSection',
     'Clipboard': 'DataTransfer',
+    'Database': 'SqlDatabase', # Avoid conflict with Index DB's Database.
+    'DatabaseSync': 'SqlDatabaseSync',
     'DOMApplicationCache': 'ApplicationCache',
     'DOMCoreException': 'DomException',
     'DOMFileSystem': 'FileSystem',
@@ -21,6 +23,8 @@
     'NamedNodeMap': '_NamedNodeMap',
     'NavigatorUserMediaErrorCallback': '_NavigatorUserMediaErrorCallback',
     'NavigatorUserMediaSuccessCallback': '_NavigatorUserMediaSuccessCallback',
+    'PositionCallback': '_PositionCallback',
+    'PositionErrorCallback': '_PositionErrorCallback',
     'SVGDocument': 'SvgDocument', # Manual to avoid name conflicts.
     'SVGElement': 'SvgElement', # Manual to avoid name conflicts.
     'SVGException': 'SvgException', # Manual of avoid conflict with Exception.
@@ -146,6 +150,9 @@
   'Event.initEvent',
   'EventTarget.addEventListener',
   'EventTarget.removeEventListener',
+  'Geolocation.clearWatch',
+  'Geolocation.getCurrentPosition',
+  'Geolocation.watchPosition',
   'HashChangeEvent.initHashChangeEvent',
   'IDBFactory.deleteDatabase',
   'IDBFactory.open',
@@ -569,6 +576,10 @@
         return 'svg'
       if 'INDEXED_DATABASE' in interface.ext_attrs['Conditional']:
         return 'indexed_db'
+      if 'SQL_DATABASE' in interface.ext_attrs['Conditional']:
+        # WorkerContext has attributes merged in from many other interfaces.
+        if interface.id != 'WorkerContext':
+          return 'web_sql'
 
     return 'html'
 
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 0ef461e..e3ba590 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -58,6 +58,7 @@
     'Navigator.webkitGetUserMedia',
     'URL.createObjectURL',
     'URL.revokeObjectURL',
+    'WheelEvent.deltaMode',
     'WheelEvent.wheelDeltaX',
     'WheelEvent.wheelDeltaY',
     'Window.cancelAnimationFrame',
@@ -260,6 +261,7 @@
   'indexed_db': {},
   'svg': _svg_element_constructors,
   'web_audio': {},
+  'web_sql': {},
 }
 
 _factory_ctr_strings = {
@@ -279,6 +281,10 @@
     'provider_name': 'document',
     'constructor_name': '$dom_createElement'
   },
+  'web_sql': {
+    'provider_name': 'document',
+    'constructor_name': '$dom_createElement'
+  },
 }
 
 def ElementConstructorInfos(typename, element_constructors,
diff --git a/tools/dom/templates/html/dart2js/chrome_dart2js.darttemplate b/tools/dom/templates/html/dart2js/chrome_dart2js.darttemplate
index 1752434..6449f29 100644
--- a/tools/dom/templates/html/dart2js/chrome_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/chrome_dart2js.darttemplate
@@ -3,7 +3,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// DO NOT EDIT
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:chrome library.
 
 /// Native wrappers for the Chrome Packaged App APIs.
@@ -26,4 +27,4 @@
 
 // Generated files below this line.
 part "$AUXILIARY_DIR/chrome/app_window.dart";
-part "$AUXILIARY_DIR/chrome/app_runtime.dart";
\ No newline at end of file
+part "$AUXILIARY_DIR/chrome/app_runtime.dart";
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index 20350cc..2823cdd 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -2,7 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// DO NOT EDIT
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:html library.
 
 /// The Dart HTML library.
@@ -15,6 +16,7 @@
 import 'dart:isolate';
 import 'dart:json' as json;
 import 'dart:math';
+import 'dart:web_sql';
 // Not actually used, but imported since dart:html can generate these objects.
 import 'dart:svg' as svg;
 import 'dart:web_audio' as web_audio;
diff --git a/tools/dom/templates/html/dart2js/indexed_db_dart2js.darttemplate b/tools/dom/templates/html/dart2js/indexed_db_dart2js.darttemplate
index cf7542f..0d29c1c 100644
--- a/tools/dom/templates/html/dart2js/indexed_db_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/indexed_db_dart2js.darttemplate
@@ -2,7 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// DO NOT EDIT
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:svg library.
 
 library dart.dom.indexed_db;
diff --git a/tools/dom/templates/html/dart2js/svg_dart2js.darttemplate b/tools/dom/templates/html/dart2js/svg_dart2js.darttemplate
index d907998..eedcc3c 100644
--- a/tools/dom/templates/html/dart2js/svg_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/svg_dart2js.darttemplate
@@ -1,4 +1,5 @@
-// DO NOT EDIT
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:svg library.
 
 library dart.dom.svg;
diff --git a/tools/dom/templates/html/dart2js/web_audio_dart2js.darttemplate b/tools/dom/templates/html/dart2js/web_audio_dart2js.darttemplate
index 17c774a..8cc027d 100644
--- a/tools/dom/templates/html/dart2js/web_audio_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/web_audio_dart2js.darttemplate
@@ -1,4 +1,5 @@
-// DO NOT EDIT
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:audio library.
 
 library dart.dom.web_audio;
diff --git a/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate b/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate
new file mode 100644
index 0000000..2c6fec6
--- /dev/null
+++ b/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate
@@ -0,0 +1,14 @@
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:audio library.
+
+library dart.dom.web_sql;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:_js_helper' show convertDartClosureToJS, Creates, JavaScriptIndexingBehavior, JSName;
+import 'dart:_foreign_helper' show JS;
+
+$!GENERATED_DART_FILES
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index 825b6c8..4e2b5e7 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -14,6 +14,7 @@
 import 'dart:isolate';
 import 'dart:json' as json;
 import 'dart:nativewrappers';
+import 'dart:web_sql';
 // Not actually used, but imported since dart:html can generate these objects.
 import 'dart:svg' as svg;
 import 'dart:web_audio' as web_audio;
diff --git a/tools/dom/templates/html/dartium/web_sql_dartium.darttemplate b/tools/dom/templates/html/dartium/web_sql_dartium.darttemplate
new file mode 100644
index 0000000..0556070
--- /dev/null
+++ b/tools/dom/templates/html/dartium/web_sql_dartium.darttemplate
@@ -0,0 +1,13 @@
+// DO NOT EDIT - unless you are editing documentation as per:
+// https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
+// Auto-generated dart:audio library.
+
+library dart.dom.web_sql;
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:html_common';
+import 'dart:nativewrappers';
+
+$!GENERATED_DART_FILES
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 605731c..3e0080a 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -495,7 +495,7 @@
   _ElementCssClassSet(this._element);
 
   Set<String> readClasses() {
-    var s = new Set<String>();
+    var s = new LinkedHashSet<String>();
     var classname = _element.$dom_className;
 
     for (String name in classname.split(' ')) {
diff --git a/tools/dom/templates/html/impl/impl_Geolocation.darttemplate b/tools/dom/templates/html/impl/impl_Geolocation.darttemplate
new file mode 100644
index 0000000..52dac0c
--- /dev/null
+++ b/tools/dom/templates/html/impl/impl_Geolocation.darttemplate
@@ -0,0 +1,103 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of $LIBRARYNAME;
+
+@DocsEditable
+$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+
+  @DomName('Geolocation.getCurrentPosition')
+  Future<Geoposition> getCurrentPosition({bool enableHighAccuracy,
+      Duration timeout, Duration maximumAge}) {
+    var options = {};
+    if (enableHighAccuracy != null) {
+      options['enableHighAccuracy'] = enableHighAccuracy;
+    }
+    if (timeout != null) {
+      options['timeout'] = timeout.inMilliseconds;
+    }
+    if (maximumAge != null) {
+      options['maximumAge'] = maximumAge.inMilliseconds;
+    }
+    var completer = new Completer<Geoposition>();
+    try {
+      $dom_getCurrentPosition(
+          (position) {
+            completer.complete(_ensurePosition(position));
+          },
+          (error) {
+            completer.completeError(error);
+          },
+          options);
+    } catch (e, stacktrace) {
+      completer.completeError(e, stacktrace);
+    }
+    return completer.future;
+  }
+
+  @DomName('Geolocation.watchPosition')
+  Stream<Geoposition> watchPosition({bool enableHighAccuracy,
+      Duration timeout, Duration maximumAge}) {
+
+    var options = {};
+    if (enableHighAccuracy != null) {
+      options['enableHighAccuracy'] = enableHighAccuracy;
+    }
+    if (timeout != null) {
+      options['timeout'] = timeout.inMilliseconds;
+    }
+    if (maximumAge != null) {
+      options['maximumAge'] = maximumAge.inMilliseconds;
+    }
+
+    int watchId;
+    var controller;
+    controller = new StreamController<Geoposition>(
+      onSubscriptionStateChange: () {
+        if (controller.hasSubscribers) {
+          assert(watchId == null);
+          watchId = $dom_watchPosition(
+              (position) {
+                controller.add(_ensurePosition(position));
+              },
+              (error) {
+                controller.signalError(error);
+              },
+              options);
+        } else {
+          assert(watchId != null);
+          $dom_clearWatch(watchId);
+        }
+      });
+
+    return controller.stream;
+  }
+
+  Geoposition _ensurePosition(domPosition) {
+    try {
+      // Firefox may throw on this.
+      if (domPosition is Geoposition) {
+        return domPosition;
+      }
+    } catch(e) {}
+    return new _GeopositionWrapper(domPosition);
+  }
+$!MEMBERS}
+
+$if DART2JS
+/**
+ * Wrapper for Firefox- it returns an object which we cannot map correctly.
+ * Basically Firefox was returning a [xpconnect wrapped nsIDOMGeoPosition] but
+ * which has further oddities.
+ */
+class _GeopositionWrapper implements Geoposition {
+  var _ptr;
+  _GeopositionWrapper(this._ptr);
+
+  Coordinates get coords => JS('Coordinates', '#.coords', _ptr);
+  int get timestamp => JS('int', '#.timestamp', _ptr);
+}
+$endif
+
+
diff --git a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
index 61cf7f6..9ab3886 100644
--- a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
@@ -12,7 +12,7 @@
   Set<String> readClasses() {
     var classname = _element.attributes['class'];
 
-    Set<String> s = new Set<String>();
+    Set<String> s = new LinkedHashSet<String>();
     if (classname == null) {
       return s;
     }
diff --git a/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate b/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate
index a3cf320..c49d8f6 100644
--- a/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate
@@ -134,12 +134,13 @@
         'deltaX is not supported');
   }
 
+  @DomName('WheelEvent.deltaMode')
   int get deltaMode {
-    if (JS('bool', '!!#.deltaMode', this)) {
-      // If not available then we're poly-filling and doing pixel scroll.
-      return 0;
+    if (JS('bool', '!!(#.deltaMode)', this)) {
+      return JS('int', '#.deltaMode', this);
     }
-    return this._deltaMode;
+    // If not available then we're poly-filling and doing pixel scroll.
+    return 0;
   }
 
   num get _deltaY => JS('num', '#.deltaY', this);
@@ -147,7 +148,6 @@
   num get _wheelDelta => JS('num', '#.wheelDelta', this);
   num get _wheelDeltaX => JS('num', '#.wheelDeltaX', this);
   num get _detail => JS('num', '#.detail', this);
-  int get _deltaMode => JS('int', '#.deltaMode', this);
 
   bool get _hasInitMouseScrollEvent =>
       JS('bool', '!!(#.initMouseScrollEvent)', this);
@@ -197,8 +197,5 @@
   num get deltaX => $dom_wheelDeltaX;
   @DomName('WheelEvent.deltaY')
   num get deltaY => $dom_wheelDeltaY;
-  @DomName('WheelEvent.deltaMode')
-  int get deltaMode => 0;
-
 $endif
 }
diff --git a/tools/gyp/all.gypi b/tools/gyp/all.gypi
index 236d48e..d75e339 100644
--- a/tools/gyp/all.gypi
+++ b/tools/gyp/all.gypi
@@ -30,6 +30,5 @@
     'xcode.gypi',
     'msvs.gypi',
     'configurations.gypi',
-    'source_filter.gypi',
   ],
 }
diff --git a/tools/gyp/common.gypi b/tools/gyp/common.gypi
index 861efe0..adfc1db 100644
--- a/tools/gyp/common.gypi
+++ b/tools/gyp/common.gypi
@@ -33,6 +33,5 @@
     'xcode.gypi',
     'msvs.gypi',
     'configurations.gypi',
-    'source_filter.gypi',
   ],
 }
diff --git a/tools/line_doc_comments.dart b/tools/line_doc_comments.dart
index aa7627c..a51d84d 100755
--- a/tools/line_doc_comments.dart
+++ b/tools/line_doc_comments.dart
@@ -22,11 +22,14 @@
   }
 
   var dir = new Directory(args[0]);
-  var lister = dir.list(recursive: true);
-  lister.onFile = (file) {
-    if (path.extension(file) != '.dart') return;
-    fixFile(file);
-  };
+  dir.list(recursive: true).listen(
+      (entity) {
+        if (entity is File) {
+          var file = entity.name;
+          if (path.extension(file) != '.dart') return;
+          fixFile(file);
+        }
+      });
 }
 
 void fixFile(String path) {
diff --git a/tools/test-runtime.dart b/tools/test-runtime.dart
index 867d39e..32e4e07 100755
--- a/tools/test-runtime.dart
+++ b/tools/test-runtime.dart
@@ -73,6 +73,8 @@
   }
 
   var testSuites = new List<TestSuite>();
+  TestingServerRunner.setBuildDir(firstConf);
+  TestingServerRunner.setPackageRootDir(firstConf);
   for (var conf in configurations) {
     if (selectors.containsKey('co19')) {
       testSuites.add(new Co19TestSuite(conf));
diff --git a/tools/test.dart b/tools/test.dart
index 1f88fd7..398230d 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -126,6 +126,10 @@
   }
 
   var testSuites = new List<TestSuite>();
+  // FIXME(kustermann,ricow): This is broken and should be fixed ASAP.
+  // Issue: 8366
+  TestingServerRunner.setBuildDir(firstConf);
+  TestingServerRunner.setPackageRootDir(firstConf);
   var maxBrowserProcesses = maxProcesses;
   for (var conf in configurations) {
     // There should not be more than one InternetExplorerDriver instance
@@ -134,7 +138,6 @@
     if (conf['runtime'].startsWith('ie')) {
       maxBrowserProcesses = 1;
     }
-    TestingServerRunner.setPackageRootDir(conf);
     for (String key in selectors.keys) {
       if (key == 'co19') {
         testSuites.add(new Co19TestSuite(conf));
diff --git a/tools/testing/dart/browser_test.dart b/tools/testing/dart/browser_test.dart
index 6bfc93a..5e7c715 100644
--- a/tools/testing/dart/browser_test.dart
+++ b/tools/testing/dart/browser_test.dart
@@ -5,8 +5,6 @@
 part of test_suite;
 
 String getHtmlContents(String title,
-                       Path controllerScript,
-                       Path dartJsScript,
                        String scriptType,
                        Path sourceScript) =>
 """
@@ -24,10 +22,13 @@
 </head>
 <body>
   <h1> Running $title </h1>
-  <script type="text/javascript" src="$controllerScript"></script>
+  <script type="text/javascript"
+          src="/root_dart/pkg/unittest/lib/test_controller.js">
+  </script>
   <script type="$scriptType" src="$sourceScript" onerror="externalError(null)">
   </script>
-  <script type="text/javascript" src="$dartJsScript"></script>
+  <script type="text/javascript"
+          src="/root_dart/pkg/browser/lib/dart.js"></script>
 </body>
 </html>
 """;
@@ -48,37 +49,27 @@
 </html>
 """;
 
-String wrapDartTestInLibrary(Path test, String testPath) =>
+String wrapDartTestInLibrary(Path testRelativeToDart) =>
 """
 library libraryWrapper;
-part '${pathLib.relative(test.toNativePath(),
-    from: pathLib.dirname(testPath)).replaceAll('\\', '\\\\')}';
+part '/$testRelativeToDart';
 """;
 
-String dartTestWrapper(Path dartHome, String testPath, Path library) {
-  var testPathDir = pathLib.dirname(testPath);
-  var dartHomePath = dartHome.toNativePath();
-  // TODO(efortuna): Unify path libraries used in test.dart.
-  var unitTest = pathLib.relative(pathLib.join(dartHomePath,
-    'pkg/unittest/lib'), from: testPathDir).replaceAll('\\', '\\\\');
-
-  var libString = library.toNativePath();
-  if (!pathLib.isAbsolute(libString)) {
-    libString = pathLib.join(dartHome.toNativePath(), libString);
-  }
+String dartTestWrapper(bool usePackageImport, String libraryPathComponent) {
   // Tests inside "pkg" import unittest using "package:". All others use a
   // relative path. The imports need to agree, so use a matching form here.
-  if (pathLib.split(pathLib.relative(libString,
-      from: dartHome.toNativePath())).contains("pkg")) {
+  var unitTest;
+  if (usePackageImport) {
     unitTest = 'package:unittest';
+  } else {
+    unitTest = '/root_dart/pkg/unittest/lib';
   }
   return """
 library test;
 
 import '$unitTest/unittest.dart' as unittest;
 import '$unitTest/html_config.dart' as config;
-import '${pathLib.relative(libString, from: testPathDir).replaceAll(
-    '\\', '\\\\')}' as Test;
+import '$libraryPathComponent' as Test;
 
 main() {
   config.useHtmlConfiguration();
diff --git a/tools/testing/dart/http_server.dart b/tools/testing/dart/http_server.dart
index 06b87da..6ab495b 100644
--- a/tools/testing/dart/http_server.dart
+++ b/tools/testing/dart/http_server.dart
@@ -4,6 +4,7 @@
 
 library http_server;
 
+import 'dart:async';
 import 'dart:io';
 import 'dart:isolate';
 import 'dart:uri';
@@ -12,6 +13,30 @@
 // expected number of arguments, so test.dart doesn't rely on the args library?
 // See discussion on https://codereview.chromium.org/11931025/.
 import 'vendored_pkg/args/args.dart';
+import 'utils.dart';
+
+
+/// Interface of the HTTP server:
+///
+/// /echo: This will stream the data received in the request stream back 
+///        to the client.
+/// /root_dart/X: This will serve the corresponding file from the dart
+///               directory (i.e. '$DartDirectory/X').
+/// /root_build/X: This will serve the corresponding file from the build
+///                directory (i.e. '$BuildDirectory/X').
+/// /FOO/packages/BAR: This will serve the corresponding file from the packages
+///                    directory (i.e. '$BuildDirectory/packages/BAR')
+///
+/// In case a path does not refer to a file but rather to a directory, a
+/// directory listing will be displayed.
+
+const PREFIX_BUILDDIR = 'root_build';
+const PREFIX_DARTDIR = 'root_dart';
+
+// TODO(kustermann,ricow): We could change this to the following scheme:
+// http://host:port/root_packages/X -> $BuildDir/packages/X
+// Issue: 8368
+
 
 main() {
   /** Convenience method for local testing. */
@@ -43,7 +68,11 @@
         .join(new Path('../../test.dart'))
         .canonicalize()
         .toNativePath();
+    // Note: args['package-root'] is always the build directory. We have the
+    // implicit assumption that it contains the 'packages' subdirectory.
+    // TODO: We should probably rename 'package-root' to 'build-directory'.
     TestingServerRunner._packageRootDir = new Path(args['package-root']);
+    TestingServerRunner._buildDirectory = new Path(args['package-root']);
     var network = args['network'];
     TestingServerRunner.startHttpServer(network,
         port: int.parse(args['port']));
@@ -63,98 +92,129 @@
 class TestingServerRunner {
   static List serverList = [];
   static Path _packageRootDir = null;
+  static Path _buildDirectory = null;
 
   // Added as a getter so that the function will be called again each time the
   // default request handler closure is executed.
   static Path get packageRootDir => _packageRootDir;
+  static Path get buildDirectory => _buildDirectory;
 
   static setPackageRootDir(Map configuration) {
-    _packageRootDir = TestUtils.currentWorkingDirectory.join(
+    _packageRootDir = TestUtils.absolutePath(
+        new Path(TestUtils.buildDir(configuration)));
+  }
+
+  static setBuildDir(Map configuration) {
+    _buildDirectory = TestUtils.absolutePath(
         new Path(TestUtils.buildDir(configuration)));
   }
 
   static startHttpServer(String host, {int allowedPort:-1, int port: 0}) {
-    var basePath = TestUtils.dartDir();
     var httpServer = new HttpServer();
-    var packagesDirName = 'packages';
     httpServer.onError = (e) {
-      // TODO(ricow): Once we have a debug log we should write this out there.
-      print('Test http server error: $e');
+      DebugLogger.error('HttpServer: an error occured: $e');
     };
-    httpServer.defaultRequestHandler = (request, resp) {
-      var requestPath = new Path(request.path.substring(1)).canonicalize();
-      var path = basePath.join(requestPath);
-      var file = new File(path.toNativePath());
-
-      if (requestPath.segments().contains(packagesDirName)) {
-        // Essentially implement the packages path rewriting, so we don't have
-        // to pass environment variables to the browsers.
-        var requestPathStr = requestPath.toNativePath().substring(
-            requestPath.toNativePath().indexOf(packagesDirName));
-        path = packageRootDir.append(requestPathStr);
-        file = new File(path.toNativePath());
-      }
-      file.exists().then((exists) {
-        if (exists) {
-          if (allowedPort != -1) {
-            if (request.headers.value('Origin') != null) {
-              var origin = new Uri(request.headers.value('Origin'));
-              // Allow loading from http://*:$allowedPort in browsers.
-              var allowedOrigin =
-                  '${origin.scheme}://${origin.domain}:${allowedPort}';
-              resp.headers.set("Access-Control-Allow-Origin", allowedOrigin);
-              resp.headers.set('Access-Control-Allow-Credentials', 'true');
-            }
-          } else {
-            // No allowedPort specified. Allow from anywhere (but cross-origin
-            // requests *with credentials* will fail because you can't use "*").
-            resp.headers.set("Access-Control-Allow-Origin", "*");
-          }
-          if (path.toNativePath().endsWith('.html')) {
-            resp.headers.set('Content-Type', 'text/html');
-          } else if (path.toNativePath().endsWith('.js')) {
-            resp.headers.set('Content-Type', 'application/javascript');
-          } else if (path.toNativePath().endsWith('.dart')) {
-            resp.headers.set('Content-Type', 'application/dart');
-          }
-          file.openInputStream().pipe(resp.outputStream);
-        } else {
-          var directory = new Directory.fromPath(path);
-          directory.exists().then((exists) {
-            if (!exists) {
-              sendNotFound(resp);
-            } else {
-              sendDirectoryListing(directory, request, resp);
-            }
-          });
-        }
-      });
+    httpServer.defaultRequestHandler = (request, response) {
+      handleFileOrDirectoryRequest(request, response, allowedPort);
     };
-
-    // Echos back the contents of the request as the response data.
-    httpServer.addRequestHandler((req) => req.path == "/echo", (request, resp) {
-      resp.headers.set("Access-Control-Allow-Origin", "*");
-
-      request.inputStream.pipe(resp.outputStream);
-    });
+    httpServer.addRequestHandler(
+        (req) => req.path == "/echo", handleEchoRequest);
 
     httpServer.listen(host, port);
     serverList.add(httpServer);
   }
 
-  static void sendNotFound(HttpResponse response) {
-    response.statusCode = HttpStatus.NOT_FOUND;
-    try {
-      response.outputStream.close();
-    } catch (e) {
-      if (e is StreamException) {
-        print('Test http_server error closing the response stream: $e');
+
+  static void handleFileOrDirectoryRequest(HttpRequest request,
+                                           HttpResponse response,
+                                           int allowedPort) {
+    var path = getFilePathFromRequestPath(request.path);
+    if (path != null) {
+      var file = new File.fromPath(path);
+      file.exists().then((exists) {
+        if (exists) {
+          sendFileContent(request, response, allowedPort, path, file);
+        } else {
+          var directory = new Directory.fromPath(path);
+          directory.exists().then((exists) {
+            if (exists) {
+              listDirectory(directory).then((entries) {
+                sendDirectoryListing(entries, request, response);
+              });
+            } else {
+              sendNotFound(request, response);
+            }
+          });
+        }
+      });
+    } else {
+      if (request.path == '/') {
+        var entries = [new _Entry('root_dart', 'root_dart/'),
+                       new _Entry('root_build', 'root_build/'),
+                       new _Entry('echo', 'echo')];
+        sendDirectoryListing(entries, request, response);
       } else {
-        throw e;
+        sendNotFound(request, response);
       }
     }
   }
 
+  static void handleEchoRequest(HttpRequest request, HttpResponse response) {
+    response.headers.set("Access-Control-Allow-Origin", "*");
+    request.inputStream.pipe(response.outputStream);
+  }
+
+  static Path getFilePathFromRequestPath(String urlRequestPath) {
+    // Go to the top of the file to see an explanation of the URL path scheme.
+    var requestPath = new Path(urlRequestPath.substring(1)).canonicalize();
+    var pathSegments = requestPath.segments();
+    if (pathSegments.length > 0) {
+      var basePath;
+      var relativePath;
+      if (pathSegments[0] == PREFIX_BUILDDIR) {
+        basePath = _buildDirectory;
+        relativePath = new Path(
+            pathSegments.getRange(1, pathSegments.length - 1).join('/'));
+      } else if (pathSegments[0] == PREFIX_DARTDIR) {
+        basePath = TestUtils.dartDir();
+        relativePath = new Path(
+            pathSegments.getRange(1, pathSegments.length - 1).join('/'));
+      }
+      var packagesDirName = 'packages';
+      var packagesIndex = pathSegments.indexOf(packagesDirName);
+      if (packagesIndex != -1) {
+        var start = packagesIndex + 1;
+        var length = pathSegments.length - start;
+        basePath = _packageRootDir.append(packagesDirName);
+        relativePath = new Path(
+            pathSegments.getRange(start, length).join('/'));
+      }
+      if (basePath != null && relativePath != null) {
+        return basePath.join(relativePath);
+      }
+    }
+    return null;
+  }
+
+  static Future<List<_Entry>> listDirectory(Directory directory) {
+    var completer = new Completer();
+    var entries = [];
+
+    directory.list()
+      ..onFile = (filepath) {
+        var filename = new Path(filepath).filename;
+        entries.add(new _Entry(filename, filename));
+      }
+      ..onDir = (dirpath) {
+        var filename = new Path(dirpath).filename;
+        entries.add(new _Entry(filename, '$filename/'));
+      }
+      ..onDone = (_) {
+        completer.complete(entries);
+      };
+    return completer.future;
+  }
+
   /**
    * Sends a simple listing of all the files and sub-directories within
    * directory.
@@ -162,8 +222,9 @@
    * This is intended to make it easier to browse tests when manually running
    * tests against this test server.
    */
-  static void sendDirectoryListing(Directory directory, HttpRequest request,
-      HttpResponse response) {
+  static void sendDirectoryListing(entries,
+                                   HttpRequest request,
+                                   HttpResponse response) {
     response.headers.set('Content-Type', 'text/html');
     var header = '''<!DOCTYPE html>
     <html>
@@ -181,30 +242,62 @@
     </body>
     </html>''';
 
-    var entries = [];
 
-    directory.list()
-      ..onFile = (filepath) {
-        var filename = new Path(filepath).filename;
-        entries.add(new _Entry(filename, filename));
-      }
-      ..onDir = (dirpath) {
-        var filename = new Path(dirpath).filename;
-        entries.add(new _Entry(filename, '$filename/'));
-      }
-      ..onDone = (_) {
-        var requestPath = new Path.raw(request.path);
-        entries.sort();
+    entries.sort();
+    response.outputStream.writeString(header);
+    for (var entry in entries) {
+      response.outputStream.writeString(
+          '<li><a href="${new Path(request.path).append(entry.name)}">'
+          '${entry.displayName}</a></li>');
+    }
+    response.outputStream.writeString(footer);
+    response.outputStream.close();
+  }
 
-        response.outputStream.writeString(header);
-        for (var entry in entries) {
-          response.outputStream.writeString(
-              '<li><a href="${requestPath.append(entry.name)}">'
-              '${entry.displayName}</a></li>');
-        }
-        response.outputStream.writeString(footer);
-        response.outputStream.close();
-      };
+  static void sendFileContent(HttpRequest request,
+                              HttpResponse response,
+                              int allowedPort,
+                              Path path,
+                              File file) {
+    if (allowedPort != -1) {
+      var origin = new Uri(request.headers.value('Origin'));
+      // Allow loading from http://*:$allowedPort in browsers.
+      var allowedOrigin =
+          '${origin.scheme}://${origin.domain}:${allowedPort}';
+      response.headers.set("Access-Control-Allow-Origin", allowedOrigin);
+      response.headers.set('Access-Control-Allow-Credentials', 'true');
+    } else {
+      // No allowedPort specified. Allow from anywhere (but cross-origin
+      // requests *with credentials* will fail because you can't use "*").
+      response.headers.set("Access-Control-Allow-Origin", "*");
+    }
+    if (path.filename.endsWith('.html')) {
+      response.headers.set('Content-Type', 'text/html');
+    } else if (path.filename.endsWith('.js')) {
+      response.headers.set('Content-Type', 'application/javascript');
+    } else if (path.filename.endsWith('.dart')) {
+      response.headers.set('Content-Type', 'application/dart');
+    }
+    file.openInputStream().pipe(response.outputStream);
+  }
+
+  static void sendNotFound(HttpRequest request, HttpResponse response) {
+    // NOTE: Since some tests deliberately try to access non-existent files.
+    // We might want to remove this warning (otherwise it will show
+    // up in the debug.log every time).
+    DebugLogger.warning('HttpServer: could not find file for request path: '
+                        '"${request.path}"');
+    response.statusCode = HttpStatus.NOT_FOUND;
+    try {
+      response.outputStream.close();
+    } catch (e) {
+      if (e is StreamException) {
+        DebugLogger.warning('HttpServer: error while closing the response '
+                            'stream: $e');
+      } else {
+        throw e;
+      }
+    }
   }
 
   static terminateHttpServers() {
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 9833dd4..6ebd60c 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -1594,7 +1594,9 @@
         new Timer(100, (_) => _tryRunTest());  // Don't lose a process.
         return;
       }
-      if (_verbose) {
+      // Before running any commands, we print out all commands if '--verbose'
+      // was specified.
+      if (_verbose && test.commandOutputs.length == 0) {
         int i = 1;
         if (test is BrowserTestCase) {
           // Additional command for rerunning the steps locally after the fact.
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index f8b59d8..f6ff12c 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -23,9 +23,7 @@
 import "status_file_parser.dart";
 import "test_runner.dart";
 import "utils.dart";
-
-// TODO(efortuna,whess): Remove this import.
-import 'vendored_pkg/path/path.dart' as pathLib;
+import "http_server.dart" show PREFIX_BUILDDIR, PREFIX_DARTDIR;
 
 part "browser_test.dart";
 
@@ -812,7 +810,77 @@
     };
   }
 
- /**
+
+  /**
+   * _createUrlPathFromFile takes a [file], which is either located in the dart
+   * or in the build directory, and will return a String representing
+   * the relative path to either the dart or the build directory.
+   * Thus, the returned [String] will be the path component of the URL
+   * corresponding to [file] (the http server serves files relative to the
+   * dart/build directories).
+   */
+  String _createUrlPathFromFile(Path file) {
+    file = TestUtils.absolutePath(file);
+    
+    var relativeBuildDir = new Path(TestUtils.buildDir(configuration));
+    var buildDir = TestUtils.absolutePath(relativeBuildDir);
+    var dartDir = TestUtils.absolutePath(TestUtils.dartDir());
+
+    var fileString = file.toString();
+    if (fileString.startsWith(buildDir.toString())) {
+      var fileRelativeToBuildDir = file.relativeTo(buildDir);
+      return "/$PREFIX_BUILDDIR/$fileRelativeToBuildDir";
+    } else if (fileString.startsWith(dartDir.toString())) {
+      var fileRelativeToDartDir = file.relativeTo(dartDir);
+      return "/$PREFIX_DARTDIR/$fileRelativeToDartDir";
+    }
+    // Unreachable
+    Except.fail('This should be unreachable.');
+  }
+
+  void _getUriForBrowserTest(TestInformation info,
+                            String pathComponent,
+                            subtestNames,
+                            subtestIndex) {
+    // Note: If we run test.py with the "--list" option, no http servers
+    // will be started. Therefore serverList is an empty list in this
+    // case. So we use PORT/CROSS_ORIGIN_PORT instead of real ports.
+    var serverPort = "PORT";
+    var crossOriginPort = "CROSS_ORIGIN_PORT";
+    if (!configuration['list']) {
+      serverPort = serverList[0].port.toString();
+      crossOriginPort = serverList[1].port.toString();
+    }
+
+    var url= 'http://127.0.0.1:$serverPort$pathComponent'
+        '?crossOriginPort=$crossOriginPort';
+    if (info.optionsFromFile['isMultiHtmlTest'] && subtestNames.length > 0) {
+      url= '${url}&group=${subtestNames[subtestIndex]}';
+    }
+    return url;
+  }
+
+  void _createWrapperFile(String dartWrapperFilename, dartLibraryFilename) {
+    File file = new File(dartWrapperFilename);
+    RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE);
+
+    var usePackageImport = dartLibraryFilename.segments().contains("pkg");
+    var libraryPathComponent = _createUrlPathFromFile(dartLibraryFilename);
+    dartWrapper.writeStringSync(dartTestWrapper(usePackageImport,
+                                                libraryPathComponent));
+    dartWrapper.closeSync();
+  }
+
+  void _createLibraryWrapperFile(Path dartLibraryFilename, filePath) {
+    File file = new File(dartLibraryFilename.toNativePath());
+    RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE);
+    var requestPath = new Path(PREFIX_DARTDIR)
+        .join(filePath.relativeTo(TestUtils.dartDir()));
+    dartLibrary.writeStringSync(wrapDartTestInLibrary(requestPath));
+    dartLibrary.closeSync();
+  }
+
+  /**
    * The [StandardTestSuite] has support for tests that
    * compile a test from Dart to JavaScript, and then run the resulting
    * JavaScript.  This function creates a working directory to hold the
@@ -867,18 +935,9 @@
         if (!isLibraryDefinition) {
           dartLibraryFilename = new Path(tempDir).append(
               'test_as_library.dart');
-          File file = new File(dartLibraryFilename.toNativePath());
-          RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE);
-          dartLibrary.writeStringSync(
-              wrapDartTestInLibrary(filePath, file.name));
-          dartLibrary.closeSync();
+          _createLibraryWrapperFile(dartLibraryFilename, filePath);
         }
-
-        File file = new File(dartWrapperFilename);
-        RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE);
-        dartWrapper.writeStringSync(
-            dartTestWrapper(dartDir, file.name, dartLibraryFilename));
-        dartWrapper.closeSync();
+        _createWrapperFile(dartWrapperFilename, dartLibraryFilename);
       } else {
         dartWrapperFilename = filename;
         // TODO(whesse): Once test.py is retired, adjust the relative path in
@@ -895,8 +954,10 @@
         }
         htmlPath = '$tempDir/../$htmlFilename';
       }
-      final String scriptPath = (compiler == 'none') ?
+      String scriptPath = (compiler == 'none') ?
           dartWrapperFilename : compiledDartWrapperFilename;
+      scriptPath = _createUrlPathFromFile(new Path(scriptPath));
+
       // Create the HTML file for the test.
       RandomAccessFile htmlTest = new File(htmlPath).openSync(FileMode.WRITE);
       String content = null;
@@ -907,22 +968,13 @@
       Path expectedOutput = null;
       if (new File.fromPath(pngPath).existsSync()) {
         expectedOutput = pngPath;
-        // TODO(efortuna): Unify path libraries in test.dart.
-        content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath,
-            from: pathLib.dirname(htmlPath)));
+        content = getHtmlLayoutContents(scriptType, new Path("$scriptPath"));
       } else if (new File.fromPath(txtPath).existsSync()) {
         expectedOutput = txtPath;
-        content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath,
-            from: pathLib.dirname(htmlPath)));
+        content = getHtmlLayoutContents(scriptType, new Path("$scriptPath"));
       } else {
-        final htmlLocation = new Path(htmlPath);
-        content = getHtmlContents(
-          filename,
-          dartDir.append('pkg/unittest/lib/test_controller.js')
-              .relativeTo(htmlLocation),
-          dartDir.append('pkg/browser/lib/dart.js').relativeTo(htmlLocation),
-          scriptType,
-          new Path(scriptPath).relativeTo(htmlLocation));
+        content = getHtmlContents(filename, scriptType,
+            new Path("$scriptPath"));
       }
       htmlTest.writeStringSync(content);
       htmlTest.closeSync();
@@ -962,35 +1014,11 @@
           commandSet = [];
         }
 
-        List<String> args = <String>[];
-        var basePath = TestUtils.dartDir().toString();
-        if (!htmlPath.startsWith('/') && !htmlPath.startsWith('http')) {
-          htmlPath = '/$htmlPath';
-        }
-        htmlPath = htmlPath.startsWith(basePath) ?
-            htmlPath.substring(basePath.length) : htmlPath;
-        String fullHtmlPath = htmlPath;
-        var searchStr = '?';
-        if (!htmlPath.startsWith('http')) {
-          // Note: If we run test.py with the "--list" option, no http servers
-          // will be started. Therefore serverList is an empty list in this
-          // case. So we use PORT/CROSS_ORIGIN_PORT instead of real ports.
-          var serverPort = "PORT";
-          var crossOriginPort = "CROSS_ORIGIN_PORT";
-          if (!configuration['list']) {
-            serverPort = serverList[0].port.toString();
-            crossOriginPort = serverList[1].port.toString();
-          }
-          fullHtmlPath = 'http://127.0.0.1:$serverPort$htmlPath${searchStr}'
-              'crossOriginPort=$crossOriginPort';
-          searchStr = '&';
-        }
-        if (info.optionsFromFile['isMultiHtmlTest']
-            && subtestNames.length > 0) {
-          fullHtmlPath = '${fullHtmlPath}${searchStr}group='
-              '${subtestNames[subtestIndex]}';
-        }
+        var htmlPath_subtest = _createUrlPathFromFile(new Path(htmlPath));
+        var fullHtmlPath = _getUriForBrowserTest(info, htmlPath_subtest,
+                                                 subtestNames, subtestIndex);
 
+        List<String> args = <String>[];
         if (TestUtils.usesWebDriver(runtime)) {
           args = [
               dartDir.append('tools/testing/run_selenium.py').toNativePath(),
@@ -1125,8 +1153,7 @@
     var minified = configuration['minified'] ? '-minified' : '';
     var dirName = "${configuration['compiler']}-${configuration['runtime']}"
                   "$checked$minified";
-    Path generatedTestPath = new Path(dartDir.toNativePath())
-        .append(buildDir)
+    Path generatedTestPath = new Path(buildDir)
         .append('generated_tests')
         .append(dirName)
         .append(testUniqueName);
@@ -1816,6 +1843,10 @@
       const ['d8', 'jsshell'].contains(runtime);
 
   static String buildDir(Map configuration) {
+    // FIXME(kustermann,ricow): Our code assumes that the returned 'buildDir'
+    // is relative to the current working directory.
+    // Thus, if we pass in an absolute path (e.g. '--build-directory=/tmp/out')
+    // we get into trouble.
     if (configuration['build_directory'] != '') {
       return configuration['build_directory'];
     }
diff --git a/tools/testing/dart/vendored_pkg/path/path.dart b/tools/testing/dart/vendored_pkg/path/path.dart
deleted file mode 100644
index f27d558..0000000
--- a/tools/testing/dart/vendored_pkg/path/path.dart
+++ /dev/null
@@ -1,689 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/// A comprehensive, cross-platform path manipulation library.
-library path;
-
-import 'dart:io' as io;
-
-/// An internal builder for the current OS so we can provide a straight
-/// functional interface and not require users to create one.
-final _builder = new Builder();
-
-/// Gets the path to the current working directory.
-String get current => new io.Directory.current().path;
-
-/// Gets the path separator for the current platform. On Mac and Linux, this
-/// is `/`. On Windows, it's `\`.
-String get separator => _builder.separator;
-
-/// Converts [path] to an absolute path by resolving it relative to the current
-/// working directory. If [path] is already an absolute path, just returns it.
-///
-///     path.absolute('foo/bar.txt'); // -> /your/current/dir/foo/bar.txt
-String absolute(String path) => join(current, path);
-
-/// Gets the part of [path] after the last separator.
-///
-///     path.basename('path/to/foo.dart'); // -> 'foo.dart'
-///     path.basename('path/to');          // -> 'to'
-///
-/// Trailing separators are ignored.
-///
-///     builder.dirname('path/to/'); // -> 'to'
-String basename(String path) => _builder.basename(path);
-
-/// Gets the part of [path] after the last separator, and without any trailing
-/// file extension.
-///
-///     path.basenameWithoutExtension('path/to/foo.dart'); // -> 'foo'
-///
-/// Trailing separators are ignored.
-///
-///     builder.dirname('path/to/foo.dart/'); // -> 'foo'
-String basenameWithoutExtension(String path) =>
-    _builder.basenameWithoutExtension(path);
-
-/// Gets the part of [path] before the last separator.
-///
-///     path.dirname('path/to/foo.dart'); // -> 'path/to'
-///     path.dirname('path/to');          // -> 'to'
-///
-/// Trailing separators are ignored.
-///
-///     builder.dirname('path/to/'); // -> 'path'
-String dirname(String path) => _builder.dirname(path);
-
-/// Gets the file extension of [path]: the portion of [basename] from the last
-/// `.` to the end (including the `.` itself).
-///
-///     path.extension('path/to/foo.dart');    // -> '.dart'
-///     path.extension('path/to/foo');         // -> ''
-///     path.extension('path.to/foo');         // -> ''
-///     path.extension('path/to/foo.dart.js'); // -> '.js'
-///
-/// If the file name starts with a `.`, then that is not considered the
-/// extension:
-///
-///     path.extension('~/.bashrc');    // -> ''
-///     path.extension('~/.notes.txt'); // -> '.txt'
-String extension(String path) => _builder.extension(path);
-
-// TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
-/// Returns the root of [path], if it's absolute, or the empty string if it's
-/// relative.
-///
-///     // Unix
-///     path.rootPrefix('path/to/foo'); // -> ''
-///     path.rootPrefix('/path/to/foo'); // -> '/'
-///
-///     // Windows
-///     path.rootPrefix(r'path\to\foo'); // -> ''
-///     path.rootPrefix(r'C:\path\to\foo'); // -> r'C:\'
-String rootPrefix(String path) => _builder.rootPrefix(path);
-
-/// Returns `true` if [path] is an absolute path and `false` if it is a
-/// relative path. On POSIX systems, absolute paths start with a `/` (forward
-/// slash). On Windows, an absolute path starts with `\\`, or a drive letter
-/// followed by `:/` or `:\`.
-bool isAbsolute(String path) => _builder.isAbsolute(path);
-
-/// Returns `true` if [path] is a relative path and `false` if it is absolute.
-/// On POSIX systems, absolute paths start with a `/` (forward slash). On
-/// Windows, an absolute path starts with `\\`, or a drive letter followed by
-/// `:/` or `:\`.
-bool isRelative(String path) => _builder.isRelative(path);
-
-/// Joins the given path parts into a single path using the current platform's
-/// [separator]. Example:
-///
-///     path.join('path', 'to', 'foo'); // -> 'path/to/foo'
-///
-/// If any part ends in a path separator, then a redundant separator will not
-/// be added:
-///
-///     path.join('path/', 'to', 'foo'); // -> 'path/to/foo
-///
-/// If a part is an absolute path, then anything before that will be ignored:
-///
-///     path.join('path', '/to', 'foo'); // -> '/to/foo'
-String join(String part1, [String part2, String part3, String part4,
-            String part5, String part6, String part7, String part8]) =>
-  _builder.join(part1, part2, part3, part4, part5, part6, part7, part8);
-
-// TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
-/// Splits [path] into its components using the current platform's [separator].
-///
-///     path.split('path/to/foo'); // -> ['path', 'to', 'foo']
-///
-/// The path will *not* be normalized before splitting.
-///
-///     path.split('path/../foo'); // -> ['path', '..', 'foo']
-///
-/// If [path] is absolute, the root directory will be the first element in the
-/// array. Example:
-///
-///     // Unix
-///     path.split('/path/to/foo'); // -> ['/', 'path', 'to', 'foo']
-///
-///     // Windows
-///     path.split(r'C:\path\to\foo'); // -> [r'C:\', 'path', 'to', 'foo']
-List<String> split(String path) => _builder.split(path);
-
-/// Normalizes [path], simplifying it by handling `..`, and `.`, and
-/// removing redundant path separators whenever possible.
-///
-///     path.normalize('path/./to/..//file.text'); // -> 'path/file.txt'
-String normalize(String path) => _builder.normalize(path);
-
-/// Attempts to convert [path] to an equivalent relative path from the current
-/// directory.
-///
-///     // Given current directory is /root/path:
-///     path.relative('/root/path/a/b.dart'); // -> 'a/b.dart'
-///     path.relative('/root/other.dart'); // -> '../other.dart'
-///
-/// If the [from] argument is passed, [path] is made relative to that instead.
-///
-///     path.relative('/root/path/a/b.dart',
-///         from: '/root/path'); // -> 'a/b.dart'
-///     path.relative('/root/other.dart',
-///         from: '/root/path'); // -> '../other.dart'
-///
-/// Since there is no relative path from one drive letter to another on Windows,
-/// this will return an absolute path in that case.
-///
-///     path.relative(r'D:\other', from: r'C:\home'); // -> 'D:\other'
-String relative(String path, {String from}) =>
-    _builder.relative(path, from: from);
-
-/// Removes a trailing extension from the last part of [path].
-///
-///     withoutExtension('path/to/foo.dart'); // -> 'path/to/foo'
-String withoutExtension(String path) => _builder.withoutExtension(path);
-
-/// An instantiable class for manipulating paths. Unlike the top-level
-/// functions, this lets you explicitly select what platform the paths will use.
-class Builder {
-  /// Creates a new path builder for the given style and root directory.
-  ///
-  /// If [style] is omitted, it uses the host operating system's path style. If
-  /// [root] is omitted, it defaults to the current working directory. If [root]
-  /// is relative, it is considered relative to the current working directory.
-  factory Builder({Style style, String root}) {
-    if (style == null) {
-      if (io.Platform.operatingSystem == 'windows') {
-        style = Style.windows;
-      } else {
-        style = Style.posix;
-      }
-    }
-
-    if (root == null) root = current;
-
-    return new Builder._(style, root);
-  }
-
-  Builder._(this.style, this.root);
-
-  /// The style of path that this builder works with.
-  final Style style;
-
-  /// The root directory that relative paths will be relative to.
-  final String root;
-
-  /// Gets the path separator for the builder's [style]. On Mac and Linux,
-  /// this is `/`. On Windows, it's `\`.
-  String get separator => style.separator;
-
-  /// Gets the part of [path] after the last separator on the builder's
-  /// platform.
-  ///
-  ///     builder.basename('path/to/foo.dart'); // -> 'foo.dart'
-  ///     builder.basename('path/to');          // -> 'to'
-  ///
-  /// Trailing separators are ignored.
-  ///
-  ///     builder.dirname('path/to/'); // -> 'to'
-  String basename(String path) => _parse(path).basename;
-
-  /// Gets the part of [path] after the last separator on the builder's
-  /// platform, and without any trailing file extension.
-  ///
-  ///     builder.basenameWithoutExtension('path/to/foo.dart'); // -> 'foo'
-  ///
-  /// Trailing separators are ignored.
-  ///
-  ///     builder.dirname('path/to/foo.dart/'); // -> 'foo'
-  String basenameWithoutExtension(String path) =>
-    _parse(path).basenameWithoutExtension;
-
-  /// Gets the part of [path] before the last separator.
-  ///
-  ///     builder.dirname('path/to/foo.dart'); // -> 'path/to'
-  ///     builder.dirname('path/to');          // -> 'path'
-  ///
-  /// Trailing separators are ignored.
-  ///
-  ///     builder.dirname('path/to/'); // -> 'path'
-  String dirname(String path) {
-    var parsed = _parse(path);
-    parsed.removeTrailingSeparators();
-    if (parsed.parts.isEmpty) return parsed.root == null ? '.' : parsed.root;
-    if (parsed.parts.length == 1) {
-      return parsed.root == null ? '.' : parsed.root;
-    }
-    parsed.parts.removeLast();
-    parsed.separators.removeLast();
-    parsed.removeTrailingSeparators();
-    return parsed.toString();
-  }
-
-  /// Gets the file extension of [path]: the portion of [basename] from the last
-  /// `.` to the end (including the `.` itself).
-  ///
-  ///     builder.extension('path/to/foo.dart'); // -> '.dart'
-  ///     builder.extension('path/to/foo'); // -> ''
-  ///     builder.extension('path.to/foo'); // -> ''
-  ///     builder.extension('path/to/foo.dart.js'); // -> '.js'
-  ///
-  /// If the file name starts with a `.`, then it is not considered an
-  /// extension:
-  ///
-  ///     builder.extension('~/.bashrc');    // -> ''
-  ///     builder.extension('~/.notes.txt'); // -> '.txt'
-  String extension(String path) => _parse(path).extension;
-
-  // TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
-  /// Returns the root of [path], if it's absolute, or an empty string if it's
-  /// relative.
-  ///
-  ///     // Unix
-  ///     builder.rootPrefix('path/to/foo'); // -> ''
-  ///     builder.rootPrefix('/path/to/foo'); // -> '/'
-  ///
-  ///     // Windows
-  ///     builder.rootPrefix(r'path\to\foo'); // -> ''
-  ///     builder.rootPrefix(r'C:\path\to\foo'); // -> r'C:\'
-  String rootPrefix(String path) {
-    var root = _parse(path).root;
-    return root == null ? '' : root;
-  }
-
-  /// Returns `true` if [path] is an absolute path and `false` if it is a
-  /// relative path. On POSIX systems, absolute paths start with a `/` (forward
-  /// slash). On Windows, an absolute path starts with `\\`, or a drive letter
-  /// followed by `:/` or `:\`.
-  bool isAbsolute(String path) => _parse(path).isAbsolute;
-
-  /// Returns `true` if [path] is a relative path and `false` if it is absolute.
-  /// On POSIX systems, absolute paths start with a `/` (forward slash). On
-  /// Windows, an absolute path starts with `\\`, or a drive letter followed by
-  /// `:/` or `:\`.
-  bool isRelative(String path) => !isAbsolute(path);
-
-  /// Joins the given path parts into a single path. Example:
-  ///
-  ///     builder.join('path', 'to', 'foo'); // -> 'path/to/foo'
-  ///
-  /// If any part ends in a path separator, then a redundant separator will not
-  /// be added:
-  ///
-  ///     builder.join('path/', 'to', 'foo'); // -> 'path/to/foo
-  ///
-  /// If a part is an absolute path, then anything before that will be ignored:
-  ///
-  ///     builder.join('path', '/to', 'foo'); // -> '/to/foo'
-  ///
-  String join(String part1, [String part2, String part3, String part4,
-              String part5, String part6, String part7, String part8]) {
-    var buffer = new StringBuffer();
-    var needsSeparator = false;
-
-    var parts = [part1, part2, part3, part4, part5, part6, part7, part8];
-    for (var i = 1; i < parts.length; i++) {
-      if (parts[i] != null && parts[i - 1] == null) {
-        throw new ArgumentError("join(): part ${i - 1} was null, but part $i "
-            "was not.");
-      }
-    }
-
-    for (var part in parts) {
-      if (part == null) continue;
-
-      if (this.isAbsolute(part)) {
-        // An absolute path discards everything before it.
-        buffer.clear();
-        buffer.add(part);
-      } else {
-        if (part.length > 0 && part[0].contains(style.separatorPattern)) {
-          // The part starts with a separator, so we don't need to add one.
-        } else if (needsSeparator) {
-          buffer.add(separator);
-        }
-
-        buffer.add(part);
-      }
-
-      // Unless this part ends with a separator, we'll need to add one before
-      // the next part.
-      needsSeparator = part.length > 0 &&
-          !part[part.length - 1].contains(style.separatorPattern);
-    }
-
-    return buffer.toString();
-  }
-
-  // TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
-  /// Splits [path] into its components using the current platform's
-  /// [separator]. Example:
-  ///
-  ///     builder.split('path/to/foo'); // -> ['path', 'to', 'foo']
-  ///
-  /// The path will *not* be normalized before splitting.
-  ///
-  ///     builder.split('path/../foo'); // -> ['path', '..', 'foo']
-  ///
-  /// If [path] is absolute, the root directory will be the first element in the
-  /// array. Example:
-  ///
-  ///     // Unix
-  ///     builder.split('/path/to/foo'); // -> ['/', 'path', 'to', 'foo']
-  ///
-  ///     // Windows
-  ///     builder.split(r'C:\path\to\foo'); // -> [r'C:\', 'path', 'to', 'foo']
-  List<String> split(String path) {
-    var parsed = _parse(path);
-    // Filter out empty parts that exist due to multiple separators in a row.
-    parsed.parts = parsed.parts.where((part) => !part.isEmpty).toList();
-    if (parsed.root != null) parsed.parts.insertRange(0, 1, parsed.root);
-    return parsed.parts;
-  }
-
-  /// Normalizes [path], simplifying it by handling `..`, and `.`, and
-  /// removing redundant path separators whenever possible.
-  ///
-  ///     builder.normalize('path/./to/..//file.text'); // -> 'path/file.txt'
-  String normalize(String path) {
-    if (path == '') return path;
-
-    var parsed = _parse(path);
-    parsed.normalize();
-    return parsed.toString();
-  }
-
-  /// Creates a new path by appending the given path parts to the [root].
-  /// Equivalent to [join()] with [root] as the first argument. Example:
-  ///
-  ///     var builder = new Builder(root: 'root');
-  ///     builder.resolve('path', 'to', 'foo'); // -> 'root/path/to/foo'
-  String resolve(String part1, [String part2, String part3, String part4,
-              String part5, String part6, String part7]) {
-    if (!?part2) return join(root, part1);
-    if (!?part3) return join(root, part1, part2);
-    if (!?part4) return join(root, part1, part2, part3);
-    if (!?part5) return join(root, part1, part2, part3, part4);
-    if (!?part6) return join(root, part1, part2, part3, part4, part5);
-    if (!?part7) return join(root, part1, part2, part3, part4, part5, part6);
-    return join(root, part1, part2, part3, part4, part5, part6, part7);
-  }
-
-  /// Attempts to convert [path] to an equivalent relative path relative to
-  /// [root].
-  ///
-  ///     var builder = new Builder(root: '/root/path');
-  ///     builder.relative('/root/path/a/b.dart'); // -> 'a/b.dart'
-  ///     builder.relative('/root/other.dart'); // -> '../other.dart'
-  ///
-  /// If the [from] argument is passed, [path] is made relative to that instead.
-  ///
-  ///     builder.relative('/root/path/a/b.dart',
-  ///         from: '/root/path'); // -> 'a/b.dart'
-  ///     builder.relative('/root/other.dart',
-  ///         from: '/root/path'); // -> '../other.dart'
-  ///
-  /// Since there is no relative path from one drive letter to another on
-  /// Windows, this will return an absolute path in that case.
-  ///
-  ///     builder.relative(r'D:\other', from: r'C:\other'); // -> 'D:\other'
-  ///
-  /// This will also return an absolute path if an absolute [path] is passed to
-  /// a builder with a relative [root].
-  ///
-  ///     var builder = new Builder(r'some/relative/path');
-  ///     builder.relative(r'/absolute/path'); // -> '/absolute/path'
-  String relative(String path, {String from}) {
-    if (path == '') return '.';
-
-    from = from == null ? root : this.join(root, from);
-
-    // We can't determine the path from a relative path to an absolute path.
-    if (this.isRelative(from) && this.isAbsolute(path)) {
-      return this.normalize(path);
-    }
-
-    // If the given path is relative, resolve it relative to the root of the
-    // builder.
-    if (this.isRelative(path)) path = this.resolve(path);
-
-    // If the path is still relative and `from` is absolute, we're unable to
-    // find a path from `from` to `path`.
-    if (this.isRelative(path) && this.isAbsolute(from)) {
-      throw new ArgumentError('Unable to find a path to "$path" from "$from".');
-    }
-
-    var fromParsed = _parse(from)..normalize();
-    var pathParsed = _parse(path)..normalize();
-
-    // If the root prefixes don't match (for example, different drive letters
-    // on Windows), then there is no relative path, so just return the absolute
-    // one. In Windows, drive letters are case-insenstive and we allow
-    // calculation of relative paths, even if a path has not been normalized.
-    if (fromParsed.root != pathParsed.root &&
-        ((fromParsed.root ==  null || pathParsed.root == null) ||
-          fromParsed.root.toLowerCase().replaceAll('/', '\\') !=
-          pathParsed.root.toLowerCase().replaceAll('/', '\\'))) {
-      return pathParsed.toString();
-    }
-
-    // Strip off their common prefix.
-    while (fromParsed.parts.length > 0 && pathParsed.parts.length > 0 &&
-           fromParsed.parts[0] == pathParsed.parts[0]) {
-      fromParsed.parts.removeAt(0);
-      fromParsed.separators.removeAt(0);
-      pathParsed.parts.removeAt(0);
-      pathParsed.separators.removeAt(0);
-    }
-
-    // If there are any directories left in the root path, we need to walk up
-    // out of them.
-    pathParsed.parts.insertRange(0, fromParsed.parts.length, '..');
-    pathParsed.separators.insertRange(0, fromParsed.parts.length,
-        style.separator);
-
-    // Corner case: the paths completely collapsed.
-    if (pathParsed.parts.length == 0) return '.';
-
-    // Make it relative.
-    pathParsed.root = '';
-    pathParsed.removeTrailingSeparators();
-
-    return pathParsed.toString();
-  }
-
-  /// Removes a trailing extension from the last part of [path].
-  ///
-  ///     builder.withoutExtension('path/to/foo.dart'); // -> 'path/to/foo'
-  String withoutExtension(String path) {
-    var parsed = _parse(path);
-
-    for (var i = parsed.parts.length - 1; i >= 0; i--) {
-      if (!parsed.parts[i].isEmpty) {
-        parsed.parts[i] = parsed.basenameWithoutExtension;
-        break;
-      }
-    }
-
-    return parsed.toString();
-  }
-
-  _ParsedPath _parse(String path) {
-    var before = path;
-
-    // Remove the root prefix, if any.
-    var root = style.getRoot(path);
-    if (root != null) path = path.substring(root.length);
-
-    // Split the parts on path separators.
-    var parts = [];
-    var separators = [];
-    var start = 0;
-    for (var match in style.separatorPattern.allMatches(path)) {
-      parts.add(path.substring(start, match.start));
-      separators.add(match[0]);
-      start = match.end;
-    }
-
-    // Add the final part, if any.
-    if (start < path.length) {
-      parts.add(path.substring(start));
-      separators.add('');
-    }
-
-    return new _ParsedPath(style, root, parts, separators);
-  }
-}
-
-/// An enum type describing a "flavor" of path.
-class Style {
-  /// POSIX-style paths use "/" (forward slash) as separators. Absolute paths
-  /// start with "/". Used by UNIX, Linux, Mac OS X, and others.
-  static final posix = new Style._('posix', '/', '/', '/');
-
-  /// Windows paths use "\" (backslash) as separators. Absolute paths start with
-  /// a drive letter followed by a colon (example, "C:") or two backslashes
-  /// ("\\") for UNC paths.
-  // TODO(rnystrom): The UNC root prefix should include the drive name too, not
-  // just the "\\".
-  static final windows = new Style._('windows', '\\', r'[/\\]',
-      r'\\\\|[a-zA-Z]:[/\\]');
-
-  Style._(this.name, this.separator, String separatorPattern,
-      String rootPattern)
-    : separatorPattern = new RegExp(separatorPattern),
-      _rootPattern = new RegExp('^$rootPattern');
-
-  /// The name of this path style. Will be "posix" or "windows".
-  final String name;
-
-  /// The path separator for this style. On POSIX, this is `/`. On Windows,
-  /// it's `\`.
-  final String separator;
-
-  /// The [Pattern] that can be used to match a separator for a path in this
-  /// style. Windows allows both "/" and "\" as path separators even though
-  /// "\" is the canonical one.
-  final Pattern separatorPattern;
-
-  // TODO(nweiz): make this a Pattern when issue 7080 is fixed.
-  /// The [RegExp] that can be used to match the root prefix of an absolute
-  /// path in this style.
-  final RegExp _rootPattern;
-
-  /// Gets the root prefix of [path] if path is absolute. If [path] is relative,
-  /// returns `null`.
-  String getRoot(String path) {
-    var match = _rootPattern.firstMatch(path);
-    if (match == null) return null;
-    return match[0];
-  }
-
-  String toString() => name;
-}
-
-// TODO(rnystrom): Make this public?
-class _ParsedPath {
-  /// The [Style] that was used to parse this path.
-  Style style;
-
-  /// The absolute root portion of the path, or `null` if the path is relative.
-  /// On POSIX systems, this will be `null` or "/". On Windows, it can be
-  /// `null`, "//" for a UNC path, or something like "C:\" for paths with drive
-  /// letters.
-  String root;
-
-  /// The path-separated parts of the path. All but the last will be
-  /// directories.
-  List<String> parts;
-
-  /// The path separators following each part. The last one will be an empty
-  /// string unless the path ends with a trailing separator.
-  List<String> separators;
-
-  /// The file extension of the last part, or "" if it doesn't have one.
-  String get extension => _splitExtension()[1];
-
-  /// `true` if this is an absolute path.
-  bool get isAbsolute => root != null;
-
-  _ParsedPath(this.style, this.root, this.parts, this.separators);
-
-  String get basename {
-    var copy = this.clone();
-    copy.removeTrailingSeparators();
-    if (copy.parts.isEmpty) return root == null ? '' : root;
-    return copy.parts.last;
-  }
-
-  String get basenameWithoutExtension {
-    var copy = this.clone();
-    copy.removeTrailingSeparators();
-    if (copy.parts.isEmpty) return root == null ? '' : root;
-    return copy._splitExtension()[0];
-  }
-
-  void removeTrailingSeparators() {
-    while (!parts.isEmpty && parts.last == '') {
-      parts.removeLast();
-      separators.removeLast();
-    }
-    if (separators.length > 0) separators[separators.length - 1] = '';
-  }
-
-  void normalize() {
-    // Handle '.', '..', and empty parts.
-    var leadingDoubles = 0;
-    var newParts = [];
-    for (var part in parts) {
-      if (part == '.' || part == '') {
-        // Do nothing. Ignore it.
-      } else if (part == '..') {
-        // Pop the last part off.
-        if (newParts.length > 0) {
-          newParts.removeLast();
-        } else {
-          // Backed out past the beginning, so preserve the "..".
-          leadingDoubles++;
-        }
-      } else {
-        newParts.add(part);
-      }
-    }
-
-    // A relative path can back out from the start directory.
-    if (!isAbsolute) {
-      newParts.insertRange(0, leadingDoubles, '..');
-    }
-
-    // If we collapsed down to nothing, do ".".
-    if (newParts.length == 0 && !isAbsolute) {
-      newParts.add('.');
-    }
-
-    // Canonicalize separators.
-    var newSeparators = [];
-    newSeparators.insertRange(0, newParts.length, style.separator);
-
-    parts = newParts;
-    separators = newSeparators;
-
-    // Normalize the Windows root if needed.
-    if (root != null && style == Style.windows) {
-      root = root.replaceAll('/', '\\');
-    }
-    removeTrailingSeparators();
-  }
-
-  String toString() {
-    var builder = new StringBuffer();
-    if (root != null) builder.add(root);
-    for (var i = 0; i < parts.length; i++) {
-      builder.add(parts[i]);
-      builder.add(separators[i]);
-    }
-
-    return builder.toString();
-  }
-
-  /// Splits the last part of the path into a two-element list. The first is
-  /// the name of the file without any extension. The second is the extension
-  /// or "" if it has none.
-  List<String> _splitExtension() {
-    if (parts.isEmpty) return ['', ''];
-
-    var file = parts.last;
-    if (file == '..') return ['..', ''];
-
-    var lastDot = file.lastIndexOf('.');
-
-    // If there is no dot, or it's the first character, like '.bashrc', it
-    // doesn't count.
-    if (lastDot <= 0) return [file, ''];
-
-    return [file.substring(0, lastDot), file.substring(lastDot)];
-  }
-
-  _ParsedPath clone() => new _ParsedPath(
-      style, root, new List.from(parts), new List.from(separators));
-}
diff --git a/tools/utils.py b/tools/utils.py
index c1305b5..2245516 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -60,6 +60,78 @@
     return int(win_cpu_count)
   return int(os.getenv("DART_NUMBER_OF_CORES", 2))
 
+def GetWindowsRegistryKeyName(name):
+  import win32process
+  # Check if python process is 64-bit or if it's 32-bit running in 64-bit OS.
+  # We need to know whether host is 64-bit so that we are looking in right
+  # registry for Visual Studio path.
+  if sys.maxsize > 2**32 or win32process.IsWow64Process():
+    wow6432Node = 'Wow6432Node\\'
+  else:
+    wow6432Node = ''
+  return r'SOFTWARE\%s%s' % (wow6432Node, name)
+
+# Try to guess Visual Studio location when buiding on Windows.
+def GuessVisualStudioPath():
+  defaultPath = r"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7" \
+                r"\IDE"
+  defaultExecutable = "devenv.com"
+
+  if not IsWindows():
+    return (defaultPath, defaultExecutable)
+
+  keyNamesAndExecutables = [
+    # Pair for non-Express editions.
+    (GetWindowsRegistryKeyName(r'Microsoft\VisualStudio'), 'devenv.com'),
+    # Pair for 2012 Express edition.
+    (GetWindowsRegistryKeyName(r'Microsoft\VSWinExpress'), 'VSWinExpress.exe'),
+    # Pair for pre-2012 Express editions.
+    (GetWindowsRegistryKeyName(r'Microsoft\VCExpress'), 'VCExpress.exe')]
+
+  bestGuess = (0.0, (defaultPath, defaultExecutable))
+
+  import _winreg
+  for (keyName, executable) in keyNamesAndExecutables:
+    try:
+      key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keyName)
+    except WindowsError:
+      # Can't find this key - moving on the next one.
+      continue
+
+    try:
+      subkeyCounter = 0
+      while True:
+        try:
+          subkeyName = _winreg.EnumKey(key, subkeyCounter)
+          subkeyCounter = subkeyCounter + 1
+        except WindowsError:
+          # Reached end of enumeration. Moving on the next key.
+          break
+
+        match = re.match(r'^\d+\.\d+$', subkeyName)
+        if match:
+          with _winreg.OpenKey(key, subkeyName) as subkey:
+            try:
+              (installDir, registrytype) = _winreg.QueryValueEx(subkey,
+                                                                'InstallDir')
+            except WindowsError:
+              # Can't find value under the key - continue to the next key.
+              continue
+            isExpress = executable != 'devenv.com'
+            if not isExpress and subkeyName == '10.0':
+              # Stop search since if we found non-Express VS2010 version
+              # installed, which is preferred version.
+              return (installDir, executable)
+            else:
+              version = float(subkeyName)
+              # We prefer higher version of Visual Studio and given equal
+              # version numbers we prefer non-Express edition.
+              if version > bestGuess[0]:
+                bestGuess = (version, (installDir, executable))
+    finally:
+      _winreg.CloseKey(key)
+  return bestGuess[1]
+
 
 # Returns true if we're running under Windows.
 def IsWindows():
@@ -271,6 +343,7 @@
   print "GuessArchitecture() -> ", GuessArchitecture()
   print "GuessCpus() -> ", GuessCpus()
   print "IsWindows() -> ", IsWindows()
+  print "GuessVisualStudioPath() -> ", GuessVisualStudioPath()
 
 
 class Error(Exception):
diff --git a/utils/apidoc/apidoc.dart b/utils/apidoc/apidoc.dart
index 4caf0d5..fcaf106 100644
--- a/utils/apidoc/apidoc.dart
+++ b/utils/apidoc/apidoc.dart
@@ -110,46 +110,48 @@
   });
 
   var lister = new Directory.fromPath(doc.scriptDir.append('../../pkg')).list();
-  lister.onDir = (dirPath) {
-    var path = new Path(dirPath);
-    var libName = path.filename;
+  lister.listen(
+      (entity) {
+        if (entity is Directory) {
+          var path = new Path(entity.path);
+          var libName = path.filename;
 
-    // TODO(rnystrom): Get rid of oldStylePath support when all packages are
-    // using new layout. See #5106.
-    var oldStylePath = path.append('${libName}.dart');
-    var newStylePath = path.append('lib/${libName}.dart');
+          // TODO(rnystrom): Get rid of oldStylePath support when all
+          // packages are using new layout. See #5106.
+          var oldStylePath = path.append('${libName}.dart');
+          var newStylePath = path.append('lib/${libName}.dart');
 
-    if (new File.fromPath(oldStylePath).existsSync()) {
-      apidocLibraries.add(oldStylePath);
-      includedLibraries.add(libName);
-    } else if (new File.fromPath(newStylePath).existsSync()) {
-      apidocLibraries.add(newStylePath);
-      includedLibraries.add(libName);
-    } else {
-      print('Warning: could not find package at $path');
-    }
-  };
+          if (new File.fromPath(oldStylePath).existsSync()) {
+            apidocLibraries.add(oldStylePath);
+            includedLibraries.add(libName);
+          } else if (new File.fromPath(newStylePath).existsSync()) {
+            apidocLibraries.add(newStylePath);
+            includedLibraries.add(libName);
+          } else {
+            print('Warning: could not find package at $path');
+          }
+        }
+      },
+      onDone: () {
+        print('Generating docs...');
+        final apidoc = new Apidoc(mdn, outputDir, mode, generateAppCache,
+                                  excludedLibraries, version);
+        apidoc.dartdocPath =
+            doc.scriptDir.append('../../sdk/lib/_internal/dartdoc/');
+        // Select the libraries to include in the produced documentation:
+        apidoc.includeApi = true;
+        apidoc.includedLibraries = includedLibraries;
 
-  lister.onDone = (success) {
-    print('Generating docs...');
-    final apidoc = new Apidoc(mdn, outputDir, mode, generateAppCache,
-        excludedLibraries, version);
-    apidoc.dartdocPath =
-        doc.scriptDir.append('../../sdk/lib/_internal/dartdoc/');
-    // Select the libraries to include in the produced documentation:
-    apidoc.includeApi = true;
-    apidoc.includedLibraries = includedLibraries;
+        Future.wait([copiedStatic, copiedApiDocStatic]).then((_) {
+          apidoc.documentLibraries(apidocLibraries, libPath, pkgPath);
 
-    Future.wait([copiedStatic, copiedApiDocStatic]).then((_) {
-      apidoc.documentLibraries(apidocLibraries, libPath, pkgPath);
+          final compiled = doc.compileScript(mode, outputDir, libPath);
 
-      final compiled = doc.compileScript(mode, outputDir, libPath);
-
-      Future.wait([compiled, copiedStatic, copiedApiDocStatic]).then((_) {
-        apidoc.cleanup();
+          Future.wait([compiled, copiedStatic, copiedApiDocStatic]).then((_) {
+            apidoc.cleanup();
+          });
+        });
       });
-    });
-  };
 }
 
 class Apidoc extends doc.Dartdoc {
diff --git a/utils/css/source.dart b/utils/css/source.dart
index 3875c7b..a5e981b 100644
--- a/utils/css/source.dart
+++ b/utils/css/source.dart
@@ -6,7 +6,7 @@
 /**
  * Represents a file of source code.
  */
-class SourceFile implements Comparable {
+class SourceFile implements Comparable<SourceFile> {
   // TODO(terry): This filename for in memory buffer.  May need to rework if
   //              filename is used for more than informational.
   static String IN_MEMORY_FILE = '<buffer>';
@@ -132,7 +132,7 @@
  * work.
  */
  // TODO(jmesserly): Rename to Span - but first write cool refactoring tool
-class SourceSpan implements Comparable {
+class SourceSpan implements Comparable<SourceSpan> {
   /** The [SourceFile] that contains this span. */
   final SourceFile file;
 
diff --git a/utils/pub/entrypoint.dart b/utils/pub/entrypoint.dart
index b2dc9b4..ab65950 100644
--- a/utils/pub/entrypoint.dart
+++ b/utils/pub/entrypoint.dart
@@ -232,7 +232,7 @@
       if (entryExists(linkPath)) return;
       ensureDir(packagesDir);
       return createPackageSymlink(root.name, root.dir, linkPath,
-          isSelfLink: true);
+          isSelfLink: true, relative: true);
     });
   }
 
@@ -296,7 +296,7 @@
     return defer(() {
       var symlink = path.join(dir, 'packages');
       if (entryExists(symlink)) return;
-      return createSymlink(packagesDir, symlink);
+      return createSymlink(packagesDir, symlink, relative: true);
     });
   }
 }
diff --git a/utils/pub/hosted_source.dart b/utils/pub/hosted_source.dart
index 6fdc8e9..44f7195 100644
--- a/utils/pub/hosted_source.dart
+++ b/utils/pub/hosted_source.dart
@@ -29,21 +29,20 @@
   final name = "hosted";
   final shouldCache = true;
 
-  /// The URL of the default package repository.
-  static final defaultUrl = "https://pub.dartlang.org";
-
   /// Downloads a list of all versions of a package that are available from the
   /// site.
   Future<List<Version>> getVersions(String name, description) {
-    var parsed = _parseDescription(description);
-    var fullUrl = "${parsed.last}/packages/${parsed.first}.json";
+    var url = _makeUrl(description,
+        (server, package) => "$server/packages/$package.json");
 
-    return httpClient.read(fullUrl).then((body) {
+    log.io("Get versions from $url.");
+    return httpClient.read(url).then((body) {
       var doc = json.parse(body);
       return doc['versions']
           .map((version) => new Version.parse(version))
           .toList();
     }).catchError((ex) {
+      var parsed = _parseDescription(description);
       _throwFriendlyError(ex, parsed.first, parsed.last);
     });
   }
@@ -51,13 +50,14 @@
   /// Downloads and parses the pubspec for a specific version of a package that
   /// is available from the site.
   Future<Pubspec> describe(PackageId id) {
-    var parsed = _parseDescription(id.description);
-    var fullUrl = "${parsed.last}/packages/${parsed.first}/versions/"
-      "${id.version}.yaml";
+    var url = _makeVersionUrl(id, (server, package, version) =>
+        "$server/packages/$package/versions/$version.yaml");
 
-    return httpClient.read(fullUrl).then((yaml) {
+    log.io("Describe package at $url.");
+    return httpClient.read(url).then((yaml) {
       return new Pubspec.parse(null, yaml, systemCache.sources);
     }).catchError((ex) {
+      var parsed = _parseDescription(id.description);
       _throwFriendlyError(ex, id, parsed.last);
     });
   }
@@ -65,21 +65,19 @@
   /// Downloads a package from the site and unpacks it.
   Future<bool> install(PackageId id, String destPath) {
     return defer(() {
-      var parsedDescription = _parseDescription(id.description);
-      var name = parsedDescription.first;
-      var url = parsedDescription.last;
-
-      var fullUrl = "$url/packages/$name/versions/${id.version}.tar.gz";
+      var url = _makeVersionUrl(id, (server, package, version) =>
+          "$server/packages/$package/versions/$version.tar.gz");
+      log.io("Install package from $url.");
 
       log.message('Downloading $id...');
 
       // Download and extract the archive to a temp directory.
       var tempDir = systemCache.createTempDir();
-      return httpClient.send(new http.Request("GET", Uri.parse(fullUrl)))
+      return httpClient.send(new http.Request("GET", url))
           .then((response) => response.stream)
           .then((stream) {
         return timeout(extractTarGz(stream, tempDir), HTTP_TIMEOUT,
-            'fetching URL "$fullUrl"');
+            'fetching URL "$url"');
       }).then((_) {
         // Now that the install has succeeded, move it to the real location in
         // the cache. This ensures that we don't leave half-busted ghost
@@ -142,31 +140,57 @@
     throw asyncError;
   }
 
-  /// Parses the description for a package.
-  ///
-  /// If the package parses correctly, this returns a (name, url) pair. If not,
-  /// this throws a descriptive FormatException.
-  Pair<String, String> _parseDescription(description) {
-    if (description is String) {
-      return new Pair<String, String>(description, defaultUrl);
-    }
+}
 
-    if (description is! Map) {
-      throw new FormatException(
-          "The description must be a package name or map.");
-    }
+/// The URL of the default package repository.
+final _defaultUrl = "https://pub.dartlang.org";
 
-    if (!description.containsKey("name")) {
-      throw new FormatException(
-          "The description map must contain a 'name' key.");
-    }
+/// Parses [description] into its server and package name components, then
+/// converts that to a Uri given [pattern]. Ensures the package name is
+/// properly URL encoded.
+Uri _makeUrl(description, String pattern(String server, String package)) {
+  var parsed = _parseDescription(description);
+  var server = parsed.last;
+  var package = encodeUriComponent(parsed.first);
+  return new Uri(pattern(server, package));
+}
 
-    var name = description["name"];
-    if (name is! String) {
-      throw new FormatException("The 'name' key must have a string value.");
-    }
+/// Parses [id] into its server, package name, and version components, then
+/// converts that to a Uri given [pattern]. Ensures the package name is
+/// properly URL encoded.
+Uri _makeVersionUrl(PackageId id,
+    String pattern(String server, String package, String version)) {
+  var parsed = _parseDescription(id.description);
+  var server = parsed.last;
+  var package = encodeUriComponent(parsed.first);
+  var version = encodeUriComponent(id.version.toString());
+  return new Uri(pattern(server, package, version));
+}
 
-    var url = description.containsKey("url") ? description["url"] : defaultUrl;
-    return new Pair<String, String>(name, url);
+/// Parses the description for a package.
+///
+/// If the package parses correctly, this returns a (name, url) pair. If not,
+/// this throws a descriptive FormatException.
+Pair<String, String> _parseDescription(description) {
+  if (description is String) {
+    return new Pair<String, String>(description, _defaultUrl);
   }
+
+  if (description is! Map) {
+    throw new FormatException(
+        "The description must be a package name or map.");
+  }
+
+  if (!description.containsKey("name")) {
+    throw new FormatException(
+    "The description map must contain a 'name' key.");
+  }
+
+  var name = description["name"];
+  if (name is! String) {
+    throw new FormatException("The 'name' key must have a string value.");
+  }
+
+  var url = description.containsKey("url") ? description["url"] : _defaultUrl;
+  return new Pair<String, String>(name, url);
 }
diff --git a/utils/pub/http.dart b/utils/pub/http.dart
index f8cb699..fe80834 100644
--- a/utils/pub/http.dart
+++ b/utils/pub/http.dart
@@ -60,6 +60,7 @@
         if (asyncError.error.osError.errorCode == 8 ||
             asyncError.error.osError.errorCode == -2 ||
             asyncError.error.osError.errorCode == -5 ||
+            asyncError.error.osError.errorCode == 11001 ||
             asyncError.error.osError.errorCode == 11004) {
           throw 'Could not resolve URL "${request.url.origin}".';
         } else if (asyncError.error.osError.errorCode == -12276) {
diff --git a/utils/pub/io.dart b/utils/pub/io.dart
index a031da2..2a4be97 100644
--- a/utils/pub/io.dart
+++ b/utils/pub/io.dart
@@ -81,8 +81,7 @@
 Future<String> createFileFromStream(Stream<List<int>> stream, String file) {
   log.io("Creating $file from stream.");
 
-  var outputStream = new File(file).openOutputStream();
-  return stream.pipe(wrapOutputStream(outputStream)).then((_) {
+  return stream.pipe(new File(file).openWrite()).then((_) {
     log.fine("Created $file from stream.");
     return file;
   });
@@ -158,41 +157,38 @@
     log.io("Listing directory $dir.");
     var lister = new Directory(dir).list();
 
-    lister.onDone = (done) {
-      // TODO(rnystrom): May need to sort here if it turns out onDir and onFile
-      // aren't guaranteed to be called in a certain order. So far, they seem to.
-      if (done) {
-        log.fine("Listed directory $dir:\n${contents.join('\n')}");
-        completer.complete(contents);
-      }
-    };
-
-    // TODO(nweiz): remove this when issue 4061 is fixed.
-    var stackTrace;
-    try {
-      throw "";
-    } catch (_, localStackTrace) {
-      stackTrace = localStackTrace;
-    }
-
     var children = [];
-    lister.onError = (error) => completer.completeError(error, stackTrace);
-    lister.onDir = (file) {
-      if (!includeHiddenFiles && path.basename(file).startsWith('.')) return;
-      file = path.join(dir, path.basename(file));
-      contents.add(file);
-      // TODO(nweiz): don't manually recurse once issue 7358 is fixed. Note that
-      // once we remove the manual recursion, we'll need to explicitly filter
-      // out files in hidden directories.
-      if (recursive) {
-        children.add(doList(file, listedDirectories));
-      }
-    };
-
-    lister.onFile = (file) {
-      if (!includeHiddenFiles && path.basename(file).startsWith('.')) return;
-      contents.add(path.join(dir, path.basename(file)));
-    };
+    lister.listen(
+        (entity) {
+          if (entity is File) {
+            var file = entity.name;
+            if (!includeHiddenFiles && path.basename(file).startsWith('.')) {
+              return;
+            }
+            contents.add(path.join(dir, path.basename(file)));
+          } else if (entity is Directory) {
+            var file = entity.path;
+            if (!includeHiddenFiles && path.basename(file).startsWith('.')) {
+              return;
+            }
+            file = path.join(dir, path.basename(file));
+            contents.add(file);
+            // TODO(nweiz): don't manually recurse once issue 7358 is fixed.
+            // Note that once we remove the manual recursion, we'll need to
+            // explicitly filter out files in hidden directories.
+            if (recursive) {
+              children.add(doList(file, listedDirectories));
+            }
+          }
+        },
+        onDone: () {
+          // TODO(rnystrom): May need to sort here if it turns out
+          // onDir and onFile aren't guaranteed to be called in a
+          // certain order. So far, they seem to.
+          log.fine("Listed directory $dir:\n${contents.join('\n')}");
+          completer.complete(contents);
+        },
+        onError: (error) => completer.completeError(error, stackTrace));
 
     return completer.future.then((contents) {
       return Future.wait(children).then((childContents) {
@@ -364,8 +360,8 @@
 
 /// Wrap the standard output or error [stream] in a [StreamSink]. Any errors are
 /// logged, and then the program is terminated. [name] is used for debugging.
-StreamSink<List<int>> _wrapStdio(OutputStream stream, String name) {
-  var pair = consumerToSink(wrapOutputStream(stream));
+StreamSink<List<int>> _wrapStdio(IOSink sink, String name) {
+  var pair = consumerToSink(sink);
   pair.last.catchError((e) {
     // This log may or may not work, depending on how the stream failed. Not
     // much we can do about that.
@@ -376,8 +372,8 @@
 }
 
 /// A line-by-line stream of standard input.
-final Stream<String> stdinLines =
-    streamToLines(wrapInputStream(stdin).toStringStream());
+final Stream<String> stdinLines = streamToLines(
+    new ByteStream(stdin).toStringStream());
 
 /// Displays a message and reads a yes/no confirmation from the user. Returns
 /// a [Future] that completes to `true` if the user confirms or `false` if they
@@ -392,82 +388,10 @@
       .then((line) => new RegExp(r"^[yY]").hasMatch(line));
 }
 
-/// Reads and discards all output from [inputStream]. Returns a [Future] that
+/// Reads and discards all output from [stream]. Returns a [Future] that
 /// completes when the stream is closed.
-Future drainInputStream(InputStream inputStream) {
-  var completer = new Completer();
-  if (inputStream.closed) {
-    completer.complete();
-    return completer.future;
-  }
-
-  inputStream.onClosed = () => completer.complete();
-  inputStream.onData = inputStream.read;
-  inputStream.onError = (error) => completer.completeError(error);
-  return completer.future;
-}
-
-/// Wraps [stream] in a single-subscription [Stream] that emits the same data.
-ByteStream wrapInputStream(InputStream stream) {
-  var controller = new StreamController();
-  if (stream.closed) {
-    controller.close();
-    return new ByteStream(controller.stream);
-  }
-
-  stream.onClosed = controller.close;
-  stream.onData = () => controller.add(stream.read());
-  stream.onError = (e) => controller.signalError(new AsyncError(e));
-  return new ByteStream(controller.stream);
-}
-
-/// Wraps [stream] in a [StreamConsumer] so that [Stream]s can by piped into it
-/// using [Stream.pipe]. Errors piped to the returned [StreamConsumer] will be
-/// forwarded to the [Future] returned by [Stream.pipe].
-StreamConsumer<List<int>, dynamic> wrapOutputStream(OutputStream stream) =>
-  new _OutputStreamConsumer(stream);
-
-/// A [StreamConsumer] that pipes data into an [OutputStream].
-class _OutputStreamConsumer implements StreamConsumer<List<int>, dynamic> {
-  final OutputStream _outputStream;
-
-  _OutputStreamConsumer(this._outputStream);
-
-  Future consume(Stream<List<int>> stream) {
-    // TODO(nweiz): we have to manually keep track of whether or not the
-    // completer has completed since the output stream could signal an error
-    // after close() has been called but before it has shut down internally. See
-    // the following TODO.
-    var completed = false;
-    var completer = new Completer();
-    stream.listen((data) {
-      // Writing empty data to a closed stream can cause errors.
-      if (data.isEmpty) return;
-
-      // TODO(nweiz): remove this try/catch when issue 7836 is fixed.
-      try {
-        _outputStream.write(data);
-      } catch (e, stack) {
-        if (!completed) completer.completeError(e, stack);
-        completed = true;
-      }
-    }, onError: (e) {
-      if (!completed) completer.completeError(e.error, e.stackTrace);
-      completed = true;
-    }, onDone: () => _outputStream.close());
-
-    _outputStream.onError = (e) {
-      if (!completed) completer.completeError(e);
-      completed = true;
-    };
-
-    _outputStream.onClosed = () {
-      if (!completed) completer.complete();
-      completed = true;
-    };
-
-    return completer.future;
-  }
+Future drainStream(Stream stream) {
+  return stream.reduce(null, (x, y) {});
 }
 
 /// Returns a [StreamSink] that pipes all data to [consumer] and a [Future] that
@@ -609,18 +533,18 @@
     : _process = process {
     var errorGroup = new ErrorGroup();
 
-    var pair = consumerToSink(wrapOutputStream(process.stdin));
+    var pair = consumerToSink(process.stdin);
     _stdin = pair.first;
     _stdinClosed = errorGroup.registerFuture(pair.last);
 
     _stdout = new ByteStream(
-        errorGroup.registerStream(wrapInputStream(process.stdout)));
+        errorGroup.registerStream(process.stdout));
     _stderr = new ByteStream(
-        errorGroup.registerStream(wrapInputStream(process.stderr)));
+        errorGroup.registerStream(process.stderr));
 
     var exitCodeCompleter = new Completer();
     _exitCode = errorGroup.registerFuture(exitCodeCompleter.future);
-    _process.onExit = (code) => exitCodeCompleter.complete(code);
+    _process.exitCode.then((code) => exitCodeCompleter.complete(code));
   }
 
   /// Sends [signal] to the underlying process.
@@ -796,8 +720,6 @@
   contents.forEach((file) => buffer.add('$file\n'));
   log.fine(buffer.toString());
 
-  // TODO(nweiz): Propagate errors to the returned stream (including non-zero
-  // exit codes). See issue 3657.
   var controller = new StreamController<List<int>>();
 
   if (baseDir == null) baseDir = path.current;
diff --git a/utils/pub/oauth2.dart b/utils/pub/oauth2.dart
index 276fb25..f2ec1b5 100644
--- a/utils/pub/oauth2.dart
+++ b/utils/pub/oauth2.dart
@@ -170,35 +170,37 @@
   // Spin up a one-shot HTTP server to receive the authorization code from the
   // Google OAuth2 server via redirect. This server will close itself as soon as
   // the code is received.
-  var completer = new Completer();
-  var server = new HttpServer();
-  server.addRequestHandler((request) => request.path == "/",
-      (request, response) {
-    chainToCompleter(defer(() {
-      log.message('Authorization received, processing...');
-      var queryString = request.queryString;
-      if (queryString == null) queryString = '';
-      response.statusCode = 302;
-      response.headers.set('location', 'http://pub.dartlang.org/authorized');
-      response.outputStream.close();
-      return grant.handleAuthorizationResponse(queryToMap(queryString));
-    }).then((client) {
-      server.close();
-      return client;
-    }), completer);
-  });
-  server.listen('127.0.0.1', 0);
+  return HttpServer.bind('127.0.0.1', 0).then((server) {
+    var authUrl = grant.getAuthorizationUrl(
+        Uri.parse('http://localhost:${server.port}'), scopes: _scopes);
 
-  var authUrl = grant.getAuthorizationUrl(
-      Uri.parse('http://localhost:${server.port}'), scopes: _scopes);
-
-  log.message(
-      'Pub needs your authorization to upload packages on your behalf.\n'
-      'In a web browser, go to $authUrl\n'
-      'Then click "Allow access".\n\n'
-      'Waiting for your authorization...');
-
-  return completer.future.then((client) {
+    log.message(
+        'Pub needs your authorization to upload packages on your behalf.\n'
+        'In a web browser, go to $authUrl\n'
+        'Then click "Allow access".\n\n'
+        'Waiting for your authorization...');
+    return server.first.then((request) {
+      var response = request.response;
+      if (request.uri.path == "/") {
+        log.message('Authorization received, processing...');
+        var queryString = request.uri.query;
+        if (queryString == null) queryString = '';
+        response.statusCode = 302;
+        response.headers.set('location',
+                             'http://pub.dartlang.org/authorized');
+        response.close();
+        return grant.handleAuthorizationResponse(queryToMap(queryString))
+        .then((client) {
+          server.close();
+          return client;
+        });
+      } else {
+        response.statusCode = 404;
+        response.close();
+      }
+    });
+  })
+  .then((client) {
     log.message('Successfully authorized.\n');
     return client;
   });
diff --git a/utils/pub/package.dart b/utils/pub/package.dart
index dd988cb..8731655 100644
--- a/utils/pub/package.dart
+++ b/utils/pub/package.dart
@@ -85,7 +85,7 @@
 /// different directories that happen to contain identical packages. For
 /// example, the same package may be available from multiple sources. As far as
 /// Pub is concerned, those packages are different.
-class PackageId implements Comparable {
+class PackageId implements Comparable<PackageId> {
   /// The name of the package being identified.
   final String name;
 
@@ -129,9 +129,7 @@
     return "$name $version from $source";
   }
 
-  int compareTo(Comparable other) {
-    if (other is! PackageId) throw new ArgumentError(other);
-
+  int compareTo(PackageId other) {
     var sourceComp = source.name.compareTo(other.source.name);
     if (sourceComp != 0) return sourceComp;
 
diff --git a/utils/pub/validator/name.dart b/utils/pub/validator/name.dart
index 2ad4bc9..c183f9c 100644
--- a/utils/pub/validator/name.dart
+++ b/utils/pub/validator/name.dart
@@ -16,9 +16,10 @@
 
 /// Dart reserved words, from the Dart spec.
 final _RESERVED_WORDS = [
-  "abstract", "as", "dynamic", "export", "external", "factory", "get",
-  "implements", "import", "library", "operator", "part", "set", "static",
-  "typedef"
+  "assert", "break", "case", "catch", "class", "const", "continue", "default",
+  "do", "else", "extends", "false", "final", "finally", "for", "if", "in", "is",
+  "new", "null", "return", "super", "switch", "this", "throw", "true", "try",
+  "var", "void", "while", "with"
 ];
 
 /// A validator that validates the name of the package and its libraries.
@@ -27,12 +28,14 @@
     : super(entrypoint);
 
   Future validate() {
-    _checkName(entrypoint.root.name, 'Package name "${entrypoint.root.name}"');
+    _checkName(entrypoint.root.name, 'Package name "${entrypoint.root.name}"',
+        isPackage: true);
 
     return _libraries.then((libraries) {
       for (var library in libraries) {
         var libName = path.basenameWithoutExtension(library);
-        _checkName(libName, 'The name of "$library", "$libName",');
+        _checkName(libName, 'The name of "$library", "$libName",',
+            isPackage: false);
       }
 
       if (libraries.length == 1) {
@@ -61,18 +64,21 @@
     });
   }
 
-  void _checkName(String name, String description) {
+  void _checkName(String name, String description, {bool isPackage}) {
+    // Packages names are more stringent than libraries.
+    var messages = isPackage ? errors : warnings;
+
     if (name == "") {
       errors.add("$description may not be empty.");
     } else if (!new RegExp(r"^[a-zA-Z0-9_]*$").hasMatch(name)) {
-      errors.add("$description may only contain letters, numbers, and "
+      messages.add("$description may only contain letters, numbers, and "
           "underscores.\n"
           "Using a valid Dart identifier makes the name usable in Dart code.");
     } else if (!new RegExp(r"^[a-zA-Z]").hasMatch(name)) {
-      errors.add("$description must begin with letter.\n"
+      messages.add("$description must begin with letter.\n"
           "Using a valid Dart identifier makes the name usable in Dart code.");
     } else if (_RESERVED_WORDS.contains(name.toLowerCase())) {
-      errors.add("$description may not be a reserved word in Dart.\n"
+      messages.add("$description may not be a reserved word in Dart.\n"
           "Using a valid Dart identifier makes the name usable in Dart code.");
     } else if (new RegExp(r"[A-Z]").hasMatch(name)) {
       warnings.add('$description should be lower-case. Maybe use '
diff --git a/utils/pub/version.dart b/utils/pub/version.dart
index 06c14fd..62669e4 100644
--- a/utils/pub/version.dart
+++ b/utils/pub/version.dart
@@ -11,18 +11,25 @@
 
 import 'utils.dart';
 
+
+/// Regex that matches a version number at the beginning of a string.
+final _START_VERSION = new RegExp(
+    r'^'                                        // Start at beginning.
+    r'(\d+).(\d+).(\d+)'                        // Version number.
+    r'(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?'    // Pre-release.
+    r'(\+([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?'); // Build.
+
+/// Like [_START_VERSION] but matches the entire string.
+final _COMPLETE_VERSION = new RegExp("${_START_VERSION.pattern}\$");
+
+/// Parses a comparison operator ("<", ">", "<=", or ">=") at the beginning of
+/// a string.
+final _START_COMPARISON = new RegExp(r"^[<>]=?");
+
 /// A parsed semantic version number.
-class Version implements Comparable, VersionConstraint {
+class Version implements Comparable<Version>, VersionConstraint {
   /// No released version: i.e. "0.0.0".
   static Version get none => new Version(0, 0, 0);
-
-  static final _PARSE_REGEX = new RegExp(
-      r'^'                                       // Start at beginning.
-      r'(\d+).(\d+).(\d+)'                       // Version number.
-      r'(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?'   // Pre-release.
-      r'(\+([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?'  // Build.
-      r'$');                                     // Consume entire string.
-
   /// The major version number: "1" in "1.2.3".
   final int major;
 
@@ -51,7 +58,7 @@
 
   /// Creates a new [Version] by parsing [text].
   factory Version.parse(String text) {
-    final match = _PARSE_REGEX.firstMatch(text);
+    final match = _COMPLETE_VERSION.firstMatch(text);
     if (match == null) {
       throw new FormatException('Could not parse "$text".');
     }
@@ -146,9 +153,9 @@
 
   String toString() {
     var buffer = new StringBuffer();
-    buffer.add('$major.$minor.$patch');
-    if (preRelease != null) buffer.add('-$preRelease');
-    if (build != null) buffer.add('+$build');
+    buffer.write('$major.$minor.$patch');
+    if (preRelease != null) buffer.write('-$preRelease');
+    if (build != null) buffer.write('+$build');
     return buffer.toString();
   }
 
@@ -214,28 +221,92 @@
   /// A [VersionConstraint] that allows no versions: i.e. the empty set.
   static VersionConstraint empty = const _EmptyVersion();
 
-  /// Parses a version constraint. This string is a space-separated series of
+  /// Parses a version constraint. This string is either "any" or a series of
   /// version parts. Each part can be one of:
   ///
   ///   * A version string like `1.2.3`. In other words, anything that can be
   ///     parsed by [Version.parse()].
   ///   * A comparison operator (`<`, `>`, `<=`, or `>=`) followed by a version
-  ///     string. There cannot be a space between the operator and the version.
+  ///     string.
+  ///
+  /// Whitespace is ignored.
   ///
   /// Examples:
   ///
+  ///     any
   ///     1.2.3-alpha
   ///     <=5.1.4
-  ///     >2.0.4 <=2.4.6
+  ///     >2.0.4 <= 2.4.6
   factory VersionConstraint.parse(String text) {
-    if (text.trim() == '') {
-      throw new FormatException('Cannot parse an empty string.');
+    // Handle the "any" constraint.
+    if (text.trim() == "any") return new VersionRange();
+
+    var originalText = text;
+    var constraints = <VersionConstraint>[];
+
+    void skipWhitespace() {
+      text = text.trim();
     }
 
-    // Split it into space-separated parts.
-    var constraints = <VersionConstraint>[];
-    for (var part in text.split(' ')) {
-      constraints.add(_parseSingleConstraint(part));
+    // Try to parse and consume a version number.
+    Version matchVersion() {
+      var version = _START_VERSION.firstMatch(text);
+      if (version == null) return null;
+
+      text = text.substring(version.end);
+      return new Version.parse(version[0]);
+    }
+
+    // Try to parse and consume a comparison operator followed by a version.
+    VersionConstraint matchComparison() {
+      var comparison = _START_COMPARISON.firstMatch(text);
+      if (comparison == null) return null;
+
+      var op = comparison[0];
+      text = text.substring(comparison.end);
+      skipWhitespace();
+
+      var version = matchVersion();
+      if (version == null) {
+        throw new FormatException('Expected version number after "$op" in '
+            '"$originalText", got "$text".');
+      }
+
+      switch (op) {
+        case '<=':
+          return new VersionRange(max: version, includeMax: true);
+        case '<':
+          return new VersionRange(max: version, includeMax: false);
+        case '>=':
+          return new VersionRange(min: version, includeMin: true);
+        case '>':
+          return new VersionRange(min: version, includeMin: false);
+      }
+    }
+
+    while (true) {
+      skipWhitespace();
+      if (text.isEmpty) break;
+
+      var version = matchVersion();
+      if (version != null) {
+        constraints.add(version);
+        continue;
+      }
+
+      var comparison = matchComparison();
+      if (comparison != null) {
+        constraints.add(comparison);
+        continue;
+      }
+
+      // If we got here, we couldn't parse the remaining string.
+      throw new FormatException('Could not parse version "$originalText". '
+          'Unknown text at "$text".');
+    }
+
+    if (constraints.isEmpty) {
+      throw new FormatException('Cannot parse an empty string.');
     }
 
     return new VersionConstraint.intersection(constraints);
@@ -266,32 +337,6 @@
   /// Creates a new [VersionConstraint] that only allows [Version]s allowed by
   /// both this and [other].
   VersionConstraint intersect(VersionConstraint other);
-
-  static VersionConstraint _parseSingleConstraint(String text) {
-    if (text == 'any') {
-      return new VersionRange();
-    }
-
-    // TODO(rnystrom): Consider other syntaxes for version constraints. This
-    // one is whitespace sensitive (you can't do "< 1.2.3") and "<" is
-    // unfortunately meaningful in YAML, requiring it to be quoted in a
-    // pubspec.
-    // See if it's a comparison operator followed by a version, like ">1.2.3".
-    var match = new RegExp(r"^([<>]=?)?(.*)$").firstMatch(text);
-    if (match != null) {
-      var comparison = match[1];
-      var version = new Version.parse(match[2]);
-      switch (match[1]) {
-        case '<=': return new VersionRange(max: version, includeMax: true);
-        case '<': return new VersionRange(max: version, includeMax: false);
-        case '>=': return new VersionRange(min: version, includeMin: true);
-        case '>': return new VersionRange(min: version, includeMin: false);
-      }
-    }
-
-    // Otherwise, it must be an explicit version.
-    return new Version.parse(text);
-  }
 }
 
 /// Constrains versions to a fall within a given range. If there is a minimum,
@@ -402,17 +447,17 @@
     var buffer = new StringBuffer();
 
     if (min != null) {
-      buffer.add(includeMin ? '>=' : '>');
-      buffer.add(min);
+      buffer.write(includeMin ? '>=' : '>');
+      buffer.write(min);
     }
 
     if (max != null) {
-      if (min != null) buffer.add(' ');
-      buffer.add(includeMax ? '<=' : '<');
-      buffer.add(max);
+      if (min != null) buffer.write(' ');
+      buffer.write(includeMax ? '<=' : '<');
+      buffer.write(max);
     }
 
-    if (min == null && max == null) buffer.add('any');
+    if (min == null && max == null) buffer.write('any');
     return buffer.toString();
   }
 }
diff --git a/utils/template/source.dart b/utils/template/source.dart
index 3875c7b..a5e981b 100644
--- a/utils/template/source.dart
+++ b/utils/template/source.dart
@@ -6,7 +6,7 @@
 /**
  * Represents a file of source code.
  */
-class SourceFile implements Comparable {
+class SourceFile implements Comparable<SourceFile> {
   // TODO(terry): This filename for in memory buffer.  May need to rework if
   //              filename is used for more than informational.
   static String IN_MEMORY_FILE = '<buffer>';
@@ -132,7 +132,7 @@
  * work.
  */
  // TODO(jmesserly): Rename to Span - but first write cool refactoring tool
-class SourceSpan implements Comparable {
+class SourceSpan implements Comparable<SourceSpan> {
   /** The [SourceFile] that contains this span. */
   final SourceFile file;
 
diff --git a/utils/testrunner/utils.dart b/utils/testrunner/utils.dart
index e8f81d4..3bd7efb 100644
--- a/utils/testrunner/utils.dart
+++ b/utils/testrunner/utils.dart
@@ -70,21 +70,24 @@
       Directory d = new Directory(path);
       if (d.existsSync()) {
         ++dirCount;
-        var lister = d.list(recursive: recurse);
-        lister.onFile = (file) {
-          if (filePat.hasMatch(file)) {
-            if (excludePat == null || !excludePat.hasMatch(file)) {
-              if (includeSymLinks || file.startsWith(path)) {
-                files.add(file);
+        d.list(recursive: recurse).listen(
+            (entity) {
+              if (entity is File) {
+                var file = entity.name;
+                if (filePat.hasMatch(file)) {
+                  if (excludePat == null || !excludePat.hasMatch(file)) {
+                    if (includeSymLinks || file.startsWith(path)) {
+                      files.add(file);
+                    }
+                  }
+                }
               }
-            }
-          }
-        };
-        lister.onDone = (complete) {
-          if (complete && --dirCount == 0) {
-            onComplete(files);
-          }
-        };
+            },
+            onDone: () {
+              if (complete && --dirCount == 0) {
+                onComplete(files);
+              }
+            });
       } else { // Does not exist.
         print('$path does not exist.');
       }
diff --git a/utils/tests/pub/install/hosted/install_test.dart b/utils/tests/pub/install/hosted/install_test.dart
index 1ed4f40..5bc120c 100644
--- a/utils/tests/pub/install/hosted/install_test.dart
+++ b/utils/tests/pub/install/hosted/install_test.dart
@@ -9,6 +9,7 @@
 import '../../test_pub.dart';
 
 main() {
+  initConfig();
   integration('installs a package from a pub server', () {
     servePackages([package("foo", "1.2.3")]);
 
@@ -20,4 +21,15 @@
     cacheDir({"foo": "1.2.3"}).scheduleValidate();
     packagesDir({"foo": "1.2.3"}).scheduleValidate();
   });
+
+  integration('URL encodes the package name', () {
+    servePackages([]);
+
+    appDir([dependency("bad name!", "1.2.3")]).scheduleCreate();
+
+    schedulePub(args: ['install'],
+        error: new RegExp('Could not find package "bad name!" at '
+                          'http://localhost:'),
+        exitCode: 1);
+  });
 }
diff --git a/utils/tests/pub/install/pub_install_test.dart b/utils/tests/pub/install/pub_install_test.dart
index 233b7c2..b82565a 100644
--- a/utils/tests/pub/install/pub_install_test.dart
+++ b/utils/tests/pub/install/pub_install_test.dart
@@ -10,6 +10,8 @@
 import '../test_pub.dart';
 
 main() {
+  initConfig();
+
   group('requires', () {
     integration('a pubspec', () {
       dir(appPath, []).scheduleCreate();
diff --git a/utils/tests/pub/install/relative_symlink_test.dart b/utils/tests/pub/install/relative_symlink_test.dart
new file mode 100644
index 0000000..166a7ca
--- /dev/null
+++ b/utils/tests/pub/install/relative_symlink_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import 'dart:io';
+
+import '../../../../pkg/unittest/lib/unittest.dart';
+import '../test_pub.dart';
+
+main() {
+  // Pub uses NTFS junction points to create links in the packages directory.
+  // These (unlike the symlinks that are supported in Vista and later) do not
+  // support relative paths. So this test, by design, will not pass on Windows.
+  // So just skip it.
+  if (Platform.operatingSystem == "windows") return;
+
+  initConfig();
+  integration('uses a relative symlink for the self link', () {
+    dir(appPath, [
+      appPubspec([]),
+      libDir('foo')
+    ]).scheduleCreate();
+
+    schedulePub(args: ['install'],
+        output: new RegExp(r"Dependencies installed!$"));
+
+    scheduleRename(appPath, "moved");
+
+    dir("moved", [
+      dir("packages", [
+        dir("myapp", [
+          file('foo.dart', 'main() => "foo";')
+        ])
+      ])
+    ]).scheduleValidate();
+  });
+
+  integration('uses a relative symlink for secondary packages directory', () {
+    dir(appPath, [
+      appPubspec([]),
+      libDir('foo'),
+      dir("bin")
+    ]).scheduleCreate();
+
+    schedulePub(args: ['install'],
+        output: new RegExp(r"Dependencies installed!$"));
+
+    scheduleRename(appPath, "moved");
+
+    dir("moved", [
+      dir("bin", [
+        dir("packages", [
+          dir("myapp", [
+            file('foo.dart', 'main() => "foo";')
+          ])
+        ])
+      ])
+    ]).scheduleValidate();
+  });
+}
diff --git a/utils/tests/pub/oauth2_test.dart b/utils/tests/pub/oauth2_test.dart
index 62d4f91..c4d0873 100644
--- a/utils/tests/pub/oauth2_test.dart
+++ b/utils/tests/pub/oauth2_test.dart
@@ -28,7 +28,7 @@
       expect(request.headers.value('authorization'),
           equals('Bearer access token'));
 
-      response.outputStream.close();
+      response.close();
     });
 
     // After we give pub an invalid response, it should crash. We wait for it to
@@ -48,7 +48,7 @@
       expect(request.headers.value('authorization'),
           equals('Bearer access token'));
 
-      response.outputStream.close();
+      response.close();
     });
 
     pub.kill();
@@ -66,17 +66,17 @@
     confirmPublish(pub);
 
     server.handle('POST', '/token', (request, response) {
-      return wrapInputStream(request.inputStream).toBytes().then((bytes) {
+      return new ByteStream(request).toBytes().then((bytes) {
         var body = new String.fromCharCodes(bytes);
         expect(body, matches(
             new RegExp(r'(^|&)refresh_token=refresh\+token(&|$)')));
 
         response.headers.contentType = new ContentType("application", "json");
-        response.outputStream.writeString(json.stringify({
+        response.addString(json.stringify({
           "access_token": "new access token",
           "token_type": "bearer"
         }));
-        response.outputStream.close();
+        response.close();
       });
     });
 
@@ -84,7 +84,7 @@
       expect(request.headers.value('authorization'),
           equals('Bearer new access token'));
 
-      response.outputStream.close();
+      response.close();
     });
 
     pub.shouldExit();
@@ -111,7 +111,7 @@
       expect(request.headers.value('authorization'),
           equals('Bearer new access token'));
 
-      response.outputStream.close();
+      response.close();
     });
 
     // After we give pub an invalid response, it should crash. We wait for it to
@@ -136,7 +136,7 @@
       expect(request.headers.value('authorization'),
           equals('Bearer new access token'));
 
-      response.outputStream.close();
+      response.close();
     });
 
 
@@ -159,10 +159,10 @@
       response.statusCode = 401;
       response.headers.set('www-authenticate', 'Bearer error="invalid_token",'
           ' error_description="your token sucks"');
-      response.outputStream.writeString(json.stringify({
+      response.addString(json.stringify({
         'error': {'message': 'your token sucks'}
       }));
-      response.outputStream.close();
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('OAuth2 authorization failed (your '
@@ -205,16 +205,16 @@
 
 void handleAccessTokenRequest(ScheduledServer server, String accessToken) {
   server.handle('POST', '/token', (request, response) {
-    return wrapInputStream(request.inputStream).toBytes().then((bytes) {
+    return new ByteStream(request).toBytes().then((bytes) {
       var body = new String.fromCharCodes(bytes);
       expect(body, matches(new RegExp(r'(^|&)code=access\+code(&|$)')));
 
       response.headers.contentType = new ContentType("application", "json");
-      response.outputStream.writeString(json.stringify({
+      response.addString(json.stringify({
         "access_token": accessToken,
         "token_type": "bearer"
       }));
-      response.outputStream.close();
+      response.close();
     });
   });
 }
diff --git a/utils/tests/pub/pub_lish_test.dart b/utils/tests/pub/pub_lish_test.dart
index 05b8ff5..62fcdf8 100644
--- a/utils/tests/pub/pub_lish_test.dart
+++ b/utils/tests/pub/pub_lish_test.dart
@@ -29,8 +29,8 @@
       }
 
       response.headers.contentType = new ContentType("application", "json");
-      response.outputStream.writeString(json.stringify(body));
-      response.outputStream.close();
+      response.addString(json.stringify(body));
+      response.close();
     });
   });
 }
@@ -39,12 +39,12 @@
   server.handle('POST', '/upload', (request, response) {
     // TODO(nweiz): Once a multipart/form-data parser in Dart exists, validate
     // that the request body is correctly formatted. See issue 6952.
-    return drainInputStream(request.inputStream).then((_) {
+    return drainStream(request).then((_) {
       return server.url;
     }).then((url) {
       response.statusCode = 302;
       response.headers.set('location', url.resolve('/create').toString());
-      response.outputStream.close();
+      response.close();
     });
   });
 }
@@ -63,10 +63,10 @@
     handleUpload(server);
 
     server.handle('GET', '/create', (request, response) {
-      response.outputStream.writeString(json.stringify({
+      response.addString(json.stringify({
         'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
       }));
-      response.outputStream.close();
+      response.close();
     });
 
     // TODO(rnystrom): The confirm line is run together with this one because
@@ -150,10 +150,10 @@
     handleUpload(server);
 
     server.handle('GET', '/create', (request, response) {
-      response.outputStream.writeString(json.stringify({
+      response.addString(json.stringify({
         'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
       }));
-      response.outputStream.close();
+      response.close();
     });
 
     pub.shouldExit(0);
@@ -170,10 +170,10 @@
 
     server.handle('GET', '/packages/versions/new.json', (request, response) {
       response.statusCode = 400;
-      response.outputStream.writeString(json.stringify({
+      response.addString(json.stringify({
         'error': {'message': 'your request sucked'}
       }));
-      response.outputStream.close();
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('your request sucked'));
@@ -188,8 +188,8 @@
     confirmPublish(pub);
 
     server.handle('GET', '/packages/versions/new.json', (request, response) {
-      response.outputStream.writeString('{not json');
-      response.outputStream.close();
+      response.addString('{not json');
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('Invalid server response:'));
@@ -292,12 +292,12 @@
     handleUploadForm(server);
 
     server.handle('POST', '/upload', (request, response) {
-      return drainInputStream(request.inputStream).then((_) {
+      return drainStream(request).then((_) {
         response.statusCode = 400;
         response.headers.contentType = new ContentType('application', 'xml');
-        response.outputStream.writeString('<Error><Message>Your request sucked.'
+        response.addString('<Error><Message>Your request sucked.'
             '</Message></Error>');
-        response.outputStream.close();
+        response.close();
       });
     });
 
@@ -316,9 +316,9 @@
     handleUploadForm(server);
 
     server.handle('POST', '/upload', (request, response) {
-      return drainInputStream(request.inputStream).then((_) {
+      return drainStream(request).then((_) {
         // Don't set the location header.
-        response.outputStream.close();
+        response.close();
       });
     });
 
@@ -337,10 +337,10 @@
 
     server.handle('GET', '/create', (request, response) {
       response.statusCode = 400;
-      response.outputStream.writeString(json.stringify({
+      response.addString(json.stringify({
         'error': {'message': 'Your package was too boring.'}
       }));
-      response.outputStream.close();
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('Your package was too boring.'));
@@ -357,8 +357,8 @@
     handleUpload(server);
 
     server.handle('GET', '/create', (request, response) {
-      response.outputStream.writeString('{not json');
-      response.outputStream.close();
+      response.addString('{not json');
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('Invalid server response:'));
@@ -378,8 +378,8 @@
     var body = {'error': 'Your package was too boring.'};
     server.handle('GET', '/create', (request, response) {
       response.statusCode = 400;
-      response.outputStream.writeString(json.stringify(body));
-      response.outputStream.close();
+      response.addString(json.stringify(body));
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('Invalid server response:'));
@@ -398,8 +398,8 @@
 
     var body = {'success': 'Your package was awesome.'};
     server.handle('GET', '/create', (request, response) {
-      response.outputStream.writeString(json.stringify(body));
-      response.outputStream.close();
+      response.addString(json.stringify(body));
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('Invalid server response:'));
@@ -425,10 +425,10 @@
       handleUpload(server);
 
       server.handle('GET', '/create', (request, response) {
-        response.outputStream.writeString(json.stringify({
+        response.addString(json.stringify({
           'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
         }));
-        response.outputStream.close();
+        response.close();
       });
 
       pub.shouldExit(0);
@@ -449,10 +449,10 @@
       handleUpload(server);
 
       server.handle('GET', '/create', (request, response) {
-        response.outputStream.writeString(json.stringify({
+        response.addString(json.stringify({
           'success': {'message': 'Package test_pkg 1.0.0 uploaded!'}
         }));
-        response.outputStream.close();
+        response.close();
       });
 
       pub.shouldExit(0);
diff --git a/utils/tests/pub/pub_uploader_test.dart b/utils/tests/pub/pub_uploader_test.dart
index 2ac8722..d8f8721 100644
--- a/utils/tests/pub/pub_uploader_test.dart
+++ b/utils/tests/pub/pub_uploader_test.dart
@@ -54,14 +54,14 @@
     var pub = startPubUploader(server, ['--package', 'pkg', 'add', 'email']);
 
     server.handle('POST', '/packages/pkg/uploaders.json', (request, response) {
-      expect(wrapInputStream(request.inputStream).toBytes().then((bodyBytes) {
+      expect(new ByteStream(request).toBytes().then((bodyBytes) {
         expect(new String.fromCharCodes(bodyBytes), equals('email=email'));
 
         response.headers.contentType = new ContentType("application", "json");
-        response.outputStream.writeString(json.stringify({
+        response.addString(json.stringify({
           'success': {'message': 'Good job!'}
         }));
-        response.outputStream.close();
+        response.close();
       }), completes);
     });
 
@@ -77,10 +77,10 @@
     server.handle('DELETE', '/packages/pkg/uploaders/email.json',
         (request, response) {
       response.headers.contentType = new ContentType("application", "json");
-      response.outputStream.writeString(json.stringify({
+      response.addString(json.stringify({
         'success': {'message': 'Good job!'}
       }));
-      response.outputStream.close();
+      response.close();
     });
 
     expectLater(pub.nextLine(), equals('Good job!'));
@@ -97,10 +97,10 @@
     server.handle('POST', '/packages/test_pkg/uploaders.json',
         (request, response) {
       response.headers.contentType = new ContentType("application", "json");
-      response.outputStream.writeString(json.stringify({
+      response.addString(json.stringify({
         'success': {'message': 'Good job!'}
       }));
-      response.outputStream.close();
+      response.close();
     });
 
     expectLater(pub.nextLine(), equals('Good job!'));
@@ -115,10 +115,10 @@
     server.handle('POST', '/packages/pkg/uploaders.json', (request, response) {
       response.statusCode = 400;
       response.headers.contentType = new ContentType("application", "json");
-      response.outputStream.writeString(json.stringify({
+      response.addString(json.stringify({
         'error': {'message': 'Bad job!'}
       }));
-      response.outputStream.close();
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('Bad job!'));
@@ -135,10 +135,10 @@
         (request, response) {
       response.statusCode = 400;
       response.headers.contentType = new ContentType("application", "json");
-      response.outputStream.writeString(json.stringify({
+      response.addString(json.stringify({
         'error': {'message': 'Bad job!'}
       }));
-      response.outputStream.close();
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('Bad job!'));
@@ -151,8 +151,8 @@
     var pub = startPubUploader(server, ['--package', 'pkg', 'add', 'email']);
 
     server.handle('POST', '/packages/pkg/uploaders.json', (request, response) {
-      response.outputStream.writeString("{not json");
-      response.outputStream.close();
+      response.addString("{not json");
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('Invalid server response:'));
@@ -167,8 +167,8 @@
 
     server.handle('DELETE', '/packages/pkg/uploaders/email.json',
         (request, response) {
-      response.outputStream.writeString("{not json");
-      response.outputStream.close();
+      response.addString("{not json");
+      response.close();
     });
 
     expectLater(pub.nextErrLine(), equals('Invalid server response:'));
diff --git a/utils/tests/pub/test_pub.dart b/utils/tests/pub/test_pub.dart
index 2a148f2..64ca423 100644
--- a/utils/tests/pub/test_pub.dart
+++ b/utils/tests/pub/test_pub.dart
@@ -102,36 +102,38 @@
 
   _schedule((_) {
     return _closeServer().then((_) {
-      _server = new HttpServer();
-      _server.defaultRequestHandler = (request, response) {
-        var path = request.uri.replaceFirst("/", "").split("/");
-        response.persistentConnection = false;
-        var stream;
-        try {
-          stream = baseDir.load(path);
-        } catch (e) {
-          response.statusCode = 404;
-          response.contentLength = 0;
-          response.outputStream.close();
-          return;
-        }
+      return HttpServer.bind("127.0.0.1", 0).then((server) {
+        _server = server;
+        server.listen((request) {
+          var response = request.response;
+          var path = request.uri.path.replaceFirst("/", "").split("/");
+          response.persistentConnection = false;
+          var stream;
+          try {
+            stream = baseDir.load(path);
+          } catch (e) {
+            response.statusCode = 404;
+            response.contentLength = 0;
+            response.close();
+            return;
+          }
 
-        stream.toBytes().then((data) {
-          response.statusCode = 200;
-          response.contentLength = data.length;
-          response.outputStream.write(data);
-          response.outputStream.close();
-        }).catchError((e) {
-          print("Exception while handling ${request.uri}: $e");
-          response.statusCode = 500;
-          response.reasonPhrase = e.message;
-          response.outputStream.close();
+          stream.toBytes().then((data) {
+            response.statusCode = 200;
+            response.contentLength = data.length;
+            response.add(data);
+            response.close();
+          }).catchError((e) {
+            print("Exception while handling ${request.uri}: $e");
+            response.statusCode = 500;
+            response.reasonPhrase = e.message;
+            response.close();
+          });
         });
-      };
-      _server.listen("127.0.0.1", 0);
-      _portCompleter.complete(_server.port);
-      _scheduleCleanup((_) => _closeServer());
-      return null;
+        _portCompleter.complete(_server.port);
+        _scheduleCleanup((_) => _closeServer());
+        return null;
+      });
     });
   });
 }
@@ -467,15 +469,15 @@
 typedef Future _ScheduledEvent(String parentDir);
 
 /// The list of events that are scheduled to run as part of the test case.
-List<_ScheduledEvent> _scheduled;
+Queue<_ScheduledEvent> _scheduled;
 
 /// The list of events that are scheduled to run after the test case, even if
 /// it failed.
-List<_ScheduledEvent> _scheduledCleanup;
+Queue<_ScheduledEvent> _scheduledCleanup;
 
 /// The list of events that are scheduled to run after the test case only if it
 /// failed.
-List<_ScheduledEvent> _scheduledOnException;
+Queue<_ScheduledEvent> _scheduledOnException;
 
 /// Set to true when the current batch of scheduled events should be aborted.
 bool _abortScheduled = false;
@@ -704,18 +706,16 @@
   });
 }
 
-Future _runScheduled(List<_ScheduledEvent> scheduled) {
+Future _runScheduled(Queue<_ScheduledEvent> scheduled) {
   if (scheduled == null) return new Future.immediate(null);
-  var iterator = scheduled.iterator;
 
   Future runNextEvent(_) {
-    if (_abortScheduled || !iterator.moveNext()) {
+    if (_abortScheduled || scheduled.isEmpty) {
       _abortScheduled = false;
-      scheduled.clear();
       return new Future.immediate(null);
     }
 
-    var future = iterator.current(_sandboxDir);
+    var future = scheduled.removeFirst()(_sandboxDir);
     if (future != null) {
       return future.then(runNextEvent);
     } else {
@@ -1155,8 +1155,8 @@
     // TODO(nweiz): propagate any errors to the return value. See issue 3657.
     withTempDir((tempDir) {
       return create(tempDir).then((tar) {
-        var sourceStream = new File(tar).openInputStream();
-        return store(wrapInputStream(sourceStream), controller);
+        var sourceStream = new File(tar).openRead();
+        return store(sourceStream, controller);
       });
     });
     return new ByteStream(controller.stream);
@@ -1500,11 +1500,11 @@
   factory ScheduledServer() {
     var scheduledServer;
     scheduledServer = new ScheduledServer._(_scheduleValue((_) {
-      var server = new HttpServer();
-      server.defaultRequestHandler = scheduledServer._awaitHandle;
-      server.listen("127.0.0.1", 0);
-      _scheduleCleanup((_) => server.close());
-      return new Future.immediate(server);
+      return HttpServer.bind("127.0.0.1", 0).then((server) {
+        server.listen(scheduledServer._awaitHandle);
+        _scheduleCleanup((_) => server.close());
+        return server;
+      });
     }));
     return scheduledServer;
   }
@@ -1526,8 +1526,7 @@
       var requestCompleteCompleter = new Completer();
       handlerCompleter.complete((request, response) {
         expect(request.method, equals(method));
-        // TODO(nweiz): Use request.path once issue 7464 is fixed.
-        expect(Uri.parse(request.uri).path, equals(path));
+        expect(request.uri.path, equals(path));
 
         var future = handler(request, response);
         if (future == null) future = new Future.immediate(null);
@@ -1545,17 +1544,18 @@
     _ignored.add(new Pair(method, path));
 
   /// Raises an error complaining of an unexpected request.
-  void _awaitHandle(HttpRequest request, HttpResponse response) {
-    if (_ignored.contains(new Pair(request.method, request.path))) return;
+  void _awaitHandle(HttpRequest request) {
+    HttpResponse response = request.response;
+    if (_ignored.contains(new Pair(request.method, request.uri.path))) return;
     var future = timeout(defer(() {
       if (_handlers.isEmpty) {
-        fail('Unexpected ${request.method} request to ${request.path}.');
+        fail('Unexpected ${request.method} request to ${request.uri.path}.');
       }
       return _handlers.removeFirst();
     }).then((handler) {
       handler(request, response);
     }), _SCHEDULE_TIMEOUT, "waiting for a handler for ${request.method} "
-        "${request.path}");
+        "${request.uri.path}");
     expect(future, completes);
   }
 }
@@ -1587,8 +1587,8 @@
 
 /// Schedules a callback to be called as part of the test case.
 void _schedule(_ScheduledEvent event) {
-  if (_scheduled == null) _scheduled = [];
-  _scheduled.add(event);
+  if (_scheduled == null) _scheduled = new Queue();
+  _scheduled.addLast(event);
 }
 
 /// Like [_schedule], but pipes the return value of [event] to a returned
@@ -1605,15 +1605,15 @@
 /// Schedules a callback to be called after the test case has completed, even
 /// if it failed.
 void _scheduleCleanup(_ScheduledEvent event) {
-  if (_scheduledCleanup == null) _scheduledCleanup = [];
-  _scheduledCleanup.add(event);
+  if (_scheduledCleanup == null) _scheduledCleanup = new Queue();
+  _scheduledCleanup.addLast(event);
 }
 
 /// Schedules a callback to be called after the test case has completed, but
 /// only if it failed.
 void _scheduleOnException(_ScheduledEvent event) {
-  if (_scheduledOnException == null) _scheduledOnException = [];
-  _scheduledOnException.add(event);
+  if (_scheduledOnException == null) _scheduledOnException = new Queue();
+  _scheduledOnException.addLast(event);
 }
 
 /// Like [expect], but for [Future]s that complete as part of the scheduled
diff --git a/utils/tests/pub/validator_test.dart b/utils/tests/pub/validator_test.dart
index 3dbb5ad..4f59bba 100644
--- a/utils/tests/pub/validator_test.dart
+++ b/utils/tests/pub/validator_test.dart
@@ -298,7 +298,7 @@
     });
 
     integration('has a package name that is a Dart reserved word', () {
-      dir(appPath, [libPubspec("operator", "1.0.0")]).scheduleCreate();
+      dir(appPath, [libPubspec("final", "1.0.0")]).scheduleCreate();
       expectValidationError(name);
     });
 
@@ -307,7 +307,7 @@
         libPubspec("test_pkg", "1.0.0"),
         dir("lib", [file("test-pkg.dart", "int i = 0;")])
       ]).scheduleCreate();
-      expectValidationError(name);
+      expectValidationWarning(name);
     });
 
     integration('has a library name that begins with a number', () {
@@ -315,7 +315,7 @@
         libPubspec("test_pkg", "1.0.0"),
         dir("lib", [file("8ball.dart", "int i = 0;")])
       ]).scheduleCreate();
-      expectValidationError(name);
+      expectValidationWarning(name);
     });
 
     integration('has a library name that contains upper-case letters', () {
@@ -329,9 +329,9 @@
     integration('has a library name that is a Dart reserved word', () {
       dir(appPath, [
         libPubspec("test_pkg", "1.0.0"),
-        dir("lib", [file("operator.dart", "int i = 0;")])
+        dir("lib", [file("for.dart", "int i = 0;")])
       ]).scheduleCreate();
-      expectValidationError(name);
+      expectValidationWarning(name);
     });
 
     integration('has a single library named differently than the package', () {
diff --git a/utils/tests/pub/version_test.dart b/utils/tests/pub/version_test.dart
index d5b1849..7543298 100644
--- a/utils/tests/pub/version_test.dart
+++ b/utils/tests/pub/version_test.dart
@@ -10,6 +10,8 @@
 import '../../pub/version.dart';
 
 main() {
+  initConfig();
+
   final v123 = new Version.parse('1.2.3');
   final v114 = new Version.parse('1.1.4');
   final v124 = new Version.parse('1.2.4');
@@ -386,12 +388,38 @@
             new Version.parse('3.4.5')]));
       });
 
-      test('throws FormatException on a bad string', () {
-        expect(() => new VersionConstraint.parse(''), throwsFormatException);
-        expect(() => new VersionConstraint.parse('   '), throwsFormatException);
-        expect(() => new VersionConstraint.parse('not a version'),
+      test('ignores whitespace around operators', () {
+        var constraint = new VersionConstraint.parse(' >1.0.0>=1.2.3 < 1.3.0');
+        expect(constraint, allows([
+            new Version.parse('1.2.3'),
+            new Version.parse('1.2.5')]));
+        expect(constraint, doesNotAllow([
+            new Version.parse('1.2.3-pre'),
+            new Version.parse('1.3.0'),
+            new Version.parse('3.4.5')]));
+      });
+
+      test('does not allow "any" to be mixed with other constraints', () {
+        expect(() => new VersionConstraint.parse('any 1.0.0'),
             throwsFormatException);
       });
+
+      test('throws FormatException on a bad string', () {
+        var bad = [
+           "", "   ",               // Empty string.
+           "foo",                   // Bad text.
+           ">foo",                  // Bad text after operator.
+           "1.0.0 foo", "1.0.0foo", // Bad text after version.
+           "anything",              // Bad text after "any".
+           "<>1.0.0",               // Multiple operators.
+           "1.0.0<"                 // Trailing operator.
+        ];
+
+        for (var text in bad) {
+          expect(() => new VersionConstraint.parse(text),
+              throwsFormatException);
+        }
+      });
     });
   });
 }