Version 0.5.6.0

svn merge -r 22413:22491 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@22493 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/browser/lib/dart.js b/pkg/browser/lib/dart.js
index b507378..d610647 100644
--- a/pkg/browser/lib/dart.js
+++ b/pkg/browser/lib/dart.js
@@ -27,9 +27,9 @@
           var script = document.createElement('script');
           script.src = scripts[i].src.replace(/\.dart(?=\?|$)/, '.dart.js');
           var parent = scripts[i].parentNode;
-	  // TODO(vsm): Find a solution for issue 8455 that works with more
-	  // than one script.
-	  document.currentScript = script;
+          // TODO(vsm): Find a solution for issue 8455 that works with more
+          // than one script.
+          document.currentScript = script;
           parent.replaceChild(script, scripts[i]);
         }
       }
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 53e34af..c1abb38 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -110,6 +110,9 @@
 unittest/test/mock_regexp_negative_test: Fail
 unittest/test/mock_stepwise_negative_test: Fail
 
+[ $compiler == dartanalyzer ]
+unittest/test/mock_regexp_negative_test: fail
+unittest/test/mock_stepwise_negative_test: fail
 
 [ $compiler == dart2js ]
 unittest/test/instance_test: Skip
@@ -140,3 +143,6 @@
 # test on Dartium, which requires all tests to have a library.
 [ $runtime == dartium || $runtime == drt ]
 serialization/test/no_library_test: Skip # Expected Failure
+
+[ $compiler == none && ($runtime == dartium || $runtime == drt) ]
+unittest/test/unittest_test: Timeout # http://dartbug.com/10470
diff --git a/pkg/scheduled_test/test/substitute_future_test.dart b/pkg/scheduled_test/test/substitute_future_test.dart
index 7202c86..5cffb4b 100644
--- a/pkg/scheduled_test/test/substitute_future_test.dart
+++ b/pkg/scheduled_test/test/substitute_future_test.dart
@@ -148,7 +148,9 @@
     var completer = new Completer();
     var future = new SubstituteFuture(completer.future);
     completer.complete('success');
-    expect(() => future.substitute(new Future.value()),
-        throwsStateError);
+    future.then(expectAsync1((_) {
+      expect(() => future.substitute(new Future.value()),
+          throwsStateError);
+    }));
   });
 }
diff --git a/pkg/scheduled_test/test/value_future_test.dart b/pkg/scheduled_test/test/value_future_test.dart
index 61ab436..3cf0fb9 100644
--- a/pkg/scheduled_test/test/value_future_test.dart
+++ b/pkg/scheduled_test/test/value_future_test.dart
@@ -98,30 +98,39 @@
     });
 
     test('.value is the result of the future', () {
-      expect(future.value, equals(12));
+      future.then(expectAsync1((_) {
+        expect(future.value, equals(12));
+      }));
     });
 
     test('.hasValue is true', () {
-      expect(future.hasValue, isTrue);
+      future.then(expectAsync1((_) {
+        expect(future.hasValue, isTrue);
+      }));
     });
   });
 
   group('after an error completion', () {
     var future;
+    var safeFuture;
 
     setUp(() {
       var completer = new Completer();
       future = new ValueFuture(completer.future);
-      future.catchError((e) {});
+      safeFuture = future.catchError((e) {});
       completer.completeError('bad');
     });
 
     test('.value is null', () {
-      expect(future.value, isNull);
+      safeFuture.then(expectAsync1((_) {
+        expect(future.value, isNull);
+      }));
     });
 
     test('.hasValue is false', () {
-      expect(future.hasValue, isFalse);
+      safeFuture.then(expectAsync1((_) {
+        expect(future.hasValue, isFalse);
+      }));
     });
   });
 }
diff --git a/pkg/unittest/lib/interactive_html_config.dart b/pkg/unittest/lib/interactive_html_config.dart
index 0f7ff03..1fcb07c 100644
--- a/pkg/unittest/lib/interactive_html_config.dart
+++ b/pkg/unittest/lib/interactive_html_config.dart
@@ -8,6 +8,9 @@
  * IFrame, so the configuration consists of two parts - a 'parent'
  * config that manages all the tests, and a 'child' config for the
  * IFrame that runs the individual tests.
+ * 
+ * Note: this unit test configuration will not work with the debugger (the tests
+ * are executed in a separate IFrame).
  */
 library unittest_interactive_html_config;
 
@@ -462,8 +465,11 @@
 }
 
 /**
- * Allocate a Configuration. We allocate either a parent or
- * child, depending on whether the URL has a search part.
+ * Allocate a Configuration. We allocate either a parent or child, depending on
+ * whether the URL has a search part.
+ * 
+ * Note: this unit test configuration will not work with the debugger (the tests
+ * are executed in a separate IFrame).
  */
 void useInteractiveHtmlConfiguration() {
   if (window.location.search == '') { // This is the parent.
diff --git a/pkg/unittest/lib/src/config.dart b/pkg/unittest/lib/src/config.dart
index 8b5a60c..490ef80 100644
--- a/pkg/unittest/lib/src/config.dart
+++ b/pkg/unittest/lib/src/config.dart
@@ -160,6 +160,28 @@
   }
   
   /**
+   * Format a test result.
+   */
+  String formatResult(TestCase testCase) {
+    var result = new StringBuffer();
+    result.write(testCase.result.toUpperCase());
+    result.write(": ");
+    result.write(testCase.description);
+    result.write("\n");
+
+    if (testCase.message != '') {
+      result.write(_indent(testCase.message));
+      result.write("\n");
+    }
+
+    if (testCase.stackTrace != null && testCase.stackTrace != '') {
+      result.write(_indent(testCase.stackTrace));
+      result.write("\n");
+    }
+    return result.toString();
+  }
+
+  /**
    * Called with the result of all test cases. The default implementation prints
    * the result summary using the built-in [print] command. Browser tests
    * commonly override this to reformat the output.
@@ -171,16 +193,7 @@
       String uncaughtError) {
     // Print each test's result.
     for (final t in results) {
-      var resultString = "${t.result}".toUpperCase();
-      print('$resultString: ${t.description}');
-
-      if (t.message != '') {
-        print(_indent(t.message));
-      }
-
-      if (t.stackTrace != null && t.stackTrace != '') {
-        print(_indent(t.stackTrace));
-      }
+      print(formatResult(t));
     }
 
     // Show the summary.
diff --git a/pkg/unittest/lib/vm_config.dart b/pkg/unittest/lib/vm_config.dart
index 9d2e6ea..d8b3f23 100644
--- a/pkg/unittest/lib/vm_config.dart
+++ b/pkg/unittest/lib/vm_config.dart
@@ -11,6 +11,32 @@
 import 'unittest.dart';
 
 class VMConfiguration extends Configuration {
+  // Color constants used for generating messages.
+  final String GREEN_COLOR = '\u001b[32m';
+  final String RED_COLOR = '\u001b[31m';
+  final String MAGENTA_COLOR = '\u001b[35m';
+  final String NO_COLOR = '\u001b[0m';
+
+  // We make this public so the user can turn it off if they want.
+  bool useColor;
+
+  VMConfiguration() :
+    super(), useColor = stdioType(stdout) == StdioType.TERMINAL;
+
+  String formatResult(TestCase testCase) {
+    String result = super.formatResult(testCase);
+    if (useColor) {
+      if (testCase.result == PASS) {
+        return "${GREEN_COLOR}${result}${NO_COLOR}";
+      } else if (testCase.result == FAIL) {
+        return "${RED_COLOR}${result}${NO_COLOR}";
+      } else if (testCase.result == ERROR) {
+        return "${MAGENTA_COLOR}${result}${NO_COLOR}";
+      }
+    }
+    return result;
+  }
+
   void onDone(bool success) {
     try {
       super.onDone(success);
diff --git a/runtime/embedders/openglui/common/vm_glue.cc b/runtime/embedders/openglui/common/vm_glue.cc
index 4836c8a..4cb5ff8 100644
--- a/runtime/embedders/openglui/common/vm_glue.cc
+++ b/runtime/embedders/openglui/common/vm_glue.cc
@@ -143,6 +143,7 @@
                        NULL,
                        NULL,
                        NULL,
+                       NULL,
                        NULL)) {
     LOGE("VM initialization failed\n");
     return -1;
diff --git a/runtime/lib/date_patch.dart b/runtime/lib/date_patch.dart
index b1f2f8d..f959723 100644
--- a/runtime/lib/date_patch.dart
+++ b/runtime/lib/date_patch.dart
@@ -5,6 +5,19 @@
 
 // VM implementation of DateTime.
 patch class DateTime {
+  // Natives.
+  // The natives have been moved up here to work around Issue 10401.
+  static int _getCurrentMs() native "DateNatives_currentTimeMillis";
+
+  static String _timeZoneNameForClampedSeconds(int secondsSinceEpoch)
+      native "DateNatives_timeZoneName";
+
+  static int _timeZoneOffsetInSecondsForClampedSeconds(int secondsSinceEpoch)
+      native "DateNatives_timeZoneOffsetInSeconds";
+
+  static int _localTimeZoneAdjustmentInSeconds()
+      native "DateNatives_localTimeZoneAdjustmentInSeconds";
+
   /* patch */ DateTime._internal(int year,
                                  int month,
                                  int day,
@@ -310,16 +323,4 @@
     int equivalentSeconds = _equivalentSeconds(millisecondsSinceEpoch);
     return _timeZoneNameForClampedSeconds(equivalentSeconds);
   }
-
-  // Natives
-  static int _getCurrentMs() native "DateNatives_currentTimeMillis";
-
-  static String _timeZoneNameForClampedSeconds(int secondsSinceEpoch)
-      native "DateNatives_timeZoneName";
-
-  static int _timeZoneOffsetInSecondsForClampedSeconds(int secondsSinceEpoch)
-      native "DateNatives_timeZoneOffsetInSeconds";
-
-  static int _localTimeZoneAdjustmentInSeconds()
-      native "DateNatives_localTimeZoneAdjustmentInSeconds";
 }
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index a4daac2..2280aa9 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -136,7 +136,7 @@
   }
 
   Future call(var message) {
-    final completer = new Completer();
+    final completer = new Completer.sync();
     final port = new _ReceivePortImpl();
     send(message, port.toSendPort());
     port.receive((value, ignoreReplyTo) {
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 614e5589..ef95c2b 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -199,36 +199,31 @@
       var arg = positionalArguments[i];
       _validateArgument(i, arg);
     }
-    Completer<InstanceMirror> completer = new Completer<InstanceMirror>();
     try {
-      completer.complete(
+      return new Future<InstanceMirror>.value(
           _invoke(this, _n(memberName), positionalArguments, true));
     } catch (exception, s) {
-      completer.completeError(exception, s);
+      return new Future<InstanceMirror>.error(exception, s);
     }
-    return completer.future;
   }
 
   Future<InstanceMirror> getFieldAsync(Symbol fieldName) {
-    Completer<InstanceMirror> completer = new Completer<InstanceMirror>();
     try {
-      completer.complete(_getField(this, _n(fieldName)));
+      return new Future<InstanceMirror>.value(_getField(this, _n(fieldName)));
     } catch (exception, s) {
-      completer.completeError(exception, s);
+      return new Future<InstanceMirror>.error(exception, s);
     }
-    return completer.future;
   }
 
   Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object arg) {
     _validateArgument(0, arg);
 
-    Completer<InstanceMirror> completer = new Completer<InstanceMirror>();
     try {
-      completer.complete(_setField(this, _n(fieldName), arg, true));
+      return new Future<InstanceMirror>.value(
+          _setField(this, _n(fieldName), arg, true));
     } catch (exception, s) {
-      completer.completeError(exception, s);
+      return new Future<InstanceMirror>.error(exception, s);
     }
-    return completer.future;
   }
 
   static _validateArgument(int i, Object arg)
@@ -388,14 +383,12 @@
       var arg = positionalArguments[i];
       _LocalObjectMirrorImpl._validateArgument(i, arg);
     }
-    Completer<InstanceMirror> completer = new Completer<InstanceMirror>();
     try {
-      completer.complete(
+      return new Future<InstanceMirror>.value(
           _apply(this, positionalArguments, true));
     } catch (exception) {
-      completer.completeError(exception);
+      return new Future<InstanceMirror>.error(exception);
     }
-    return completer.future;
   }
 
   Future<InstanceMirror> findInContext(Symbol name) {
@@ -598,17 +591,15 @@
       var arg = positionalArguments[i];
       _LocalObjectMirrorImpl._validateArgument(i, arg);
     }
-    Completer<InstanceMirror> completer = new Completer<InstanceMirror>();
     try {
-      completer.complete(
+      return new Future<InstanceMirror>.value(
           _invokeConstructor(this,
                              _n(constructorName),
                              positionalArguments,
                              true));
     } catch (exception) {
-      completer.completeError(exception);
+      return new Future<InstanceMirror>.error(exception);
     }
-    return completer.future;
   }
 
   static _invokeConstructor(ref, constructorName, positionalArguments, async)
@@ -1046,20 +1037,18 @@
   }
 
   static Future<MirrorSystem> mirrorSystemOf(SendPort port) {
-    Completer<MirrorSystem> completer = new Completer<MirrorSystem>();
     if (isLocalPort(port)) {
       // Make a local mirror system.
       try {
-        completer.complete(currentMirrorSystem());
+        return new Future<MirrorSystem>.value(currentMirrorSystem());
       } catch (exception) {
-        completer.completeError(exception);
+        return new Future<MirrorSystem>.error(exception);
       }
     } else {
       // Make a remote mirror system
       throw new UnimplementedError(
           'Remote mirror support is not implemented');
     }
-    return completer.future;
   }
 
   // Creates a new local InstanceMirror
diff --git a/runtime/tools/gen_library_src_paths.py b/runtime/tools/gen_library_src_paths.py
index 2cb082b..2751215 100644
--- a/runtime/tools/gen_library_src_paths.py
+++ b/runtime/tools/gen_library_src_paths.py
@@ -38,6 +38,7 @@
           os.path.basename(string_file).replace('\\', '\\\\') + '", ')
       part_index.append('"' +
           os.path.abspath(string_file).replace('\\', '\\\\') + '", \n')
+  bootstrap_cc_text = bootstrap_cc_text.replace("{{LIBRARY_SOURCE_MAP}}", '')
   bootstrap_cc_text = bootstrap_cc_text.replace("{{PART_SOURCE_MAP}}",
                                                 ''.join(part_index))
   open(output_file, 'w').write(bootstrap_cc_text)
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 5f74eeb..7a0f82f 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -5,6 +5,11 @@
 #include "vm/globals.h"
 #if defined(TARGET_ARCH_ARM)
 
+// An extra check since we are assuming the existence of /proc/cpuinfo below.
+#if !defined(USING_SIMULATOR) && !defined(__linux__)
+#error ARM cross-compile only supported on Linux
+#endif
+
 #include "vm/assembler.h"
 #include "vm/simulator.h"
 #include "vm/runtime_entry.h"
@@ -27,6 +32,8 @@
 }
 
 
+// If we are using the simulator, allow tests to enable/disable support for
+// integer division.
 #if defined(USING_SIMULATOR)
 void CPUFeatures::set_integer_division_supported(bool supported) {
   integer_division_supported_ = supported;
@@ -34,21 +41,56 @@
 #endif
 
 
-#define __ assembler.
+// Probe /proc/cpuinfo for features of the ARM processor.
+#if !defined(USING_SIMULATOR)
+static bool CPUInfoContainsString(const char* search_string) {
+  const char* file_name = "/proc/cpuinfo";
+  // This is written as a straight shot one pass parser
+  // and not using STL string and ifstream because,
+  // on Linux, it's reading from a (non-mmap-able)
+  // character special device.
+  FILE* f = NULL;
+  const char* what = search_string;
+
+  if (NULL == (f = fopen(file_name, "r")))
+    return false;
+
+  int k;
+  while (EOF != (k = fgetc(f))) {
+    if (k == *what) {
+      ++what;
+      while ((*what != '\0') && (*what == fgetc(f))) {
+        ++what;
+      }
+      if (*what == '\0') {
+        fclose(f);
+        return true;
+      } else {
+        what = search_string;
+      }
+    }
+  }
+  fclose(f);
+
+  // Did not find string in the proc file.
+  return false;
+}
+#endif
 
 void CPUFeatures::InitOnce() {
 #if defined(USING_SIMULATOR)
   integer_division_supported_ = true;
 #else
-  integer_division_supported_ = false;
+  ASSERT(CPUInfoContainsString("ARMv7"));  // Implements ARMv7.
+  ASSERT(CPUInfoContainsString("vfp"));  // Has floating point unit.
+  // Has integer division.
+  integer_division_supported_ = CPUInfoContainsString("idiva");
 #endif  // defined(USING_SIMULATOR)
 #if defined(DEBUG)
   initialized_ = true;
 #endif
 }
 
-#undef __
-
 
 // Instruction encoding bits.
 enum {
@@ -89,13 +131,6 @@
   B25 = 1 << 25,
   B26 = 1 << 26,
   B27 = 1 << 27,
-
-  // ldrex/strex register field encodings.
-  kLdExRnShift = 16,
-  kLdExRtShift = 12,
-  kStrExRnShift = 16,
-  kStrExRdShift = 12,
-  kStrExRtShift = 0,
 };
 
 
@@ -491,10 +526,10 @@
   ASSERT(cond != kNoCondition);
   int32_t encoding = opcode |
     (static_cast<int32_t>(cond) << kConditionShift) |
-    (static_cast<int32_t>(rn) << kRnShift) |
-    (static_cast<int32_t>(rd) << kRdShift) |
+    (static_cast<int32_t>(rn) << kDivRnShift) |
+    (static_cast<int32_t>(rd) << kDivRdShift) |
     B26 | B25 | B24 | B20 | B4 |
-    (static_cast<int32_t>(rm) << kRmShift);
+    (static_cast<int32_t>(rm) << kDivRmShift);
   Emit(encoding);
 }
 
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index fa2744d..6195664 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -660,7 +660,7 @@
   // Instruction pattern from entrypoint is used in Dart frame prologs
   // to set up the frame and save a PC which can be used to figure out the
   // RawInstruction object corresponding to the code running in the frame.
-  static const intptr_t kOffsetOfSavedPCfromEntrypoint = Instr::kPCReadOffset;
+  static const intptr_t kEntryPointToPcMarkerOffset = Instr::kPCReadOffset;
 
   // Inlined allocation of an instance of class 'cls', code has no runtime
   // calls. Jump to 'failure' if the instance cannot be allocated here.
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 7a18568..52de670 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -1389,7 +1389,10 @@
 // are in agreement.
 #if defined(USING_SIMULATOR)
 ASSEMBLER_TEST_GENERATE(MrcHaveDiv, assembler) {
-  __ mrc(R0, 15, 0, 0, 2, 0);
+  __ mrc(R0, 15, 0, 0, 2, 0);  // Accesses ID_ISAR0.
+  // Bits 24 - 27 describe the presence of integer division. Bit 24 is set if
+  // it is available in the Thumb instruction set. Bit 25 is set if it is
+  // available both in Thumb and in the ARM instruction set.
   __ Lsr(R0, R0, 24);
   __ and_(R0, R0, ShifterOperand(0xf));
   __ mov(PC, ShifterOperand(LR));
@@ -1401,7 +1404,7 @@
   typedef int (*Tst)();
   bool b = CPUFeatures::integer_division_supported();
   CPUFeatures::set_integer_division_supported(true);
-  EXPECT_LT(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+  EXPECT_EQ(2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
   CPUFeatures::set_integer_division_supported(b);
 }
 
@@ -1422,7 +1425,6 @@
   EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
   CPUFeatures::set_integer_division_supported(b);
 }
-#endif  // defined(USING_SIMULATOR)
 
 
 ASSEMBLER_TEST_GENERATE(MrcReal, assembler) {
@@ -1439,18 +1441,23 @@
   bool have_div = CPUFeatures::integer_division_supported();
   int32_t r = EXECUTE_TEST_CODE_INT32(Tst, test->entry());
   if (have_div) {
-    EXPECT_LT(0, r);
+    EXPECT_EQ(2, r);
   } else {
     EXPECT_EQ(0, r);
   }
 }
+#endif  // defined(USING_SIMULATOR)
 
 
 ASSEMBLER_TEST_GENERATE(Udiv, assembler) {
-  __ mov(R0, ShifterOperand(27));
-  __ mov(R1, ShifterOperand(9));
-  __ udiv(R2, R0, R1);
-  __ Mov(R0, R2);
+  if (CPUFeatures::integer_division_supported()) {
+    __ mov(R0, ShifterOperand(27));
+    __ mov(R1, ShifterOperand(9));
+    __ udiv(R2, R0, R1);
+    __ Mov(R0, R2);
+  } else {
+    __ mov(R0, ShifterOperand(3));
+  }
   __ mov(PC, ShifterOperand(LR));
 }
 
@@ -1463,10 +1470,14 @@
 
 
 ASSEMBLER_TEST_GENERATE(Sdiv, assembler) {
-  __ mov(R0, ShifterOperand(27));
-  __ LoadImmediate(R1, -9);
-  __ sdiv(R2, R0, R1);
-  __ Mov(R0, R2);
+  if (CPUFeatures::integer_division_supported()) {
+    __ mov(R0, ShifterOperand(27));
+    __ LoadImmediate(R1, -9);
+    __ sdiv(R2, R0, R1);
+    __ Mov(R0, R2);
+  } else {
+    __ LoadImmediate(R0, -3);
+  }
   __ mov(PC, ShifterOperand(LR));
 }
 
@@ -1479,10 +1490,14 @@
 
 
 ASSEMBLER_TEST_GENERATE(Udiv_zero, assembler) {
-  __ mov(R0, ShifterOperand(27));
-  __ mov(R1, ShifterOperand(0));
-  __ udiv(R2, R0, R1);
-  __ Mov(R0, R2);
+  if (CPUFeatures::integer_division_supported()) {
+    __ mov(R0, ShifterOperand(27));
+    __ mov(R1, ShifterOperand(0));
+    __ udiv(R2, R0, R1);
+    __ Mov(R0, R2);
+  } else {
+    __ LoadImmediate(R0, 0);
+  }
   __ mov(PC, ShifterOperand(LR));
 }
 
@@ -1495,10 +1510,14 @@
 
 
 ASSEMBLER_TEST_GENERATE(Sdiv_zero, assembler) {
-  __ mov(R0, ShifterOperand(27));
-  __ mov(R1, ShifterOperand(0));
-  __ udiv(R2, R0, R1);
-  __ Mov(R0, R2);
+  if (CPUFeatures::integer_division_supported()) {
+    __ mov(R0, ShifterOperand(27));
+    __ mov(R1, ShifterOperand(0));
+    __ udiv(R2, R0, R1);
+    __ Mov(R0, R2);
+  } else {
+    __ LoadImmediate(R0, 0);
+  }
   __ mov(PC, ShifterOperand(LR));
 }
 
@@ -1511,10 +1530,14 @@
 
 
 ASSEMBLER_TEST_GENERATE(Udiv_corner, assembler) {
-  __ LoadImmediate(R0, 0x80000000);
-  __ LoadImmediate(R1, 0xffffffff);
-  __ udiv(R2, R0, R1);
-  __ Mov(R0, R2);
+  if (CPUFeatures::integer_division_supported()) {
+    __ LoadImmediate(R0, 0x80000000);
+    __ LoadImmediate(R1, 0xffffffff);
+    __ udiv(R2, R0, R1);
+    __ Mov(R0, R2);
+  } else {
+    __ LoadImmediate(R0, 0);
+  }
   __ mov(PC, ShifterOperand(LR));
 }
 
@@ -1527,10 +1550,14 @@
 
 
 ASSEMBLER_TEST_GENERATE(Sdiv_corner, assembler) {
-  __ LoadImmediate(R0, 0x80000000);
-  __ LoadImmediate(R1, 0xffffffff);
-  __ sdiv(R2, R0, R1);
-  __ Mov(R0, R2);
+  if (CPUFeatures::integer_division_supported()) {
+    __ LoadImmediate(R0, 0x80000000);
+    __ LoadImmediate(R1, 0xffffffff);
+    __ sdiv(R2, R0, R1);
+    __ Mov(R0, R2);
+  } else {
+    __ LoadImmediate(R0, 0x80000000);
+  }
   __ mov(PC, ShifterOperand(LR));
 }
 
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index d28f814..56891a5 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -726,7 +726,7 @@
   //   movl ebp, esp      (size is 2 bytes)
   //   call L             (size is 5 bytes)
   //   L:
-  static const intptr_t kOffsetOfSavedPCfromEntrypoint = 8;
+  static const intptr_t kEntryPointToPcMarkerOffset = 8;
 
   // Inlined allocation of an instance of class 'cls', code has no runtime
   // calls. Jump to 'failure' if the instance cannot be allocated here.
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 07d19bc..5604c26 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -179,7 +179,7 @@
   // to set up the frame and save a PC which can be used to figure out the
   // RawInstruction object corresponding to the code running in the frame.
   // See EnterDartFrame. There are 6 instructions before we know the PC.
-  static const intptr_t kOffsetOfSavedPCfromEntrypoint = 6 * Instr::kInstrSize;
+  static const intptr_t kEntryPointToPcMarkerOffset = 6 * Instr::kInstrSize;
 
   // Inlined allocation of an instance of class 'cls', code has no runtime
   // calls. Jump to 'failure' if the instance cannot be allocated here.
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 9ba4fba..7572d0e 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -749,7 +749,7 @@
   //   movq rbp, rsp      (size is 3 bytes)
   //   call L             (size is 5 bytes)
   //   L:
-  static const intptr_t kOffsetOfSavedPCfromEntrypoint = 9;
+  static const intptr_t kEntryPointToPcMarkerOffset = 9;
 
   // Inlined allocation of an instance of class 'cls', code has no runtime
   // calls. Jump to 'failure' if the instance cannot be allocated here.
diff --git a/runtime/vm/benchmark_test.h b/runtime/vm/benchmark_test.h
index ce7f2d0..6b3fcf9 100644
--- a/runtime/vm/benchmark_test.h
+++ b/runtime/vm/benchmark_test.h
@@ -23,7 +23,7 @@
 // of the VM
 #define BENCHMARK(name)                                                        \
   void Dart_Benchmark##name(Benchmark* benchmark);                             \
-  static const Benchmark kRegister##name(Dart_Benchmark##name, #name);         \
+  static Benchmark kRegister##name(Dart_Benchmark##name, #name);               \
   static void Dart_BenchmarkHelper##name(Benchmark* benchmark);                \
   void Dart_Benchmark##name(Benchmark* benchmark) {                            \
     FLAG_heap_growth_space_ratio = 100;                                        \
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 01008aa..e95dc90 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -27,7 +27,7 @@
   const char* uri_;
   const char** source_paths_;
   const char* patch_uri_;
-  const char* patch_source_;
+  const char** patch_paths_;
 } bootstrap_lib_props;
 
 
@@ -35,19 +35,19 @@
   INIT_LIBRARY(ObjectStore::kCore,
                core,
                Bootstrap::corelib_source_paths_,
-               Bootstrap::corelib_patch_),
+               Bootstrap::corelib_patch_paths_),
   INIT_LIBRARY(ObjectStore::kAsync,
                async,
                Bootstrap::async_source_paths_,
-               Bootstrap::async_patch_),
+               Bootstrap::async_patch_paths_),
   INIT_LIBRARY(ObjectStore::kCollection,
                collection,
                Bootstrap::collection_source_paths_,
-               Bootstrap::collection_patch_),
+               Bootstrap::collection_patch_paths_),
   INIT_LIBRARY(ObjectStore::kCollectionDev,
                _collection-dev,
                Bootstrap::collection_dev_source_paths_,
-               Bootstrap::collection_dev_patch_),
+               Bootstrap::collection_dev_patch_paths_),
   INIT_LIBRARY(ObjectStore::kCrypto,
                crypto,
                Bootstrap::crypto_source_paths_,
@@ -55,23 +55,23 @@
   INIT_LIBRARY(ObjectStore::kIsolate,
                isolate,
                Bootstrap::isolate_source_paths_,
-               Bootstrap::isolate_patch_),
+               Bootstrap::isolate_patch_paths_),
   INIT_LIBRARY(ObjectStore::kJson,
                json,
                Bootstrap::json_source_paths_,
-               Bootstrap::json_patch_),
+               Bootstrap::json_patch_paths_),
   INIT_LIBRARY(ObjectStore::kMath,
                math,
                Bootstrap::math_source_paths_,
-               Bootstrap::math_patch_),
+               Bootstrap::math_patch_paths_),
   INIT_LIBRARY(ObjectStore::kMirrors,
                mirrors,
                Bootstrap::mirrors_source_paths_,
-               Bootstrap::mirrors_patch_),
+               Bootstrap::mirrors_patch_paths_),
   INIT_LIBRARY(ObjectStore::kTypedData,
                typed_data,
                Bootstrap::typed_data_source_paths_,
-               Bootstrap::typed_data_patch_),
+               Bootstrap::typed_data_patch_paths_),
   INIT_LIBRARY(ObjectStore::kUtf,
                utf,
                Bootstrap::utf_source_paths_,
@@ -90,38 +90,32 @@
                                    bool patch) {
   // First check if this is a valid boot strap library and find it's index
   // in the 'bootstrap_libraries' table above.
-  intptr_t index = 0;
+  intptr_t index;
   const String& lib_uri = String::Handle(lib.url());
-  while (bootstrap_libraries[index].index_ != ObjectStore::kNone) {
+  for (index = 0;
+       bootstrap_libraries[index].index_ != ObjectStore::kNone;
+       ++index) {
     if (lib_uri.Equals(bootstrap_libraries[index].uri_)) {
       break;
     }
-    index += 1;
   }
   if (bootstrap_libraries[index].index_ == ObjectStore::kNone) {
     return String::null();  // Library is not a boot strap library.
   }
 
-  if (patch) {
-    // TODO(asiva): Replace with actual read of the source file.
-    const char* source = bootstrap_libraries[index].patch_source_;
-    ASSERT(source != NULL);
-    return String::New(source, Heap::kOld);
-  }
-
   // Try to read the source using the path specified for the uri.
-  const char** source_paths = bootstrap_libraries[index].source_paths_;
+  const char** source_paths = patch ?
+      bootstrap_libraries[index].patch_paths_ :
+      bootstrap_libraries[index].source_paths_;
   if (source_paths == NULL) {
     return String::null();  // No path mapping information exists for library.
   }
-  intptr_t i = 0;
   const char* source_path = NULL;
-  while (source_paths[i] != NULL) {
+  for (intptr_t i = 0; source_paths[i] != NULL; i += 2) {
     if (uri.Equals(source_paths[i])) {
       source_path = source_paths[i + 1];
       break;
     }
-    i += 2;
   }
   if (source_path == NULL) {
     return String::null();  // Uri does not exist in path mapping information.
@@ -234,6 +228,39 @@
 }
 
 
+static RawError* LoadPatchFiles(Isolate* isolate,
+                                const Library& lib,
+                                const String& patch_uri,
+                                const char** patch_files) {
+  String& patch_file_uri = String::Handle(isolate);
+  String& source = String::Handle(isolate);
+  Script& script = Script::Handle(isolate);
+  Error& error = Error::Handle(isolate);
+  const Array& strings = Array::Handle(isolate, Array::New(3));
+  strings.SetAt(0, patch_uri);
+  strings.SetAt(1, Symbols::Slash());
+  for (intptr_t j = 0; patch_files[j] != NULL; j += 2) {
+    patch_file_uri = String::New(patch_files[j]);
+    source = GetLibrarySource(lib, patch_file_uri, true);
+    if (source.IsNull()) {
+      return Api::UnwrapErrorHandle(
+          isolate,
+          Api::NewError("Unable to find dart patch source for %s",
+                        patch_file_uri.ToCString())).raw();
+    }
+    // Prepend the patch library URI to form a unique script URI for the patch.
+    strings.SetAt(2, patch_file_uri);
+    patch_file_uri = String::ConcatAll(strings);
+    script = Script::New(patch_file_uri, source, RawScript::kPatchTag);
+    error = lib.Patch(script);
+    if (!error.IsNull()) {
+      return error.raw();
+    }
+  }
+  return Error::null();
+}
+
+
 RawError* Bootstrap::LoadandCompileScripts() {
   Isolate* isolate = Isolate::Current();
   String& uri = String::Handle();
@@ -253,8 +280,9 @@
   Dart_EnterScope();
 
   // Create library objects for all the bootstrap libraries.
-  intptr_t i = 0;
-  while (bootstrap_libraries[i].index_ != ObjectStore::kNone) {
+  for (intptr_t i = 0;
+       bootstrap_libraries[i].index_ != ObjectStore::kNone;
+       ++i) {
     uri = Symbols::New(bootstrap_libraries[i].uri_);
     lib = Library::LookupLibrary(uri);
     if (lib.IsNull()) {
@@ -263,12 +291,12 @@
     }
     isolate->object_store()->set_bootstrap_library(
         bootstrap_libraries[i].index_, lib);
-    i = i + 1;
   }
 
-  // Load and compile bootstrap libraries.
-  i = 0;
-  while (bootstrap_libraries[i].index_ != ObjectStore::kNone) {
+  // Load, compile and patch bootstrap libraries.
+  for (intptr_t i = 0;
+       bootstrap_libraries[i].index_ != ObjectStore::kNone;
+       ++i) {
     uri = Symbols::New(bootstrap_libraries[i].uri_);
     lib = Library::LookupLibrary(uri);
     ASSERT(!lib.IsNull());
@@ -285,23 +313,16 @@
       break;
     }
     // If a patch exists, load and patch the script.
-    if (bootstrap_libraries[i].patch_source_ != NULL) {
-      patch_uri = String::New(bootstrap_libraries[i].patch_uri_,
-                              Heap::kOld);
-      source = GetLibrarySource(lib, uri, true);
-      if (source.IsNull()) {
-        error ^= Api::UnwrapErrorHandle(
-            isolate, Api::NewError("Unable to find dart patch source for %s",
-                                   uri.ToCString())).raw();
-        break;
-      }
-      script = Script::New(patch_uri, source, RawScript::kPatchTag);
-      error = lib.Patch(script);
+    if (bootstrap_libraries[i].patch_paths_ != NULL) {
+      patch_uri = Symbols::New(bootstrap_libraries[i].patch_uri_);
+      error = LoadPatchFiles(isolate,
+                             lib,
+                             patch_uri,
+                             bootstrap_libraries[i].patch_paths_);
       if (!error.IsNull()) {
         break;
       }
     }
-    i = i + 1;
   }
   if (error.IsNull()) {
     SetupNativeResolver();
diff --git a/runtime/vm/bootstrap.h b/runtime/vm/bootstrap.h
index 8c3ae55..d873541 100644
--- a/runtime/vm/bootstrap.h
+++ b/runtime/vm/bootstrap.h
@@ -31,16 +31,16 @@
   static const char* uri_source_paths_[];
   static const char* utf_source_paths_[];
 
-  // Patch sources for libaries (concatenated source).
-  static const char async_patch_[];
-  static const char corelib_patch_[];
-  static const char collection_patch_[];
-  static const char collection_dev_patch_[];
-  static const char isolate_patch_[];
-  static const char json_patch_[];
-  static const char math_patch_[];
-  static const char mirrors_patch_[];
-  static const char typed_data_patch_[];
+  // Source path mapping for patch URI and 'parts'.
+  static const char* async_patch_paths_[];
+  static const char* corelib_patch_paths_[];
+  static const char* collection_patch_paths_[];
+  static const char* collection_dev_patch_paths_[];
+  static const char* isolate_patch_paths_[];
+  static const char* json_patch_paths_[];
+  static const char* math_patch_paths_[];
+  static const char* mirrors_patch_paths_[];
+  static const char* typed_data_patch_paths_[];
 };
 
 }  // namespace dart
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index fb9e846..d4a4ce2 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -1482,15 +1482,16 @@
   // FP, PC-marker and return-address will be copied as well.
   const intptr_t frame_copy_size =
       // Deoptimized function's return address: caller_frame->pc().
-      - kPcSlotIndexFromSp
+      - kSavedPcSlotFromSp
       + ((frame.fp() - frame.sp()) / kWordSize)
-      + kLastParamSlotIndex
+      + 1  // For fp.
+      + kParamEndSlotFromFp
       + num_args;
   intptr_t* frame_copy = new intptr_t[frame_copy_size];
   ASSERT(frame_copy != NULL);
   // Include the return address of optimized code.
   intptr_t* start = reinterpret_cast<intptr_t*>(
-      frame.sp() + (kPcSlotIndexFromSp * kWordSize));
+      frame.sp() + (kSavedPcSlotFromSp * kWordSize));
   for (intptr_t i = 0; i < frame_copy_size; i++) {
     frame_copy[i] = *(start + i);
   }
@@ -1545,8 +1546,10 @@
   const intptr_t num_args =
       function.HasOptionalParameters() ? 0 : function.num_fixed_parameters();
   intptr_t unoptimized_stack_size =
-      + deopt_info.TranslationLength() - num_args
-      - kLastParamSlotIndex;  // Subtract caller FP and PC (possibly pc marker).
+      + deopt_info.FrameSize()
+      - num_args
+      - kParamEndSlotFromFp
+      - 1;  // For fp.
   return unoptimized_stack_size * kWordSize;
 }
 END_LEAF_RUNTIME_ENTRY
@@ -1563,30 +1566,59 @@
   deopt_info.ToInstructions(deopt_table, &deopt_instructions);
 
   intptr_t* start = reinterpret_cast<intptr_t*>(
-      caller_frame.sp() + (kPcSlotIndexFromSp * kWordSize));
+      caller_frame.sp() + (kSavedPcSlotFromSp * kWordSize));
   const Function& function = Function::Handle(code.function());
   const intptr_t num_args =
       function.HasOptionalParameters() ? 0 : function.num_fixed_parameters();
   const intptr_t to_frame_size =
-      - kPcSlotIndexFromSp  // Deoptimized function's return address.
+      - kSavedPcSlotFromSp  // Deoptimized function's return address.
       + (caller_frame.fp() - caller_frame.sp()) / kWordSize
-      + kLastParamSlotIndex
+      + 1  // For fp.
+      + kParamEndSlotFromFp
       + num_args;
   DeoptimizationContext deopt_context(start,
                                       to_frame_size,
                                       Array::Handle(code.object_table()),
                                       num_args,
                                       static_cast<DeoptReasonId>(deopt_reason));
-  for (intptr_t to_index = len - 1; to_index >= 0; to_index--) {
-    deopt_instructions[to_index]->Execute(&deopt_context, to_index);
+  const intptr_t frame_size = deopt_info.FrameSize();
+
+  // All kMaterializeObject instructions are emitted before the instructions
+  // that describe stack frames. Skip them and defer materialization of
+  // objects until the frame is fully reconstructed and it is safe to perform
+  // GC.
+  // Arguments (class of the instance to allocate and field-value pairs) are
+  // described as part of the expression stack for the bottom-most deoptimized
+  // frame. They will be used during materialization and removed from the stack
+  // right before control switches to the unoptimized code.
+  const intptr_t num_materializations = len - frame_size;
+  Isolate::Current()->PrepareForDeferredMaterialization(num_materializations);
+  for (intptr_t from_index = 0, to_index = 1;
+       from_index < num_materializations;
+       from_index++) {
+    const intptr_t field_count =
+        DeoptInstr::GetFieldCount(deopt_instructions[from_index]);
+    intptr_t* args = deopt_context.GetToFrameAddressAt(to_index);
+    DeferredObject* obj = new DeferredObject(field_count, args);
+    Isolate::Current()->SetDeferredObjectAt(from_index, obj);
+    to_index += obj->ArgumentCount();
   }
+
+  // Populate stack frames.
+  for (intptr_t to_index = frame_size - 1, from_index = len - 1;
+       to_index >= 0;
+       to_index--, from_index--) {
+    intptr_t* to_addr = deopt_context.GetToFrameAddressAt(to_index);
+    deopt_instructions[from_index]->Execute(&deopt_context, to_addr);
+  }
+
   if (FLAG_trace_deoptimization_verbose) {
-    for (intptr_t i = 0; i < len; i++) {
-      OS::PrintErr("*%"Pd". [%p] %#014"Px" [%s]\n",
-          i,
-          &start[i],
-          start[i],
-          deopt_instructions[i]->ToCString());
+    for (intptr_t i = 0; i < frame_size; i++) {
+      OS::PrintErr("*%"Pd". [%"Px"] %#014"Px" [%s]\n",
+                   i,
+                   reinterpret_cast<uword>(&start[i]),
+                   start[i],
+                   deopt_instructions[i + (len - frame_size)]->ToCString());
     }
   }
   return deopt_context.GetCallerFp();
@@ -1637,17 +1669,30 @@
 
 
 // This is the last step in the deoptimization, GC can occur.
-DEFINE_RUNTIME_ENTRY(DeoptimizeMaterializeDoubles, 0) {
-  DeferredObject* deferred_object = Isolate::Current()->DetachDeferredObjects();
+// Returns number of bytes to remove from the expression stack of the
+// bottom-most deoptimized frame. Those arguments were artificially injected
+// under return address to keep them discoverable by GC that can occur during
+// materialization phase.
+DEFINE_RUNTIME_ENTRY(DeoptimizeMaterialize, 0) {
+  // First materialize all unboxed "primitive" values (doubles, mints, simd)
+  // then materialize objects. The order is important: objects might be
+  // referencing boxes allocated on the first step. At the same time
+  // objects can't be referencing other deferred objects because storing
+  // an object into a field is always conservatively treated as escaping by
+  // allocation sinking and load forwarding.
+  isolate->MaterializeDeferredBoxes();
+  isolate->MaterializeDeferredObjects();
 
-  while (deferred_object != NULL) {
-    DeferredObject* current = deferred_object;
-    deferred_object  = deferred_object->next();
-
-    current->Materialize();
-
-    delete current;
+  // Compute total number of artificial arguments used during deoptimization.
+  intptr_t deopt_arguments = 0;
+  for (intptr_t i = 0; i < isolate->DeferredObjectsCount(); i++) {
+    deopt_arguments += isolate->GetDeferredObject(i)->ArgumentCount();
   }
+  Isolate::Current()->DeleteDeferredObjects();
+
+  // Return value tells deoptimization stub to remove the given number of bytes
+  // from the stack.
+  arguments.SetReturn(Smi::Handle(Smi::New(deopt_arguments * kWordSize)));
 
   // Since this is the only step where GC can occur during deoptimization,
   // use it to report the source line where deoptimization occured.
diff --git a/runtime/vm/code_generator.h b/runtime/vm/code_generator.h
index 8b0a59c..dcea908 100644
--- a/runtime/vm/code_generator.h
+++ b/runtime/vm/code_generator.h
@@ -47,7 +47,7 @@
 DECLARE_RUNTIME_ENTRY(Throw);
 DECLARE_RUNTIME_ENTRY(TraceFunctionEntry);
 DECLARE_RUNTIME_ENTRY(TraceFunctionExit);
-DECLARE_RUNTIME_ENTRY(DeoptimizeMaterializeDoubles);
+DECLARE_RUNTIME_ENTRY(DeoptimizeMaterialize);
 DECLARE_RUNTIME_ENTRY(UpdateICDataTwoArgs);
 DECLARE_RUNTIME_ENTRY(UpdateFieldCid);
 
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 60af119..a16d853 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -45,6 +45,8 @@
 DEFINE_FLAG(bool, loop_invariant_code_motion, true,
     "Do loop invariant code motion.");
 DEFINE_FLAG(bool, propagate_types, true, "Do static type propagation.");
+DEFINE_FLAG(bool, allocation_sinking, true,
+    "attempt to sink temporary allocations to side exits");
 DEFINE_FLAG(int, deoptimization_counter_threshold, 16,
     "How many times we allow deoptimization before we disallow optimization.");
 DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining");
@@ -267,6 +269,7 @@
         licm.Optimize();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
       }
+      flow_graph->RemoveRedefinitions();
 
       if (FLAG_range_analysis) {
         // We have to perform range analysis after LICM because it
@@ -291,6 +294,20 @@
         propagator.Propagate();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
       }
+
+      // Detach environments from the instructions that can't deoptimize.
+      // Do it before we attempt to perform allocation sinking to minimize
+      // amount of materializations it has to perform.
+      optimizer.EliminateEnvironments();
+
+      // Attempt to sink allocations of temporary non-escaping objects to
+      // the deoptimization path.
+      AllocationSinking* sinking = NULL;
+      if (FLAG_allocation_sinking) {
+        sinking = new AllocationSinking(flow_graph);
+        sinking->Optimize();
+      }
+
       if (optimizer.Canonicalize()) {
         // To fully remove redundant boxing (e.g. BoxDouble used only in
         // environments and UnboxDouble instructions) instruction we
@@ -301,6 +318,14 @@
       }
       DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
+      if (sinking != NULL) {
+        // Remove all MaterializeObject instructions inserted by allocation
+        // sinking from the flow graph and let them float on the side referenced
+        // only from environments. Register allocator will consider them
+        // as part of a deoptimization environment.
+        sinking->DetachMaterializations();
+      }
+
       // Perform register allocation on the SSA graph.
       FlowGraphAllocator allocator(*flow_graph);
       allocator.AllocateRegisters();
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 6dc3034..8caf86d 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -293,12 +293,27 @@
   kOffset12Bits = 12,
   kOffset12Mask = 0x00000fff,
 
-  // Mul instruction register fields encodings.
+  // Mul instruction register field encodings.
   kMulRdShift = 16,
   kMulRdBits = 4,
   kMulRnShift = 12,
   kMulRnBits = 4,
 
+  // Div instruction register field encodings.
+  kDivRdShift = 16,
+  kDivRdBits = 4,
+  kDivRmShift = 8,
+  kDivRmBits = 4,
+  kDivRnShift = 0,
+  kDivRnBits = 4,
+
+  // ldrex/strex register field encodings.
+  kLdExRnShift = 16,
+  kLdExRtShift = 12,
+  kStrExRnShift = 16,
+  kStrExRdShift = 12,
+  kStrExRtShift = 0,
+
   // MRC instruction offset field encoding.
   kCRmShift = 0,
   kCRmBits = 4,
@@ -444,6 +459,16 @@
     return bit_cast<double, uint64_t>(imm64);
   }
 
+  inline Register DivRdField() const {
+    return static_cast<Register>(Bits(kDivRdShift, kDivRdBits));
+  }
+  inline Register DivRmField() const {
+    return static_cast<Register>(Bits(kDivRmShift, kDivRmBits));
+  }
+  inline Register DivRnField() const {
+    return static_cast<Register>(Bits(kDivRnShift, kDivRnBits));
+  }
+
   // Test for data processing instructions of type 0 or 1.
   // See "ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition",
   // section A5.1 "ARM instruction set encoding".
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index db8bb6f..dbf0407 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -32,7 +32,11 @@
 
 
 const char* CPU::Id() {
-  return "arm";
+  return
+#if !defined(HOST_ARCH_ARM)
+  "sim"
+#endif  // !defined(HOST_ARCH_ARM)
+  "arm";
 }
 
 }  // namespace dart
diff --git a/runtime/vm/cpu_mips.cc b/runtime/vm/cpu_mips.cc
index 51a679b..095ec4c 100644
--- a/runtime/vm/cpu_mips.cc
+++ b/runtime/vm/cpu_mips.cc
@@ -30,7 +30,11 @@
 
 
 const char* CPU::Id() {
-  return "mips";
+  return
+#if !defined(HOST_ARCH_MIPS)
+  "sim"
+#endif  // !defined(HOST_ARCH_MIPS)
+  "mips";
 }
 
 }  // namespace dart
diff --git a/runtime/vm/cpu_test.cc b/runtime/vm/cpu_test.cc
index 6f129fe..99e0b23 100644
--- a/runtime/vm/cpu_test.cc
+++ b/runtime/vm/cpu_test.cc
@@ -15,9 +15,17 @@
 #elif defined(TARGET_ARCH_X64)
   EXPECT_STREQ("x64", CPU::Id());
 #elif defined(TARGET_ARCH_ARM)
+#if defined(HOST_ARCH_ARM)
   EXPECT_STREQ("arm", CPU::Id());
+#else  // defined(HOST_ARCH_ARM)
+  EXPECT_STREQ("simarm", CPU::Id());
+#endif  // defined(HOST_ARCH_ARM)
 #elif defined(TARGET_ARCH_MIPS)
+#if defined(HOST_ARCH_MIPS)
   EXPECT_STREQ("mips", CPU::Id());
+#else  // defined(HOST_ARCH_MIPS)
+  EXPECT_STREQ("simmips", CPU::Id());
+#endif  // defined(HOST_ARCH_MIPS)
 #else
 #error Architecture was not detected as supported by Dart.
 #endif
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 2757b83..db0b878 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -3813,16 +3813,16 @@
                                  function_name,
                                  (number_of_arguments + 1),
                                  Resolver::kIsQualified));
-    // TODO(5415268): Invoke noSuchMethod instead of failing.
-    if (function.IsNull()) {
-      const Type& type = Type::Handle(isolate, instance.GetType());
-      const String& cls_name = String::Handle(isolate, type.ClassName());
-      return Api::NewError("%s: did not find instance method '%s.%s'.",
-                           CURRENT_FUNC,
-                           cls_name.ToCString(),
-                           function_name.ToCString());
-    }
     args.SetAt(0, instance);
+    if (function.IsNull()) {
+      const Array& args_descriptor =
+          Array::Handle(ArgumentsDescriptor::New(args.Length()));
+      return Api::NewHandle(isolate,
+                            DartEntry::InvokeNoSuchMethod(instance,
+                                                          function_name,
+                                                          args,
+                                                          args_descriptor));
+    }
     return Api::NewHandle(isolate, DartEntry::InvokeFunction(function, args));
 
   } else if (obj.IsClass()) {
@@ -3933,9 +3933,9 @@
     // field.
     const Instance& instance = Instance::Cast(obj);
     Class& cls = Class::Handle(isolate, instance.clazz());
+    String& getter_name =
+        String::Handle(isolate, Field::GetterName(field_name));
     while (!cls.IsNull()) {
-      String& getter_name =
-          String::Handle(isolate, Field::GetterName(field_name));
       getter = cls.LookupDynamicFunctionAllowPrivate(getter_name);
       if (!getter.IsNull()) {
         break;
@@ -3943,15 +3943,19 @@
       cls = cls.SuperClass();
     }
 
-    if (getter.IsNull()) {
-      return Api::NewError("%s: did not find instance field '%s'.",
-                           CURRENT_FUNC, field_name.ToCString());
-    }
-
     // Invoke the getter and return the result.
     const int kNumArgs = 1;
     const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
     args.SetAt(0, instance);
+    if (getter.IsNull()) {
+      const Array& args_descriptor =
+          Array::Handle(ArgumentsDescriptor::New(args.Length()));
+      return Api::NewHandle(isolate,
+                            DartEntry::InvokeNoSuchMethod(instance,
+                                                          getter_name,
+                                                          args,
+                                                          args_descriptor));
+    }
     return Api::NewHandle(isolate, DartEntry::InvokeFunction(getter, args));
 
   } else if (obj.IsClass()) {
@@ -4055,14 +4059,14 @@
     // field.
     const Instance& instance = Instance::Cast(obj);
     Class& cls = Class::Handle(isolate, instance.clazz());
+    String& setter_name =
+        String::Handle(isolate, Field::SetterName(field_name));
     while (!cls.IsNull()) {
       field = cls.LookupInstanceField(field_name);
       if (!field.IsNull() && field.is_final()) {
         return Api::NewError("%s: cannot set final field '%s'.",
                              CURRENT_FUNC, field_name.ToCString());
       }
-      String& setter_name =
-          String::Handle(isolate, Field::SetterName(field_name));
       setter = cls.LookupDynamicFunctionAllowPrivate(setter_name);
       if (!setter.IsNull()) {
         break;
@@ -4070,16 +4074,20 @@
       cls = cls.SuperClass();
     }
 
-    if (setter.IsNull()) {
-      return Api::NewError("%s: did not find instance field '%s'.",
-                           CURRENT_FUNC, field_name.ToCString());
-    }
-
     // Invoke the setter and return the result.
     const int kNumArgs = 2;
     const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
     args.SetAt(0, instance);
     args.SetAt(1, value_instance);
+    if (setter.IsNull()) {
+      const Array& args_descriptor =
+          Array::Handle(ArgumentsDescriptor::New(args.Length()));
+      return Api::NewHandle(isolate,
+                            DartEntry::InvokeNoSuchMethod(instance,
+                                                          setter_name,
+                                                          args,
+                                                          args_descriptor));
+    }
     return Api::NewHandle(isolate, DartEntry::InvokeFunction(setter, args));
 
   } else if (obj.IsClass()) {
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 6008c9c..b3e96e6 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -3755,7 +3755,8 @@
 
   // Instance method, wrong arg count.
   EXPECT_ERROR(Dart_Invoke(instance, name, 2, bad_args),
-               "did not find instance method 'Methods.instanceMethod'");
+               "Class 'Methods' has no instance method 'instanceMethod'"
+               " with matching arguments");
 
   name = PrivateLibName(lib, "_instanceMethod");
   EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
@@ -3888,15 +3889,77 @@
   EXPECT_VALID(Dart_StringToCString(result, &value));
   EXPECT_STREQ("null", value);
 
-  // Should throw a NullPointerException. Disabled due to bug 5415268.
-  /*
-    Dart_Handle function_name2 = NewString("NoNoNo");
-    result = Dart_Invoke(null_receiver,
-    function_name2,
-    number_of_arguments,
-    dart_arguments);
-    EXPECT(Dart_IsError(result));
-    EXPECT(Dart_ErrorHasException(result)); */
+  Dart_Handle function_name = NewString("NoNoNo");
+  result = Dart_Invoke(Dart_Null(),
+                       function_name,
+                       0,
+                       NULL);
+  EXPECT(Dart_IsError(result));
+  EXPECT(Dart_ErrorHasException(result));
+}
+
+
+TEST_CASE(InvokeNoSuchMethod) {
+  const char* kScriptChars =
+      "import 'dart:_collection-dev' as _collection_dev;\n"
+      "class Expect {\n"
+      "  static equals(a, b) {\n"
+      "    if (a != b) {\n"
+      "      throw 'not equal. expected: $a, got: $b';\n"
+      "    }\n"
+      "  }\n"
+      "}\n"
+      "class TestClass {\n"
+      "  static int fld1 = 0;\n"
+      "  void noSuchMethod(Invocation invocation) {\n"
+      "    var name = _collection_dev.Symbol.getName(invocation.memberName);\n"
+      "    if (name == 'fld') {\n"
+      "      Expect.equals(true, invocation.isGetter);\n"
+      "      Expect.equals(false, invocation.isMethod);\n"
+      "      Expect.equals(false, invocation.isSetter);\n"
+      "    } else if (name == 'setfld') {\n"
+      "      Expect.equals(true, invocation.isSetter);\n"
+      "      Expect.equals(false, invocation.isMethod);\n"
+      "      Expect.equals(false, invocation.isGetter);\n"
+      "    } else if (name == 'method') {\n"
+      "      Expect.equals(true, invocation.isMethod);\n"
+      "      Expect.equals(false, invocation.isSetter);\n"
+      "      Expect.equals(false, invocation.isGetter);\n"
+      "    }\n"
+      "    TestClass.fld1 += 1;\n"
+      "  }\n"
+      "  static TestClass testMain() {\n"
+      "    return new TestClass();\n"
+      "  }\n"
+      "}\n";
+  Dart_Handle result;
+  Dart_Handle instance;
+  // Create a test library and Load up a test script in it.
+  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+  Dart_Handle cls = Dart_GetClass(lib, NewString("TestClass"));
+  EXPECT_VALID(cls);
+
+  // Invoke a function which returns an object.
+  instance = Dart_Invoke(cls, NewString("testMain"), 0, NULL);
+  EXPECT_VALID(instance);
+
+  // Try to get a field that does not exist, should call noSuchMethod.
+  result = Dart_GetField(instance, NewString("fld"));
+  EXPECT_VALID(result);
+
+  // Try to set a field that does not exist, should call noSuchMethod.
+  result = Dart_SetField(instance, NewString("setfld"), Dart_NewInteger(13));
+  EXPECT_VALID(result);
+
+  // Try to invoke a method that does not exist, should call noSuchMethod.
+  result = Dart_Invoke(instance, NewString("method"), 0, NULL);
+  EXPECT_VALID(result);
+
+  result = Dart_GetField(cls, NewString("fld1"));
+  EXPECT_VALID(result);
+  int64_t value = 0;
+  result = Dart_IntegerToInt64(result, &value);
+  EXPECT_EQ(3, value);
 }
 
 
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index fce3e71..9054358 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -41,12 +41,12 @@
 
 
 intptr_t DeoptimizationContext::GetFromFp() const {
-  return from_frame_[from_frame_size_ - num_args_ - kLastParamSlotIndex];
+  return from_frame_[from_frame_size_ - num_args_ - 1 - kParamEndSlotFromFp];
 }
 
 
 intptr_t DeoptimizationContext::GetFromPc() const {
-  return from_frame_[from_frame_size_ - num_args_ + kPcSlotIndexFromSp];
+  return from_frame_[from_frame_size_ - num_args_ + kSavedPcSlotFromSp];
 }
 
 intptr_t DeoptimizationContext::GetCallerFp() const {
@@ -72,18 +72,14 @@
   virtual DeoptInstr::Kind kind() const { return kStackSlot; }
 
   virtual const char* ToCString() const {
-    const char* format = "s%"Pd"";
-    intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_);
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, stack_slot_index_);
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "s%"Pd"", stack_slot_index_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     intptr_t from_index =
        deopt_context->from_frame_size() - stack_slot_index_ - 1;
     intptr_t* from_addr = deopt_context->GetFromFrameAddressAt(from_index);
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
     *to_addr = *from_addr;
   }
 
@@ -105,19 +101,15 @@
   virtual DeoptInstr::Kind kind() const { return kDoubleStackSlot; }
 
   virtual const char* ToCString() const {
-    const char* format = "ds%"Pd"";
-    intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_);
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, stack_slot_index_);
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "ds%"Pd"", stack_slot_index_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     intptr_t from_index =
        deopt_context->from_frame_size() - stack_slot_index_ - 1;
     double* from_addr = reinterpret_cast<double*>(
         deopt_context->GetFromFrameAddressAt(from_index));
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
     *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
     Isolate::Current()->DeferDoubleMaterialization(
         *from_addr, reinterpret_cast<RawDouble**>(to_addr));
@@ -141,19 +133,15 @@
   virtual DeoptInstr::Kind kind() const { return kInt64StackSlot; }
 
   virtual const char* ToCString() const {
-    const char* format = "ms%"Pd"";
-    intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_);
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, stack_slot_index_);
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "ms%"Pd"", stack_slot_index_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     intptr_t from_index =
        deopt_context->from_frame_size() - stack_slot_index_ - 1;
     int64_t* from_addr = reinterpret_cast<int64_t*>(
         deopt_context->GetFromFrameAddressAt(from_index));
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
     *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
     if (Smi::IsValid64(*from_addr)) {
       *to_addr = reinterpret_cast<intptr_t>(
@@ -182,19 +170,15 @@
   virtual DeoptInstr::Kind kind() const { return kFloat32x4StackSlot; }
 
   virtual const char* ToCString() const {
-    const char* format = "f32x4s%"Pd"";
-    intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_);
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, stack_slot_index_);
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "f32x4s%"Pd"", stack_slot_index_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     intptr_t from_index =
        deopt_context->from_frame_size() - stack_slot_index_ - 1;
     simd128_value_t* from_addr = reinterpret_cast<simd128_value_t*>(
         deopt_context->GetFromFrameAddressAt(from_index));
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
     *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
     Isolate::Current()->DeferFloat32x4Materialization(
         *from_addr, reinterpret_cast<RawFloat32x4**>(to_addr));
@@ -218,19 +202,15 @@
   virtual DeoptInstr::Kind kind() const { return kUint32x4StackSlot; }
 
   virtual const char* ToCString() const {
-    const char* format = "ui32x4s%"Pd"";
-    intptr_t len = OS::SNPrint(NULL, 0, format, stack_slot_index_);
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, stack_slot_index_);
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "ui32x4s%"Pd"", stack_slot_index_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     intptr_t from_index =
        deopt_context->from_frame_size() - stack_slot_index_ - 1;
     simd128_value_t* from_addr = reinterpret_cast<simd128_value_t*>(
         deopt_context->GetFromFrameAddressAt(from_index));
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
     *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
     Isolate::Current()->DeferUint32x4Materialization(
         *from_addr, reinterpret_cast<RawUint32x4**>(to_addr));
@@ -270,7 +250,7 @@
         "ret oti:%"Pd"(%"Pd")", object_table_index_, deopt_id_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     Function& function = Function::Handle(deopt_context->isolate());
     function ^= deopt_context->ObjectAt(object_table_index_);
     const Code& code =
@@ -279,7 +259,6 @@
     uword continue_at_pc = code.GetPcForDeoptId(deopt_id_,
                                                 PcDescriptors::kDeopt);
     ASSERT(continue_at_pc != 0);
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
     *to_addr = continue_at_pc;
 
     uword pc = code.GetPcForDeoptId(deopt_id_, PcDescriptors::kIcCall);
@@ -321,19 +300,14 @@
   virtual DeoptInstr::Kind kind() const { return kConstant; }
 
   virtual const char* ToCString() const {
-    const char* format = "const oti:%"Pd"";
-    intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_);
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, object_table_index_);
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "const oti:%"Pd"", object_table_index_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     const Object& obj = Object::Handle(
         deopt_context->isolate(), deopt_context->ObjectAt(object_table_index_));
-    RawObject** to_addr = reinterpret_cast<RawObject**>(
-        deopt_context->GetToFrameAddressAt(to_index));
-    *to_addr = obj.raw();
+    *reinterpret_cast<RawObject**>(to_addr) = obj.raw();
   }
 
  private:
@@ -356,10 +330,8 @@
     return Assembler::RegisterName(reg_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
-    intptr_t value = deopt_context->RegisterValue(reg_);
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
-    *to_addr = value;
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
+    *to_addr = deopt_context->RegisterValue(reg_);
   }
 
  private:
@@ -382,9 +354,8 @@
     return Assembler::FpuRegisterName(reg_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     double value = deopt_context->FpuRegisterValue(reg_);
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
     *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
     Isolate::Current()->DeferDoubleMaterialization(
         value, reinterpret_cast<RawDouble**>(to_addr));
@@ -406,17 +377,12 @@
   virtual DeoptInstr::Kind kind() const { return kInt64FpuRegister; }
 
   virtual const char* ToCString() const {
-    const char* format = "%s(m)";
-    intptr_t len =
-        OS::SNPrint(NULL, 0, format, Assembler::FpuRegisterName(reg_));
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, Assembler::FpuRegisterName(reg_));
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "%s(m)", Assembler::FpuRegisterName(reg_));
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     int64_t value = deopt_context->FpuRegisterValueAsInt64(reg_);
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
     *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
     if (Smi::IsValid64(value)) {
       *to_addr = reinterpret_cast<intptr_t>(
@@ -444,17 +410,12 @@
   virtual DeoptInstr::Kind kind() const { return kFloat32x4FpuRegister; }
 
   virtual const char* ToCString() const {
-    const char* format = "%s(f32x4)";
-    intptr_t len =
-        OS::SNPrint(NULL, 0, format, Assembler::FpuRegisterName(reg_));
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, Assembler::FpuRegisterName(reg_));
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "%s(f32x4)", Assembler::FpuRegisterName(reg_));
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     simd128_value_t value = deopt_context->FpuRegisterValueAsSimd128(reg_);
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
     *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
     Isolate::Current()->DeferFloat32x4Materialization(
         value, reinterpret_cast<RawFloat32x4**>(to_addr));
@@ -477,17 +438,12 @@
   virtual DeoptInstr::Kind kind() const { return kFloat32x4FpuRegister; }
 
   virtual const char* ToCString() const {
-    const char* format = "%s(f32x4)";
-    intptr_t len =
-        OS::SNPrint(NULL, 0, format, Assembler::FpuRegisterName(reg_));
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, Assembler::FpuRegisterName(reg_));
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "%s(f32x4)", Assembler::FpuRegisterName(reg_));
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     simd128_value_t value = deopt_context->FpuRegisterValueAsSimd128(reg_);
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
     *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
     Isolate::Current()->DeferUint32x4Materialization(
         value, reinterpret_cast<RawUint32x4**>(to_addr));
@@ -513,22 +469,18 @@
   virtual DeoptInstr::Kind kind() const { return kPcMarker; }
 
   virtual const char* ToCString() const {
-    const char* format = "pcmark oti:%"Pd"";
-    intptr_t len = OS::SNPrint(NULL, 0, format, object_table_index_);
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, object_table_index_);
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "pcmark oti:%"Pd"", object_table_index_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     Function& function = Function::Handle(deopt_context->isolate());
     function ^= deopt_context->ObjectAt(object_table_index_);
     const Code& code =
         Code::Handle(deopt_context->isolate(), function.unoptimized_code());
     ASSERT(!code.IsNull());
-    intptr_t pc_marker = code.EntryPoint() +
-                         Assembler::kOffsetOfSavedPCfromEntrypoint;
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
+    const intptr_t pc_marker =
+        code.EntryPoint() + Assembler::kEntryPointToPcMarkerOffset;
     *to_addr = pc_marker;
     // Increment the deoptimization counter. This effectively increments each
     // function occurring in the optimized frame.
@@ -563,10 +515,8 @@
     return "callerfp";
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
-    intptr_t from = deopt_context->GetCallerFp();
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
-    *to_addr = from;
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
+    *to_addr = deopt_context->GetCallerFp();
     deopt_context->SetCallerFp(reinterpret_cast<intptr_t>(to_addr));
   }
 
@@ -588,10 +538,8 @@
     return "callerpc";
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
-    intptr_t from = deopt_context->GetFromPc();
-    intptr_t* to_addr = deopt_context->GetToFrameAddressAt(to_index);
-    *to_addr = from;
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
+    *to_addr = deopt_context->GetFromPc();
   }
 
  private:
@@ -623,14 +571,11 @@
   virtual DeoptInstr::Kind kind() const { return kSuffix; }
 
   virtual const char* ToCString() const {
-    const char* format = "suffix %"Pd":%"Pd;
-    intptr_t len = OS::SNPrint(NULL, 0, format, info_number_, suffix_length_);
-    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
-    OS::SNPrint(chars, len + 1, format, info_number_, suffix_length_);
-    return chars;
+    return Isolate::Current()->current_zone()->PrintToString(
+        "suffix %"Pd":%"Pd, info_number_, suffix_length_);
   }
 
-  void Execute(DeoptimizationContext* deopt_context, intptr_t to_index) {
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
     // The deoptimization info is uncompressed by translating away suffixes
     // before executing the instructions.
     UNREACHABLE();
@@ -652,6 +597,66 @@
 };
 
 
+// Write reference to a materialized object with the given index into the
+// stack slot.
+class DeoptMaterializedObjectRefInstr : public DeoptInstr {
+ public:
+  explicit DeoptMaterializedObjectRefInstr(intptr_t index)
+      : index_(index) {
+    ASSERT(index >= 0);
+  }
+
+  virtual intptr_t from_index() const { return index_; }
+  virtual DeoptInstr::Kind kind() const { return kMaterializedObjectRef; }
+
+  virtual const char* ToCString() const {
+    return Isolate::Current()->current_zone()->PrintToString(
+        "mat ref #%"Pd"", index_);
+  }
+
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
+    *reinterpret_cast<RawSmi**>(to_addr) = Smi::New(0);
+    Isolate::Current()->DeferMaterializedObjectRef(
+        index_, to_addr);
+  }
+
+ private:
+  intptr_t index_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeoptMaterializedObjectRefInstr);
+};
+
+
+// Materialize object with the given number of fields.
+// Arguments for materialization (class and field-value pairs) are pushed
+// to the expression stack of the bottom-most frame.
+class DeoptMaterializeObjectInstr : public DeoptInstr {
+ public:
+  explicit DeoptMaterializeObjectInstr(intptr_t field_count)
+      : field_count_(field_count) {
+    ASSERT(field_count >= 0);
+  }
+
+  virtual intptr_t from_index() const { return field_count_; }
+  virtual DeoptInstr::Kind kind() const { return kMaterializeObject; }
+
+  virtual const char* ToCString() const {
+    return Isolate::Current()->current_zone()->PrintToString(
+        "mat obj len:%"Pd"", field_count_);
+  }
+
+  void Execute(DeoptimizationContext* deopt_context, intptr_t* to_addr) {
+    // This instructions are executed manually by the DeoptimizeWithDeoptInfo.
+    UNREACHABLE();
+  }
+
+ private:
+  intptr_t field_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeoptMaterializeObjectInstr);
+};
+
+
 intptr_t DeoptInstr::DecodeSuffix(intptr_t from_index, intptr_t* info_number) {
   *info_number = DeoptSuffixInstr::InfoNumber::decode(from_index);
   return DeoptSuffixInstr::SuffixLength::decode(from_index);
@@ -700,6 +705,9 @@
     case kCallerFp: return new DeoptCallerFpInstr();
     case kCallerPc: return new DeoptCallerPcInstr();
     case kSuffix: return new DeoptSuffixInstr(from_index);
+    case kMaterializedObjectRef:
+        return new DeoptMaterializedObjectRefInstr(from_index);
+    case kMaterializeObject: return new DeoptMaterializeObjectInstr(from_index);
   }
   UNREACHABLE();
   return NULL;
@@ -743,7 +751,9 @@
       object_table_(GrowableObjectArray::Handle(GrowableObjectArray::New())),
       num_args_(num_args),
       trie_root_(new TrieNode()),
-      current_info_number_(0) {
+      current_info_number_(0),
+      frame_start_(-1),
+      materializations_() {
 }
 
 
@@ -763,7 +773,7 @@
 intptr_t DeoptInfoBuilder::CalculateStackIndex(const Location& from_loc) const {
   return from_loc.stack_index() < 0 ?
             from_loc.stack_index() + num_args_ :
-            from_loc.stack_index() + num_args_ - kFirstLocalSlotIndex + 1;
+            from_loc.stack_index() + num_args_ - kFirstLocalSlotFromFp + 1;
 }
 
 
@@ -778,7 +788,7 @@
       (code.GetPcForDeoptId(deopt_id, PcDescriptors::kDeopt) != 0));
 #endif
   const intptr_t object_table_index = FindOrAddObjectInTable(function);
-  ASSERT(to_index == instructions_.length());
+  ASSERT(to_index == FrameSize());
   instructions_.Add(new DeoptRetAddressInstr(object_table_index, deopt_id));
 }
 
@@ -787,7 +797,7 @@
                                    intptr_t to_index) {
   // Function object was already added by AddReturnAddress, find it.
   intptr_t from_index = FindOrAddObjectInTable(function);
-  ASSERT(to_index == instructions_.length());
+  ASSERT(to_index == FrameSize());
   instructions_.Add(new DeoptPcMarkerInstr(from_index));
 }
 
@@ -833,35 +843,102 @@
       ASSERT(value->definition()->representation() == kUnboxedUint32x4);
       deopt_instr = new DeoptUint32x4StackSlotInstr(from_index);
     }
+  } else if (from_loc.IsInvalid() &&
+             value->definition()->IsMaterializeObject()) {
+    const intptr_t index = FindMaterialization(
+        value->definition()->AsMaterializeObject());
+    ASSERT(index >= 0);
+    deopt_instr = new DeoptMaterializedObjectRefInstr(index);
   } else {
     UNREACHABLE();
   }
-  ASSERT(to_index == instructions_.length());
+  ASSERT(to_index == FrameSize());
   ASSERT(deopt_instr != NULL);
   instructions_.Add(deopt_instr);
 }
 
 
 void DeoptInfoBuilder::AddCallerFp(intptr_t to_index) {
-  ASSERT(to_index == instructions_.length());
+  ASSERT(to_index == FrameSize());
   instructions_.Add(new DeoptCallerFpInstr());
 }
 
 
 void DeoptInfoBuilder::AddCallerPc(intptr_t to_index) {
-  ASSERT(to_index == instructions_.length());
+  ASSERT(to_index == FrameSize());
   instructions_.Add(new DeoptCallerPcInstr());
 }
 
 
+void DeoptInfoBuilder::AddConstant(const Object& obj, intptr_t to_index) {
+  ASSERT(to_index == FrameSize());
+  intptr_t object_table_index = FindOrAddObjectInTable(obj);
+  instructions_.Add(new DeoptConstantInstr(object_table_index));
+}
+
+
+void DeoptInfoBuilder::AddMaterialization(MaterializeObjectInstr* mat) {
+  const intptr_t index = FindMaterialization(mat);
+  if (index >= 0) {
+    return;  // Already added.
+  }
+  materializations_.Add(mat);
+
+  // Count initialized fields and emit kMaterializeObject instruction.
+  // There is no need to write nulls into fields because object is null
+  // initialized by default.
+  intptr_t non_null_fields = 0;
+  for (intptr_t i = 0; i < mat->InputCount(); i++) {
+    if (!mat->InputAt(i)->BindsToConstantNull()) {
+      non_null_fields++;
+    }
+  }
+
+  instructions_.Add(new DeoptMaterializeObjectInstr(non_null_fields));
+}
+
+
+intptr_t DeoptInfoBuilder::EmitMaterializationArguments() {
+  intptr_t slot_idx = 1;  // Return address is emitted at 0.
+  for (intptr_t i = 0; i < materializations_.length(); i++) {
+    MaterializeObjectInstr* mat = materializations_[i];
+    AddConstant(mat->cls(), slot_idx++);  // Class of the instance to allocate.
+    for (intptr_t i = 0; i < mat->InputCount(); i++) {
+      if (!mat->InputAt(i)->BindsToConstantNull()) {
+        // Emit field-value pair.
+        AddConstant(mat->FieldAt(i), slot_idx++);
+        AddCopy(mat->InputAt(i), mat->LocationAt(i), slot_idx++);
+      }
+    }
+  }
+  return slot_idx;
+}
+
+
+intptr_t DeoptInfoBuilder::FindMaterialization(
+    MaterializeObjectInstr* mat) const {
+  for (intptr_t i = 0; i < materializations_.length(); i++) {
+    if (materializations_[i] == mat) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+
 RawDeoptInfo* DeoptInfoBuilder::CreateDeoptInfo() {
+  // TODO(vegorov): enable compression of deoptimization info containing object
+  // materialization instructions.
+  const bool disable_compression =
+      (instructions_[0]->kind() == DeoptInstr::kMaterializeObject);
+
   intptr_t length = instructions_.length();
 
   // Count the number of instructions that are a shared suffix of some deopt
   // info already written.
   TrieNode* suffix = trie_root_;
   intptr_t suffix_length = 0;
-  if (FLAG_compress_deopt_info) {
+  if (FLAG_compress_deopt_info && !disable_compression) {
     for (intptr_t i = length - 1; i >= 0; --i) {
       TrieNode* node = suffix->FindChild(*instructions_[i]);
       if (node == NULL) break;
@@ -894,6 +971,9 @@
   }
 
   instructions_.Clear();
+  materializations_.Clear();
+  frame_start_ = -1;
+
   ++current_info_number_;
   return deopt_info.raw();
 }
diff --git a/runtime/vm/deopt_instructions.h b/runtime/vm/deopt_instructions.h
index 0d41ffd..024eb93 100644
--- a/runtime/vm/deopt_instructions.h
+++ b/runtime/vm/deopt_instructions.h
@@ -15,6 +15,7 @@
 
 class Location;
 class Value;
+class MaterializeObjectInstr;
 
 // Holds all data relevant for execution of deoptimization instructions.
 class DeoptimizationContext : public ValueObject {
@@ -111,6 +112,8 @@
     kCallerFp,
     kCallerPc,
     kSuffix,
+    kMaterializedObjectRef,
+    kMaterializeObject
   };
 
   static DeoptInstr* Create(intptr_t kind_as_int, intptr_t from_index);
@@ -121,7 +124,7 @@
   virtual const char* ToCString() const = 0;
 
   virtual void Execute(DeoptimizationContext* deopt_context,
-                       intptr_t to_index) = 0;
+                       intptr_t* to_addr) = 0;
 
   virtual DeoptInstr::Kind kind() const = 0;
 
@@ -139,11 +142,18 @@
                              const Array& object_table,
                              Function* func);
 
- protected:
-  virtual intptr_t from_index() const = 0;
+  // Return number of initialized fields in the object that will be
+  // materialized by kMaterializeObject instruction.
+  static intptr_t GetFieldCount(DeoptInstr* instr) {
+    ASSERT(instr->kind() == DeoptInstr::kMaterializeObject);
+    return instr->from_index();
+  }
 
+ protected:
   friend class DeoptInfoBuilder;
 
+  virtual intptr_t from_index() const = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(DeoptInstr);
 };
@@ -173,14 +183,42 @@
   void AddCallerFp(intptr_t to_index);
   void AddCallerPc(intptr_t to_index);
 
+  // Add object to be materialized. Emit kMaterializeObject instruction.
+  void AddMaterialization(MaterializeObjectInstr* mat);
+
+  // For every materialized object emit instructions describing data required
+  // for materialization: class of the instance to allocate and field-value
+  // pairs for initialization.
+  // Emitted instructions are expected to follow return-address slot emitted
+  // first. This way they become a part of the bottom-most deoptimized frame
+  // and are discoverable by GC.
+  // At deoptimization they will be removed by the stub at the very end:
+  // after they were used to materialize objects.
+  // Returns the index of the next stack slot. Used for verification.
+  intptr_t EmitMaterializationArguments();
+
   RawDeoptInfo* CreateDeoptInfo();
 
+  // Mark the actual start of the frame description after all materialization
+  // instructions were emitted. Used for verification purposes.
+  void MarkFrameStart() {
+    ASSERT(frame_start_ == -1);
+    frame_start_ = instructions_.length();
+  }
+
  private:
   class TrieNode;
 
   intptr_t FindOrAddObjectInTable(const Object& obj) const;
+  intptr_t FindMaterialization(MaterializeObjectInstr* mat) const;
   intptr_t CalculateStackIndex(const Location& from_loc) const;
 
+  intptr_t FrameSize() const {
+    return instructions_.length() - frame_start_;
+  }
+
+  void AddConstant(const Object& obj, intptr_t to_index);
+
   GrowableArray<DeoptInstr*> instructions_;
   const GrowableObjectArray& object_table_;
   const intptr_t num_args_;
@@ -189,6 +227,9 @@
   TrieNode* trie_root_;
   intptr_t current_info_number_;
 
+  intptr_t frame_start_;
+  GrowableArray<MaterializeObjectInstr*> materializations_;
+
   DISALLOW_COPY_AND_ASSIGN(DeoptInfoBuilder);
 };
 
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index a9cc7f0..8a7b5ea 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -601,8 +601,8 @@
           break;
         }
         case 7: {
-          if (instr->Bits(21, 2) == 0x1) {
-            Format(instr, "bkpt'cond #'imm12_4");
+          if ((instr->Bits(21, 2) == 0x1) && (instr->ConditionField() == AL)) {
+            Format(instr, "bkpt #'imm12_4");
           } else {
              // Format(instr, "smc'cond");
             Unknown(instr);  // Not used.
@@ -861,9 +861,9 @@
 void ARMDecoder::DecodeType3(Instr* instr) {
   if (instr->IsDivision()) {
     if (instr->Bit(21)) {
-      Format(instr, "udiv'cond 'rd, 'rn, 'rm");
+      Format(instr, "udiv'cond 'rn, 'rs, 'rm");
     } else {
-      Format(instr, "sdiv'cond 'rd, 'rn, 'rm");
+      Format(instr, "sdiv'cond 'rn, 'rs, 'rm");
     }
     return;
   }
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index 34ca693..ae130d4 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -29,17 +29,17 @@
     preorder_(),
     postorder_(),
     reverse_postorder_(),
-    block_effects_(NULL) {
+    block_effects_(NULL),
+    licm_allowed_(true) {
   DiscoverBlocks();
 }
 
 
-ConstantInstr* FlowGraph::AddConstantToInitialDefinitions(
-    const Object& object) {
+ConstantInstr* FlowGraph::GetConstant(const Object& object) {
   // Check if the constant is already in the pool.
-  for (intptr_t i = 0; i < graph_entry_->initial_definitions()->length(); ++i) {
-    ConstantInstr* constant =
-        (*graph_entry_->initial_definitions())[i]->AsConstant();
+  GrowableArray<Definition*>* pool = graph_entry_->initial_definitions();
+  for (intptr_t i = 0; i < pool->length(); ++i) {
+    ConstantInstr* constant = (*pool)[i]->AsConstant();
     if ((constant != NULL) && (constant->value().raw() == object.raw())) {
       return constant;
     }
@@ -51,6 +51,7 @@
   return constant;
 }
 
+
 void FlowGraph::AddToInitialDefinitions(Definition* defn) {
   // TODO(zerny): Set previous to the graph entry so it is accessible by
   // GetBlock. Remove this once there is a direct pointer to the block.
@@ -522,7 +523,6 @@
       dom_index = idom[dom_index];
     }
     idom[block_index] = dom_index;
-    preorder_[block_index]->set_dominator(preorder_[dom_index]);
     preorder_[dom_index]->AddDominatedBlock(preorder_[block_index]);
   }
 
@@ -626,8 +626,7 @@
   GrowableArray<Definition*> env(variable_count());
 
   // Add global constants to the initial definitions.
-  constant_null_ =
-      AddConstantToInitialDefinitions(Object::ZoneHandle());
+  constant_null_ = GetConstant(Object::ZoneHandle());
 
   // Add parameters to the initial definitions and renaming environment.
   if (inlining_parameters != NULL) {
@@ -699,7 +698,6 @@
   AttachEnvironment(block_entry, env);
 
   // 2. Process normal instructions.
-
   for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) {
     Instruction* current = it.Current();
 
@@ -709,18 +707,20 @@
     }
 
     // 2a. Handle uses:
-    // Update expression stack environment for each use.
-    // For each use of a LoadLocal or StoreLocal: Replace it with the value
-    // from the environment.
+    // Update the expression stack renaming environment for each use by
+    // removing the renamed value.
+    // For each use of a LoadLocal, StoreLocal, or Constant: Replace it with
+    // the renamed value.
     for (intptr_t i = current->InputCount() - 1; i >= 0; --i) {
       Value* v = current->InputAt(i);
       // Update expression stack.
       ASSERT(env->length() > variable_count());
 
       Definition* reaching_defn = env->RemoveLast();
-
       Definition* input_defn = v->definition();
-      if (input_defn->IsLoadLocal() || input_defn->IsStoreLocal()) {
+      if (input_defn->IsLoadLocal() ||
+          input_defn->IsStoreLocal() ||
+          input_defn->IsConstant()) {
         // Remove the load/store from the graph.
         input_defn->RemoveFromGraph();
         // Assert we are not referencing nulls in the initial environment.
@@ -736,14 +736,13 @@
       env->RemoveLast();
     }
 
-    // 2b. Handle LoadLocal and StoreLocal.
-    // For each LoadLocal: Remove it from the graph.
-    // For each StoreLocal: Remove it from the graph and update the environment.
+    // 2b. Handle LoadLocal, StoreLocal, and Constant.
     Definition* definition = current->AsDefinition();
     if (definition != NULL) {
       LoadLocalInstr* load = definition->AsLoadLocal();
       StoreLocalInstr* store = definition->AsStoreLocal();
-      if ((load != NULL) || (store != NULL)) {
+      ConstantInstr* constant = definition->AsConstant();
+      if ((load != NULL) || (store != NULL) || (constant != NULL)) {
         intptr_t index;
         Definition* result;
         if (store != NULL) {
@@ -756,7 +755,7 @@
           } else {
             (*env)[index] = constant_null();
           }
-        } else {
+        } else if (load != NULL) {
           // The graph construction ensures we do not have an unused LoadLocal
           // computation.
           ASSERT(definition->is_used());
@@ -772,16 +771,21 @@
           if (variable_liveness->IsLastLoad(block_entry, load)) {
             (*env)[index] = constant_null();
           }
+        } else {
+          ASSERT(definition->is_used());
+          result = GetConstant(constant->value());
         }
         // Update expression stack or remove from graph.
         if (definition->is_used()) {
+          ASSERT(result != NULL);
           env->Add(result);
-          // We remove load/store instructions when we find their use in 2a.
+          // We remove load/store/constant instructions when we find their
+          // use in 2a.
         } else {
           it.RemoveCurrentFromGraph();
         }
       } else {
-        // Not a load or store.
+        // Not a load, store, or constant.
         if (definition->is_used()) {
           // Assign fresh SSA temporary and update expression stack.
           definition->set_ssa_temp_index(alloc_ssa_temp_index());
@@ -847,6 +851,28 @@
 }
 
 
+void FlowGraph::RemoveRedefinitions() {
+  // Remove redefinition instructions inserted to inhibit hoisting.
+  for (BlockIterator block_it = reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    for (ForwardInstructionIterator instr_it(block_it.Current());
+         !instr_it.Done();
+         instr_it.Advance()) {
+      RedefinitionInstr* redefinition = instr_it.Current()->AsRedefinition();
+      if (redefinition != NULL) {
+        Definition* original;
+        do {
+          original = redefinition->value()->definition();
+        } while (original->IsRedefinition());
+        redefinition->ReplaceUsesWith(original);
+        instr_it.RemoveCurrentFromGraph();
+      }
+    }
+  }
+}
+
+
 // Find the natural loop for the back edge m->n and attach loop information
 // to block n (loop header). The algorithm is described in "Advanced Compiler
 // Design & Implementation" (Muchnick) p192.
diff --git a/runtime/vm/flow_graph.h b/runtime/vm/flow_graph.h
index 7016767..ec85594 100644
--- a/runtime/vm/flow_graph.h
+++ b/runtime/vm/flow_graph.h
@@ -98,6 +98,7 @@
 
   intptr_t max_block_id() const { return max_block_id_; }
   void set_max_block_id(intptr_t id) { max_block_id_ = id; }
+  intptr_t allocate_block_id() { return ++max_block_id_; }
 
   GraphEntryInstr* graph_entry() const {
     return graph_entry_;
@@ -111,7 +112,7 @@
 
   intptr_t InstructionCount() const;
 
-  ConstantInstr* AddConstantToInitialDefinitions(const Object& object);
+  ConstantInstr* GetConstant(const Object& object);
   void AddToInitialDefinitions(Definition* defn);
 
   void InsertBefore(Instruction* next,
@@ -146,6 +147,26 @@
   void ComputeBlockEffects();
   BlockEffects* block_effects() const { return block_effects_; }
 
+  // Remove the redefinition instructions inserted to inhibit code motion.
+  void RemoveRedefinitions();
+
+  // Copy deoptimization target from one instruction to another if we still
+  // have to keep deoptimization environment at gotos for LICM purposes.
+  void CopyDeoptTarget(Instruction* to, Instruction* from) {
+    if (is_licm_allowed()) {
+      to->InheritDeoptTarget(from);
+    }
+  }
+
+  // Returns true if every Goto in the graph is expected to have a
+  // deoptimization environment and can be used as deoptimization target
+  // for hoisted instructions.
+  bool is_licm_allowed() const { return licm_allowed_; }
+
+  // Stop preserving environments on Goto instructions. LICM is not allowed
+  // after this point.
+  void disallow_licm() { licm_allowed_ = false; }
+
  private:
   friend class IfConverter;
   friend class BranchSimplifier;
@@ -201,6 +222,7 @@
   ConstantInstr* constant_null_;
 
   BlockEffects* block_effects_;
+  bool licm_allowed_;
 };
 
 
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index 5125f97..5c16a8b 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -102,18 +102,6 @@
 }
 
 
-// Remove environments from the instructions which can't deoptimize.
-void FlowGraphAllocator::EliminateEnvironments() {
-  for (intptr_t i = 0; i < block_order_.length(); ++i) {
-    BlockEntryInstr* block = block_order_[i];
-    for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
-      Instruction* current = it.Current();
-      if (!current->CanDeoptimize()) current->RemoveEnvironment();
-    }
-  }
-}
-
-
 void SSALivenessAnalysis::ComputeInitialSets() {
   const intptr_t block_count = postorder_.length();
   for (intptr_t i = 0; i < block_count; i++) {
@@ -152,10 +140,17 @@
         for (Environment::DeepIterator env_it(current->env());
              !env_it.Done();
              env_it.Advance()) {
-          Value* value = env_it.CurrentValue();
-          if (!value->definition()->IsPushArgument() &&
-              !value->BindsToConstant()) {
-            live_in->Add(value->definition()->ssa_temp_index());
+          Definition* defn = env_it.CurrentValue()->definition();
+          if (defn->IsMaterializeObject()) {
+            // MaterializeObject instruction is not in the graph.
+            // Treat its inputs as part of the environment.
+            for (intptr_t i = 0; i < defn->InputCount(); i++) {
+              if (!defn->InputAt(i)->BindsToConstant()) {
+                live_in->Add(defn->InputAt(i)->definition()->ssa_temp_index());
+              }
+            }
+          } else if (!defn->IsPushArgument() && !defn->IsConstant()) {
+            live_in->Add(defn->ssa_temp_index());
           }
         }
       }
@@ -742,6 +737,16 @@
         continue;
       }
 
+      MaterializeObjectInstr* mat = def->AsMaterializeObject();
+      if (mat != NULL) {
+        // MaterializeObject itself produces no value. But its uses
+        // are treated as part of the environment: allocated locations
+        // will be used when building deoptimization data.
+        locations[i] = Location::NoLocation();
+        ProcessMaterializationUses(block, block_start_pos, use_pos, mat);
+        continue;
+      }
+
       const intptr_t vreg = def->ssa_temp_index();
       LiveRange* range = GetLiveRange(vreg);
       range->AddUseInterval(block_start_pos, use_pos);
@@ -754,6 +759,42 @@
 }
 
 
+void FlowGraphAllocator::ProcessMaterializationUses(
+    BlockEntryInstr* block,
+    const intptr_t block_start_pos,
+    const intptr_t use_pos,
+    MaterializeObjectInstr* mat) {
+  // Materialization can occur several times in the same environment.
+  // Check if we already processed this one.
+  if (mat->locations() != NULL) {
+    return;  // Already processed.
+  }
+
+  // Initialize location for every input of the MaterializeObject instruction.
+  Location* locations =
+      Isolate::Current()->current_zone()->Alloc<Location>(mat->InputCount());
+
+  for (intptr_t i = 0; i < mat->InputCount(); ++i) {
+    Definition* def = mat->InputAt(i)->definition();
+
+    ConstantInstr* constant = def->AsConstant();
+    if (constant != NULL) {
+      locations[i] = Location::Constant(constant->value());
+      continue;
+    }
+
+    locations[i] = Location::Any();
+
+    const intptr_t vreg = def->ssa_temp_index();
+    LiveRange* range = GetLiveRange(vreg);
+    range->AddUseInterval(block_start_pos, use_pos);
+    range->AddUse(use_pos, &locations[i]);
+  }
+
+  mat->set_locations(locations);
+}
+
+
 // Create and update live ranges corresponding to instruction's inputs,
 // temporaries and output.
 void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
@@ -2187,7 +2228,10 @@
   for (intptr_t i = unallocated_.length() - 1; i >= 1; i--) {
     LiveRange* a = unallocated_[i];
     LiveRange* b = unallocated_[i - 1];
-    if (!ShouldBeAllocatedBefore(a, b)) return false;
+    if (!ShouldBeAllocatedBefore(a, b)) {
+      UNREACHABLE();
+      return false;
+    }
   }
   return true;
 }
@@ -2432,8 +2476,6 @@
 void FlowGraphAllocator::AllocateRegisters() {
   CollectRepresentations();
 
-  EliminateEnvironments();
-
   liveness_.Analyze();
 
   NumberInstructions();
diff --git a/runtime/vm/flow_graph_allocator.h b/runtime/vm/flow_graph_allocator.h
index 8919e38..0efca0c 100644
--- a/runtime/vm/flow_graph_allocator.h
+++ b/runtime/vm/flow_graph_allocator.h
@@ -66,9 +66,6 @@
  private:
   void CollectRepresentations();
 
-  // Eliminate unnecessary environments from the IL.
-  void EliminateEnvironments();
-
   // Visit blocks in the code generation order (reverse post order) and
   // linearly assign consequent lifetime positions to every instruction.
   // We assign position as follows:
@@ -107,6 +104,10 @@
   Instruction* ConnectOutgoingPhiMoves(BlockEntryInstr* block,
                                        BitVector* interference_set);
   void ProcessEnvironmentUses(BlockEntryInstr* block, Instruction* current);
+  void ProcessMaterializationUses(BlockEntryInstr* block,
+                                  const intptr_t block_start_pos,
+                                  const intptr_t use_pos,
+                                  MaterializeObjectInstr* mat);
   void ProcessOneInstruction(BlockEntryInstr* block,
                              Instruction* instr,
                              BitVector* interference_set);
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index e341f28..ff98680 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -97,6 +97,15 @@
 }
 
 
+void InlineExitCollector::Union(const InlineExitCollector* other) {
+  // It doesn't make sense to combine different calls or calls from
+  // different graphs.
+  ASSERT(caller_graph_ == other->caller_graph_);
+  ASSERT(call_ == other->call_);
+  exits_.AddArray(other->exits_);
+}
+
+
 int InlineExitCollector::LowestBlockIdFirst(const Data* a, const Data* b) {
   return (a->exit_block->block_id() - b->exit_block->block_id());
 }
@@ -133,7 +142,7 @@
     caller_graph_->set_max_block_id(join_id);
     JoinEntryInstr* join =
         new JoinEntryInstr(join_id, CatchClauseNode::kInvalidTryIndex);
-    join->InheritDeoptTarget(call_);
+    join->InheritDeoptTargetAfter(call_);
 
     // The dominator set of the join is the intersection of the dominator
     // sets of all the predecessors.  If we keep the dominator sets ordered
@@ -180,7 +189,8 @@
             // We either exhausted the dominators for this block before
             // exhausting the current intersection, or else we found a block
             // on the path from the root of the tree that is not in common.
-            ASSERT(j >= 2);
+            // I.e., there cannot be an empty set of dominators.
+            ASSERT(j > 0);
             join_dominators.TruncateTo(j);
             break;
           }
@@ -189,7 +199,6 @@
     }
     // The immediate dominator of the join is the last one in the ordered
     // intersection.
-    join->set_dominator(join_dominators.Last());
     join_dominators.Last()->AddDominatedBlock(join);
     *exit_block = join;
     *last_instruction = join;
@@ -273,7 +282,6 @@
     ASSERT(callee_exit->dominated_blocks().is_empty());
     for (intptr_t i = 0; i < call_block->dominated_blocks().length(); ++i) {
       BlockEntryInstr* block = call_block->dominated_blocks()[i];
-      block->set_dominator(callee_exit);
       callee_exit->AddDominatedBlock(block);
     }
     // The call block is now the immediate dominator of blocks whose
@@ -281,10 +289,14 @@
     call_block->ClearDominatedBlocks();
     for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) {
       BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
-      block->set_dominator(call_block);
       call_block->AddDominatedBlock(block);
     }
   }
+
+  // Neither call nor callee entry are in the graph at this point. Remove them
+  // from use lists.
+  callee_entry->UnuseAllInputs();
+  call_->UnuseAllInputs();
 }
 
 
@@ -2956,10 +2968,10 @@
       const Function& function = owner()->parsed_function().function();
       int num_params = function.NumParameters();
       int param_frame_index = (num_params == function.num_fixed_parameters()) ?
-          (kLastParamSlotIndex + num_params - 1) : kFirstLocalSlotIndex;
+          (kParamEndSlotFromFp + num_params) : kFirstLocalSlotFromFp;
       // Handle the saved arguments descriptor as an additional parameter.
       if (owner()->parsed_function().GetSavedArgumentsDescriptorVar() != NULL) {
-        ASSERT(param_frame_index == kFirstLocalSlotIndex);
+        ASSERT(param_frame_index == kFirstLocalSlotFromFp);
         num_params++;
       }
       for (int pos = 0; pos < num_params; param_frame_index--, pos++) {
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index ec525ec..950224f 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -46,6 +46,8 @@
 
   void AddExit(ReturnInstr* exit);
 
+  void Union(const InlineExitCollector* other);
+
   // Before replacing a call with a graph, the outer environment needs to be
   // attached to each instruction in the callee graph and the caller graph
   // needs to have its block and instruction ID state updated.
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 2ec6ebc..222501c 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -41,14 +41,27 @@
   if (env == NULL) return;
   AllocateIncomingParametersRecursive(env->outer(), stack_height);
   for (Environment::ShallowIterator it(env); !it.Done(); it.Advance()) {
-    if (it.CurrentLocation().IsInvalid()) {
-      ASSERT(it.CurrentValue()->definition()->IsPushArgument());
+    if (it.CurrentLocation().IsInvalid() &&
+        it.CurrentValue()->definition()->IsPushArgument()) {
       it.SetCurrentLocation(Location::StackSlot((*stack_height)++));
     }
   }
 }
 
 
+void CompilerDeoptInfo::EmitMaterializations(Environment* env,
+                                             DeoptInfoBuilder* builder) {
+  for (Environment::DeepIterator it(env); !it.Done(); it.Advance()) {
+    if (it.CurrentLocation().IsInvalid()) {
+      MaterializeObjectInstr* mat =
+          it.CurrentValue()->definition()->AsMaterializeObject();
+      ASSERT(mat != NULL);
+      builder->AddMaterialization(mat);
+    }
+  }
+}
+
+
 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
                                                  DeoptInfoBuilder* builder) {
   if (deoptimization_env_ == NULL) return DeoptInfo::null();
@@ -59,10 +72,21 @@
   intptr_t slot_ix = 0;
   Environment* current = deoptimization_env_;
 
+  // Emit all kMaterializeObject instructions describing objects to be
+  // materialized on the deoptimization as a prefix to the deoptimization info.
+  EmitMaterializations(deoptimization_env_, builder);
+
+  // The real frame starts here.
+  builder->MarkFrameStart();
   builder->AddReturnAddress(current->function(),
                             deopt_id(),
                             slot_ix++);
 
+  // Emit all values that are needed for materialization as a part of the
+  // expression stack for the bottom-most frame. This guarantees that GC
+  // will be able to find them during materialization.
+  slot_ix = builder->EmitMaterializationArguments();
+
   // For the innermost environment, set outgoing arguments and the locals.
   for (intptr_t i = current->Length() - 1;
        i >= current->fixed_parameter_count();
@@ -1125,6 +1149,12 @@
 }
 
 
+static int HighestCountFirst(const CidTarget* a, const CidTarget* b) {
+  // Negative if 'a' should sort before 'b'.
+  return b->count - a->count;
+}
+
+
 // Returns 'sorted' array in decreasing count order.
 // The expected number of elements to sort is less than 10.
 void FlowGraphCompiler::SortICDataByCount(const ICData& ic_data,
@@ -1138,20 +1168,7 @@
                           &Function::ZoneHandle(ic_data.GetTargetAt(i)),
                           ic_data.GetCountAt(i)));
   }
-  for (int i = 0; i < len; i++) {
-    intptr_t largest_ix = i;
-    for (int k = i + 1; k < len; k++) {
-      if ((*sorted)[largest_ix].count < (*sorted)[k].count) {
-        largest_ix = k;
-      }
-    }
-    if (i != largest_ix) {
-      // Swap.
-      CidTarget temp = (*sorted)[i];
-      (*sorted)[i] = (*sorted)[largest_ix];
-      (*sorted)[largest_ix] = temp;
-    }
-  }
+  sorted->Sort(HighestCountFirst);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 4c7204a..ffdf981 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -116,8 +116,6 @@
   RawDeoptInfo* CreateDeoptInfo(FlowGraphCompiler* compiler,
                                 DeoptInfoBuilder* builder);
 
-  void AllocateIncomingParametersRecursive(Environment* env,
-                                           intptr_t* stack_height);
 
   // No code needs to be generated.
   virtual void GenerateCode(FlowGraphCompiler* compiler, intptr_t stub_ix) {}
@@ -133,6 +131,11 @@
   void set_deoptimization_env(Environment* env) { deoptimization_env_ = env; }
 
  private:
+  void EmitMaterializations(Environment* env, DeoptInfoBuilder* builder);
+
+  void AllocateIncomingParametersRecursive(Environment* env,
+                                           intptr_t* stack_height);
+
   intptr_t pc_offset_;
   const intptr_t deopt_id_;
   const DeoptReasonId reason_;
@@ -452,6 +455,10 @@
                                                    Register array,
                                                    Register index);
 
+  // Returns 'sorted' array in decreasing count order.
+  static void SortICDataByCount(const ICData& ic_data,
+                                GrowableArray<CidTarget>* sorted);
+
  private:
   friend class CheckStackOverflowSlowPath;  // For pending_deoptimization_env_.
 
@@ -541,11 +548,6 @@
     return block_order_.length() - index - 1;
   }
 
-  // Returns 'sorted' array in decreasing count order.
-  // The expected number of elements to sort is less than 10.
-  static void SortICDataByCount(const ICData& ic_data,
-                                GrowableArray<CidTarget>* sorted);
-
   void CompactBlock(BlockEntryInstr* block);
   void CompactBlocks();
 
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index e88a8f7..6d32025 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -575,7 +575,7 @@
   const int num_params =
       num_fixed_params + num_opt_pos_params + num_opt_named_params;
   ASSERT(function.NumParameters() == num_params);
-  ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotIndex);
+  ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp);
 
   // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args,
   // where num_pos_args is the number of positional arguments passed in.
@@ -592,20 +592,20 @@
   __ b(&wrong_num_arguments, GT);
 
   // Copy positional arguments.
-  // Argument i passed at fp[kLastParamSlotIndex + num_args - 1 - i] is copied
-  // to fp[kFirstLocalSlotIndex - i].
+  // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied
+  // to fp[kFirstLocalSlotFromFp - i].
 
   __ ldr(R7, FieldAddress(R4, ArgumentsDescriptor::count_offset()));
   // Since R7 and R8 are Smi, use LSL 1 instead of LSL 2.
   // Let R7 point to the last passed positional argument, i.e. to
-  // fp[kLastParamSlotIndex + num_args - 1 - (num_pos_args - 1)].
+  // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)].
   __ sub(R7, R7, ShifterOperand(R8));
   __ add(R7, FP, ShifterOperand(R7, LSL, 1));
-  __ add(R7, R7, ShifterOperand(kLastParamSlotIndex * kWordSize));
+  __ add(R7, R7, ShifterOperand((kParamEndSlotFromFp + 1) * kWordSize));
 
   // Let R6 point to the last copied positional argument, i.e. to
-  // fp[kFirstLocalSlotIndex - (num_pos_args - 1)].
-  __ AddImmediate(R6, FP, (kFirstLocalSlotIndex + 1) * kWordSize);
+  // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)].
+  __ AddImmediate(R6, FP, (kFirstLocalSlotFromFp + 1) * kWordSize);
   __ sub(R6, R6, ShifterOperand(R8, LSL, 1));  // R8 is a Smi.
   __ SmiUntag(R8);
   Label loop, loop_condition;
@@ -649,9 +649,9 @@
            FieldAddress(R4, ArgumentsDescriptor::positional_count_offset()));
     __ SmiUntag(R8);
     // Let R7 point to the first passed argument, i.e. to
-    // fp[kLastParamSlotIndex + num_args - 1 - 0]; num_args (R7) is Smi.
+    // fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi.
     __ add(R7, FP, ShifterOperand(R7, LSL, 1));
-    __ AddImmediate(R7, R7, (kLastParamSlotIndex - 1) * kWordSize);
+    __ AddImmediate(R7, R7, kParamEndSlotFromFp * kWordSize);
     // Let R6 point to the entry of the first named argument.
     __ add(R6, R4, ShifterOperand(
         ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag));
@@ -665,7 +665,7 @@
       __ CompareObject(R5, opt_param[i]->name());
       __ b(&load_default_value, NE);
       // Load R5 with passed-in argument at provided arg_pos, i.e. at
-      // fp[kLastParamSlotIndex + num_args - 1 - arg_pos].
+      // fp[kParamEndSlotFromFp + num_args - arg_pos].
       __ ldr(R5, Address(R6, ArgumentsDescriptor::position_offset()));
       // R5 is arg_pos as Smi.
       // Point to next named entry.
@@ -681,11 +681,11 @@
               param_pos - num_fixed_params));
       __ LoadObject(R5, value);
       __ Bind(&assign_optional_parameter);
-      // Assign R5 to fp[kFirstLocalSlotIndex - param_pos].
+      // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos].
       // We do not use the final allocation index of the variable here, i.e.
       // scope->VariableAt(i)->index(), because captured variables still need
       // to be copied to the context that is not yet allocated.
-      const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos;
+      const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
       const Address param_addr(FP, computed_param_pos * kWordSize);
       __ str(R5, param_addr);
     }
@@ -712,11 +712,11 @@
       const Object& value = Object::ZoneHandle(
           parsed_function().default_parameter_values().At(i));
       __ LoadObject(R5, value);
-      // Assign R5 to fp[kFirstLocalSlotIndex - param_pos].
+      // Assign R5 to fp[kFirstLocalSlotFromFp - param_pos].
       // We do not use the final allocation index of the variable here, i.e.
       // scope->VariableAt(i)->index(), because captured variables still need
       // to be copied to the context that is not yet allocated.
-      const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos;
+      const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
       const Address param_addr(FP, computed_param_pos * kWordSize);
       __ str(R5, param_addr);
       __ Bind(&next_parameter);
@@ -778,7 +778,7 @@
   // R4 : arguments descriptor array.
   __ ldr(R8, FieldAddress(R4, ArgumentsDescriptor::count_offset()));
   __ SmiUntag(R8);
-  __ add(R7, FP, ShifterOperand(kLastParamSlotIndex * kWordSize));
+  __ add(R7, FP, ShifterOperand((kParamEndSlotFromFp + 1) * kWordSize));
   const Address original_argument_addr(R7, R8, LSL, 2);
   __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
   Label null_args_loop, null_args_loop_condition;
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index e609740..13c4965 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -669,7 +669,7 @@
   const int num_params =
       num_fixed_params + num_opt_pos_params + num_opt_named_params;
   ASSERT(function.NumParameters() == num_params);
-  ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotIndex);
+  ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp);
 
   // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args,
   // where num_pos_args is the number of positional arguments passed in.
@@ -687,19 +687,20 @@
   __ j(GREATER, &wrong_num_arguments);
 
   // Copy positional arguments.
-  // Argument i passed at fp[kLastParamSlotIndex + num_args - 1 - i] is copied
-  // to fp[kFirstLocalSlotIndex - i].
+  // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied
+  // to fp[kFirstLocalSlotFromFp - i].
 
   __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
   // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4.
   // Let EBX point to the last passed positional argument, i.e. to
-  // fp[kLastParamSlotIndex + num_args - 1 - (num_pos_args - 1)].
+  // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)].
   __ subl(EBX, ECX);
-  __ leal(EBX, Address(EBP, EBX, TIMES_2, kLastParamSlotIndex * kWordSize));
+  __ leal(EBX, Address(EBP, EBX, TIMES_2,
+                       (kParamEndSlotFromFp + 1) * kWordSize));
 
   // Let EDI point to the last copied positional argument, i.e. to
-  // fp[kFirstLocalSlotIndex - (num_pos_args - 1)].
-  __ leal(EDI, Address(EBP, (kFirstLocalSlotIndex + 1) * kWordSize));
+  // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)].
+  __ leal(EDI, Address(EBP, (kFirstLocalSlotFromFp + 1) * kWordSize));
   __ subl(EDI, ECX);  // ECX is a Smi, subtract twice for TIMES_4 scaling.
   __ subl(EDI, ECX);
   __ SmiUntag(ECX);
@@ -746,9 +747,9 @@
             FieldAddress(EDX, ArgumentsDescriptor::positional_count_offset()));
     __ SmiUntag(ECX);
     // Let EBX point to the first passed argument, i.e. to
-    // fp[kLastParamSlotIndex + num_args - 1 - 0]; num_args (EBX) is Smi.
+    // fp[kParamEndSlotFromFp + num_args - 0]; num_args (EBX) is Smi.
     __ leal(EBX,
-            Address(EBP, EBX, TIMES_2, (kLastParamSlotIndex - 1) * kWordSize));
+            Address(EBP, EBX, TIMES_2, kParamEndSlotFromFp * kWordSize));
     // Let EDI point to the entry of the first named argument.
     __ leal(EDI,
             FieldAddress(EDX, ArgumentsDescriptor::first_named_entry_offset()));
@@ -762,7 +763,7 @@
       __ CompareObject(EAX, opt_param[i]->name());
       __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump);
       // Load EAX with passed-in argument at provided arg_pos, i.e. at
-      // fp[kLastParamSlotIndex + num_args - 1 - arg_pos].
+      // fp[kParamEndSlotFromFp + num_args - arg_pos].
       __ movl(EAX, Address(EDI, ArgumentsDescriptor::position_offset()));
       // EAX is arg_pos as Smi.
       // Point to next named entry.
@@ -778,11 +779,11 @@
               param_pos - num_fixed_params));
       __ LoadObject(EAX, value);
       __ Bind(&assign_optional_parameter);
-      // Assign EAX to fp[kFirstLocalSlotIndex - param_pos].
+      // Assign EAX to fp[kFirstLocalSlotFromFp - param_pos].
       // We do not use the final allocation index of the variable here, i.e.
       // scope->VariableAt(i)->index(), because captured variables still need
       // to be copied to the context that is not yet allocated.
-      const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos;
+      const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
       const Address param_addr(EBP, computed_param_pos * kWordSize);
       __ movl(param_addr, EAX);
     }
@@ -808,11 +809,11 @@
       const Object& value = Object::ZoneHandle(
           parsed_function().default_parameter_values().At(i));
       __ LoadObject(EAX, value);
-      // Assign EAX to fp[kFirstLocalSlotIndex - param_pos].
+      // Assign EAX to fp[kFirstLocalSlotFromFp - param_pos].
       // We do not use the final allocation index of the variable here, i.e.
       // scope->VariableAt(i)->index(), because captured variables still need
       // to be copied to the context that is not yet allocated.
-      const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos;
+      const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
       const Address param_addr(EBP, computed_param_pos * kWordSize);
       __ movl(param_addr, EAX);
       __ Bind(&next_parameter);
@@ -875,7 +876,7 @@
   Label null_args_loop, null_args_loop_condition;
   __ jmp(&null_args_loop_condition, Assembler::kNearJump);
   const Address original_argument_addr(
-      EBP, ECX, TIMES_4, kLastParamSlotIndex * kWordSize);
+      EBP, ECX, TIMES_4, (kParamEndSlotFromFp + 1) * kWordSize);
   __ Bind(&null_args_loop);
   __ movl(original_argument_addr, raw_null);
   __ Bind(&null_args_loop_condition);
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 466846f..7729e57 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -598,7 +598,7 @@
   const int num_params =
       num_fixed_params + num_opt_pos_params + num_opt_named_params;
   ASSERT(function.NumParameters() == num_params);
-  ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotIndex);
+  ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp);
 
   // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args,
   // where num_pos_args is the number of positional arguments passed in.
@@ -616,21 +616,21 @@
                          &wrong_num_arguments);
 
   // Copy positional arguments.
-  // Argument i passed at fp[kLastParamSlotIndex + num_args - 1 - i] is copied
-  // to fp[kFirstLocalSlotIndex - i].
+  // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied
+  // to fp[kFirstLocalSlotFromFp - i].
 
   __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
   // Since T1 and T2 are Smi, use sll 1 instead of sll 2.
   // Let T1 point to the last passed positional argument, i.e. to
-  // fp[kLastParamSlotIndex + num_args - 1 - (num_pos_args - 1)].
+  // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)].
   __ subu(T1, T1, T2);
   __ sll(T1, T1, 1);
   __ addu(T1, FP, T1);
-  __ AddImmediate(T1, kLastParamSlotIndex * kWordSize);
+  __ AddImmediate(T1, (kParamEndSlotFromFp + 1) * kWordSize);
 
   // Let T0 point to the last copied positional argument, i.e. to
-  // fp[kFirstLocalSlotIndex - (num_pos_args - 1)].
-  __ AddImmediate(T0, FP, (kFirstLocalSlotIndex + 1) * kWordSize);
+  // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)].
+  __ AddImmediate(T0, FP, (kFirstLocalSlotFromFp + 1) * kWordSize);
   __ sll(T2, T2, 1);  // T2 is a Smi.
 
   Label loop, loop_exit;
@@ -671,10 +671,10 @@
     __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::positional_count_offset()));
     __ SmiUntag(T2);
     // Let T1 point to the first passed argument, i.e. to
-    // fp[kLastParamSlotIndex + num_args - 1 - 0]; num_args (T1) is Smi.
+    // fp[kParamEndSlotFromFp + num_args - 0]; num_args (T1) is Smi.
     __ sll(T3, T1, 1);
     __ addu(T1, FP, T3);
-    __ AddImmediate(T1, (kLastParamSlotIndex - 1) * kWordSize);
+    __ AddImmediate(T1, kParamEndSlotFromFp * kWordSize);
     // Let T0 point to the entry of the first named argument.
     __ AddImmediate(T0, S4,
         ArgumentsDescriptor::first_named_entry_offset() - kHeapObjectTag);
@@ -688,7 +688,7 @@
       __ BranchNotEqual(T3, opt_param[i]->name(), &load_default_value);
 
       // Load T3 with passed-in argument at provided arg_pos, i.e. at
-      // fp[kLastParamSlotIndex + num_args - 1 - arg_pos].
+      // fp[kParamEndSlotFromFp + num_args - arg_pos].
       __ lw(T3, Address(T0, ArgumentsDescriptor::position_offset()));
       // T3 is arg_pos as Smi.
       // Point to next named entry.
@@ -706,11 +706,11 @@
               param_pos - num_fixed_params));
       __ LoadObject(T3, value);
       __ Bind(&assign_optional_parameter);
-      // Assign T3 to fp[kFirstLocalSlotIndex - param_pos].
+      // Assign T3 to fp[kFirstLocalSlotFromFp - param_pos].
       // We do not use the final allocation index of the variable here, i.e.
       // scope->VariableAt(i)->index(), because captured variables still need
       // to be copied to the context that is not yet allocated.
-      const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos;
+      const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
       __ sw(T3, Address(FP, computed_param_pos * kWordSize));
     }
     delete[] opt_param;
@@ -735,11 +735,11 @@
       const Object& value = Object::ZoneHandle(
           parsed_function().default_parameter_values().At(i));
       __ LoadObject(T3, value);
-      // Assign T3 to fp[kFirstLocalSlotIndex - param_pos].
+      // Assign T3 to fp[kFirstLocalSlotFromFp - param_pos].
       // We do not use the final allocation index of the variable here, i.e.
       // scope->VariableAt(i)->index(), because captured variables still need
       // to be copied to the context that is not yet allocated.
-      const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos;
+      const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
       __ sw(T3, Address(FP, computed_param_pos * kWordSize));
       __ Bind(&next_parameter);
     }
@@ -803,7 +803,8 @@
 
   Label null_args_loop, null_args_loop_exit;
   __ blez(T2, &null_args_loop_exit);
-  __ delay_slot()->addiu(T1, FP, Immediate(kLastParamSlotIndex * kWordSize));
+  __ delay_slot()->addiu(T1, FP,
+                         Immediate((kParamEndSlotFromFp + 1) * kWordSize));
   __ Bind(&null_args_loop);
   __ addiu(T2, T2, Immediate(-kWordSize));
   __ addu(T3, T1, T2);
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 400ab4e..70074ca 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -665,7 +665,7 @@
   const int num_params =
       num_fixed_params + num_opt_pos_params + num_opt_named_params;
   ASSERT(function.NumParameters() == num_params);
-  ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotIndex);
+  ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotFromFp);
 
   // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args,
   // where num_pos_args is the number of positional arguments passed in.
@@ -683,24 +683,25 @@
   __ j(GREATER, &wrong_num_arguments);
 
   // Copy positional arguments.
-  // Argument i passed at fp[kLastParamSlotIndex + num_args - 1 - i] is copied
-  // to fp[kFirstLocalSlotIndex - i].
+  // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied
+  // to fp[kFirstLocalSlotFromFp - i].
 
   __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
   // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8.
   // Let RBX point to the last passed positional argument, i.e. to
-  // fp[kLastParamSlotIndex + num_args - 1 - (num_pos_args - 1)].
+  // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)].
   __ subq(RBX, RCX);
-  __ leaq(RBX, Address(RBP, RBX, TIMES_4, kLastParamSlotIndex * kWordSize));
+  __ leaq(RBX, Address(RBP, RBX, TIMES_4,
+                       (kParamEndSlotFromFp + 1) * kWordSize));
 
   // Let RDI point to the last copied positional argument, i.e. to
-  // fp[kFirstLocalSlotIndex - (num_pos_args - 1)].
+  // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)].
   __ SmiUntag(RCX);
   __ movq(RAX, RCX);
   __ negq(RAX);
   // -num_pos_args is in RAX.
   __ leaq(RDI,
-          Address(RBP, RAX, TIMES_8, (kFirstLocalSlotIndex + 1) * kWordSize));
+          Address(RBP, RAX, TIMES_8, (kFirstLocalSlotFromFp + 1) * kWordSize));
   Label loop, loop_condition;
   __ jmp(&loop_condition, Assembler::kNearJump);
   // We do not use the final allocation index of the variable here, i.e.
@@ -744,9 +745,9 @@
             FieldAddress(R10, ArgumentsDescriptor::positional_count_offset()));
     __ SmiUntag(RCX);
     // Let RBX point to the first passed argument, i.e. to
-    // fp[kLastParamSlotIndex + num_args - 1]; num_args (RBX) is Smi.
+    // fp[kParamEndSlotFromFp + num_args]; num_args (RBX) is Smi.
     __ leaq(RBX,
-            Address(RBP, RBX, TIMES_4, (kLastParamSlotIndex - 1) * kWordSize));
+            Address(RBP, RBX, TIMES_4, kParamEndSlotFromFp * kWordSize));
     // Let RDI point to the entry of the first named argument.
     __ leaq(RDI,
             FieldAddress(R10, ArgumentsDescriptor::first_named_entry_offset()));
@@ -760,7 +761,7 @@
       __ CompareObject(RAX, opt_param[i]->name());
       __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump);
       // Load RAX with passed-in argument at provided arg_pos, i.e. at
-      // fp[kLastParamSlotIndex + num_args - 1 - arg_pos].
+      // fp[kParamEndSlotFromFp + num_args - arg_pos].
       __ movq(RAX, Address(RDI, ArgumentsDescriptor::position_offset()));
       // RAX is arg_pos as Smi.
       // Point to next named entry.
@@ -776,11 +777,11 @@
               param_pos - num_fixed_params));
       __ LoadObject(RAX, value);
       __ Bind(&assign_optional_parameter);
-      // Assign RAX to fp[kFirstLocalSlotIndex - param_pos].
+      // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos].
       // We do not use the final allocation index of the variable here, i.e.
       // scope->VariableAt(i)->index(), because captured variables still need
       // to be copied to the context that is not yet allocated.
-      const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos;
+      const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
       const Address param_addr(RBP, computed_param_pos * kWordSize);
       __ movq(param_addr, RAX);
     }
@@ -806,11 +807,11 @@
       const Object& value = Object::ZoneHandle(
           parsed_function().default_parameter_values().At(i));
       __ LoadObject(RAX, value);
-      // Assign RAX to fp[kFirstLocalSlotIndex - param_pos].
+      // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos].
       // We do not use the final allocation index of the variable here, i.e.
       // scope->VariableAt(i)->index(), because captured variables still need
       // to be copied to the context that is not yet allocated.
-      const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos;
+      const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos;
       const Address param_addr(RBP, computed_param_pos * kWordSize);
       __ movq(param_addr, RAX);
       __ Bind(&next_parameter);
@@ -873,7 +874,7 @@
   Label null_args_loop, null_args_loop_condition;
   __ jmp(&null_args_loop_condition, Assembler::kNearJump);
   const Address original_argument_addr(
-      RBP, RCX, TIMES_8, kLastParamSlotIndex * kWordSize);
+      RBP, RCX, TIMES_8, (kParamEndSlotFromFp + 1) * kWordSize);
   __ Bind(&null_args_loop);
   __ movq(original_argument_addr, raw_null);
   __ Bind(&null_args_loop_condition);
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index af3f6e2..f57251c 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -8,6 +8,7 @@
 #include "vm/flags.h"
 #include "vm/flow_graph.h"
 #include "vm/flow_graph_builder.h"
+#include "vm/flow_graph_compiler.h"
 #include "vm/flow_graph_optimizer.h"
 #include "vm/il_printer.h"
 #include "vm/intrinsifier.h"
@@ -135,7 +136,6 @@
 
 // Pair of an argument name and its value.
 struct NamedArgument {
- public:
   String* name;
   Value* value;
   NamedArgument(String* name, Value* value)
@@ -290,6 +290,51 @@
 };
 
 
+struct InlinedCallData {
+  InlinedCallData(Definition* call, GrowableArray<Value*>* arguments)
+      : call(call),
+        arguments(arguments),
+        callee_graph(NULL),
+        parameter_stubs(NULL),
+        exit_collector(NULL) { }
+
+  Definition* call;
+  GrowableArray<Value*>* arguments;
+  FlowGraph* callee_graph;
+  ZoneGrowableArray<Definition*>* parameter_stubs;
+  InlineExitCollector* exit_collector;
+};
+
+
+class CallSiteInliner;
+
+class PolymorphicInliner : public ValueObject {
+ public:
+  PolymorphicInliner(CallSiteInliner* owner,
+                     PolymorphicInstanceCallInstr* call);
+
+  void Inline();
+
+ private:
+  bool CheckInlinedDuplicate(const Function& target);
+  bool CheckNonInlinedDuplicate(const Function& target);
+
+  bool TryInlining(const Function& target);
+
+  TargetEntryInstr* BuildDecisionGraph();
+
+  CallSiteInliner* const owner_;
+  PolymorphicInstanceCallInstr* const call_;
+  const intptr_t num_variants_;
+  GrowableArray<CidTarget> variants_;
+
+  GrowableArray<CidTarget> inlined_variants_;
+  GrowableArray<CidTarget> non_inlined_variants_;
+  GrowableArray<BlockEntryInstr*> inlined_entries_;
+  InlineExitCollector* exit_collector_;
+};
+
+
 class CallSiteInliner : public ValueObject {
  public:
   CallSiteInliner(FlowGraph* flow_graph,
@@ -304,6 +349,8 @@
         function_cache_(),
         guarded_fields_(guarded_fields) { }
 
+  FlowGraph* caller_graph() const { return caller_graph_; }
+
   // Inlining heuristics based on Cooper et al. 2008.
   bool ShouldWeInline(intptr_t instr_count,
                       intptr_t call_site_count,
@@ -359,23 +406,6 @@
         static_cast<double>(initial_size_);
   }
 
- private:
-  struct InlinedCallData {
-   public:
-    InlinedCallData(Definition* call, GrowableArray<Value*>* arguments)
-        : call(call),
-          arguments(arguments),
-          callee_graph(NULL),
-          parameter_stubs(NULL),
-          exit_collector(NULL) { }
-
-    Definition* call;
-    GrowableArray<Value*>* arguments;
-    FlowGraph* callee_graph;
-    ZoneGrowableArray<Definition*>* parameter_stubs;
-    InlineExitCollector* exit_collector;
-  };
-
   bool TryInlining(const Function& function,
                    const Array& argument_names,
                    InlinedCallData* call_data) {
@@ -603,6 +633,7 @@
     }
   }
 
+ private:
   void InlineCall(InlinedCallData* call_data) {
     TimerScope timer(FLAG_compiler_stats,
                      &CompilerStats::graphinliner_subst_timer,
@@ -639,8 +670,7 @@
       ConstantInstr* constant = (*defns)[i]->AsConstant();
       if ((constant != NULL) && constant->HasUses()) {
         constant->ReplaceUsesWith(
-            caller_graph_->AddConstantToInitialDefinitions(
-                constant->value()));
+            caller_graph_->GetConstant(constant->value()));
       }
     }
 
@@ -739,24 +769,22 @@
         inlining_call_sites_->instance_calls();
     TRACE_INLINING(OS::Print("  Polymorphic Instance Calls (%d)\n",
                              call_info.length()));
-    for (intptr_t i = 0; i < call_info.length(); ++i) {
-      PolymorphicInstanceCallInstr* call = call_info[i].call;
-      const ICData& ic_data = call->ic_data();
-      const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
+    for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) {
+      PolymorphicInstanceCallInstr* call = call_info[call_idx].call;
       if (call->with_checks()) {
-        TRACE_INLINING(OS::Print(
-            "  => %s (deopt count %d)\n     Bailout: %"Pd" checks\n",
-            target.ToCString(),
-            target.deoptimization_counter(),
-            ic_data.NumberOfChecks()));
+        PolymorphicInliner inliner(this, call);
+        inliner.Inline();
         continue;
       }
-      if ((call_info[i].ratio * 100) < FLAG_inlining_hotness) {
+
+      const ICData& ic_data = call->ic_data();
+      const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
+      if ((call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
         TRACE_INLINING(OS::Print(
             "  => %s (deopt count %d)\n     Bailout: cold %f\n",
             target.ToCString(),
             target.deoptimization_counter(),
-            call_info[i].ratio));
+            call_info[call_idx].ratio));
         continue;
       }
       GrowableArray<Value*> arguments(call->ArgumentCount());
@@ -876,6 +904,383 @@
 };
 
 
+PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner,
+                                       PolymorphicInstanceCallInstr* call)
+    : owner_(owner),
+      call_(call),
+      num_variants_(call->ic_data().NumberOfChecks()),
+      variants_(num_variants_),
+      inlined_variants_(num_variants_),
+      non_inlined_variants_(num_variants_),
+      inlined_entries_(num_variants_),
+      exit_collector_(new InlineExitCollector(owner->caller_graph(), call)) {
+}
+
+
+// Inlined bodies are shared if two different class ids have the same
+// inlined target.  This sharing is represented by using three different
+// types of entries in the inlined_entries_ array:
+//
+//   * GraphEntry: the inlined body is not shared.
+//
+//   * TargetEntry: the inlined body is shared and this is the first variant.
+//
+//   * JoinEntry: the inlined body is shared and this is a subsequent variant.
+bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) {
+  for (intptr_t i = 0; i < inlined_variants_.length(); ++i) {
+    if (target.raw() == inlined_variants_[i].target->raw()) {
+      // The call target is shared with a previous inlined variant.  Share
+      // the graph.  This requires a join block at the entry, and edge-split
+      // form requires a target for each branch.
+      //
+      // Represent the sharing by recording a fresh target for the first
+      // variant and the shared join for all later variants.
+      if (inlined_entries_[i]->IsGraphEntry()) {
+        // Convert the old target entry to a new join entry.
+        TargetEntryInstr* old_target =
+            inlined_entries_[i]->AsGraphEntry()->normal_entry();
+        JoinEntryInstr* new_join = BranchSimplifier::ToJoinEntry(old_target);
+        old_target->ReplaceAsPredecessorWith(new_join);
+        for (intptr_t j = 0; j < old_target->dominated_blocks().length(); ++j) {
+          BlockEntryInstr* block = old_target->dominated_blocks()[j];
+          new_join->AddDominatedBlock(block);
+        }
+        // Create a new target with the join as unconditional successor.
+        TargetEntryInstr* new_target =
+            new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(),
+                                 old_target->try_index());
+        new_target->InheritDeoptTarget(new_join);
+        GotoInstr* new_goto = new GotoInstr(new_join);
+        new_goto->InheritDeoptTarget(new_join);
+        new_target->LinkTo(new_goto);
+        new_target->set_last_instruction(new_goto);
+        new_join->predecessors_.Add(new_target);
+
+        // Record the new target for the first variant.
+        inlined_entries_[i] = new_target;
+      }
+      ASSERT(inlined_entries_[i]->IsTargetEntry());
+      // Record the shared join for this variant.
+      BlockEntryInstr* join =
+          inlined_entries_[i]->last_instruction()->SuccessorAt(0);
+      ASSERT(join->IsJoinEntry());
+      inlined_entries_.Add(join);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) {
+  for (intptr_t i = 0; i < non_inlined_variants_.length(); ++i) {
+    if (target.raw() == non_inlined_variants_[i].target->raw()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+bool PolymorphicInliner::TryInlining(const Function& target) {
+  GrowableArray<Value*> arguments(call_->ArgumentCount());
+  for (int i = 0; i < call_->ArgumentCount(); ++i) {
+    arguments.Add(call_->PushArgumentAt(i)->value());
+  }
+  InlinedCallData call_data(call_, &arguments);
+  if (!owner_->TryInlining(target,
+                           call_->instance_call()->argument_names(),
+                           &call_data)) {
+    return false;
+  }
+
+  FlowGraph* callee_graph = call_data.callee_graph;
+  call_data.exit_collector->PrepareGraphs(callee_graph);
+  inlined_entries_.Add(callee_graph->graph_entry());
+  exit_collector_->Union(call_data.exit_collector);
+
+  // Replace parameter stubs and constants.  Replace the receiver argument
+  // with a redefinition to prevent code from the inlined body from being
+  // hoisted above the inlined entry.
+  ASSERT(arguments.length() > 0);
+  Value* actual = arguments[0];
+  RedefinitionInstr* redefinition = new RedefinitionInstr(actual->Copy());
+  redefinition->set_ssa_temp_index(
+      owner_->caller_graph()->alloc_ssa_temp_index());
+  redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry());
+  Definition* stub = (*call_data.parameter_stubs)[0];
+  stub->ReplaceUsesWith(redefinition);
+
+  for (intptr_t i = 1; i < arguments.length(); ++i) {
+    actual = arguments[i];
+    if (actual != NULL) {
+      stub = (*call_data.parameter_stubs)[i];
+      stub->ReplaceUsesWith(actual->definition());
+    }
+  }
+  GrowableArray<Definition*>* defns =
+      callee_graph->graph_entry()->initial_definitions();
+  for (intptr_t i = 0; i < defns->length(); ++i) {
+    ConstantInstr* constant = (*defns)[i]->AsConstant();
+    if ((constant != NULL) && constant->HasUses()) {
+      constant->ReplaceUsesWith(
+          owner_->caller_graph()->GetConstant(constant->value()));
+    }
+  }
+  return true;
+}
+
+
+static Instruction* AppendInstruction(Instruction* first,
+                                      Instruction* second) {
+  for (intptr_t i = second->InputCount() - 1; i >= 0; --i) {
+    Value* input = second->InputAt(i);
+    input->definition()->AddInputUse(input);
+  }
+  first->LinkTo(second);
+  return second;
+}
+
+
+// Build a DAG to dispatch to the inlined function bodies.  Load the class
+// id of the receiver and make explicit comparisons for each inlined body,
+// in frequency order.  If all variants are inlined, the entry to the last
+// inlined body is guarded by a CheckClassId instruction which can deopt.
+// If not all variants are inlined, we add a PolymorphicInstanceCall
+// instruction to handle the non-inlined variants.
+TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() {
+  // Start with a fresh target entry.
+  TargetEntryInstr* entry =
+      new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(),
+                           call_->GetBlock()->try_index());
+  entry->InheritDeoptTarget(call_);
+
+  // This function uses a cursor (a pointer to the 'current' instruction) to
+  // build the graph.  The next instruction will be inserted after the
+  // cursor.
+  TargetEntryInstr* current_block = entry;
+  Instruction* cursor = entry;
+
+  Definition* receiver = call_->ArgumentAt(0);
+  // There are at least two variants including non-inlined ones, so we have
+  // at least one branch on the class id.
+  LoadClassIdInstr* load_cid = new LoadClassIdInstr(new Value(receiver));
+  load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index());
+  cursor = AppendInstruction(cursor, load_cid);
+  for (intptr_t i = 0; i < inlined_variants_.length(); ++i) {
+    // 1. Guard the body with a class id check.
+    if ((i == (inlined_variants_.length() - 1)) &&
+        non_inlined_variants_.is_empty()) {
+      // If it is the last variant use a check class or check smi
+      // instruction which can deoptimize, followed unconditionally by the
+      // body.
+      if (inlined_variants_[i].cid == kSmiCid) {
+        CheckSmiInstr* check_smi =
+            new CheckSmiInstr(new Value(receiver), call_->deopt_id());
+        check_smi->InheritDeoptTarget(call_);
+        cursor = AppendInstruction(cursor, check_smi);
+      } else {
+        const ICData& old_checks = call_->ic_data();
+        const ICData& new_checks = ICData::ZoneHandle(
+            ICData::New(Function::Handle(old_checks.function()),
+                        String::Handle(old_checks.target_name()),
+                        old_checks.deopt_id(),
+                        1));  // Number of args tested.
+        new_checks.AddReceiverCheck(inlined_variants_[i].cid,
+                                    *inlined_variants_[i].target);
+        CheckClassInstr* check_class =
+            new CheckClassInstr(new Value(receiver),
+                                call_->deopt_id(),
+                                new_checks);
+        check_class->InheritDeoptTarget(call_);
+        cursor = AppendInstruction(cursor, check_class);
+      }
+      // The next instruction is the first instruction of the inlined body.
+      // Handle the two possible cases (unshared and shared subsequent
+      // predecessors) separately.
+      BlockEntryInstr* callee_entry = inlined_entries_[i];
+      if (callee_entry->IsGraphEntry()) {
+        // Unshared.  Graft the normal entry on after the check class
+        // instruction.
+        TargetEntryInstr* target =
+            callee_entry->AsGraphEntry()->normal_entry();
+        cursor->LinkTo(target->next());
+        target->ReplaceAsPredecessorWith(current_block);
+        // All blocks that were dominated by the normal entry are now
+        // dominated by the current block.
+        for (intptr_t j = 0;
+             j < target->dominated_blocks().length();
+             ++j) {
+          BlockEntryInstr* block = target->dominated_blocks()[j];
+          current_block->AddDominatedBlock(block);
+        }
+      } else if (callee_entry->IsJoinEntry()) {
+        // Shared inlined body and this is a subsequent entry.  We have
+        // already constructed a join and set its dominator.  Add a jump to
+        // the join.
+        JoinEntryInstr* join = callee_entry->AsJoinEntry();
+        ASSERT(join->dominator() != NULL);
+        GotoInstr* goto_join = new GotoInstr(join);
+        goto_join->InheritDeoptTarget(join);
+        cursor->LinkTo(goto_join);
+        current_block->set_last_instruction(goto_join);
+      } else {
+        // There is no possibility of a TargetEntry (the first entry to a
+        // shared inlined body) because this is the last inlined entry.
+        UNREACHABLE();
+      }
+      cursor = NULL;
+    } else {
+      // For all variants except the last, use a branch on the loaded class
+      // id.
+      const Smi& cid = Smi::ZoneHandle(Smi::New(inlined_variants_[i].cid));
+      ConstantInstr* cid_constant = new ConstantInstr(cid);
+      cid_constant->set_ssa_temp_index(
+          owner_->caller_graph()->alloc_ssa_temp_index());
+      StrictCompareInstr* compare =
+          new StrictCompareInstr(Token::kEQ_STRICT,
+                                 new Value(load_cid),
+                                 new Value(cid_constant));
+      BranchInstr* branch = new BranchInstr(compare);
+      branch->InheritDeoptTarget(call_);
+      AppendInstruction(AppendInstruction(cursor, cid_constant), branch);
+      current_block->set_last_instruction(branch);
+      cursor = NULL;
+
+      // 2. Handle a match by linking to the inlined body.  There are three
+      // cases (unshared, shared first predecessor, and shared subsequent
+      // predecessors).
+      BlockEntryInstr* callee_entry = inlined_entries_[i];
+      TargetEntryInstr* true_target = NULL;
+      if (callee_entry->IsGraphEntry()) {
+        // Unshared.
+        true_target = callee_entry->AsGraphEntry()->normal_entry();
+      } else if (callee_entry->IsTargetEntry()) {
+        // Shared inlined body and this is the first entry.  We have already
+        // constructed a join and this target jumps to it.
+        true_target = callee_entry->AsTargetEntry();
+        BlockEntryInstr* join =
+            true_target->last_instruction()->SuccessorAt(0);
+        current_block->AddDominatedBlock(join);
+      } else {
+        // Shared inlined body and this is a subsequent entry.  We have
+        // already constructed a join.  We need a fresh target that jumps to
+        // the join.
+        JoinEntryInstr* join = callee_entry->AsJoinEntry();
+        ASSERT(join != NULL);
+        ASSERT(join->dominator() != NULL);
+        true_target =
+            new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(),
+                                 call_->GetBlock()->try_index());
+        true_target->InheritDeoptTarget(join);
+        GotoInstr* goto_join = new GotoInstr(join);
+        goto_join->InheritDeoptTarget(join);
+        true_target->LinkTo(goto_join);
+        true_target->set_last_instruction(goto_join);
+      }
+      *branch->true_successor_address() = true_target;
+      current_block->AddDominatedBlock(true_target);
+
+      // 3. Prepare to handle a match failure on the next iteration or the
+      // fall-through code below for non-inlined variants.
+      TargetEntryInstr* false_target =
+          new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(),
+                               call_->GetBlock()->try_index());
+      false_target->InheritDeoptTarget(call_);
+      *branch->false_successor_address() = false_target;
+      current_block->AddDominatedBlock(false_target);
+      cursor = current_block = false_target;
+    }
+  }
+
+  // Handle any non-inlined variants.
+  if (!non_inlined_variants_.is_empty()) {
+    // Move 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->previous()->LinkTo(push->next());
+      cursor->LinkTo(push);
+      cursor = push;
+    }
+    const ICData& old_checks = call_->ic_data();
+    const ICData& new_checks = ICData::ZoneHandle(
+        ICData::New(Function::Handle(old_checks.function()),
+                    String::Handle(old_checks.target_name()),
+                    old_checks.deopt_id(),
+                    1));  // Number of args tested.
+    for (intptr_t i = 0; i < non_inlined_variants_.length(); ++i) {
+      new_checks.AddReceiverCheck(non_inlined_variants_[i].cid,
+                                  *non_inlined_variants_[i].target,
+                                  non_inlined_variants_[i].count);
+    }
+    PolymorphicInstanceCallInstr* fallback_call =
+        new PolymorphicInstanceCallInstr(call_->instance_call(),
+                                         new_checks,
+                                         true);  // With checks.
+    fallback_call->set_ssa_temp_index(
+        owner_->caller_graph()->alloc_ssa_temp_index());
+    fallback_call->InheritDeoptTarget(call_);
+    ReturnInstr* fallback_return =
+        new ReturnInstr(call_->instance_call()->token_pos(),
+                        new Value(fallback_call));
+    fallback_return->InheritDeoptTargetAfter(call_);
+    AppendInstruction(AppendInstruction(cursor, fallback_call),
+                      fallback_return);
+    exit_collector_->AddExit(fallback_return);
+    cursor = NULL;
+  } else {
+    // 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->RemoveFromGraph();
+    }
+  }
+  return entry;
+}
+
+
+void PolymorphicInliner::Inline() {
+  // Consider the polymorphic variants in order by frequency.
+  FlowGraphCompiler::SortICDataByCount(call_->ic_data(), &variants_);
+  for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) {
+    const Function& target = *variants_[var_idx].target;
+
+    // First check if this is the same target as an earlier inlined variant.
+    if (CheckInlinedDuplicate(target)) {
+      inlined_variants_.Add(variants_[var_idx]);
+      continue;
+    }
+
+    // Also check if this is the same target as an earlier non-inlined
+    // variant.  If so and since inlining decisions are costly, do not try
+    // to inline this variant.
+    if (CheckNonInlinedDuplicate(target)) {
+      non_inlined_variants_.Add(variants_[var_idx]);
+      continue;
+    }
+
+    // Make an inlining decision.
+    if (TryInlining(target)) {
+      inlined_variants_.Add(variants_[var_idx]);
+    } else {
+      non_inlined_variants_.Add(variants_[var_idx]);
+    }
+  }
+
+  // If there are no inlined variants, leave the call in place.
+  if (inlined_variants_.is_empty()) return;
+
+  // Now build a decision tree (a DAG because of shared inline variants) and
+  // inline it at the call site.
+  TargetEntryInstr* entry = BuildDecisionGraph();
+  exit_collector_->ReplaceCall(entry);
+}
+
+
 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph) {
   GraphInfoCollector info;
   info.Collect(*flow_graph);
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 3182806..3db0a65 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -306,10 +306,9 @@
   bool changed = false;
   for (intptr_t i = 0; i < block_order_.length(); ++i) {
     BlockEntryInstr* entry = block_order_[i];
-    entry->Accept(this);
     for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
       Instruction* current = it.Current();
-      Instruction* replacement = current->Canonicalize(this);
+      Instruction* replacement = current->Canonicalize(flow_graph());
       if (replacement != current) {
         // For non-definitions Canonicalize should return either NULL or
         // this.
@@ -363,8 +362,7 @@
       const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue();
       const Double& dbl_obj =
           Double::ZoneHandle(Double::New(dbl_val, Heap::kOld));
-      ConstantInstr* double_const = new ConstantInstr(dbl_obj);
-      InsertBefore(insert_before, double_const, NULL, Definition::kValue);
+      ConstantInstr* double_const = flow_graph()->GetConstant(dbl_obj);
       converted = new UnboxDoubleInstr(new Value(double_const), deopt_id);
     } else {
       converted = new UnboxDoubleInstr(use->CopyWithType(), deopt_id);
@@ -1131,8 +1129,7 @@
                  call->env(),
                  Definition::kEffect);
     ConstantInstr* constant =
-        new ConstantInstr(Smi::Handle(Smi::New(value - 1)));
-    InsertBefore(call, constant, NULL, Definition::kValue);
+        flow_graph()->GetConstant(Smi::Handle(Smi::New(value - 1)));
     BinarySmiOpInstr* bin_op =
         new BinarySmiOpInstr(Token::kBIT_AND, call,
                              new Value(left),
@@ -1178,8 +1175,7 @@
              (op_kind == Token::kNEGATE)) {
     AddReceiverCheck(call);
     ConstantInstr* minus_one =
-        new ConstantInstr(Double::ZoneHandle(Double::NewCanonical(-1)));
-    InsertBefore(call, minus_one, NULL, Definition::kValue);
+        flow_graph()->GetConstant(Double::ZoneHandle(Double::NewCanonical(-1)));
     unary_op = new BinaryDoubleOpInstr(Token::kMUL,
                                        new Value(input),
                                        new Value(minus_one),
@@ -1372,9 +1368,7 @@
   LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0));
   InsertBefore(call, load, NULL, Definition::kValue);
 
-  ConstantInstr* zero = new ConstantInstr(Smi::Handle(Smi::New(0)));
-  InsertBefore(call, zero, NULL, Definition::kValue);
-
+  ConstantInstr* zero = flow_graph()->GetConstant(Smi::Handle(Smi::New(0)));
   StrictCompareInstr* compare =
       new StrictCompareInstr(Token::kEQ_STRICT,
                              new Value(load),
@@ -2025,8 +2019,7 @@
   // 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);
+      flow_graph()->GetConstant(Smi::Handle(Smi::New(element_size)));
   BinarySmiOpInstr* len_in_bytes =
       new BinarySmiOpInstr(Token::kMUL,
                            call,
@@ -2113,8 +2106,15 @@
       if (negate) {
         as_bool = Bool::Get(!as_bool.value());
       }
-      ConstantInstr* bool_const = new ConstantInstr(as_bool);
-      ReplaceCall(call, bool_const);
+      ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool);
+      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+        PushArgumentInstr* push = call->PushArgumentAt(i);
+        push->ReplaceUsesWith(push->value()->definition());
+        push->RemoveFromGraph();
+      }
+      call->ReplaceUsesWith(bool_const);
+      ASSERT(current_iterator()->Current() == call);
+      current_iterator()->RemoveCurrentFromGraph();
       return;
     }
   }
@@ -2679,6 +2679,15 @@
 
 
 void RangeAnalysis::CollectSmiValues() {
+  const GrowableArray<Definition*>& initial =
+      *flow_graph_->graph_entry()->initial_definitions();
+  for (intptr_t i = 0; i < initial.length(); ++i) {
+    Definition* current = initial[i];
+    if (current->Type()->ToCid() == kSmiCid) {
+      smi_values_.Add(current);
+    }
+  }
+
   for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
        !block_it.Done();
        block_it.Advance()) {
@@ -2702,7 +2711,7 @@
     if (join != NULL) {
       for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) {
         PhiInstr* current = phi_it.Current();
-        if ((current->Type()->ToCid() == kSmiCid)) {
+        if (current->Type()->ToCid() == kSmiCid) {
           smi_values_.Add(current);
         }
       }
@@ -3106,6 +3115,14 @@
   }
 
   // Infer initial values of ranges.
+  const GrowableArray<Definition*>& initial =
+      *flow_graph_->graph_entry()->initial_definitions();
+  for (intptr_t i = 0; i < initial.length(); ++i) {
+    Definition* definition = initial[i];
+    if (smi_definitions_->Contains(definition->ssa_temp_index())) {
+      definition->InferRange();
+    }
+  }
   InferRangesRecursive(flow_graph_->graph_entry());
 
   if (FLAG_trace_range_analysis) {
@@ -3148,6 +3165,7 @@
 
 
 LICM::LICM(FlowGraph* flow_graph) : flow_graph_(flow_graph) {
+  ASSERT(flow_graph->is_licm_allowed());
 }
 
 
@@ -3238,8 +3256,7 @@
            !it.Done();
            it.Advance()) {
         Instruction* current = it.Current();
-        if (!current->IsPushArgument() &&
-            current->AllowsCSE() &&
+        if (current->AllowsCSE() &&
             flow_graph()->block_effects()->CanBeMovedTo(current, pre_header)) {
           bool inputs_loop_invariant = true;
           for (int i = 0; i < current->InputCount(); ++i) {
@@ -3268,10 +3285,7 @@
 
 
 static bool IsLoadEliminationCandidate(Definition* def) {
-  // Immutable loads (not affected by side effects) are handled
-  // in the DominatorBasedCSE pass.
-  // TODO(fschneider): Extend to other load instructions.
-  return (def->IsLoadField() && !def->Dependencies().IsNone())
+  return def->IsLoadField()
       || def->IsLoadIndexed()
       || def->IsLoadStaticField()
       || def->IsCurrentContext();
@@ -3344,14 +3358,19 @@
 };
 
 
-// Set mapping alias to a list of loads sharing this alias.
+// Set mapping alias to a list of loads sharing this alias. Additionally
+// carries a set of loads that can be aliased by side-effects, essentially
+// those that are affected by calls.
 class AliasedSet : public ZoneAllocated {
  public:
   explicit AliasedSet(intptr_t max_expr_id)
       : max_expr_id_(max_expr_id),
         sets_(),
-        field_ids_(),
-        max_field_id_(0) { }
+        // BitVector constructor throws if requested length is 0.
+        aliased_by_effects_(max_expr_id > 0 ? new BitVector(max_expr_id)
+                                            : NULL),
+        max_field_id_(0),
+        field_ids_() { }
 
   Alias ComputeAliasForLoad(Definition* defn) {
     if (defn->IsLoadIndexed()) {
@@ -3422,7 +3441,14 @@
     return sets_[alias.ToIndex()];
   }
 
-  void Add(const Alias alias, intptr_t ssa_index) {
+  void AddRepresentative(Definition* defn) {
+    AddIdForAlias(ComputeAliasForLoad(defn), defn->expr_id());
+    if (!IsIndependentFromEffects(defn)) {
+      aliased_by_effects_->Add(defn->expr_id());
+    }
+  }
+
+  void AddIdForAlias(const Alias alias, intptr_t expr_id) {
     const intptr_t idx = alias.ToIndex();
 
     while (sets_.length() <= idx) {
@@ -3433,19 +3459,15 @@
       sets_[idx] = new BitVector(max_expr_id_);
     }
 
-    sets_[idx]->Add(ssa_index);
+    sets_[idx]->Add(expr_id);
   }
 
   intptr_t max_expr_id() const { return max_expr_id_; }
   bool IsEmpty() const { return max_expr_id_ == 0; }
 
+  BitVector* aliased_by_effects() const { return aliased_by_effects_; }
+
  private:
-  const intptr_t max_expr_id_;
-
-  // Maps alias index to a set of ssa indexes corresponding to loads with the
-  // given alias.
-  GrowableArray<BitVector*> sets_;
-
   // Get id assigned to the given field. Assign a new id if the field is seen
   // for the first time.
   intptr_t GetFieldId(intptr_t instance_id, const Field& field) {
@@ -3509,15 +3531,51 @@
           escapes = true;
           break;
         }
-
-        alloc->set_identity(escapes ? AllocateObjectInstr::kAliased
-                                    : AllocateObjectInstr::kNotAliased);
       }
+
+      alloc->set_identity(escapes ? AllocateObjectInstr::kAliased
+                                  : AllocateObjectInstr::kNotAliased);
     }
 
     return alloc->identity() != AllocateObjectInstr::kNotAliased;
   }
 
+  // Returns true if the given load is unaffected by external side-effects.
+  // This essentially means that no stores to the same location can
+  // occur in other functions.
+  bool IsIndependentFromEffects(Definition* defn) {
+    LoadFieldInstr* load_field = defn->AsLoadField();
+    if (load_field != NULL) {
+      // Note that we can't use LoadField's is_immutable attribute here because
+      // some VM-fields (those that have no corresponding Field object and
+      // accessed through offset alone) can share offset but have different
+      // immutability properties.
+      // One example is the length property of growable and fixed size list. If
+      // loads of these two properties occur in the same function for the same
+      // receiver then they will get the same expression number. However
+      // immutability of the length of fixed size list does not mean that
+      // growable list also has immutable property. Thus we will make a
+      // conservative assumption for the VM-properties.
+      // TODO(vegorov): disambiguate immutable and non-immutable VM-fields with
+      // the same offset e.g. through recognized kind.
+      if ((load_field->field() != NULL) &&
+          (load_field->field()->is_final())) {
+        return true;
+      }
+
+      AllocateObjectInstr* alloc =
+          load_field->instance()->definition()->AsAllocateObject();
+      return (alloc != NULL) && !CanBeAliased(alloc);
+    }
+
+    LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField();
+    if (load_static_field != NULL) {
+      return load_static_field->field().is_final();
+    }
+
+    return false;
+  }
+
   class FieldIdPair {
    public:
     struct Key {
@@ -3555,9 +3613,17 @@
     Value value_;
   };
 
+  const intptr_t max_expr_id_;
+
+  // Maps alias index to a set of ssa indexes corresponding to loads with the
+  // given alias.
+  GrowableArray<BitVector*> sets_;
+
+  BitVector* aliased_by_effects_;
+
   // Table mapping static field to their id used during optimization pass.
-  DirectChainedHashMap<FieldIdPair> field_ids_;
   intptr_t max_field_id_;
+  DirectChainedHashMap<FieldIdPair> field_ids_;
 };
 
 
@@ -3724,7 +3790,7 @@
   AliasedSet* aliased_set = new AliasedSet(expr_id);
   for (intptr_t i = 0; i < loads.length(); i++) {
     Definition* defn = loads[i];
-    aliased_set->Add(aliased_set->ComputeAliasForLoad(defn), defn->expr_id());
+    aliased_set->AddRepresentative(defn);
   }
   return aliased_set;
 }
@@ -3760,6 +3826,25 @@
     }
   }
 
+  static bool OptimizeGraph(FlowGraph* graph) {
+    ASSERT(FLAG_load_cse);
+
+    DirectChainedHashMap<LoadKeyValueTrait> map;
+    AliasedSet* aliased_set = NumberLoadExpressions(graph, &map);
+    if (!aliased_set->IsEmpty()) {
+      // If any loads were forwarded return true from Optimize to run load
+      // forwarding again. This will allow to forward chains of loads.
+      // This is especially important for context variables as they are built
+      // as loads from loaded context.
+      // TODO(vegorov): renumber newly discovered congruences during the
+      // forwarding to forward chains without running whole pass twice.
+      LoadOptimizer load_optimizer(graph, aliased_set, &map);
+      return load_optimizer.Optimize();
+    }
+    return false;
+  }
+
+ private:
   bool Optimize() {
     ComputeInitialSets();
     ComputeOutValues();
@@ -3768,7 +3853,6 @@
     return forwarded_;
   }
 
- private:
   // Compute sets of loads generated and killed by each block.
   // Additionally compute upwards exposed and generated loads for each block.
   // Exposed loads are those that can be replaced if a corresponding
@@ -3826,18 +3910,59 @@
           continue;
         }
 
-        // Other instructions with side effects kill all loads.
+        // If instruction has effects then kill all loads affected.
         if (!instr->Effects().IsNone()) {
-          kill->SetAll();
-          // There is no need to clear out_values when clearing GEN set
-          // because only those values that are in the GEN set
+          kill->AddAll(aliased_set_->aliased_by_effects());
+          // There is no need to clear out_values when removing values from GEN
+          // set because only those values that are in the GEN set
           // will ever be used.
-          gen->Clear();
+          gen->RemoveAll(aliased_set_->aliased_by_effects());
           continue;
         }
 
         Definition* defn = instr->AsDefinition();
-        if ((defn == NULL) || !IsLoadEliminationCandidate(defn)) {
+        if (defn == NULL) {
+          continue;
+        }
+
+        // For object allocation forward initial values of the fields to
+        // subsequent loads.
+        // For simplicity we ignore escaping objects and objects that have
+        // type arguments.
+        // The reason to ignore escaping objects is that final fields are
+        // initialized in constructor that potentially can be not inlined into
+        // the function that we are currently optimizing. However at the same
+        // time we assume that values of the final fields can be forwarded
+        // across side-effects. If we add 'null' as known values for these
+        // fields here we will incorrectly propagate this null across
+        // constructor invocation.
+        // TODO(vegorov): record null-values at least for not final fields of
+        // escaping object.
+        // TODO(vegorov): enable forwarding of type arguments.
+        AllocateObjectInstr* alloc = instr->AsAllocateObject();
+        if ((alloc != NULL) &&
+            (alloc->identity() == AllocateObjectInstr::kNotAliased) &&
+            (alloc->ArgumentCount() == 0)) {
+          for (Value* use = alloc->input_use_list();
+               use != NULL;
+               use = use->next_use()) {
+            // Look for all immediate loads from this object.
+            if (use->use_index() != 0) {
+              continue;
+            }
+
+            LoadFieldInstr* load = use->instruction()->AsLoadField();
+            if (load != NULL) {
+              // Found a load. Initialize current value of the field to null.
+              gen->Add(load->expr_id());
+              if (out_values == NULL) out_values = CreateBlockOutValues();
+              (*out_values)[load->expr_id()] = graph_->constant_null();
+            }
+          }
+          continue;
+        }
+
+        if (!IsLoadEliminationCandidate(defn)) {
           continue;
         }
 
@@ -4241,19 +4366,7 @@
 bool DominatorBasedCSE::Optimize(FlowGraph* graph) {
   bool changed = false;
   if (FLAG_load_cse) {
-    GrowableArray<BitVector*> kill_by_offs(10);
-    DirectChainedHashMap<LoadKeyValueTrait> map;
-    AliasedSet* aliased_set = NumberLoadExpressions(graph, &map);
-    if (!aliased_set->IsEmpty()) {
-      // If any loads were forwarded return true from Optimize to run load
-      // forwarding again. This will allow to forward chains of loads.
-      // This is especially important for context variables as they are built
-      // as loads from loaded context.
-      // TODO(vegorov): renumber newly discovered congruences during the
-      // forwarding to forward chains without running whole pass twice.
-      LoadOptimizer load_optimizer(graph, aliased_set, &map);
-      changed = load_optimizer.Optimize() || changed;
-    }
+    changed = LoadOptimizer::OptimizeGraph(graph) || changed;
   }
 
   CSEInstructionMap map;
@@ -4530,6 +4643,11 @@
 }
 
 
+void ConstantPropagator::VisitRedefinition(RedefinitionInstr* instr) {
+  SetValue(instr, instr->value()->definition()->constant_value());
+}
+
+
 void ConstantPropagator::VisitParameter(ParameterInstr* instr) {
   SetValue(instr, non_constant_);
 }
@@ -4804,6 +4922,11 @@
 }
 
 
+void ConstantPropagator::VisitLoadClassId(LoadClassIdInstr* instr) {
+  SetValue(instr, non_constant_);
+}
+
+
 void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) {
   if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) &&
       (instr->instance()->definition()->IsCreateArray())) {
@@ -5023,6 +5146,12 @@
 }
 
 
+void ConstantPropagator::VisitMaterializeObject(MaterializeObjectInstr* instr) {
+  // Should not be used outside of allocation elimination pass.
+  UNREACHABLE();
+}
+
+
 void ConstantPropagator::VisitBinaryDoubleOp(
     BinaryDoubleOpInstr* instr) {
   const Object& left = instr->left()->definition()->constant_value();
@@ -5350,7 +5479,9 @@
                     defn->ssa_temp_index(),
                     defn->constant_value().ToCString());
         }
-        defn->ReplaceWith(new ConstantInstr(defn->constant_value()), &i);
+        ConstantInstr* constant = graph_->GetConstant(defn->constant_value());
+        defn->ReplaceUsesWith(constant);
+        i.RemoveCurrentFromGraph();
       }
     }
 
@@ -5440,10 +5571,9 @@
   //   Branch(Comparison(kind, Phi, Constant))
   //
   // These are the branches produced by inlining in a test context.  Also,
-  // the phi and the constant have no other uses so they can simply be
-  // eliminated.  The block has no other phis and no instructions
-  // intervening between the phi, constant, and branch so the block can
-  // simply be eliminated.
+  // the phi has no other uses so they can simply be eliminated.  The block
+  // has no other phis and no instructions intervening between the phi and
+  // branch so the block can simply be eliminated.
   BranchInstr* branch = block->last_instruction()->AsBranch();
   ASSERT(branch != NULL);
   ComparisonInstr* comparison = branch->comparison();
@@ -5455,9 +5585,7 @@
       (constant != NULL) &&
       (phi->GetBlock() == block) &&
       PhiHasSingleUse(phi, left) &&
-      constant->HasOnlyUse(right) &&
-      (block->next() == constant) &&
-      (constant->next() == branch) &&
+      (block->next() == branch) &&
       (block->phis()->length() == 1);
 }
 
@@ -5476,14 +5604,6 @@
 }
 
 
-ConstantInstr* BranchSimplifier::CloneConstant(FlowGraph* flow_graph,
-                                               ConstantInstr* constant) {
-  ConstantInstr* new_constant = new ConstantInstr(constant->value());
-  new_constant->set_ssa_temp_index(flow_graph->alloc_ssa_temp_index());
-  return new_constant;
-}
-
-
 BranchInstr* BranchSimplifier::CloneBranch(BranchInstr* branch,
                                            Value* left,
                                            Value* right) {
@@ -5569,16 +5689,35 @@
             block->PredecessorAt(i)->last_instruction()->AsGoto();
         ASSERT(old_goto != NULL);
 
-        // Insert a copy of the constant in all the predecessors.
-        ConstantInstr* new_constant = CloneConstant(flow_graph, constant);
-        new_constant->InsertBefore(old_goto);
-
         // Replace the goto in each predecessor with a rewritten branch,
         // rewritten to use the corresponding phi input instead of the phi.
         Value* new_left = phi->InputAt(i)->Copy();
-        Value* new_right = new Value(new_constant);
+        Value* new_right = new Value(constant);
         BranchInstr* new_branch = CloneBranch(branch, new_left, new_right);
-        new_branch->InheritDeoptTarget(old_goto);
+        if (branch->env() == NULL) {
+          new_branch->InheritDeoptTarget(old_goto);
+        } else {
+          // Take the environment from the branch if it has one.
+          new_branch->InheritDeoptTarget(branch);
+          // InheritDeoptTarget gave the new branch's comparison the same
+          // deopt id that it gave the new branch.  The id should be the
+          // deopt id of the original comparison.
+          new_branch->comparison()->SetDeoptId(comparison->GetDeoptId());
+          // The phi can be used in the branch's environment.  Rename such
+          // uses.
+          for (Environment::DeepIterator it(new_branch->env());
+               !it.Done();
+               it.Advance()) {
+            Value* use = it.CurrentValue();
+            if (use->definition() == phi) {
+              Definition* replacement = phi->InputAt(i)->definition();
+              use->RemoveFromUseList();
+              use->set_definition(replacement);
+              replacement->AddEnvUse(use);
+            }
+          }
+        }
+
         new_branch->InsertBefore(old_goto);
         new_branch->set_next(NULL);  // Detaching the goto from the graph.
         old_goto->UnuseAllInputs();
@@ -5616,6 +5755,7 @@
       phi->UnuseAllInputs();
       branch->UnuseAllInputs();
       block->UnuseAllInputs();
+      ASSERT(!phi->HasUses());
     }
   }
 
@@ -5757,4 +5897,240 @@
 }
 
 
+void FlowGraphOptimizer::EliminateEnvironments() {
+  // After this pass we can no longer perform LICM and hoist instructions
+  // that can deoptimize.
+
+  flow_graph_->disallow_licm();
+  for (intptr_t i = 0; i < block_order_.length(); ++i) {
+    BlockEntryInstr* block = block_order_[i];
+    block->RemoveEnvironment();
+    for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+      Instruction* current = it.Current();
+      if (!current->CanDeoptimize()) current->RemoveEnvironment();
+    }
+  }
+}
+
+
+// Right now we are attempting to sink allocation only into
+// deoptimization exit. So candidate should only be used in StoreInstanceField
+// instructions that write into fields of the allocated object.
+// We do not support materialization of the object that has type arguments.
+static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc) {
+  // TODO(vegorov): support AllocateObject with type arguments.
+  if (alloc->ArgumentCount() > 0) {
+    return false;
+  }
+
+  for (Value* use = alloc->input_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    if (!(use->instruction()->IsStoreInstanceField() &&
+          use->use_index() == 0)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+// Remove the given allocation from the graph. It is not observable.
+// If deoptimization occurs the object will be materialized.
+static void EliminateAllocation(AllocateObjectInstr* alloc) {
+  ASSERT(IsAllocationSinkingCandidate(alloc));
+
+  if (FLAG_trace_optimization) {
+    OS::Print("removing allocation from the graph: v%"Pd"\n",
+              alloc->ssa_temp_index());
+  }
+
+  // As an allocation sinking candidate it is only used in stores to its own
+  // fields. Remove these stores.
+  for (Value* use = alloc->input_use_list();
+       use != NULL;
+       use = alloc->input_use_list()) {
+    use->instruction()->RemoveFromGraph();
+  }
+
+  // There should be no environment uses. The pass replaced them with
+  // MaterializeObject instructions.
+  ASSERT(alloc->env_use_list() == NULL);
+  ASSERT(alloc->input_use_list() == NULL);
+  alloc->RemoveFromGraph();
+}
+
+
+void AllocationSinking::Optimize() {
+  GrowableArray<AllocateObjectInstr*> candidates(5);
+
+  // Collect sinking candidates.
+  const GrowableArray<BlockEntryInstr*>& postorder = flow_graph_->postorder();
+  for (BlockIterator block_it(postorder);
+       !block_it.Done();
+       block_it.Advance()) {
+    BlockEntryInstr* block = block_it.Current();
+    for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+      AllocateObjectInstr* alloc = it.Current()->AsAllocateObject();
+      if ((alloc != NULL) && IsAllocationSinkingCandidate(alloc)) {
+        if (FLAG_trace_optimization) {
+          OS::Print("discovered allocation sinking candidate: v%"Pd"\n",
+                    alloc->ssa_temp_index());
+        }
+        candidates.Add(alloc);
+      }
+    }
+  }
+
+  // Insert MaterializeObject instructions that will describe the state of the
+  // object at all deoptimization points. Each inserted materialization looks
+  // like this (where v_0 is allocation that we are going to eliminate):
+  //   v_1     <- LoadField(v_0, field_1)
+  //           ...
+  //   v_N     <- LoadField(v_0, field_N)
+  //   v_{N+1} <- MaterializeObject(field_1 = v_1, ..., field_N = v_{N})
+  for (intptr_t i = 0; i < candidates.length(); i++) {
+    InsertMaterializations(candidates[i]);
+  }
+
+  // Run load forwarding to eliminate LoadField instructions inserted above.
+  // All loads will be successfully eliminated because:
+  //   a) they use fields (not offsets) and thus provide precise aliasing
+  //      information
+  //   b) candidate does not escape and thus its fields is not affected by
+  //      external effects from calls.
+  LoadOptimizer::OptimizeGraph(flow_graph_);
+
+  // At this point we have computed the state of object at each deoptimization
+  // point and we can eliminate it. Loads inserted above were forwarded so there
+  // are no uses of the allocation just as in the begging of the pass.
+  for (intptr_t i = 0; i < candidates.length(); i++) {
+    EliminateAllocation(candidates[i]);
+  }
+
+  // Process materializations and unbox their arguments: materializations
+  // are part of the environment and can materialize boxes for double/mint/simd
+  // values when needed.
+  // TODO(vegorov): handle all box types here.
+  for (intptr_t i = 0; i < materializations_.length(); i++) {
+    MaterializeObjectInstr* mat = materializations_[i];
+    for (intptr_t j = 0; j < mat->InputCount(); j++) {
+      Definition* defn = mat->InputAt(j)->definition();
+      if (defn->IsBoxDouble()) {
+        mat->InputAt(j)->BindTo(defn->InputAt(0)->definition());
+      }
+    }
+  }
+}
+
+
+// Remove materializations from the graph. Register allocator will treat them
+// as part of the environment not as a real instruction.
+void AllocationSinking::DetachMaterializations() {
+  for (intptr_t i = 0; i < materializations_.length(); i++) {
+    ASSERT(materializations_[i]->input_use_list() == NULL);
+    materializations_[i]->previous()->LinkTo(materializations_[i]->next());
+  }
+}
+
+
+// Add the given field to the list of fields if it is not yet present there.
+static void AddField(ZoneGrowableArray<const Field*>* fields,
+                     const Field& field) {
+  for (intptr_t i = 0; i < fields->length(); i++) {
+    if ((*fields)[i]->raw() == field.raw()) {
+      return;
+    }
+  }
+  fields->Add(&field);
+}
+
+
+// Add given instruction to the list of the instructions if it is not yet
+// present there.
+static void AddInstruction(GrowableArray<Instruction*>* exits,
+                           Instruction* exit) {
+  for (intptr_t i = 0; i < exits->length(); i++) {
+    if ((*exits)[i] == exit) {
+      return;
+    }
+  }
+  exits->Add(exit);
+}
+
+
+// Insert MaterializeObject instruction for the given allocation before
+// the given instruction that can deoptimize.
+void AllocationSinking::CreateMaterializationAt(
+    Instruction* exit,
+    AllocateObjectInstr* alloc,
+    const Class& cls,
+    const ZoneGrowableArray<const Field*>& fields) {
+  ZoneGrowableArray<Value*>* values =
+      new ZoneGrowableArray<Value*>(fields.length());
+
+  // Insert load instruction for every field.
+  for (intptr_t i = 0; i < fields.length(); i++) {
+    const Field* field = fields[i];
+    LoadFieldInstr* load = new LoadFieldInstr(new Value(alloc),
+                                              field->Offset(),
+                                              AbstractType::ZoneHandle());
+    load->set_field(field);
+    flow_graph_->InsertBefore(
+        exit, load, NULL, Definition::kValue);
+    values->Add(new Value(load));
+  }
+
+  MaterializeObjectInstr* mat = new MaterializeObjectInstr(cls, fields, values);
+  flow_graph_->InsertBefore(exit, mat, NULL, Definition::kValue);
+
+  // Replace all mentions of this allocation with a newly inserted
+  // MaterializeObject instruction.
+  // We must preserve the identity: all mentions are replaced by the same
+  // materialization.
+  for (Environment::DeepIterator env_it(exit->env());
+       !env_it.Done();
+       env_it.Advance()) {
+    Value* use = env_it.CurrentValue();
+    if (use->definition() == alloc) {
+      use->RemoveFromUseList();
+      use->set_definition(mat);
+      mat->AddEnvUse(use);
+    }
+  }
+
+  // Record inserted materialization.
+  materializations_.Add(mat);
+}
+
+
+void AllocationSinking::InsertMaterializations(AllocateObjectInstr* alloc) {
+  // Collect all fields that are written for this instance.
+  ZoneGrowableArray<const Field*>* fields =
+      new ZoneGrowableArray<const Field*>(5);
+
+  for (Value* use = alloc->input_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    ASSERT(use->instruction()->IsStoreInstanceField());
+    AddField(fields, use->instruction()->AsStoreInstanceField()->field());
+  }
+
+  // Collect all instructions that mention this object in the environment.
+  GrowableArray<Instruction*> exits(10);
+  for (Value* use = alloc->env_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    AddInstruction(&exits, use->instruction());
+  }
+
+  // Insert materializations at environment uses.
+  const Class& cls = Class::Handle(alloc->constructor().Owner());
+  for (intptr_t i = 0; i < exits.length(); i++) {
+    CreateMaterializationAt(exits[i], alloc, cls, *fields);
+  }
+}
+
+
 }  // namespace dart
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 5b2bfa6..46111e9 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -44,6 +44,9 @@
 
   void InferSmiRanges();
 
+  // Remove environments from the instructions which do not deoptimize.
+  void EliminateEnvironments();
+
   virtual void VisitStaticCall(StaticCallInstr* instr);
   virtual void VisitInstanceCall(InstanceCallInstr* instr);
   virtual void VisitRelationalOp(RelationalOpInstr* instr);
@@ -291,19 +294,15 @@
  public:
   static void Simplify(FlowGraph* flow_graph);
 
- private:
-  // Match an instance of the pattern to rewrite.  See the implementation
-  // for the patterns that are handled by this pass.
-  static bool Match(JoinEntryInstr* block);
-
   // Replace a target entry instruction with a join entry instruction.  Does
   // not update the original target's predecessors to point to the new block
   // and does not replace the target in already computed block order lists.
   static JoinEntryInstr* ToJoinEntry(TargetEntryInstr* target);
 
-  // Duplicate a constant, assigning it a new SSA name.
-  static ConstantInstr* CloneConstant(FlowGraph* flow_graph,
-                                      ConstantInstr* constant);
+ private:
+  // Match an instance of the pattern to rewrite.  See the implementation
+  // for the patterns that are handled by this pass.
+  static bool Match(JoinEntryInstr* block);
 
   // Duplicate a branch while replacing its comparison's left and right
   // inputs.
@@ -322,6 +321,30 @@
 };
 
 
+class AllocationSinking : public ZoneAllocated {
+ public:
+  explicit AllocationSinking(FlowGraph* flow_graph)
+      : flow_graph_(flow_graph),
+        materializations_(5) { }
+
+  void Optimize();
+
+  void DetachMaterializations();
+
+ private:
+  void InsertMaterializations(AllocateObjectInstr* alloc);
+
+  void CreateMaterializationAt(
+      Instruction* exit,
+      AllocateObjectInstr* alloc,
+      const Class& cls,
+      const ZoneGrowableArray<const Field*>& fields);
+
+  FlowGraph* flow_graph_;
+
+  GrowableArray<MaterializeObjectInstr*> materializations_;
+};
+
 }  // namespace dart
 
 #endif  // VM_FLOW_GRAPH_OPTIMIZER_H_
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 2b5f1a4..9cc0858 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -645,6 +645,16 @@
 }
 
 
+CompileType RedefinitionInstr::ComputeType() const {
+  return CompileType::None();
+}
+
+
+bool RedefinitionInstr::RecomputeType() {
+  return UpdateType(*value()->Type());
+}
+
+
 CompileType IfThenElseInstr::ComputeType() const {
   ASSERT(InputCount() == 2);
   return CompileType::FromCid(kSmiCid);
@@ -879,6 +889,11 @@
 }
 
 
+CompileType LoadClassIdInstr::ComputeType() const {
+  return CompileType::FromCid(kSmiCid);
+}
+
+
 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
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 406c445..ebac00a 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -494,6 +494,16 @@
 }
 
 
+void MaterializeObjectInstr::PrintOperandsTo(BufferFormatter* f) const {
+  f->Print("%s", String::Handle(cls_.Name()).ToCString());
+  for (intptr_t i = 0; i < InputCount(); i++) {
+    f->Print(", ");
+    f->Print("%s: ", String::Handle(fields_[i]->name()).ToCString());
+    InputAt(i)->PrintTo(f);
+  }
+}
+
+
 void CreateArrayInstr::PrintOperandsTo(BufferFormatter* f) const {
   for (int i = 0; i < ArgumentCount(); ++i) {
     if (i != 0) f->Print(", ");
@@ -735,7 +745,7 @@
 
 void GraphEntryInstr::PrintTo(BufferFormatter* f) const {
   const GrowableArray<Definition*>& defns = initial_definitions_;
-  f->Print("B%"Pd"[graph]", block_id());
+  f->Print("B%"Pd"[graph]:%"Pd, block_id(), GetDeoptId());
   if (defns.length() > 0) {
     f->Print(" {");
     for (intptr_t i = 0; i < defns.length(); ++i) {
@@ -749,7 +759,7 @@
 
 
 void JoinEntryInstr::PrintTo(BufferFormatter* f) const {
-  f->Print("B%"Pd"[join] pred(", block_id());
+  f->Print("B%"Pd"[join]:%"Pd" pred(", block_id(), GetDeoptId());
   for (intptr_t i = 0; i < predecessors_.length(); ++i) {
     if (i > 0) f->Print(", ");
     f->Print("B%"Pd, predecessors_[i]->block_id());
@@ -800,7 +810,7 @@
 
 
 void TargetEntryInstr::PrintTo(BufferFormatter* f) const {
-  f->Print("B%"Pd"[target]", block_id());
+  f->Print("B%"Pd"[target]:%"Pd, block_id(), GetDeoptId());
   if (HasParallelMove()) {
     f->Print(" ");
     parallel_move()->PrintTo(f);
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index bb57209..daa9d96 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -157,9 +157,12 @@
 bool LoadFieldInstr::AttributesEqual(Instruction* other) const {
   LoadFieldInstr* other_load = other->AsLoadField();
   ASSERT(other_load != NULL);
-  ASSERT((offset_in_bytes() != other_load->offset_in_bytes()) ||
-         ((immutable_ == other_load->immutable_)));
-  return offset_in_bytes() == other_load->offset_in_bytes();
+  if (field() != NULL) {
+    return (other_load->field() != NULL) &&
+        (field()->raw() == other_load->field()->raw());
+  }
+  return (other_load->field() == NULL) &&
+      (offset_in_bytes() == other_load->offset_in_bytes());
 }
 
 
@@ -499,12 +502,16 @@
 }
 
 
+// True if the definition has a single input use and is used only in
+// environments at the same instruction as that input use.
 bool Definition::HasOnlyUse(Value* use) const {
-  return (input_use_list() == use) &&
-     (use->next_use() == NULL) &&
-     ((env_use_list() == NULL) ||
-      ((env_use_list()->instruction() == use->instruction()) &&
-       (env_use_list()->next_use() == NULL)));
+  if ((input_use_list() != use) || (use->next_use() != NULL)) return false;
+
+  Instruction* target = use->instruction();
+  for (Value::Iterator it(env_use_list()); !it.Done(); it.Advance()) {
+    if (it.Current()->instruction() != target) return false;
+  }
+  return true;
 }
 
 
@@ -1049,7 +1056,7 @@
 }
 
 
-Definition* BinaryDoubleOpInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* BinaryDoubleOpInstr::Canonicalize(FlowGraph* flow_graph) {
   Definition* result = NULL;
 
   result = CanonicalizeCommutativeArithmetic(op_kind(),
@@ -1072,7 +1079,7 @@
 }
 
 
-Definition* BinarySmiOpInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* BinarySmiOpInstr::Canonicalize(FlowGraph* flow_graph) {
   Definition* result = NULL;
 
   result = CanonicalizeCommutativeArithmetic(op_kind(),
@@ -1095,7 +1102,7 @@
 }
 
 
-Definition* BinaryMintOpInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* BinaryMintOpInstr::Canonicalize(FlowGraph* flow_graph) {
   Definition* result = NULL;
 
   result = CanonicalizeCommutativeArithmetic(op_kind(),
@@ -1119,12 +1126,12 @@
 
 
 // Optimizations that eliminate or simplify individual instructions.
-Instruction* Instruction::Canonicalize(FlowGraphOptimizer* optimizer) {
+Instruction* Instruction::Canonicalize(FlowGraph* flow_graph) {
   return this;
 }
 
 
-Definition* Definition::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* Definition::Canonicalize(FlowGraph* flow_graph) {
   return this;
 }
 
@@ -1163,21 +1170,14 @@
 
 
 bool LoadFieldInstr::IsFixedLengthArrayCid(intptr_t cid) {
+  if (RawObject::IsTypedDataClassId(cid) ||
+      RawObject::IsExternalTypedDataClassId(cid)) {
+    return true;
+  }
+
   switch (cid) {
     case kArrayCid:
     case kImmutableArrayCid:
-    case kTypedDataInt8ArrayCid:
-    case kTypedDataUint8ArrayCid:
-    case kTypedDataUint8ClampedArrayCid:
-    case kTypedDataInt16ArrayCid:
-    case kTypedDataUint16ArrayCid:
-    case kTypedDataInt32ArrayCid:
-    case kTypedDataUint32ArrayCid:
-    case kTypedDataInt64ArrayCid:
-    case kTypedDataUint64ArrayCid:
-    case kTypedDataFloat32ArrayCid:
-    case kTypedDataFloat64ArrayCid:
-    case kTypedDataFloat32x4ArrayCid:
       return true;
     default:
       return false;
@@ -1185,12 +1185,12 @@
 }
 
 
-Definition* ConstantInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* ConstantInstr::Canonicalize(FlowGraph* flow_graph) {
   return HasUses() ? this : NULL;
 }
 
 
-Definition* LoadFieldInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* LoadFieldInstr::Canonicalize(FlowGraph* flow_graph) {
   if (!IsImmutableLengthLoad()) return this;
 
   // For fixed length arrays if the array is the result of a known constructor
@@ -1206,7 +1206,7 @@
 }
 
 
-Definition* AssertBooleanInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* AssertBooleanInstr::Canonicalize(FlowGraph* flow_graph) {
   if (FLAG_eliminate_type_checks && (value()->Type()->ToCid() == kBoolCid)) {
     return value()->definition();
   }
@@ -1215,7 +1215,7 @@
 }
 
 
-Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* AssertAssignableInstr::Canonicalize(FlowGraph* flow_graph) {
   if (FLAG_eliminate_type_checks &&
       value()->Type()->IsAssignableTo(dst_type())) {
     return value()->definition();
@@ -1235,17 +1235,14 @@
     const AbstractType& new_dst_type = AbstractType::Handle(
         dst_type().InstantiateFrom(instantiator_type_args, NULL));
     set_dst_type(AbstractType::ZoneHandle(new_dst_type.Canonicalize()));
-    ConstantInstr* null_constant = new ConstantInstr(Object::ZoneHandle());
-    // It is ok to insert instructions before the current during
-    // forward iteration.
-    optimizer->InsertBefore(this, null_constant, NULL, Definition::kValue);
+    ConstantInstr* null_constant = flow_graph->constant_null();
     instantiator_type_arguments()->BindTo(null_constant);
   }
   return this;
 }
 
 
-Definition* BoxDoubleInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* BoxDoubleInstr::Canonicalize(FlowGraph* flow_graph) {
   if (input_use_list() == NULL) {
     // Environments can accomodate any representation. No need to box.
     return value()->definition();
@@ -1261,17 +1258,17 @@
 }
 
 
-Definition* UnboxDoubleInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* UnboxDoubleInstr::Canonicalize(FlowGraph* flow_graph) {
   // Fold away UnboxDouble(BoxDouble(v)).
   BoxDoubleInstr* defn = value()->definition()->AsBoxDouble();
   return (defn != NULL) ? defn->value()->definition() : this;
 }
 
 
-Instruction* BranchInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) {
   // Only handle strict-compares.
   if (comparison()->IsStrictCompare()) {
-    Definition* replacement = comparison()->Canonicalize(optimizer);
+    Definition* replacement = comparison()->Canonicalize(flow_graph);
     if ((replacement == comparison()) || (replacement == NULL)) {
       return this;
     }
@@ -1294,7 +1291,7 @@
     Value* use = comp->input_use_list();
     if ((use->instruction() == this) && comp->HasOnlyUse(use)) {
       RemoveEnvironment();
-      InheritDeoptTarget(comp);
+      flow_graph->CopyDeoptTarget(this, comp);
 
       comp->RemoveFromGraph();
       SetComparison(comp);
@@ -1312,7 +1309,7 @@
 }
 
 
-Definition* StrictCompareInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Definition* StrictCompareInstr::Canonicalize(FlowGraph* flow_graph) {
   if (!right()->BindsToConstant()) {
     return this;
   }
@@ -1342,7 +1339,7 @@
 }
 
 
-Instruction* CheckClassInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Instruction* CheckClassInstr::Canonicalize(FlowGraph* flow_graph) {
   // TODO(vegorov): Replace class checks with null checks when ToNullableCid
   // matches.
 
@@ -1355,7 +1352,7 @@
 }
 
 
-Instruction* GuardFieldInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Instruction* GuardFieldInstr::Canonicalize(FlowGraph* flow_graph) {
   if (field().guarded_cid() == kDynamicCid) {
     return NULL;  // Nothing to guard.
   }
@@ -1374,13 +1371,12 @@
 }
 
 
-Instruction* CheckSmiInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+Instruction* CheckSmiInstr::Canonicalize(FlowGraph* flow_graph) {
   return (value()->Type()->ToCid() == kSmiCid) ?  NULL : this;
 }
 
 
-Instruction* CheckEitherNonSmiInstr::Canonicalize(
-    FlowGraphOptimizer* optimizer) {
+Instruction* CheckEitherNonSmiInstr::Canonicalize(FlowGraph* flow_graph) {
   if ((left()->Type()->ToCid() == kDoubleCid) ||
       (right()->Type()->ToCid() == kDoubleCid)) {
     return NULL;  // Remove from the graph.
@@ -1494,6 +1490,17 @@
 }
 
 
+LocationSummary* RedefinitionInstr::MakeLocationSummary() const {
+  UNREACHABLE();
+  return NULL;
+}
+
+
+void RedefinitionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
+
 LocationSummary* ParameterInstr::MakeLocationSummary() const {
   UNREACHABLE();
   return NULL;
@@ -1526,6 +1533,17 @@
 }
 
 
+LocationSummary* MaterializeObjectInstr::MakeLocationSummary() const {
+  UNREACHABLE();
+  return NULL;
+}
+
+
+void MaterializeObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNREACHABLE();
+}
+
+
 LocationSummary* StoreContextInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
   const intptr_t kNumTemps = 0;
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index dc33a3f..87220a8 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -22,8 +22,8 @@
 class ControlInstruction;
 class Definition;
 class Environment;
+class FlowGraph;
 class FlowGraphCompiler;
-class FlowGraphOptimizer;
 class FlowGraphVisitor;
 class Instruction;
 class LocalVariable;
@@ -497,6 +497,7 @@
   M(TargetEntry)                                                               \
   M(CatchBlockEntry)                                                           \
   M(Phi)                                                                       \
+  M(Redefinition)                                                              \
   M(Parameter)                                                                 \
   M(ParallelMove)                                                              \
   M(PushArgument)                                                              \
@@ -534,6 +535,7 @@
   M(LoadField)                                                                 \
   M(StoreVMField)                                                              \
   M(LoadUntagged)                                                              \
+  M(LoadClassId)                                                               \
   M(InstantiateTypeArguments)                                                  \
   M(ExtractConstructorTypeArguments)                                           \
   M(ExtractConstructorInstantiator)                                            \
@@ -584,7 +586,7 @@
   M(Float32x4Clamp)                                                            \
   M(Float32x4With)                                                             \
   M(Float32x4ToUint32x4)                                                       \
-
+  M(MaterializeObject)                                                         \
 
 #define FORWARD_DECLARATION(type) class type##Instr;
 FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
@@ -764,7 +766,7 @@
   // Returns a replacement for the instruction or NULL if the instruction can
   // be eliminated.  By default returns the this instruction which means no
   // change.
-  virtual Instruction* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
   // Insert this instruction before 'next' after use lists are computed.
   // Instructions cannot be inserted before a block entry or any other
@@ -876,6 +878,10 @@
   friend class TargetEntryInstr;
   friend class JoinEntryInstr;
   friend class InstanceOfInstr;
+  friend class PolymorphicInstanceCallInstr;
+  friend class SmiToDoubleInstr;
+  friend class DoubleToIntegerInstr;
+  friend class BranchSimplifier;
 
   virtual void RawSetInputAt(intptr_t i, Value* value) = 0;
 
@@ -1044,13 +1050,13 @@
   intptr_t end_pos() const { return end_pos_; }
 
   BlockEntryInstr* dominator() const { return dominator_; }
-  void set_dominator(BlockEntryInstr* instr) { dominator_ = instr; }
 
   const GrowableArray<BlockEntryInstr*>& dominated_blocks() {
     return dominated_blocks_;
   }
 
   void AddDominatedBlock(BlockEntryInstr* block) {
+    block->set_dominator(this);
     dominated_blocks_.Add(block);
   }
   void ClearDominatedBlocks() { dominated_blocks_.Clear(); }
@@ -1151,6 +1157,8 @@
   virtual void ClearPredecessors() = 0;
   virtual void AddPredecessor(BlockEntryInstr* predecessor) = 0;
 
+  void set_dominator(BlockEntryInstr* instr) { dominator_ = instr; }
+
   intptr_t block_id_;
   const intptr_t try_index_;
   intptr_t preorder_number_;
@@ -1309,6 +1317,7 @@
   // Classes that have access to predecessors_ when inlining.
   friend class BlockEntryInstr;
   friend class InlineExitCollector;
+  friend class PolymorphicInliner;
 
   // Direct access to phis_ in order to resize it due to phi elimination.
   friend class ConstantPropagator;
@@ -1542,7 +1551,7 @@
   // Definitions can be canonicalized only into definitions to ensure
   // this check statically we override base Canonicalize with a Canonicalize
   // returning Definition (return type is covariant).
-  virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   static const intptr_t kReplacementMarker = -2;
 
@@ -1954,7 +1963,7 @@
   void ReplaceWith(ComparisonInstr* other,
                    ForwardInstructionIterator* ignored);
 
-  virtual Instruction* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
   virtual void PrintTo(BufferFormatter* f) const;
 
@@ -2000,7 +2009,7 @@
     SetInputAt(0, value);
   }
 
-  DECLARE_INSTRUCTION(StoreContext);
+  DECLARE_INSTRUCTION(StoreContext)
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
@@ -2046,6 +2055,28 @@
 };
 
 
+class RedefinitionInstr : public TemplateDefinition<1> {
+ public:
+  explicit RedefinitionInstr(Value* value) {
+    SetInputAt(0, value);
+  }
+
+  DECLARE_INSTRUCTION(Redefinition)
+
+  Value* value() const { return inputs_[0]; }
+
+  virtual CompileType ComputeType() const;
+  virtual bool RecomputeType();
+
+  virtual bool CanDeoptimize() const { return false; }
+  virtual EffectSet Dependencies() const { return EffectSet::None(); }
+  virtual EffectSet Effects() const { return EffectSet::None(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RedefinitionInstr);
+};
+
+
 class RangeBoundary : public ValueObject {
  public:
   enum Kind { kUnknown, kSymbol, kConstant };
@@ -2275,7 +2306,7 @@
   DECLARE_INSTRUCTION(Constant)
   virtual CompileType ComputeType() const;
 
-  virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   const Object& value() const { return value_; }
 
@@ -2334,7 +2365,7 @@
 
   virtual bool CanDeoptimize() const { return true; }
 
-  virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   virtual bool AllowsCSE() const { return true; }
   virtual EffectSet Effects() const { return EffectSet::None(); }
@@ -2367,7 +2398,7 @@
 
   virtual bool CanDeoptimize() const { return true; }
 
-  virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   virtual bool AllowsCSE() const { return true; }
   virtual EffectSet Effects() const { return EffectSet::None(); }
@@ -2546,6 +2577,7 @@
         ic_data_(ic_data),
         with_checks_(with_checks) {
     ASSERT(instance_call_ != NULL);
+    deopt_id_ = instance_call->deopt_id();
   }
 
   InstanceCallInstr* instance_call() const { return instance_call_; }
@@ -2675,7 +2707,7 @@
 
   virtual bool CanDeoptimize() const { return false; }
 
-  virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   virtual void EmitBranchCode(FlowGraphCompiler* compiler,
                               BranchInstr* branch);
@@ -3132,7 +3164,7 @@
 
   virtual bool CanDeoptimize() const { return true; }
 
-  virtual Instruction* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
@@ -3152,7 +3184,7 @@
  public:
   explicit LoadStaticFieldInstr(const Field& field) : field_(field) {}
 
-  DECLARE_INSTRUCTION(LoadStaticField);
+  DECLARE_INSTRUCTION(LoadStaticField)
   virtual CompileType ComputeType() const;
 
   const Field& field() const { return field_; }
@@ -3181,7 +3213,7 @@
     SetInputAt(0, value);
   }
 
-  DECLARE_INSTRUCTION(StoreStaticField);
+  DECLARE_INSTRUCTION(StoreStaticField)
   virtual CompileType* ComputeInitialType() const;
 
   const Field& field() const { return field_; }
@@ -3470,6 +3502,66 @@
 };
 
 
+// This instruction captures the state of the object which had its allocation
+// removed during the AllocationSinking pass.
+// It does not produce any real code only deoptimization information.
+class MaterializeObjectInstr : public Definition {
+ public:
+  MaterializeObjectInstr(const Class& cls,
+                         const ZoneGrowableArray<const Field*>& fields,
+                         ZoneGrowableArray<Value*>* values)
+      : cls_(cls), fields_(fields), values_(values), locations_(NULL) {
+    ASSERT(fields_.length() == values_->length());
+    for (intptr_t i = 0; i < InputCount(); i++) {
+      InputAt(i)->set_instruction(this);
+      InputAt(i)->set_use_index(i);
+    }
+  }
+
+  const Class& cls() const { return cls_; }
+  const Field& FieldAt(intptr_t i) const {
+    return *fields_[i];
+  }
+  const Location& LocationAt(intptr_t i) {
+    return locations_[i];
+  }
+
+  DECLARE_INSTRUCTION(MaterializeObject)
+  virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+  virtual intptr_t InputCount() const {
+    return values_->length();
+  }
+
+  virtual Value* InputAt(intptr_t i) const {
+    return (*values_)[i];
+  }
+
+  virtual bool CanDeoptimize() const { return false; }
+  virtual EffectSet Effects() const { return EffectSet::None(); }
+
+  LocationSummary* locs() {
+    UNREACHABLE();
+    return NULL;
+  }
+
+  Location* locations() { return locations_; }
+  void set_locations(Location* locations) { locations_ = locations; }
+
+ private:
+  virtual void RawSetInputAt(intptr_t i, Value* value) {
+    (*values_)[i] = value;
+  }
+
+  const Class& cls_;
+  const ZoneGrowableArray<const Field*>& fields_;
+  ZoneGrowableArray<Value*>* values_;
+  Location* locations_;
+
+  DISALLOW_COPY_AND_ASSIGN(MaterializeObjectInstr);
+};
+
+
 class AllocateObjectWithBoundsCheckInstr : public TemplateDefinition<2> {
  public:
   AllocateObjectWithBoundsCheckInstr(ConstructorCallNode* node,
@@ -3574,7 +3666,7 @@
 
 class LoadUntaggedInstr : public TemplateDefinition<1> {
  public:
-  explicit LoadUntaggedInstr(Value* object, intptr_t offset) : offset_(offset) {
+  LoadUntaggedInstr(Value* object, intptr_t offset) : offset_(offset) {
     SetInputAt(0, object);
   }
 
@@ -3604,6 +3696,34 @@
 };
 
 
+class LoadClassIdInstr : public TemplateDefinition<1> {
+ public:
+  explicit LoadClassIdInstr(Value* object) {
+    SetInputAt(0, object);
+  }
+
+  virtual Representation representation() const {
+    return kTagged;
+  }
+  DECLARE_INSTRUCTION(LoadClassId)
+  virtual CompileType ComputeType() const;
+
+  Value* object() const { return inputs_[0]; }
+
+  virtual bool CanDeoptimize() const { return false; }
+
+  virtual bool AllowsCSE() const { return true; }
+  virtual EffectSet Effects() const { return EffectSet::None(); }
+  virtual EffectSet Dependencies() const {
+    return EffectSet::Externalization();
+  }
+  virtual bool AttributesEqual(Instruction* other) const { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoadClassIdInstr);
+};
+
+
 class LoadFieldInstr : public TemplateDefinition<1> {
  public:
   LoadFieldInstr(Value* instance,
@@ -3652,7 +3772,7 @@
 
   bool IsImmutableLengthLoad() const;
 
-  virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   static MethodRecognizer::Kind RecognizedKindFromArrayCid(intptr_t cid);
 
@@ -3824,7 +3944,7 @@
       : token_pos_(token_pos),
         num_context_variables_(num_context_variables) {}
 
-  DECLARE_INSTRUCTION(AllocateContext);
+  DECLARE_INSTRUCTION(AllocateContext)
   virtual CompileType ComputeType() const;
 
   intptr_t token_pos() const { return token_pos_; }
@@ -3935,7 +4055,7 @@
 
   virtual bool CanDeoptimize() const { return true; }
 
-  virtual Instruction* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
   virtual bool AllowsCSE() const { return true; }
   virtual EffectSet Effects() const { return EffectSet::None(); }
@@ -3970,7 +4090,7 @@
   virtual EffectSet Dependencies() const { return EffectSet::None(); }
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
-  Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  Definition* Canonicalize(FlowGraph* flow_graph);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(BoxDoubleInstr);
@@ -4087,7 +4207,7 @@
   virtual EffectSet Dependencies() const { return EffectSet::None(); }
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
-  Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  Definition* Canonicalize(FlowGraph* flow_graph);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(UnboxDoubleInstr);
@@ -4137,8 +4257,6 @@
     return (value()->Type()->ToCid() != kUint32x4Cid);
   }
 
-  virtual bool HasSideEffect() const { return false; }
-
   virtual Representation representation() const {
     return kUnboxedUint32x4;
   }
@@ -4266,7 +4384,7 @@
   DECLARE_INSTRUCTION(BinaryDoubleOp)
   virtual CompileType ComputeType() const;
 
-  virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   virtual bool AllowsCSE() const { return true; }
   virtual EffectSet Effects() const { return EffectSet::None(); }
@@ -4953,7 +5071,7 @@
     return deopt_id_;
   }
 
-  virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   DECLARE_INSTRUCTION(BinaryMintOp)
   virtual CompileType ComputeType() const;
@@ -5125,7 +5243,7 @@
 
   virtual void InferRange();
 
-  virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   // Returns true if right is a non-zero Smi constant which absolute value is
   // a power of two.
@@ -5233,6 +5351,7 @@
   DoubleToIntegerInstr(Value* value, InstanceCallInstr* instance_call)
       : instance_call_(instance_call) {
     SetInputAt(0, value);
+    deopt_id_ = instance_call->deopt_id();
   }
 
   Value* value() const { return inputs_[0]; }
@@ -5413,7 +5532,7 @@
 
   const ICData& unary_checks() const { return unary_checks_; }
 
-  virtual Instruction* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
@@ -5451,7 +5570,7 @@
 
   virtual bool CanDeoptimize() const { return true; }
 
-  virtual Instruction* Canonicalize(FlowGraphOptimizer* optimizer);
+  virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
   virtual bool AllowsCSE() const { return true; }
   virtual EffectSet Effects() const { return EffectSet::None(); }
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 710c2be..b87afd7 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -87,7 +87,7 @@
     Label stack_ok;
     __ Comment("Stack Check");
     const intptr_t fp_sp_dist =
-        (kFirstLocalSlotIndex + 1 - compiler->StackSize()) * kWordSize;
+        (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
     ASSERT(fp_sp_dist <= 0);
     __ sub(R2, SP, ShifterOperand(FP));
     __ CompareImmediate(R2, fp_sp_dist);
@@ -800,10 +800,10 @@
   __ PushObject(Object::ZoneHandle());
   // Pass a pointer to the first argument in R2.
   if (!function().HasOptionalParameters()) {
-    __ AddImmediate(R2, FP, (kLastParamSlotIndex +
-                             function().NumParameters() - 1) * kWordSize);
+    __ AddImmediate(R2, FP, (kParamEndSlotFromFp +
+                             function().NumParameters()) * kWordSize);
   } else {
-    __ AddImmediate(R2, FP, kFirstLocalSlotIndex * kWordSize);
+    __ AddImmediate(R2, FP, kFirstLocalSlotFromFp * kWordSize);
   }
   // Compute the effective address. When running under the simulator,
   // this is a redirection address that forces the simulator to call
@@ -844,6 +844,17 @@
 }
 
 
+LocationSummary* LoadClassIdInstr::MakeLocationSummary() const {
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNIMPLEMENTED();
+}
+
+
 CompileType LoadIndexedInstr::ComputeType() const {
   switch (class_id_) {
     case kArrayCid:
@@ -1717,7 +1728,7 @@
   // Restore SP from FP as we are coming from a throw and the code for
   // popping arguments has not been run.
   const intptr_t fp_sp_dist =
-      (kFirstLocalSlotIndex + 1 - compiler->StackSize()) * kWordSize;
+      (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
   ASSERT(fp_sp_dist <= 0);
   __ AddImmediate(SP, FP, fp_sp_dist);
 
@@ -2299,7 +2310,7 @@
 
 
 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
+  Label* deopt = compiler->AddDeoptStub(deopt_id(),
                                         kDeoptPolymorphicInstanceCallTestFail);
   if (ic_data().NumberOfChecks() == 0) {
     __ b(deopt);
@@ -2309,7 +2320,7 @@
   if (!with_checks()) {
     ASSERT(ic_data().HasOneTarget());
     const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0));
-    compiler->GenerateStaticCall(instance_call()->deopt_id(),
+    compiler->GenerateStaticCall(deopt_id(),
                                  instance_call()->token_pos(),
                                  target,
                                  instance_call()->ArgumentCount(),
@@ -2329,7 +2340,7 @@
                             instance_call()->ArgumentCount(),
                             instance_call()->argument_names(),
                             deopt,
-                            instance_call()->deopt_id(),
+                            deopt_id(),
                             instance_call()->token_pos(),
                             locs());
 }
@@ -2789,4 +2800,3 @@
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM
-
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 20095ed..42ef7c0 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -85,7 +85,7 @@
     __ Comment("Stack Check");
     Label done;
     const intptr_t fp_sp_dist =
-        (kFirstLocalSlotIndex + 1 - compiler->StackSize()) * kWordSize;
+        (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
     ASSERT(fp_sp_dist <= 0);
     __ movl(EDI, ESP);
     __ subl(EDI, EBP);
@@ -1048,10 +1048,10 @@
   __ PushObject(Object::ZoneHandle());
   // Pass a pointer to the first argument in EAX.
   if (!function().HasOptionalParameters()) {
-    __ leal(EAX, Address(EBP, (kLastParamSlotIndex +
-                               function().NumParameters() - 1) * kWordSize));
+    __ leal(EAX, Address(EBP, (kParamEndSlotFromFp +
+                               function().NumParameters()) * kWordSize));
   } else {
-    __ leal(EAX, Address(EBP, kFirstLocalSlotIndex * kWordSize));
+    __ leal(EAX, Address(EBP, kFirstLocalSlotFromFp * kWordSize));
   }
   __ movl(ECX, Immediate(reinterpret_cast<uword>(native_c_function())));
   __ movl(EDX, Immediate(NativeArguments::ComputeArgcTag(function())));
@@ -1077,13 +1077,10 @@
 
 LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* locs =
-      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
   // TODO(fschneider): Allow immediate operands for the char code.
-  locs->set_in(0, Location::RequiresRegister());
-  locs->set_out(Location::RequiresRegister());
-  return locs;
+  return LocationSummary::Make(kNumInputs,
+                               Location::RequiresRegister(),
+                               LocationSummary::kNoCall);
 }
 
 
@@ -1101,12 +1098,9 @@
 
 LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* locs =
-      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  locs->set_in(0, Location::RequiresRegister());
-  locs->set_out(Location::RequiresRegister());
-  return locs;
+  return LocationSummary::Make(kNumInputs,
+                               Location::RequiresRegister(),
+                               LocationSummary::kNoCall);
 }
 
 
@@ -1117,6 +1111,29 @@
 }
 
 
+LocationSummary* LoadClassIdInstr::MakeLocationSummary() const {
+  const intptr_t kNumInputs = 1;
+  return LocationSummary::Make(kNumInputs,
+                               Location::RequiresRegister(),
+                               LocationSummary::kNoCall);
+}
+
+
+void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Register object = locs()->in(0).reg();
+  Register result = locs()->out().reg();
+  Label load, done;
+  __ testl(object, Immediate(kSmiTagMask));
+  __ j(NOT_ZERO, &load, Assembler::kNearJump);
+  __ movl(result, Immediate(Smi::RawValue(kSmiCid)));
+  __ jmp(&done);
+  __ Bind(&load);
+  __ LoadClassId(result, object);
+  __ SmiTag(result);
+  __ Bind(&done);
+}
+
+
 CompileType LoadIndexedInstr::ComputeType() const {
   switch (class_id_) {
     case kArrayCid:
@@ -2065,7 +2082,7 @@
   // Restore ESP from EBP as we are coming from a throw and the code for
   // popping arguments has not been run.
   const intptr_t fp_sp_dist =
-      (kFirstLocalSlotIndex + 1 - compiler->StackSize()) * kWordSize;
+      (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
   ASSERT(fp_sp_dist <= 0);
   __ leal(ESP, Address(EBP, fp_sp_dist));
 
@@ -3317,12 +3334,9 @@
 
 LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary =
-      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresRegister());
-  summary->set_out(Location::SameAsFirstInput());
-  return summary;
+  return LocationSummary::Make(kNumInputs,
+                               Location::SameAsFirstInput(),
+                               LocationSummary::kNoCall);
 }
 
 
@@ -3400,7 +3414,7 @@
   const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
 
   const intptr_t kNumberOfArguments = 1;
-  compiler->GenerateStaticCall(instance_call()->deopt_id(),
+  compiler->GenerateStaticCall(deopt_id(),
                                instance_call()->token_pos(),
                                target,
                                kNumberOfArguments,
@@ -3496,7 +3510,7 @@
 
 
 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
+  Label* deopt = compiler->AddDeoptStub(deopt_id(),
                                         kDeoptPolymorphicInstanceCallTestFail);
   if (ic_data().NumberOfChecks() == 0) {
     __ jmp(deopt);
@@ -3506,7 +3520,7 @@
   if (!with_checks()) {
     ASSERT(ic_data().HasOneTarget());
     const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0));
-    compiler->GenerateStaticCall(instance_call()->deopt_id(),
+    compiler->GenerateStaticCall(deopt_id(),
                                  instance_call()->token_pos(),
                                  target,
                                  instance_call()->ArgumentCount(),
@@ -3527,7 +3541,7 @@
                             instance_call()->ArgumentCount(),
                             instance_call()->argument_names(),
                             deopt,
-                            instance_call()->deopt_id(),
+                            deopt_id(),
                             instance_call()->token_pos(),
                             locs());
 }
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index cee62a3..e33d78b 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -90,7 +90,7 @@
     __ Comment("Stack Check");
     __ TraceSimMsg("Stack Check");
     const intptr_t fp_sp_dist =
-        (kFirstLocalSlotIndex + 1 - compiler->StackSize()) * kWordSize;
+        (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
     ASSERT(fp_sp_dist <= 0);
     __ subu(T2, SP, FP);
 
@@ -814,10 +814,10 @@
   __ PushObject(Object::ZoneHandle());
   // Pass a pointer to the first argument in A2.
   if (!function().HasOptionalParameters()) {
-    __ AddImmediate(A2, FP, (kLastParamSlotIndex +
-                             function().NumParameters() - 1) * kWordSize);
+    __ AddImmediate(A2, FP, (kParamEndSlotFromFp +
+                             function().NumParameters()) * kWordSize);
   } else {
-    __ AddImmediate(A2, FP, kFirstLocalSlotIndex * kWordSize);
+    __ AddImmediate(A2, FP, kFirstLocalSlotFromFp * kWordSize);
   }
   // Compute the effective address. When running under the simulator,
   // this is a redirection address that forces the simulator to call
@@ -858,6 +858,17 @@
 }
 
 
+LocationSummary* LoadClassIdInstr::MakeLocationSummary() const {
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  UNIMPLEMENTED();
+}
+
+
 CompileType LoadIndexedInstr::ComputeType() const {
   switch (class_id_) {
     case kArrayCid:
@@ -1665,7 +1676,7 @@
   // Restore SP from FP as we are coming from a throw and the code for
   // popping arguments has not been run.
   const intptr_t fp_sp_dist =
-      (kFirstLocalSlotIndex + 1 - compiler->StackSize()) * kWordSize;
+      (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
   ASSERT(fp_sp_dist <= 0);
   __ AddImmediate(SP, FP, fp_sp_dist);
 
@@ -2274,7 +2285,7 @@
 
 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   __ TraceSimMsg("PolymorphicInstanceCallInstr");
-  Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
+  Label* deopt = compiler->AddDeoptStub(deopt_id(),
                                         kDeoptPolymorphicInstanceCallTestFail);
   if (ic_data().NumberOfChecks() == 0) {
     __ b(deopt);
@@ -2284,7 +2295,7 @@
   if (!with_checks()) {
     ASSERT(ic_data().HasOneTarget());
     const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0));
-    compiler->GenerateStaticCall(instance_call()->deopt_id(),
+    compiler->GenerateStaticCall(deopt_id(),
                                  instance_call()->token_pos(),
                                  target,
                                  instance_call()->ArgumentCount(),
@@ -2304,7 +2315,7 @@
                             instance_call()->ArgumentCount(),
                             instance_call()->argument_names(),
                             deopt,
-                            instance_call()->deopt_id(),
+                            deopt_id(),
                             instance_call()->token_pos(),
                             locs());
 }
@@ -2820,4 +2831,3 @@
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_MIPS
-
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 989c41b..d01c003 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -85,7 +85,7 @@
     __ Comment("Stack Check");
     Label done;
     const intptr_t fp_sp_dist =
-        (kFirstLocalSlotIndex + 1 - compiler->StackSize()) * kWordSize;
+        (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
     ASSERT(fp_sp_dist <= 0);
     __ movq(RDI, RSP);
     __ subq(RDI, RBP);
@@ -1059,11 +1059,11 @@
   __ PushObject(Object::ZoneHandle());
   // Pass a pointer to the first argument in RAX.
   if (!function().HasOptionalParameters()) {
-    __ leaq(RAX, Address(RBP, (kLastParamSlotIndex +
-                               function().NumParameters() - 1) * kWordSize));
+    __ leaq(RAX, Address(RBP, (kParamEndSlotFromFp +
+                               function().NumParameters()) * kWordSize));
   } else {
     __ leaq(RAX,
-            Address(RBP, kFirstLocalSlotIndex * kWordSize));
+            Address(RBP, kFirstLocalSlotFromFp * kWordSize));
   }
   __ movq(RBX, Immediate(reinterpret_cast<uword>(native_c_function())));
   __ movq(R10, Immediate(NativeArguments::ComputeArgcTag(function())));
@@ -1089,13 +1089,10 @@
 
 LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* locs =
-      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
   // TODO(fschneider): Allow immediate operands for the char code.
-  locs->set_in(0, Location::RequiresRegister());
-  locs->set_out(Location::RequiresRegister());
-  return locs;
+  return LocationSummary::Make(kNumInputs,
+                               Location::RequiresRegister(),
+                               LocationSummary::kNoCall);
 }
 
 
@@ -1113,12 +1110,9 @@
 
 LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* locs =
-      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  locs->set_in(0, Location::RequiresRegister());
-  locs->set_out(Location::RequiresRegister());
-  return locs;
+  return LocationSummary::Make(kNumInputs,
+                               Location::RequiresRegister(),
+                               LocationSummary::kNoCall);
 }
 
 
@@ -1129,6 +1123,29 @@
 }
 
 
+LocationSummary* LoadClassIdInstr::MakeLocationSummary() const {
+  const intptr_t kNumInputs = 1;
+  return LocationSummary::Make(kNumInputs,
+                               Location::RequiresRegister(),
+                               LocationSummary::kNoCall);
+}
+
+
+void LoadClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Register object = locs()->in(0).reg();
+  Register result = locs()->out().reg();
+  Label load, done;
+  __ testq(object, Immediate(kSmiTagMask));
+  __ j(NOT_ZERO, &load, Assembler::kNearJump);
+  __ movq(result, Immediate(Smi::RawValue(kSmiCid)));
+  __ jmp(&done);
+  __ Bind(&load);
+  __ LoadClassId(result, object);
+  __ SmiTag(result);
+  __ Bind(&done);
+}
+
+
 CompileType LoadIndexedInstr::ComputeType() const {
   switch (class_id_) {
     case kArrayCid:
@@ -2035,7 +2052,7 @@
   // Restore RSP from RBP as we are coming from a throw and the code for
   // popping arguments has not been run.
   const intptr_t fp_sp_dist =
-      (kFirstLocalSlotIndex + 1 - compiler->StackSize()) * kWordSize;
+      (kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
   ASSERT(fp_sp_dist <= 0);
   __ leaq(RSP, Address(RBP, fp_sp_dist));
 
@@ -2747,12 +2764,9 @@
 
 LocationSummary* UnboxFloat32x4Instr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary =
-      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresRegister());
-  summary->set_out(Location::RequiresFpuRegister());
-  return summary;
+  return LocationSummary::Make(kNumInputs,
+                               Location::RequiresFpuRegister(),
+                               LocationSummary::kNoCall);
 }
 
 
@@ -3324,12 +3338,9 @@
 
 LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
-  LocationSummary* summary =
-      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresRegister());
-  summary->set_out(Location::SameAsFirstInput());
-  return summary;
+  return LocationSummary::Make(kNumInputs,
+                               Location::SameAsFirstInput(),
+                               LocationSummary::kNoCall);
 }
 
 
@@ -3411,7 +3422,7 @@
 
   const intptr_t kNumberOfArguments = 1;
   __ pushq(value_obj);
-  compiler->GenerateStaticCall(instance_call()->deopt_id(),
+  compiler->GenerateStaticCall(deopt_id(),
                                instance_call()->token_pos(),
                                target,
                                kNumberOfArguments,
@@ -3520,7 +3531,7 @@
 
 
 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  Label* deopt = compiler->AddDeoptStub(instance_call()->deopt_id(),
+  Label* deopt = compiler->AddDeoptStub(deopt_id(),
                                         kDeoptPolymorphicInstanceCallTestFail);
   if (ic_data().NumberOfChecks() == 0) {
     __ jmp(deopt);
@@ -3530,7 +3541,7 @@
   if (!with_checks()) {
     ASSERT(ic_data().HasOneTarget());
     const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0));
-    compiler->GenerateStaticCall(instance_call()->deopt_id(),
+    compiler->GenerateStaticCall(deopt_id(),
                                  instance_call()->token_pos(),
                                  target,
                                  instance_call()->ArgumentCount(),
@@ -3549,7 +3560,7 @@
                             instance_call()->ArgumentCount(),
                             instance_call()->argument_names(),
                             deopt,
-                            instance_call()->deopt_id(),
+                            deopt_id(),
                             instance_call()->token_pos(),
                             locs());
 }
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 473f001..d445f17 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -311,6 +311,56 @@
 }
 
 
+void DeferredObjectRef::Materialize() {
+  DeferredObject* obj = Isolate::Current()->GetDeferredObject(index());
+  *slot() = obj->object();
+  if (FLAG_trace_deoptimization_verbose) {
+    OS::PrintErr("writing instance ref at %"Px": %s\n",
+                 reinterpret_cast<uword>(slot()),
+                 Instance::Handle(obj->object()).ToCString());
+  }
+}
+
+
+RawInstance* DeferredObject::object() {
+  if (object_ == NULL) {
+    Materialize();
+  }
+  return object_->raw();
+}
+
+
+void DeferredObject::Materialize() {
+  Class& cls = Class::Handle();
+  cls ^= GetClass();
+
+  if (FLAG_trace_deoptimization_verbose) {
+    OS::PrintErr("materializing instance of %s (%"Px", %"Pd" fields)\n",
+                 cls.ToCString(),
+                 reinterpret_cast<uword>(args_),
+                 field_count_);
+  }
+
+  const Instance& obj = Instance::ZoneHandle(Instance::New(cls));
+
+  Field& field = Field::Handle();
+  Object& value = Object::Handle();
+  for (intptr_t i = 0; i < field_count_; i++) {
+    field ^= GetField(i);
+    value = GetValue(i);
+    obj.SetField(field, value);
+
+    if (FLAG_trace_deoptimization_verbose) {
+      OS::PrintErr("    %s <- %s\n",
+                   String::Handle(field.name()).ToCString(),
+                   value.ToCString());
+    }
+  }
+
+  object_ = &obj;
+}
+
+
 Isolate::Isolate()
     : store_buffer_(),
       message_notify_callback_(NULL),
@@ -344,6 +394,9 @@
       deopt_fpu_registers_copy_(NULL),
       deopt_frame_copy_(NULL),
       deopt_frame_copy_size_(0),
+      deferred_boxes_(NULL),
+      deferred_object_refs_(NULL),
+      deferred_objects_count_(0),
       deferred_objects_(NULL),
       stacktrace_(NULL),
       stack_frame_index_(-1) {
@@ -994,6 +1047,31 @@
 }
 
 
+static void FillDeferredSlots(DeferredSlot** slot_list) {
+  DeferredSlot* slot = *slot_list;
+  *slot_list = NULL;
+
+  while (slot != NULL) {
+    DeferredSlot* current = slot;
+    slot = slot->next();
+
+    current->Materialize();
+
+    delete current;
+  }
+}
+
+
+void Isolate::MaterializeDeferredBoxes() {
+  FillDeferredSlots(&deferred_boxes_);
+}
+
+
+void Isolate::MaterializeDeferredObjects() {
+  FillDeferredSlots(&deferred_object_refs_);
+}
+
+
 static char* GetRootScriptUri(Isolate* isolate) {
   const Library& library =
       Library::Handle(isolate->object_store()->root_library());
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index c87b56d..407a9f8 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -26,6 +26,7 @@
 class HandleVisitor;
 class Heap;
 class ICData;
+class Instance;
 class LongJump;
 class MessageHandler;
 class Mutex;
@@ -49,30 +50,31 @@
 
 // Used by the deoptimization infrastructure to defer allocation of unboxed
 // objects until frame is fully rewritten and GC is safe.
-// See callers of Isolate::DeferObjectMaterialization.
-class DeferredObject {
+// Describes a stack slot that should be populated with a reference to the
+// materialized object.
+class DeferredSlot {
  public:
-  DeferredObject(RawInstance** slot, DeferredObject* next)
+  DeferredSlot(RawInstance** slot, DeferredSlot* next)
       : slot_(slot), next_(next) { }
-  virtual ~DeferredObject() { }
+  virtual ~DeferredSlot() { }
 
   RawInstance** slot() const { return slot_; }
-  DeferredObject* next() const { return next_; }
+  DeferredSlot* next() const { return next_; }
 
   virtual void Materialize() = 0;
 
  private:
   RawInstance** const slot_;
-  DeferredObject* const next_;
+  DeferredSlot* const next_;
 
-  DISALLOW_COPY_AND_ASSIGN(DeferredObject);
+  DISALLOW_COPY_AND_ASSIGN(DeferredSlot);
 };
 
 
-class DeferredDouble : public DeferredObject {
+class DeferredDouble : public DeferredSlot {
  public:
-  DeferredDouble(double value, RawInstance** slot, DeferredObject* next)
-      : DeferredObject(slot, next), value_(value) { }
+  DeferredDouble(double value, RawInstance** slot, DeferredSlot* next)
+      : DeferredSlot(slot, next), value_(value) { }
 
   virtual void Materialize();
 
@@ -85,10 +87,10 @@
 };
 
 
-class DeferredMint : public DeferredObject {
+class DeferredMint : public DeferredSlot {
  public:
-  DeferredMint(int64_t value, RawInstance** slot, DeferredObject* next)
-      : DeferredObject(slot, next), value_(value) { }
+  DeferredMint(int64_t value, RawInstance** slot, DeferredSlot* next)
+      : DeferredSlot(slot, next), value_(value) { }
 
   virtual void Materialize();
 
@@ -101,11 +103,11 @@
 };
 
 
-class DeferredFloat32x4 : public DeferredObject {
+class DeferredFloat32x4 : public DeferredSlot {
  public:
   DeferredFloat32x4(simd128_value_t value, RawInstance** slot,
-                    DeferredObject* next)
-      : DeferredObject(slot, next), value_(value) { }
+                    DeferredSlot* next)
+      : DeferredSlot(slot, next), value_(value) { }
 
   virtual void Materialize();
 
@@ -118,11 +120,11 @@
 };
 
 
-class DeferredUint32x4 : public DeferredObject {
+class DeferredUint32x4 : public DeferredSlot {
  public:
   DeferredUint32x4(simd128_value_t value, RawInstance** slot,
-                   DeferredObject* next)
-      : DeferredObject(slot, next), value_(value) { }
+                   DeferredSlot* next)
+      : DeferredSlot(slot, next), value_(value) { }
 
   virtual void Materialize();
 
@@ -135,6 +137,86 @@
 };
 
 
+// Describes a slot that contains a reference to an object that had its
+// allocation removed by AllocationSinking pass.
+// Object itself is described and materialized by DeferredObject.
+class DeferredObjectRef : public DeferredSlot {
+ public:
+  DeferredObjectRef(intptr_t index, RawInstance** slot, DeferredSlot* next)
+      : DeferredSlot(slot, next), index_(index) { }
+
+  virtual void Materialize();
+
+  intptr_t index() const { return index_; }
+
+ private:
+  const intptr_t index_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeferredObjectRef);
+};
+
+
+// Describes an object which allocation was removed by AllocationSinking pass.
+// Arguments for materialization are stored as a part of expression stack
+// for the bottommost deoptimized frame so that GC could discover them.
+// They will be removed from the stack at the very end of deoptimization.
+class DeferredObject {
+ public:
+  DeferredObject(intptr_t field_count, intptr_t* args)
+      : field_count_(field_count),
+        args_(reinterpret_cast<RawObject**>(args)),
+        object_(NULL) { }
+
+  intptr_t ArgumentCount() const {
+    return kFieldsStartIndex + kFieldEntrySize * field_count_;
+  }
+
+  RawInstance* object();
+
+ private:
+  enum {
+    kClassIndex = 0,
+    kFieldsStartIndex = kClassIndex + 1
+  };
+
+  enum {
+    kFieldIndex = 0,
+    kValueIndex,
+    kFieldEntrySize,
+  };
+
+  // Materializes the object. Returns amount of values that were consumed
+  // and should be removed from the expression stack at the very end of
+  // deoptimization.
+  void Materialize();
+
+  RawObject* GetClass() const {
+    return args_[kClassIndex];
+  }
+
+  RawObject* GetField(intptr_t index) const {
+    return args_[kFieldsStartIndex + kFieldEntrySize * index + kFieldIndex];
+  }
+
+  RawObject* GetValue(intptr_t index) const {
+    return args_[kFieldsStartIndex + kFieldEntrySize * index + kValueIndex];
+  }
+
+  // Amount of fields that have to be initialized.
+  const intptr_t field_count_;
+
+  // Pointer to the first materialization argument on the stack.
+  // The first argument is Class of the instance to materialize followed by
+  // Field, value pairs.
+  RawObject** args_;
+
+  // Object materialized from this description.
+  const Instance* object_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeferredObject);
+};
+
+
 class Isolate : public BaseIsolate {
  public:
   ~Isolate();
@@ -424,40 +506,78 @@
   }
   intptr_t deopt_frame_copy_size() const { return deopt_frame_copy_size_; }
 
+  void PrepareForDeferredMaterialization(intptr_t count) {
+    if (count > 0) {
+      deferred_objects_ = new DeferredObject*[count];
+      deferred_objects_count_ = count;
+    }
+  }
+
+  void DeleteDeferredObjects() {
+    for (intptr_t i = 0; i < deferred_objects_count_; i++) {
+      delete deferred_objects_[i];
+    }
+    delete[] deferred_objects_;
+    deferred_objects_ = NULL;
+    deferred_objects_count_ = 0;
+  }
+
+  DeferredObject* GetDeferredObject(intptr_t idx) const {
+    return deferred_objects_[idx];
+  }
+
+  void SetDeferredObjectAt(intptr_t idx, DeferredObject* object) {
+    deferred_objects_[idx] = object;
+  }
+
+  intptr_t DeferredObjectsCount() const {
+    return deferred_objects_count_;
+  }
+
+  void DeferMaterializedObjectRef(intptr_t idx, intptr_t* slot) {
+    deferred_object_refs_ = new DeferredObjectRef(
+        idx,
+        reinterpret_cast<RawInstance**>(slot),
+        deferred_object_refs_);
+  }
+
   void DeferDoubleMaterialization(double value, RawDouble** slot) {
-    deferred_objects_ = new DeferredDouble(
+    deferred_boxes_ = new DeferredDouble(
         value,
         reinterpret_cast<RawInstance**>(slot),
-        deferred_objects_);
+        deferred_boxes_);
   }
 
   void DeferMintMaterialization(int64_t value, RawMint** slot) {
-    deferred_objects_ = new DeferredMint(value,
-                                         reinterpret_cast<RawInstance**>(slot),
-                                         deferred_objects_);
+    deferred_boxes_ = new DeferredMint(
+        value,
+        reinterpret_cast<RawInstance**>(slot),
+        deferred_boxes_);
   }
 
   void DeferFloat32x4Materialization(simd128_value_t value,
                                      RawFloat32x4** slot) {
-    deferred_objects_ = new DeferredFloat32x4(
+    deferred_boxes_ = new DeferredFloat32x4(
         value,
         reinterpret_cast<RawInstance**>(slot),
-        deferred_objects_);
+        deferred_boxes_);
   }
 
   void DeferUint32x4Materialization(simd128_value_t value,
                                     RawUint32x4** slot) {
-    deferred_objects_ = new DeferredUint32x4(
+    deferred_boxes_ = new DeferredUint32x4(
         value,
         reinterpret_cast<RawInstance**>(slot),
-        deferred_objects_);
+        deferred_boxes_);
   }
 
-  DeferredObject* DetachDeferredObjects() {
-    DeferredObject* list = deferred_objects_;
-    deferred_objects_ = NULL;
-    return list;
-  }
+  // Populate all deferred slots that contain boxes for double, mint, simd
+  // values.
+  void MaterializeDeferredBoxes();
+
+  // Populate all slots containing references to objects which allocations
+  // were eliminated by AllocationSinking pass.
+  void MaterializeDeferredObjects();
 
   static char* GetStatus(const char* request);
 
@@ -511,7 +631,11 @@
   fpu_register_t* deopt_fpu_registers_copy_;
   intptr_t* deopt_frame_copy_;
   intptr_t deopt_frame_copy_size_;
-  DeferredObject* deferred_objects_;
+  DeferredSlot* deferred_boxes_;
+  DeferredSlot* deferred_object_refs_;
+
+  intptr_t deferred_objects_count_;
+  DeferredObject** deferred_objects_;
 
   // Status support.
   char* stacktrace_;
diff --git a/runtime/vm/locations.cc b/runtime/vm/locations.cc
index e1a86bc..a80f5ff 100644
--- a/runtime/vm/locations.cc
+++ b/runtime/vm/locations.cc
@@ -90,10 +90,10 @@
 Address Location::ToStackSlotAddress() const {
   const intptr_t index = stack_index();
   if (index < 0) {
-    const intptr_t offset = (kLastParamSlotIndex - index - 1)  * kWordSize;
+    const intptr_t offset = (kParamEndSlotFromFp - index)  * kWordSize;
     return Address(FPREG, offset);
   } else {
-    const intptr_t offset = (kFirstLocalSlotIndex - index) * kWordSize;
+    const intptr_t offset = (kFirstLocalSlotFromFp - index) * kWordSize;
     return Address(FPREG, offset);
   }
 }
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index aa85a51..1a095e6 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7528,6 +7528,15 @@
 }
 
 
+intptr_t DeoptInfo::FrameSize() const {
+  intptr_t pos = 0;
+  while (Instruction(pos) == DeoptInstr::kMaterializeObject) {
+    pos++;
+  }
+  return TranslationLength() - pos;
+}
+
+
 intptr_t DeoptInfo::TranslationLength() const {
   intptr_t length = Length();
   if (Instruction(length - 1) != DeoptInstr::kSuffix) return length;
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 19802e7..6d3a70f 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2596,9 +2596,17 @@
 };
 
 
-// Holds deopt information at one deoptimization point. The information
-// is a list of DeoptInstr objects, specifying transformation information
-// for each slot in unoptimized frame(s).
+// Holds deopt information at one deoptimization point. The information consists
+// of two parts:
+//  - first a prefix consiting of kMaterializeObject instructions describing
+//    objects which had their allocation removed as part of AllocationSinking
+//    pass and have to be materialized;
+//  - followed by a list of DeoptInstr objects, specifying transformation
+//    information for each slot in unoptimized frame(s).
+// Arguments for object materialization (class of instance to be allocated and
+// field-value pairs) are added as artificial slots to the expression stack
+// of the bottom-most frame. They are removed from the stack at the very end
+// of deoptimization by the deoptimization stub.
 class DeoptInfo : public Object {
  private:
   // Describes the layout of deopt info data. The index of a deopt-info entry
@@ -2617,6 +2625,10 @@
   // deoptimization translation.
   intptr_t TranslationLength() const;
 
+  // Size of the frame part of the translation not counting kMaterializeObject
+  // instructions in the prefix.
+  intptr_t FrameSize() const;
+
   static RawDeoptInfo* New(intptr_t num_commands);
 
   static const intptr_t kBytesPerElement = (kNumberOfEntries * kWordSize);
diff --git a/runtime/vm/os.h b/runtime/vm/os.h
index a41e3bd..92c0c3b 100644
--- a/runtime/vm/os.h
+++ b/runtime/vm/os.h
@@ -18,6 +18,9 @@
 // Interface to the underlying OS platform.
 class OS {
  public:
+  // Returns the name of the given OS. For example "linux".
+  static const char* Name();
+
   // Returns the abbreviated time-zone name for the given instant.
   // For example "CET" or "CEST".
   static const char* GetTimeZoneName(int64_t seconds_since_epoch);
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index ec6413d..17a378a 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -184,6 +184,11 @@
 };
 
 
+const char* OS::Name() {
+  return "android";
+}
+
+
 static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) {
   time_t seconds = static_cast<time_t>(seconds_since_epoch);
   if (seconds != seconds_since_epoch) return false;
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index d6ddd80..2b869d4 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -268,6 +268,11 @@
 };
 
 
+const char* OS::Name() {
+  return "linux";
+}
+
+
 static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) {
   time_t seconds = static_cast<time_t>(seconds_since_epoch);
   if (seconds != seconds_since_epoch) return false;
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index cd0b53e..62c9376 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -21,6 +21,11 @@
 
 namespace dart {
 
+const char* OS::Name() {
+  return "macos";
+}
+
+
 static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) {
   time_t seconds = static_cast<time_t>(seconds_since_epoch);
   if (seconds != seconds_since_epoch) return false;
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index bdd6cec..b69dd83 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -16,6 +16,11 @@
 
 namespace dart {
 
+const char* OS::Name() {
+  return "windows";
+}
+
+
 // As a side-effect sets the globals _timezone, _daylight and _tzname.
 static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) {
   time_t seconds = static_cast<time_t>(seconds_since_epoch);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 59f6faa..33db8c2 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -159,22 +159,22 @@
   // Compute start indices to parameters and locals, and the number of
   // parameters to copy.
   if (num_opt_params == 0) {
-    // Parameter i will be at fp[kLastParamSlotIndex + num_params - 1 - i] and
-    // local variable j will be at fp[kFirstLocalSlotIndex - j].
+    // Parameter i will be at fp[kParamEndSlotFromFp + num_params - i] and
+    // local variable j will be at fp[kFirstLocalSlotFromFp - j].
     ASSERT(GetSavedArgumentsDescriptorVar() == NULL);
-    first_parameter_index_ = kLastParamSlotIndex + num_params - 1;
-    first_stack_local_index_ = kFirstLocalSlotIndex;
+    first_parameter_index_ = kParamEndSlotFromFp + num_params;
+    first_stack_local_index_ = kFirstLocalSlotFromFp;
     num_copied_params_ = 0;
   } else {
-    // Parameter i will be at fp[kFirstLocalSlotIndex - i] and local variable
-    // j will be at fp[kFirstLocalSlotIndex - num_params - j].
+    // Parameter i will be at fp[kFirstLocalSlotFromFp - i] and local variable
+    // j will be at fp[kFirstLocalSlotFromFp - num_params - j].
     // The saved arguments descriptor variable must be allocated similarly to
     // a parameter, so that it gets both a frame slot and a context slot when
     // captured.
     if (GetSavedArgumentsDescriptorVar() != NULL) {
       num_params += 1;
     }
-    first_parameter_index_ = kFirstLocalSlotIndex;
+    first_parameter_index_ = kFirstLocalSlotFromFp;
     first_stack_local_index_ = first_parameter_index_ - num_params;
     num_copied_params_ = num_params;
   }
diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc
index c71fa16..c7b0c05 100644
--- a/runtime/vm/scopes.cc
+++ b/runtime/vm/scopes.cc
@@ -569,15 +569,15 @@
 int LocalVariable::BitIndexIn(intptr_t fixed_parameter_count) const {
   ASSERT(!is_captured());
   // Parameters have positive indexes with the lowest index being
-  // kLastParamSlotIndex.  Locals and copied parameters have negative indexes
-  // with the lowest (closest to zero) index being kFirstLocalSlotIndex.
+  // kParamEndSlotFromFp + 1.  Locals and copied parameters have negative
+  // indexes with the lowest (closest to 0) index being kFirstLocalSlotFromFp.
   if (index() > 0) {
     // Shift non-negative indexes so that the lowest one is 0.
-    return (fixed_parameter_count - 1) - (index() - kLastParamSlotIndex);
+    return fixed_parameter_count - (index() - kParamEndSlotFromFp);
   } else {
     // Shift negative indexes so that the lowest one is 0 (they are still
     // non-positive).
-    return fixed_parameter_count - (index() - kFirstLocalSlotIndex);
+    return fixed_parameter_count - (index() - kFirstLocalSlotFromFp);
   }
 }
 
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index c5d9724..59d6d29 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -1482,8 +1482,8 @@
           break;
         }
         case 7: {
-          if (instr->Bits(21, 2) == 0x1) {
-            // Format(instr, "bkpt'cond #'imm12_4");
+          if ((instr->Bits(21, 2) == 0x1) && (instr->ConditionField() == AL)) {
+            // Format(instr, "bkpt #'imm12_4");
             SimulatorDebugger dbg(this);
             set_pc(get_pc() + Instr::kInstrSize);
             char buffer[32];
@@ -2067,12 +2067,12 @@
 
 void Simulator::DoDivision(Instr* instr) {
   ASSERT(CPUFeatures::integer_division_supported());
-  Register rd = instr->RdField();
-  Register rn = instr->RnField();
-  Register rm = instr->RmField();
+  Register rd = instr->DivRdField();
+  Register rn = instr->DivRnField();
+  Register rm = instr->DivRmField();
 
-  // TODO(zra): Does the hardware trap on divide-by-zero?
-  //     Revisit when we test on ARM hardware.
+  // ARMv7-a does not trap on divide-by-zero. The destination register is just
+  // set to 0.
   if (get_register(rm) == 0) {
     set_register(rd, 0);
     return;
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 3ae8d33..b45d133 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -21,7 +21,7 @@
 bool StackFrame::IsStubFrame() const {
   ASSERT(!(IsEntryFrame() || IsExitFrame()));
   uword saved_pc =
-      *(reinterpret_cast<uword*>(fp() + EntrypointMarkerOffsetFromFp()));
+      *(reinterpret_cast<uword*>(fp() + (kPcMarkerSlotFromFp * kWordSize)));
   return (saved_pc == 0);
 }
 
@@ -37,17 +37,18 @@
 
 
 RawContext* EntryFrame::SavedContext() const {
-  return *(reinterpret_cast<RawContext**>(fp() + SavedContextOffset()));
+  return *(reinterpret_cast<RawContext**>(
+      fp() + (kSavedContextSlotFromEntryFp * kWordSize)));
 }
 
 
 void EntryFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
   // Visit objects between SP and (FP - callee_save_area).
   ASSERT(visitor != NULL);
-  RawObject** start = reinterpret_cast<RawObject**>(sp());
-  RawObject** end = reinterpret_cast<RawObject**>(
-      fp() - kWordSize + ExitLinkOffset());
-  visitor->VisitPointers(start, end);
+  RawObject** first = reinterpret_cast<RawObject**>(sp());
+  RawObject** last = reinterpret_cast<RawObject**>(
+      fp() + (kExitLinkSlotFromEntryFp - 1) * kWordSize);
+  visitor->VisitPointers(first, last);
 }
 
 
@@ -60,9 +61,9 @@
   // helper functions to the raw object interface.
   ASSERT(visitor != NULL);
   NoGCScope no_gc;
-  RawObject** start_addr = reinterpret_cast<RawObject**>(sp());
-  RawObject** end_addr =
-      reinterpret_cast<RawObject**>(fp()) + kFirstLocalSlotIndex;
+  RawObject** first = reinterpret_cast<RawObject**>(sp());
+  RawObject** last = reinterpret_cast<RawObject**>(
+      fp() + (kFirstLocalSlotFromFp * kWordSize));
   Code code;
   code = LookupDartCode();
   if (!code.IsNull()) {
@@ -93,24 +94,24 @@
       // Spill slots are at the 'bottom' of the frame.
       intptr_t spill_slot_count = length - map.RegisterBitCount();
       for (intptr_t bit = 0; bit < spill_slot_count; ++bit) {
-        if (map.IsObject(bit)) visitor->VisitPointer(end_addr);
-        --end_addr;
+        if (map.IsObject(bit)) visitor->VisitPointer(last);
+        --last;
       }
 
       // The live registers at the 'top' of the frame comprise the rest of the
       // stack map.
       for (intptr_t bit = length - 1; bit >= spill_slot_count; --bit) {
-        if (map.IsObject(bit)) visitor->VisitPointer(start_addr);
-        ++start_addr;
+        if (map.IsObject(bit)) visitor->VisitPointer(first);
+        ++first;
       }
 
-      // The end address can be one slot (but not more) past the start
-      // address in the case that all slots were covered by the stack map.
-      ASSERT((end_addr + 1) >= start_addr);
+      // The last slot can be one slot (but not more) past the last slot
+      // in the case that all slots were covered by the stack map.
+      ASSERT((last + 1) >= first);
     }
   }
-  // Each slot between the start and end address are tagged objects.
-  visitor->VisitPointers(start_addr, end_addr);
+  // Each slot between the first and last included are tagged objects.
+  visitor->VisitPointers(first, last);
 }
 
 
@@ -139,11 +140,11 @@
   // a GC as we are handling raw object references here. It is possible
   // that the code is called while a GC is in progress, that is ok.
   NoGCScope no_gc;
-  uword saved_pc =
-      *(reinterpret_cast<uword*>(fp() + EntrypointMarkerOffsetFromFp()));
-  if (saved_pc != 0) {
-    uword entry_point =
-        (saved_pc - Assembler::kOffsetOfSavedPCfromEntrypoint);
+  const uword pc_marker =
+      *(reinterpret_cast<uword*>(fp() + (kPcMarkerSlotFromFp * kWordSize)));
+  if (pc_marker != 0) {
+    const uword entry_point =
+        (pc_marker - Assembler::kEntryPointToPcMarkerOffset);
     RawInstructions* instr = Instructions::FromEntryPoint(entry_point);
     if (instr != Instructions::null()) {
       return instr->ptr()->code_;
@@ -202,6 +203,21 @@
 }
 
 
+void StackFrameIterator::SetupLastExitFrameData() {
+  Isolate* current = Isolate::Current();
+  uword exit_marker = current->top_exit_frame_info();
+  frames_.fp_ = exit_marker;
+}
+
+
+void StackFrameIterator::SetupNextExitFrameData() {
+  uword exit_address = entry_.fp() + (kExitLinkSlotFromEntryFp * kWordSize);
+  uword exit_marker = *reinterpret_cast<uword*>(exit_address);
+  frames_.fp_ = exit_marker;
+  frames_.sp_ = 0;
+}
+
+
 StackFrameIterator::StackFrameIterator(bool validate)
     : validate_(validate), entry_(), exit_(), current_frame_(NULL) {
   SetupLastExitFrameData();  // Setup data for last exit frame.
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index b7a53f1..6b527f6 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -37,16 +37,11 @@
   uword sp() const { return sp_; }
   uword fp() const { return fp_; }
   uword pc() const {
-    return *reinterpret_cast<uword*>(sp_ + PcAddressOffsetFromSp());
+    return *reinterpret_cast<uword*>(sp_ + (kSavedPcSlotFromSp * kWordSize));
   }
 
   void set_pc(uword value) {
-    *reinterpret_cast<uword*>(sp_ + PcAddressOffsetFromSp()) = value;
-  }
-
-  void SetEntrypointMarker(uword value) {
-    ASSERT(!(IsStubFrame() || IsEntryFrame() || IsExitFrame()));
-    *reinterpret_cast<uword*>(fp_ + EntrypointMarkerOffsetFromFp()) = value;
+    *reinterpret_cast<uword*>(sp_ + (kSavedPcSlotFromSp * kWordSize)) = value;
   }
 
   // Visit objects in the frame.
@@ -83,11 +78,13 @@
  private:
   RawCode* GetCodeObject() const;
 
-  // Target specific implementations for locating pc and caller fp/sp values.
-  static intptr_t PcAddressOffsetFromSp();
-  static intptr_t EntrypointMarkerOffsetFromFp();
-  uword GetCallerSp() const;
-  uword GetCallerFp() const;
+  uword GetCallerSp() const {
+    return fp() + (kCallerSpSlotFromFp * kWordSize);
+  }
+  uword GetCallerFp() const {
+    return *(reinterpret_cast<uword*>(
+        fp() + (kSavedCallerFpSlotFromFp * kWordSize)));
+  }
 
   uword fp_;
   uword sp_;
@@ -142,8 +139,6 @@
 
  private:
   EntryFrame() { }
-  intptr_t ExitLinkOffset() const;
-  intptr_t SavedContextOffset() const;
 
   friend class StackFrameIterator;
   DISALLOW_COPY_AND_ASSIGN(EntryFrame);
@@ -176,8 +171,8 @@
       if (fp_ == 0) {
         return false;
       }
-      intptr_t offset = StackFrame::PcAddressOffsetFromSp();
-      uword pc = *(reinterpret_cast<uword*>(sp_ + offset));
+      const uword pc = *(reinterpret_cast<uword*>(
+          sp_ + (kSavedPcSlotFromSp * kWordSize)));
       return !StubCode::InInvocationStub(pc);
     }
 
diff --git a/runtime/vm/stack_frame_arm.cc b/runtime/vm/stack_frame_arm.cc
deleted file mode 100644
index e3ea537..0000000
--- a/runtime/vm/stack_frame_arm.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/globals.h"
-#if defined(TARGET_ARCH_ARM)
-
-#include "vm/instructions.h"
-#include "vm/isolate.h"
-#include "vm/stack_frame.h"
-
-namespace dart {
-
-// The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
-// code in the InvokeDartCode stub.
-static const int kSavedContextOffsetInEntryFrame = -10 * kWordSize;
-static const int kExitLinkOffsetInEntryFrame = -9 * kWordSize;
-static const int kPcAddressOffsetFromSp = -2 * kWordSize;
-static const int kEntrypointMarkerOffsetFromFp = 2 * kWordSize;
-static const int kSpOffsetFromPreviousFp = 3 * kWordSize;
-
-
-intptr_t StackFrame::PcAddressOffsetFromSp() {
-  return kPcAddressOffsetFromSp;
-}
-
-
-intptr_t StackFrame::EntrypointMarkerOffsetFromFp() {
-  return kEntrypointMarkerOffsetFromFp;
-}
-
-
-uword StackFrame::GetCallerSp() const {
-  return fp() + kSpOffsetFromPreviousFp;
-}
-
-
-uword StackFrame::GetCallerFp() const {
-  return *(reinterpret_cast<uword*>(fp()));
-}
-
-
-intptr_t EntryFrame::ExitLinkOffset() const {
-  return kExitLinkOffsetInEntryFrame;
-}
-
-
-intptr_t EntryFrame::SavedContextOffset() const {
-  return kSavedContextOffsetInEntryFrame;
-}
-
-
-void StackFrameIterator::SetupLastExitFrameData() {
-  Isolate* current = Isolate::Current();
-  uword exit_marker = current->top_exit_frame_info();
-  frames_.fp_ = exit_marker;
-}
-
-
-void StackFrameIterator::SetupNextExitFrameData() {
-  uword exit_address = entry_.fp() + kExitLinkOffsetInEntryFrame;
-  uword exit_marker = *reinterpret_cast<uword*>(exit_address);
-  frames_.fp_ = exit_marker;
-  frames_.sp_ = 0;
-}
-
-}  // namespace dart
-
-#endif  // defined(TARGET_ARCH_ARM)
diff --git a/runtime/vm/stack_frame_arm.h b/runtime/vm/stack_frame_arm.h
index 433830f..ae669bf 100644
--- a/runtime/vm/stack_frame_arm.h
+++ b/runtime/vm/stack_frame_arm.h
@@ -9,25 +9,32 @@
 
 /* ARM Dart Frame Layout
 
-               |                   | <- TOS
-Callee frame   | ...               |
-               | current LR        |    (PC of current frame)
-               | PC Marker         |    (callee's frame code entry)
-               +-------------------+
-Current frame  | ...               | <- SP of current frame
-               | first local       |
-               | caller's PP       |
-               | caller's FP       | <- FP of current frame
-               | caller's LR       |    (PC of caller frame)
-               | PC Marker         |    (current frame's code entry)
-               +-------------------+
-Caller frame   | last parameter    |
-               |  ...              |
+               |                    | <- TOS
+Callee frame   | ...                |
+               | current LR         |    (PC of current frame)
+               | callee's PC marker |
+               +--------------------+
+Current frame  | ...                | <- SP of current frame
+               | first local        |
+               | caller's PP        |
+               | caller's FP        | <- FP of current frame
+               | caller's LR        |    (PC of caller frame)
+               | PC marker          |    (current frame's code entry + offset)
+               +--------------------+
+Caller frame   | last parameter     | <- SP of caller frame
+               |  ...               |
 */
 
-static const int kLastParamSlotIndex = 3;  // From fp.
-static const int kFirstLocalSlotIndex = -2;  // From fp.
-static const int kPcSlotIndexFromSp = -2;
+static const int kSavedPcSlotFromSp = -2;
+static const int kFirstLocalSlotFromFp = -2;
+static const int kSavedCallerFpSlotFromFp = 0;
+static const int kPcMarkerSlotFromFp = 2;
+static const int kParamEndSlotFromFp = 2;  // Same slot as current pc marker.
+static const int kCallerSpSlotFromFp = 3;
+
+// Entry and exit frame layout.
+static const int kSavedContextSlotFromEntryFp = -10;
+static const int kExitLinkSlotFromEntryFp = -9;
 
 }  // namespace dart
 
diff --git a/runtime/vm/stack_frame_ia32.cc b/runtime/vm/stack_frame_ia32.cc
deleted file mode 100644
index ae4de47..0000000
--- a/runtime/vm/stack_frame_ia32.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/globals.h"
-#if defined(TARGET_ARCH_IA32)
-
-#include "vm/instructions.h"
-#include "vm/isolate.h"
-#include "vm/stack_frame.h"
-
-namespace dart {
-
-// The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
-// code in the InvokeDartCode stub.
-static const int kSavedContextOffsetInEntryFrame = -5 * kWordSize;
-static const int kExitLinkOffsetInEntryFrame = -4 * kWordSize;
-static const int kPcAddressOffsetFromSp = -1 * kWordSize;
-static const int kEntrypointMarkerOffsetFromFp = -1 * kWordSize;
-static const int kSpOffsetFromPreviousFp = 2 * kWordSize;
-
-
-intptr_t StackFrame::PcAddressOffsetFromSp() {
-  return kPcAddressOffsetFromSp;
-}
-
-
-intptr_t StackFrame::EntrypointMarkerOffsetFromFp() {
-  return kEntrypointMarkerOffsetFromFp;
-}
-
-
-uword StackFrame::GetCallerSp() const {
-  return fp() + kSpOffsetFromPreviousFp;
-}
-
-
-uword StackFrame::GetCallerFp() const {
-  return *(reinterpret_cast<uword*>(fp()));
-}
-
-
-intptr_t EntryFrame::ExitLinkOffset() const {
-  return kExitLinkOffsetInEntryFrame;
-}
-
-
-intptr_t EntryFrame::SavedContextOffset() const {
-  return kSavedContextOffsetInEntryFrame;
-}
-
-
-void StackFrameIterator::SetupLastExitFrameData() {
-  Isolate* current = Isolate::Current();
-  uword exit_marker = current->top_exit_frame_info();
-  frames_.fp_ = exit_marker;
-}
-
-
-void StackFrameIterator::SetupNextExitFrameData() {
-  uword exit_address = entry_.fp() + kExitLinkOffsetInEntryFrame;
-  uword exit_marker = *reinterpret_cast<uword*>(exit_address);
-  frames_.fp_ = exit_marker;
-  frames_.sp_ = 0;
-}
-
-}  // namespace dart
-
-#endif  // defined TARGET_ARCH_IA32
diff --git a/runtime/vm/stack_frame_ia32.h b/runtime/vm/stack_frame_ia32.h
index 46bdfd5..10db2aa 100644
--- a/runtime/vm/stack_frame_ia32.h
+++ b/runtime/vm/stack_frame_ia32.h
@@ -9,23 +9,30 @@
 
 /* IA32 Dart Frame Layout
 
-               |                   | <- TOS
-Callee frame   | ...               |
-               | current ret addr  |    (PC of current frame)
-               +-------------------+
-Current frame  | ...               | <- ESP of current frame
-               | first local       |
-               | PC Marker         |    (current frame's code entry)
-               | caller's EBP      | <- EBP of current frame
-               | caller's ret addr |    (PC of caller frame)
-               +-------------------+
-Caller frame   | last parameter    |
-               |  ...              |
+               |                    | <- TOS
+Callee frame   | ...                |
+               | current ret addr   |    (PC of current frame)
+               +--------------------+
+Current frame  | ...                | <- ESP of current frame
+               | first local        |
+               | PC marker          |    (current frame's code entry + offset)
+               | caller's EBP       | <- EBP of current frame
+               | caller's ret addr  |    (PC of caller frame)
+               +--------------------+
+Caller frame   | last parameter     | <- ESP of caller frame
+               |  ...               |
 */
 
-static const int kLastParamSlotIndex = 2;  // From fp.
-static const int kFirstLocalSlotIndex = -2;  // From fp.
-static const int kPcSlotIndexFromSp = -1;
+static const int kSavedPcSlotFromSp = -1;
+static const int kFirstLocalSlotFromFp = -2;
+static const int kPcMarkerSlotFromFp = -1;
+static const int kSavedCallerFpSlotFromFp = 0;
+static const int kParamEndSlotFromFp = 1;  // Same slot as caller's ret addr.
+static const int kCallerSpSlotFromFp = 2;
+
+// Entry and exit frame layout.
+static const int kSavedContextSlotFromEntryFp = -5;
+static const int kExitLinkSlotFromEntryFp = -4;
 
 }  // namespace dart
 
diff --git a/runtime/vm/stack_frame_mips.cc b/runtime/vm/stack_frame_mips.cc
deleted file mode 100644
index d713b1c..0000000
--- a/runtime/vm/stack_frame_mips.cc
+++ /dev/null
@@ -1,67 +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.
-
-#include "vm/globals.h"
-#if defined(TARGET_ARCH_MIPS)
-
-#include "vm/stack_frame.h"
-
-namespace dart {
-
-// The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
-// code in the InvokeDartCode stub.
-static const int kSavedContextOffsetInEntryFrame = -11 * kWordSize;
-static const int kExitLinkOffsetInEntryFrame = -10 * kWordSize;
-static const int kPcAddressOffsetFromSp = -2 * kWordSize;
-static const int kEntrypointMarkerOffsetFromFp = 2 * kWordSize;
-static const int kSpOffsetFromPreviousFp = 3 * kWordSize;
-
-
-intptr_t StackFrame::PcAddressOffsetFromSp() {
-  return kPcAddressOffsetFromSp;
-}
-
-
-intptr_t StackFrame::EntrypointMarkerOffsetFromFp() {
-  return kEntrypointMarkerOffsetFromFp;
-}
-
-
-uword StackFrame::GetCallerFp() const {
-  return *(reinterpret_cast<uword*>(fp()));
-}
-
-
-uword StackFrame::GetCallerSp() const {
-  return fp() + kSpOffsetFromPreviousFp;
-}
-
-
-intptr_t EntryFrame::ExitLinkOffset() const {
-  return kExitLinkOffsetInEntryFrame;
-}
-
-
-intptr_t EntryFrame::SavedContextOffset() const {
-  return kSavedContextOffsetInEntryFrame;
-}
-
-
-void StackFrameIterator::SetupLastExitFrameData() {
-  Isolate* current = Isolate::Current();
-  uword exit_marker = current->top_exit_frame_info();
-  frames_.fp_ = exit_marker;
-}
-
-
-void StackFrameIterator::SetupNextExitFrameData() {
-  uword exit_address = entry_.fp() + kExitLinkOffsetInEntryFrame;
-  uword exit_marker = *reinterpret_cast<uword*>(exit_address);
-  frames_.fp_ = exit_marker;
-  frames_.sp_ = 0;
-}
-
-}  // namespace dart
-
-#endif  // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/stack_frame_mips.h b/runtime/vm/stack_frame_mips.h
index 8a32a38..57e387e 100644
--- a/runtime/vm/stack_frame_mips.h
+++ b/runtime/vm/stack_frame_mips.h
@@ -9,25 +9,32 @@
 
 /* MIPS Dart Frame Layout
 
-               |                   | <- TOS
-Callee frame   | ...               |
-               | current RA        |    (PC of current frame)
-               | PC Marker         |    (callee's frame code entry)
-               +-------------------+
-Current frame  | ...               | <- SP of current frame
-               | first local       |
-               | caller's PP       |
-               | caller's FP       | <- FP of current frame
-               | caller's RA       |    (PC of caller frame)
-               | PC Marker         |    (current frame's code entry)
-               +-------------------+
-Caller frame   | last parameter    |
-               |  ...              |
+               |                    | <- TOS
+Callee frame   | ...                |
+               | current RA         |    (PC of current frame)
+               | callee's PC marker |
+               +--------------------+
+Current frame  | ...                | <- SP of current frame
+               | first local        |
+               | caller's PP        |
+               | caller's FP        | <- FP of current frame
+               | caller's RA        |    (PC of caller frame)
+               | PC marker          |    (current frame's code entry + offset)
+               +--------------------+
+Caller frame   | last parameter     | <- SP of caller frame
+               |  ...               |
 */
 
-static const int kLastParamSlotIndex = 3;  // From fp.
-static const int kFirstLocalSlotIndex = -2;  // From fp.
-static const int kPcSlotIndexFromSp = -2;
+static const int kSavedPcSlotFromSp = -2;
+static const int kFirstLocalSlotFromFp = -2;
+static const int kSavedCallerFpSlotFromFp = 0;
+static const int kPcMarkerSlotFromFp = 2;
+static const int kParamEndSlotFromFp = 2;  // Same slot as current pc marker.
+static const int kCallerSpSlotFromFp = 3;
+
+// Entry and exit frame layout.
+static const int kSavedContextSlotFromEntryFp = -11;
+static const int kExitLinkSlotFromEntryFp = -10;
 
 }  // namespace dart
 
diff --git a/runtime/vm/stack_frame_x64.cc b/runtime/vm/stack_frame_x64.cc
deleted file mode 100644
index 64ff644..0000000
--- a/runtime/vm/stack_frame_x64.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/globals.h"
-#if defined(TARGET_ARCH_X64)
-
-#include "vm/instructions.h"
-#include "vm/isolate.h"
-#include "vm/stack_frame.h"
-
-namespace dart {
-
-// The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
-// code in the InvokeDartCode stub.
-static const int kSavedContextOffsetInEntryFrame = -9 * kWordSize;
-static const int kExitLinkOffsetInEntryFrame = -8 * kWordSize;
-static const int kPcAddressOffsetFromSp = -1 * kWordSize;
-static const int kEntrypointMarkerOffsetFromFp = -1 * kWordSize;
-static const int kSpOffsetFromPreviousFp = 2 * kWordSize;
-
-
-intptr_t StackFrame::PcAddressOffsetFromSp() {
-  return kPcAddressOffsetFromSp;
-}
-
-
-intptr_t StackFrame::EntrypointMarkerOffsetFromFp() {
-  return kEntrypointMarkerOffsetFromFp;
-}
-
-
-uword StackFrame::GetCallerSp() const {
-  return fp() + kSpOffsetFromPreviousFp;
-}
-
-
-uword StackFrame::GetCallerFp() const {
-  return *(reinterpret_cast<uword*>(fp()));
-}
-
-
-intptr_t EntryFrame::ExitLinkOffset() const {
-  return kExitLinkOffsetInEntryFrame;
-}
-
-
-intptr_t EntryFrame::SavedContextOffset() const {
-  return kSavedContextOffsetInEntryFrame;
-}
-
-
-void StackFrameIterator::SetupLastExitFrameData() {
-  Isolate* current = Isolate::Current();
-  uword exit_marker = current->top_exit_frame_info();
-  frames_.fp_ = exit_marker;
-}
-
-
-void StackFrameIterator::SetupNextExitFrameData() {
-  uword exit_address = entry_.fp() + kExitLinkOffsetInEntryFrame;
-  uword exit_marker = *reinterpret_cast<uword*>(exit_address);
-  frames_.fp_ = exit_marker;
-  frames_.sp_ = 0;
-}
-
-}  // namespace dart
-
-#endif  // defined TARGET_ARCH_X64
diff --git a/runtime/vm/stack_frame_x64.h b/runtime/vm/stack_frame_x64.h
index 084cd9e..552bd98 100644
--- a/runtime/vm/stack_frame_x64.h
+++ b/runtime/vm/stack_frame_x64.h
@@ -9,23 +9,30 @@
 
 /* X64 Dart Frame Layout
 
-               |                   | <- TOS
-Callee frame   | ...               |
-               | current ret addr  |    (PC of current frame)
-               +-------------------+
-Current frame  | ...               | <- RSP of current frame
-               | first local       |
-               | PC Marker         |    (current frame's code entry)
-               | caller's RBP      | <- RBP of current frame
-               | caller's ret addr |    (PC of caller frame)
-               +-------------------+
-Caller frame   | last parameter    |
-               |  ...              |
+               |                    | <- TOS
+Callee frame   | ...                |
+               | current ret addr   |    (PC of current frame)
+               +--------------------+
+Current frame  | ...                | <- RSP of current frame
+               | first local        |
+               | PC marker          |    (current frame's code entry + offset)
+               | caller's RBP       | <- RBP of current frame
+               | caller's ret addr  |    (PC of caller frame)
+               +--------------------+
+Caller frame   | last parameter     | <- RSP of caller frame
+               |  ...               |
 */
 
-static const int kLastParamSlotIndex = 2;  // From fp.
-static const int kFirstLocalSlotIndex = -2;  // From fp.
-static const int kPcSlotIndexFromSp = -1;
+static const int kSavedPcSlotFromSp = -1;
+static const int kFirstLocalSlotFromFp = -2;
+static const int kPcMarkerSlotFromFp = -1;
+static const int kSavedCallerFpSlotFromFp = 0;
+static const int kParamEndSlotFromFp = 1;  // Same slot as caller's ret addr.
+static const int kCallerSpSlotFromFp = 2;
+
+// Entry and exit frame layout.
+static const int kSavedContextSlotFromEntryFp = -9;
+static const int kExitLinkSlotFromEntryFp = -8;
 
 }  // namespace dart
 
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 39f6497..50fecc1 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -241,7 +241,7 @@
 
 // Input parameters:
 //   R2: smi-tagged argument count, may be zero.
-//   FP[kLastParamSlotIndex]: last argument.
+//   FP[kParamEndSlotFromFp + 1]: last argument.
 static void PushArgumentsArray(Assembler* assembler) {
   // Allocate array to store arguments of caller.
   __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
@@ -252,7 +252,7 @@
   // R2: smi-tagged argument count, may be zero (was preserved by the stub).
   __ Push(R0);  // Array is in R0 and on top of stack.
   __ add(R1, FP, ShifterOperand(R2, LSL, 1));
-  __ AddImmediate(R1, (kLastParamSlotIndex - 1) * kWordSize);
+  __ AddImmediate(R1, kParamEndSlotFromFp * kWordSize);
   __ AddImmediate(R3, R0, Array::data_offset() - kHeapObjectTag);
   // R1: address of first argument on stack.
   // R3: address of first argument in array.
@@ -279,7 +279,7 @@
   // Load the receiver.
   __ ldr(R2, FieldAddress(R4, ArgumentsDescriptor::count_offset()));
   __ add(IP, FP, ShifterOperand(R2, LSL, 1));  // R2 is Smi.
-  __ ldr(R6, Address(IP, (kLastParamSlotIndex - 1) * kWordSize));
+  __ ldr(R6, Address(IP, kParamEndSlotFromFp * kWordSize));
 
   // Push space for the return value.
   // Push the receiver.
@@ -394,11 +394,17 @@
   if (preserve_result) {
     __ Push(R1);  // Preserve result, it will be GC-d here.
   }
-  __ CallRuntime(kDeoptimizeMaterializeDoublesRuntimeEntry);
+  __ PushObject(Smi::ZoneHandle());  // Space for the result.
+  __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry);
+  // Result tells stub how many bytes to remove from the expression stack
+  // of the bottom-most frame. They were used as materialization arguments.
+  __ Pop(R1);
   if (preserve_result) {
     __ Pop(R0);  // Restore result.
   }
   __ LeaveStubFrame();
+  // Remove materialization arguments.
+  __ add(SP, SP, ShifterOperand(R1, ASR, kSmiTagSize));
   __ Ret();
 }
 
@@ -692,16 +698,18 @@
   // Save the old Context pointer. Use R4 as a temporary register.
   // Note that VisitObjectPointers will find this saved Context pointer during
   // GC marking, since it traverses any information between SP and
-  // FP - kExitLinkOffsetInEntryFrame.
+  // FP - kExitLinkSlotFromEntryFp.
   // EntryFrame::SavedContext reads the context saved in this frame.
   __ LoadFromOffset(kLoadWord, R4, R8, Isolate::top_context_offset());
 
-  // The constants kSavedContextOffsetInEntryFrame and
-  // kExitLinkOffsetInEntryFrame must be kept in sync with the code below.
+  // The constants kSavedContextSlotFromEntryFp and
+  // kExitLinkSlotFromEntryFp must be kept in sync with the code below.
+  ASSERT(kExitLinkSlotFromEntryFp == -9);
+  ASSERT(kSavedContextSlotFromEntryFp == -10);
   __ PushList((1 << R4) | (1 << R5));
 
   // The stack pointer is restored after the call to this location.
-  const intptr_t kSavedContextOffsetInEntryFrame = -10 * kWordSize;
+  const intptr_t kSavedContextSlotFromEntryFp = -10 * kWordSize;
 
   // Load arguments descriptor array into R4, which is passed to Dart code.
   __ ldr(R4, Address(R1, VMHandles::kOffsetOfRawPtrInHandle));
@@ -737,7 +745,7 @@
   __ ldr(CTX, Address(CTX, VMHandles::kOffsetOfRawPtrInHandle));
 
   // Get rid of arguments pushed on the stack.
-  __ AddImmediate(SP, FP, kSavedContextOffsetInEntryFrame);
+  __ AddImmediate(SP, FP, kSavedContextSlotFromEntryFp);
 
   // Load Isolate pointer from Context structure into CTX. Drop Context.
   __ ldr(CTX, FieldAddress(CTX, Context::isolate_offset()));
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 0af074b..7c22076 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -14,6 +14,7 @@
 #include "vm/object_store.h"
 #include "vm/resolver.h"
 #include "vm/scavenger.h"
+#include "vm/stack_frame.h"
 #include "vm/stub_code.h"
 
 
@@ -394,11 +395,20 @@
   if (preserve_eax) {
     __ pushl(EBX);  // Preserve result, it will be GC-d here.
   }
-  __ CallRuntime(kDeoptimizeMaterializeDoublesRuntimeEntry);
+  __ pushl(Immediate(Smi::RawValue(0)));  // Space for the result.
+  __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry);
+  // Result tells stub how many bytes to remove from the expression stack
+  // of the bottom-most frame. They were used as materialization arguments.
+  __ popl(EBX);
+  __ SmiUntag(EBX);
   if (preserve_eax) {
     __ popl(EAX);  // Restore result.
   }
   __ LeaveFrame();
+
+  __ popl(ECX);  // Pop return address.
+  __ addl(ESP, EBX);  // Remove materialization arguments.
+  __ pushl(ECX);  // Push return address.
   __ ret();
 }
 
@@ -741,8 +751,9 @@
 
   // Save the top exit frame info. Use EDX as a temporary register.
   // StackFrameIterator reads the top exit frame info saved in this frame.
-  // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
-  // code below: kExitLinkOffsetInEntryFrame = -4 * kWordSize.
+  // The constant kExitLinkSlotFromEntryFp must be kept in sync with the
+  // code below.
+  ASSERT(kExitLinkSlotFromEntryFp == -4);
   __ movl(EDX, Address(EDI, Isolate::top_exit_frame_info_offset()));
   __ pushl(EDX);
   __ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), Immediate(0));
@@ -750,10 +761,11 @@
   // Save the old Context pointer. Use ECX as a temporary register.
   // Note that VisitObjectPointers will find this saved Context pointer during
   // GC marking, since it traverses any information between SP and
-  // FP - kExitLinkOffsetInEntryFrame.
+  // FP - kExitLinkSlotFromEntryFp.
   // EntryFrame::SavedContext reads the context saved in this frame.
-  // The constant kSavedContextOffsetInEntryFrame must be kept in sync with
-  // the code below: kSavedContextOffsetInEntryFrame = -5 * kWordSize.
+  // The constant kSavedContextSlotFromEntryFp must be kept in sync with
+  // the code below.
+  ASSERT(kSavedContextSlotFromEntryFp == -5);
   __ movl(ECX, Address(EDI, Isolate::top_context_offset()));
   __ pushl(ECX);
 
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 10f55d7..b85e0bc 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -261,7 +261,7 @@
 
 // Input parameters:
 //   A1: Smi-tagged argument count, may be zero.
-//   FP[kLastParamSlotIndex]: Last argument.
+//   FP[kParamEndSlotFromFp + 1]: Last argument.
 static void PushArgumentsArray(Assembler* assembler) {
   __ TraceSimMsg("PushArgumentsArray");
   // Allocate array to store arguments of caller.
@@ -275,7 +275,7 @@
   __ Push(V0);  // Array is in V0 and on top of stack.
   __ sll(T1, A1, 1);
   __ addu(T1, FP, T1);
-  __ AddImmediate(T1, (kLastParamSlotIndex - 1) * kWordSize);
+  __ AddImmediate(T1, kParamEndSlotFromFp * kWordSize);
   // T1: address of first argument on stack.
   // T2: address of first argument in array.
 
@@ -308,7 +308,7 @@
   __ lw(A1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
   __ sll(TMP1, A1, 1);  // A1 is Smi.
   __ addu(TMP1, FP, TMP1);
-  __ lw(T1, Address(TMP1, (kLastParamSlotIndex - 1) * kWordSize));
+  __ lw(T1, Address(TMP1, kParamEndSlotFromFp * kWordSize));
 
   // Push space for the return value.
   // Push the receiver.
@@ -451,12 +451,20 @@
   if (preserve_result) {
     __ Push(T1);  // Preserve result, it will be GC-d here.
   }
-  __ CallRuntime(kDeoptimizeMaterializeDoublesRuntimeEntry);
+  __ PushObject(Smi::ZoneHandle());  // Space for the result.
+  __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry);
+  // Result tells stub how many bytes to remove from the expression stack
+  // of the bottom-most frame. They were used as materialization arguments.
+  __ Pop(T1);
+  __ SmiUntag(T1);
   if (preserve_result) {
     __ Pop(V0);  // Restore result.
   }
+  __ LeaveStubFrame();
 
-  __ LeaveStubFrameAndReturn();
+  // Return.
+  __ jr(RA);
+  __ delay_slot()->addu(SP, SP, T1);  // Remove materialization arguments.
 }
 
 
@@ -773,18 +781,19 @@
   // Save the old Context pointer. Use T1 as a temporary register.
   // Note that VisitObjectPointers will find this saved Context pointer during
   // GC marking, since it traverses any information between SP and
-  // FP - kExitLinkOffsetInEntryFrame.
+  // FP - kExitLinkSlotFromEntryFp.
   // EntryFrame::SavedContext reads the context saved in this frame.
   __ lw(T1, Address(T2, Isolate::top_context_offset()));
 
-  // The constants kSavedContextOffsetInEntryFrame and
-  // kExitLinkOffsetInEntryFrame must be kept in sync with the code below.
+  // The constants kSavedContextSlotFromEntryFp and
+  // kExitLinkSlotFromEntryFp must be kept in sync with the code below.
+  ASSERT(kExitLinkSlotFromEntryFp == -10);
+  ASSERT(kSavedContextSlotFromEntryFp == -11);
   __ sw(T0, Address(SP, 1 * kWordSize));
   __ sw(T1, Address(SP, 0 * kWordSize));
 
   // After the call, The stack pointer is restored to this location.
   // Pushed A3, S0-7, T0, T1 = 11.
-  const intptr_t kSavedContextOffsetInEntryFrame = -11 * kWordSize;
 
   // Load arguments descriptor array into S4, which is passed to Dart code.
   __ lw(S4, Address(A1, VMHandles::kOffsetOfRawPtrInHandle));
@@ -824,7 +833,7 @@
   __ lw(CTX, Address(CTX, VMHandles::kOffsetOfRawPtrInHandle));
 
   // Get rid of arguments pushed on the stack.
-  __ AddImmediate(SP, FP, kSavedContextOffsetInEntryFrame);
+  __ AddImmediate(SP, FP, kSavedContextSlotFromEntryFp * kWordSize);
 
   // Load Isolate pointer from Context structure into CTX. Drop Context.
   __ lw(CTX, FieldAddress(CTX, Context::isolate_offset()));
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 1654efb..3db3c7e 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -14,6 +14,7 @@
 #include "vm/object_store.h"
 #include "vm/resolver.h"
 #include "vm/scavenger.h"
+#include "vm/stack_frame.h"
 #include "vm/stub_code.h"
 
 
@@ -387,12 +388,20 @@
   if (preserve_rax) {
     __ pushq(RBX);  // Preserve result, it will be GC-d here.
   }
-  __ CallRuntime(kDeoptimizeMaterializeDoublesRuntimeEntry);
+  __ pushq(Immediate(Smi::RawValue(0)));  // Space for the result.
+  __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry);
+  // Result tells stub how many bytes to remove from the expression stack
+  // of the bottom-most frame. They were used as materialization arguments.
+  __ popq(RBX);
+  __ SmiUntag(RBX);
   if (preserve_rax) {
     __ popq(RAX);  // Restore result.
   }
   __ LeaveFrame();
 
+  __ popq(RCX);  // Pop return address.
+  __ addq(RSP, RBX);  // Remove materialization arguments.
+  __ pushq(RCX);  // Push return address.
   __ ret();
 }
 
@@ -729,8 +738,9 @@
 
   // Save the top exit frame info. Use RAX as a temporary register.
   // StackFrameIterator reads the top exit frame info saved in this frame.
-  // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
-  // code below: kExitLinkOffsetInEntryFrame = -8 * kWordSize.
+  // The constant kExitLinkSlotFromEntryFp must be kept in sync with the
+  // code below.
+  ASSERT(kExitLinkSlotFromEntryFp == -8);
   __ movq(RAX, Address(R8, Isolate::top_exit_frame_info_offset()));
   __ pushq(RAX);
   __ movq(Address(R8, Isolate::top_exit_frame_info_offset()), Immediate(0));
@@ -738,10 +748,11 @@
   // Save the old Context pointer. Use RAX as a temporary register.
   // Note that VisitObjectPointers will find this saved Context pointer during
   // GC marking, since it traverses any information between SP and
-  // FP - kExitLinkOffsetInEntryFrame.
+  // FP - kExitLinkSlotFromEntryFp * kWordSize.
   // EntryFrame::SavedContext reads the context saved in this frame.
-  // The constant kSavedContextOffsetInEntryFrame must be kept in sync with
-  // the code below: kSavedContextOffsetInEntryFrame = -9 * kWordSize.
+  // The constant kSavedContextSlotFromEntryFp must be kept in sync with
+  // the code below.
+  ASSERT(kSavedContextSlotFromEntryFp == -9);
   __ movq(RAX, Address(R8, Isolate::top_context_offset()));
   __ pushq(RAX);
 
diff --git a/runtime/vm/version.h b/runtime/vm/version.h
index dee350b..bcc0876 100644
--- a/runtime/vm/version.h
+++ b/runtime/vm/version.h
@@ -11,7 +11,7 @@
 
 class Version : public AllStatic {
  public:
-  static const char* String() { return str_; }
+  static const char* String();
 
  private:
   static const char* str_;
diff --git a/runtime/vm/version_in.cc b/runtime/vm/version_in.cc
index d479d9f..5e40516 100644
--- a/runtime/vm/version_in.cc
+++ b/runtime/vm/version_in.cc
@@ -4,8 +4,28 @@
 
 #include "vm/version.h"
 
+#include "vm/cpu.h"
+#include "vm/os.h"
+
 namespace dart {
 
+// TODO(iposva): Avoid racy initialization.
+static const char* formatted_version = NULL;
+
+const char* Version::String() {
+  if (formatted_version == NULL) {
+    const char* format = "%s on \"%s_%s\"";
+    const char* os = OS::Name();
+    const char* arch = CPU::Id();
+
+    intptr_t len = OS::SNPrint(NULL, 0, format, str_, os, arch);
+    char* buffer = reinterpret_cast<char*>(malloc(len + 1));
+    OS::SNPrint(buffer, (len + 1), format, str_, os, arch);
+    formatted_version = buffer;
+  }
+  return formatted_version;
+}
+
 const char* Version::str_ = "{{VERSION_STR}} ({{BUILD_TIME}})";
 
 }  // namespace dart
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index a9fd7c2..9e073d1 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -274,8 +274,8 @@
         {
           'action_name': 'generate_corelib_patch_cc',
           'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
+            '../tools/gen_library_src_paths.py',
+            '<(libgen_in_cc_file)',
             '<@(_sources)',
           ],
           'outputs': [
@@ -283,11 +283,12 @@
           ],
           'action': [
             'python',
-            'tools/create_string_literal.py',
+            'tools/gen_library_src_paths.py',
             '--output', '<(corelib_patch_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
+            '--input_cc', '<(libgen_in_cc_file)',
             '--include', 'vm/bootstrap.h',
-            '--var_name', 'dart::Bootstrap::corelib_patch_',
+            '--var_name', 'dart::Bootstrap::corelib_patch_paths_',
+            '--library_name', 'dart:corelib',
             '<@(_sources)',
           ],
           'message': 'Generating ''<(corelib_patch_cc_file)'' file.'
@@ -353,8 +354,8 @@
         {
           'action_name': 'generate_collection_dev_patch_cc',
           'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
+            '../tools/gen_library_src_paths.py',
+            '<(libgen_in_cc_file)',
             '<@(_sources)',
           ],
           'outputs': [
@@ -362,11 +363,12 @@
           ],
           'action': [
             'python',
-            'tools/create_string_literal.py',
+            'tools/gen_library_src_paths.py',
             '--output', '<(collection_dev_patch_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
+            '--input_cc', '<(libgen_in_cc_file)',
             '--include', 'vm/bootstrap.h',
-            '--var_name', 'dart::Bootstrap::collection_dev_patch_',
+            '--var_name', 'dart::Bootstrap::collection_dev_patch_paths_',
+            '--library_name', 'dart:_collection-dev',
             '<@(_sources)',
           ],
           'message': 'Generating ''<(collection_dev_patch_cc_file)'' file.'
@@ -505,8 +507,8 @@
         {
           'action_name': 'generate_math_patch_cc',
           'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
+            '../tools/gen_library_src_paths.py',
+            '<(libgen_in_cc_file)',
             '<@(_sources)',
           ],
           'outputs': [
@@ -514,11 +516,12 @@
           ],
           'action': [
             'python',
-            'tools/create_string_literal.py',
+            'tools/gen_library_src_paths.py',
             '--output', '<(math_patch_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
+            '--input_cc', '<(libgen_in_cc_file)',
             '--include', 'vm/bootstrap.h',
-            '--var_name', 'dart::Bootstrap::math_patch_',
+            '--var_name', 'dart::Bootstrap::math_patch_paths_',
+            '--library_name', 'dart:math',
             '<@(_sources)',
           ],
           'message': 'Generating ''<(math_patch_cc_file)'' file.'
@@ -584,8 +587,8 @@
         {
           'action_name': 'generate_mirrors_patch_cc',
           'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
+            '../tools/gen_library_src_paths.py',
+            '<(libgen_in_cc_file)',
             '<@(_sources)',
           ],
           'outputs': [
@@ -593,11 +596,12 @@
           ],
           'action': [
             'python',
-            'tools/create_string_literal.py',
+            'tools/gen_library_src_paths.py',
             '--output', '<(mirrors_patch_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
+            '--input_cc', '<(libgen_in_cc_file)',
             '--include', 'vm/bootstrap.h',
-            '--var_name', 'dart::Bootstrap::mirrors_patch_',
+            '--var_name', 'dart::Bootstrap::mirrors_patch_paths_',
+            '--library_name', 'dart:mirrors',
             '<@(_sources)',
           ],
           'message': 'Generating ''<(mirrors_patch_cc_file)'' file.'
@@ -663,8 +667,8 @@
         {
           'action_name': 'generate_async_patch_cc',
           'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
+            '../tools/gen_library_src_paths.py',
+            '<(libgen_in_cc_file)',
             '<@(_sources)',
           ],
           'outputs': [
@@ -672,11 +676,12 @@
           ],
           'action': [
             'python',
-            'tools/create_string_literal.py',
+            'tools/gen_library_src_paths.py',
             '--output', '<(async_patch_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
+            '--input_cc', '<(libgen_in_cc_file)',
             '--include', 'vm/bootstrap.h',
-            '--var_name', 'dart::Bootstrap::async_patch_',
+            '--var_name', 'dart::Bootstrap::async_patch_paths_',
+            '--library_name', 'dart:async',
             '<@(_sources)',
           ],
           'message': 'Generating ''<(async_patch_cc_file)'' file.'
@@ -702,8 +707,8 @@
         {
           'action_name': 'generate_collection_patch_cc',
           'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
+            '../tools/gen_library_src_paths.py',
+            '<(libgen_in_cc_file)',
             '<@(_sources)',
           ],
           'outputs': [
@@ -711,11 +716,12 @@
           ],
           'action': [
             'python',
-            'tools/create_string_literal.py',
+            'tools/gen_library_src_paths.py',
             '--output', '<(collection_patch_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
+            '--input_cc', '<(libgen_in_cc_file)',
             '--include', 'vm/bootstrap.h',
-            '--var_name', 'dart::Bootstrap::collection_patch_',
+            '--var_name', 'dart::Bootstrap::collection_patch_paths_',
+            '--library_name', 'dart:collection',
             '<@(_sources)',
           ],
           'message': 'Generating ''<(collection_patch_cc_file)'' file.'
@@ -741,8 +747,8 @@
         {
           'action_name': 'generate_isolate_patch_cc',
           'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
+            '../tools/gen_library_src_paths.py',
+            '<(libgen_in_cc_file)',
             '<@(_sources)',
           ],
           'outputs': [
@@ -750,11 +756,12 @@
           ],
           'action': [
             'python',
-            'tools/create_string_literal.py',
+            'tools/gen_library_src_paths.py',
             '--output', '<(isolate_patch_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
+            '--input_cc', '<(libgen_in_cc_file)',
             '--include', 'vm/bootstrap.h',
-            '--var_name', 'dart::Bootstrap::isolate_patch_',
+            '--var_name', 'dart::Bootstrap::isolate_patch_paths_',
+            '--library_name', 'dart:isolate',
             '<@(_sources)',
           ],
           'message': 'Generating ''<(isolate_patch_cc_file)'' file.'
@@ -813,8 +820,8 @@
         {
           'action_name': 'generate_json_patch_cc',
           'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
+            '../tools/gen_library_src_paths.py',
+            '<(libgen_in_cc_file)',
             '<@(_sources)',
           ],
           'outputs': [
@@ -822,11 +829,12 @@
           ],
           'action': [
             'python',
-            'tools/create_string_literal.py',
+            'tools/gen_library_src_paths.py',
             '--output', '<(json_patch_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
+            '--input_cc', '<(libgen_in_cc_file)',
             '--include', 'vm/bootstrap.h',
-            '--var_name', 'dart::Bootstrap::json_patch_',
+            '--var_name', 'dart::Bootstrap::json_patch_paths_',
+            '--library_name', 'dart:json',
             '<@(_sources)',
           ],
           'message': 'Generating ''<(json_patch_cc_file)'' file.'
@@ -892,8 +900,8 @@
         {
           'action_name': 'generate_typed_data_patch_cc',
           'inputs': [
-            '../tools/create_string_literal.py',
-            '<(builtin_in_cc_file)',
+            '../tools/gen_library_src_paths.py',
+            '<(libgen_in_cc_file)',
             '<@(_sources)',
           ],
           'outputs': [
@@ -901,11 +909,12 @@
           ],
           'action': [
             'python',
-            'tools/create_string_literal.py',
+            'tools/gen_library_src_paths.py',
             '--output', '<(typed_data_patch_cc_file)',
-            '--input_cc', '<(builtin_in_cc_file)',
+            '--input_cc', '<(libgen_in_cc_file)',
             '--include', 'vm/bootstrap.h',
-            '--var_name', 'dart::Bootstrap::typed_data_patch_',
+            '--var_name', 'dart::Bootstrap::typed_data_patch_paths_',
+            '--library_name', 'dart:typed_data',
             '<@(_sources)',
           ],
           'message': 'Generating ''<(typed_data_patch_cc_file)'' file.'
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 48f3892..6c68fba 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -286,14 +286,10 @@
     'snapshot_test.cc',
     'stack_frame.cc',
     'stack_frame.h',
-    'stack_frame_arm.cc',
     'stack_frame_arm.h',
-    'stack_frame_ia32.cc',
     'stack_frame_ia32.h',
-    'stack_frame_mips.cc',
     'stack_frame_mips.h',
     'stack_frame_test.cc',
-    'stack_frame_x64.cc',
     'stack_frame_x64.h',
     'store_buffer.cc',
     'store_buffer.h',
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart
index 48fa3b3..b9b83e2 100644
--- a/sdk/lib/_internal/compiler/implementation/closure.dart
+++ b/sdk/lib/_internal/compiler/implementation/closure.dart
@@ -585,22 +585,25 @@
     Link<String> parts = const Link<String>();
     SourceString ownName = element.name;
     if (ownName == null || ownName.stringValue == "") {
-      parts = parts.prepend("anon");
+      parts = parts.prepend("closure");
     } else {
       parts = parts.prepend(ownName.slowToString());
     }
     for (Element enclosingElement = element.enclosingElement;
          enclosingElement != null &&
-             (identical(enclosingElement.kind,
-                        ElementKind.GENERATIVE_CONSTRUCTOR_BODY)
-              || identical(enclosingElement.kind, ElementKind.CLASS)
-              || identical(enclosingElement.kind, ElementKind.FUNCTION)
-              || identical(enclosingElement.kind, ElementKind.GETTER)
-              || identical(enclosingElement.kind, ElementKind.SETTER));
+             (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY
+              || enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR
+              || enclosingElement.kind == ElementKind.CLASS
+              || enclosingElement.kind == ElementKind.FUNCTION
+              || enclosingElement.kind == ElementKind.GETTER
+              || enclosingElement.kind == ElementKind.SETTER);
          enclosingElement = enclosingElement.enclosingElement) {
       SourceString surroundingName =
           Elements.operatorNameToIdentifier(enclosingElement.name);
       parts = parts.prepend(surroundingName.slowToString());
+      // A generative constructors's parent is the class; the class name is
+      // already part of the generative constructor's name.
+      if (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR) break;
     }
     StringBuffer sb = new StringBuffer();
     parts.printOn(sb, '_');
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 4253cb1..dffa694 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -387,14 +387,18 @@
   }
 
   void add(Element element, DiagnosticListener listener) {
+    SourceString name = element.name;
     if (element.isAccessor()) {
-      addAccessor(element, contents[element.name], listener);
+      addAccessor(element, contents[name], listener);
     } else {
-      Element existing = contents.putIfAbsent(element.name, () => element);
+      Element existing = contents.putIfAbsent(name, () => element);
       if (!identical(existing, element)) {
-        // TODO(ahe): Do something similar to Resolver.reportErrorWithContext.
-        listener.cancel('duplicate definition', token: element.position());
-        listener.cancel('existing definition', token: existing.position());
+        listener.reportErrorCode(element,
+            MessageKind.DUPLICATE_DEFINITION, {'name': name});
+        listener.reportMessage(
+            listener.spanFromSpannable(existing),
+            MessageKind.EXISTING_DEFINITION.error({'name': name}),
+            api.Diagnostic.INFO);
       }
     }
   }
diff --git a/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
index db10b54..cf639f2 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
@@ -614,7 +614,7 @@
   // TODO(sigmund): clean up above, after we make the new API the default:
 
   static spawn(String functionName, String uri, bool isLight) {
-    Completer<SendPort> completer = new Completer<SendPort>();
+    Completer<SendPort> completer = new Completer.sync<SendPort>();
     ReceivePort port = new ReceivePort();
     port.receive((msg, SendPort replyPort) {
       port.close();
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index 49cd0f9..7e1beaa 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -1757,7 +1757,12 @@
     if (doAddToScope) {
       Element existing = scope.add(element);
       if (existing != element) {
-        error(node, MessageKind.DUPLICATE_DEFINITION, {'name': node});
+        compiler.reportErrorCode(
+            node, MessageKind.DUPLICATE_DEFINITION, {'name': node});
+        compiler.reportMessage(
+            compiler.spanFromSpannable(existing),
+            MessageKind.EXISTING_DEFINITION.error({'name': node}),
+            Diagnostic.INFO);
       }
     }
     return element;
@@ -2130,18 +2135,25 @@
 
   void resolveArguments(NodeList list) {
     if (list == null) return;
-    List<SourceString> seenNamedArguments = <SourceString>[];
+    Map<SourceString, Node> seenNamedArguments = new Map<SourceString, Node>();
     for (Link<Node> link = list.nodes; !link.isEmpty; link = link.tail) {
       Expression argument = link.head;
       visit(argument);
       NamedArgument namedArgument = argument.asNamedArgument();
       if (namedArgument != null) {
         SourceString source = namedArgument.name.source;
-        if (seenNamedArguments.contains(source)) {
-          error(argument, MessageKind.DUPLICATE_DEFINITION,
-                {'name': source});
+        if (seenNamedArguments.containsKey(source)) {
+          compiler.reportErrorCode(
+              argument,
+              MessageKind.DUPLICATE_DEFINITION,
+              {'name': source});
+          compiler.reportMessage(
+              compiler.spanFromSpannable(seenNamedArguments[source]),
+              MessageKind.EXISTING_DEFINITION.error({'name': source}),
+              Diagnostic.INFO);
+        } else {
+          seenNamedArguments[source] = namedArgument;
         }
-        seenNamedArguments.add(source);
       } else if (!seenNamedArguments.isEmpty) {
         error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
       }
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index 00cdcce..189c326 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -55,7 +55,9 @@
   static const CANNOT_RESOLVE_TYPE = const MessageKind(
       'cannot resolve type #{typeName}');
   static const DUPLICATE_DEFINITION = const MessageKind(
-      'duplicate definition of #{name}');
+      "Error: Duplicate definition of '#{name}'.");
+  static const EXISTING_DEFINITION = const MessageKind(
+      "Info: Existing definition of '#{name}'.");
   static const DUPLICATE_IMPORT = const MessageKind(
       'duplicate import of #{name}');
   static const DUPLICATE_EXPORT = const MessageKind(
diff --git a/sdk/lib/_internal/pub/bin/pub.dart b/sdk/lib/_internal/pub/bin/pub.dart
index 0d6e72a..f3b8674 100644
--- a/sdk/lib/_internal/pub/bin/pub.dart
+++ b/sdk/lib/_internal/pub/bin/pub.dart
@@ -37,7 +37,7 @@
         'all':    'Show all output including internal tracing messages.'
       });
   parser.addFlag('verbose', abbr: 'v', negatable: false,
-      help: 'Shortcut for "--verbosity=all"');
+      help: 'Shortcut for "--verbosity=all".');
   return parser;
 }
 
@@ -91,8 +91,6 @@
   }
 
   validatePlatform().then((_) {
-    var cache = new SystemCache.withSources(cacheDir);
-
     // Select the command.
     var command = PubCommand.commands[globalOptions.rest[0]];
     if (command == null) {
@@ -103,7 +101,7 @@
     }
 
     var commandArgs = globalOptions.rest.sublist(1);
-    command.run(cache, globalOptions, commandArgs);
+    command.run(cacheDir, globalOptions, commandArgs);
   });
 }
 
diff --git a/sdk/lib/_internal/pub/lib/src/command.dart b/sdk/lib/_internal/pub/lib/src/command.dart
index 21ad9b6..fb0a842 100644
--- a/sdk/lib/_internal/pub/lib/src/command.dart
+++ b/sdk/lib/_internal/pub/lib/src/command.dart
@@ -69,9 +69,13 @@
   /// available in [commandOptions].
   ArgParser get commandParser => new ArgParser();
 
-  void run(SystemCache cache_, ArgResults globalOptions_,
+  /// Override this to use offline-only sources instead of hitting the network.
+  /// This will only be called before the [SystemCache] is created. After that,
+  /// it has no effect.
+  bool get isOffline => false;
+
+  void run(String cacheDir, ArgResults globalOptions_,
       List<String> commandArgs) {
-    cache = cache_;
     globalOptions = globalOptions_;
 
     try {
@@ -82,6 +86,8 @@
       exit(exit_codes.USAGE);
     }
 
+    cache = new SystemCache.withSources(cacheDir, isOffline: isOffline);
+
     handleError(error) {
       var trace = getAttachedStackTrace(error);
 
@@ -139,7 +145,7 @@
       if (commandFuture == null) return true;
 
       return commandFuture;
-    }).whenComplete(() => cache_.deleteTempDir()).catchError((e) {
+    }).whenComplete(() => cache.deleteTempDir()).catchError((e) {
       if (e is PubspecNotFoundException && e.name == null) {
         e = 'Could not find a file named "pubspec.yaml" in the directory '
           '${path.current}.';
diff --git a/sdk/lib/_internal/pub/lib/src/command_install.dart b/sdk/lib/_internal/pub/lib/src/command_install.dart
index d51b553..a57886f 100644
--- a/sdk/lib/_internal/pub/lib/src/command_install.dart
+++ b/sdk/lib/_internal/pub/lib/src/command_install.dart
@@ -6,6 +6,8 @@
 
 import 'dart:async';
 
+import 'package:args/args.dart';
+
 import 'command.dart';
 import 'entrypoint.dart';
 import 'log.dart' as log;
@@ -15,6 +17,14 @@
   String get description => "Install the current package's dependencies.";
   String get usage => "pub install";
 
+  ArgParser get commandParser {
+    return new ArgParser()
+        ..addFlag('offline',
+            help: 'Use cached packages instead of accessing the network.');
+  }
+
+  bool get isOffline => commandOptions['offline'];
+
   Future onRun() {
     return entrypoint.installDependencies()
         .then((_) => log.message("Dependencies installed!"));
diff --git a/sdk/lib/_internal/pub/lib/src/command_lish.dart b/sdk/lib/_internal/pub/lib/src/command_lish.dart
index cc03118..44a13ae 100644
--- a/sdk/lib/_internal/pub/lib/src/command_lish.dart
+++ b/sdk/lib/_internal/pub/lib/src/command_lish.dart
@@ -35,11 +35,11 @@
     // TODO(nweiz): Use HostedSource.defaultUrl as the default value once we use
     // dart:io for HTTPS requests.
     parser.addFlag('dry-run', abbr: 'n', negatable: false,
-        help: 'Validate but do not publish the package');
+        help: 'Validate but do not publish the package.');
     parser.addFlag('force', abbr: 'f', negatable: false,
-        help: 'Publish without confirmation if there are no errors');
+        help: 'Publish without confirmation if there are no errors.');
     parser.addOption('server', defaultsTo: 'https://pub.dartlang.org',
-        help: 'The package server to which to upload this package');
+        help: 'The package server to which to upload this package.');
     return parser;
   }
 
diff --git a/sdk/lib/_internal/pub/lib/src/command_update.dart b/sdk/lib/_internal/pub/lib/src/command_update.dart
index 147e925..707ac6f 100644
--- a/sdk/lib/_internal/pub/lib/src/command_update.dart
+++ b/sdk/lib/_internal/pub/lib/src/command_update.dart
@@ -6,6 +6,8 @@
 
 import 'dart:async';
 
+import 'package:args/args.dart';
+
 import 'command.dart';
 import 'entrypoint.dart';
 import 'log.dart' as log;
@@ -17,6 +19,14 @@
 
   String get usage => 'pub update [dependencies...]';
 
+  ArgParser get commandParser {
+    return new ArgParser()
+        ..addFlag('offline',
+            help: 'Use cached packages instead of accessing the network.');
+  }
+
+  bool get isOffline => commandOptions['offline'];
+
   Future onRun() {
     var future;
     if (commandOptions.rest.isEmpty) {
@@ -24,7 +34,13 @@
     } else {
       future = entrypoint.updateDependencies(commandOptions.rest);
     }
-    return future
-        .then((_) => log.message("Dependencies updated!"));
+
+    return future.then((_) {
+      log.message("Dependencies updated!");
+      if (isOffline) {
+        log.warning("Warning: Updating when offline may not update you to the "
+                    "latest versions of your dependencies.");
+      }
+    });
   }
 }
diff --git a/sdk/lib/_internal/pub/lib/src/command_uploader.dart b/sdk/lib/_internal/pub/lib/src/command_uploader.dart
index 958f298..4097fbd 100644
--- a/sdk/lib/_internal/pub/lib/src/command_uploader.dart
+++ b/sdk/lib/_internal/pub/lib/src/command_uploader.dart
@@ -31,9 +31,9 @@
     // TODO(nweiz): Use HostedSource.defaultUrl as the default value once we use
     // dart:io for HTTPS requests.
     parser.addOption('server', defaultsTo: 'https://pub.dartlang.org',
-        help: 'The package server on which the package is hosted');
+        help: 'The package server on which the package is hosted.');
     parser.addOption('package', help: 'The package whose uploaders will be '
-        'modified\n'
+        'modified.\n'
         '(defaults to the current package)');
     return parser;
   }
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
index e8fa70e..9341c9b 100644
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -171,18 +171,16 @@
         isSelfLink: true, relative: true);
   }
 
-  /// If `bin/`, `test/`, or `example/` directories exist, symlink `packages/`
-  /// into them so that their entrypoints can be run. Do the same for any
-  /// subdirectories of `test/` and `example/`.
+  /// Add "packages" directories to the whitelist of directories that may
+  /// contain Dart entrypoints.
   void _linkSecondaryPackageDirs() {
+    // Only the main "bin" directory gets a "packages" directory, not its
+    // subdirectories.
     var binDir = path.join(root.dir, 'bin');
-    var exampleDir = path.join(root.dir, 'example');
-    var testDir = path.join(root.dir, 'test');
-    var toolDir = path.join(root.dir, 'tool');
-    var webDir = path.join(root.dir, 'web');
-
     if (dirExists(binDir)) _linkSecondaryPackageDir(binDir);
-    for (var dir in ['example', 'test', 'tool', 'web']) {
+
+    // The others get "packages" directories in subdirectories too.
+    for (var dir in ['benchmark', 'example', 'test', 'tool', 'web']) {
       _linkSecondaryPackageDirsRecursively(path.join(root.dir, dir));
     }
  }
diff --git a/sdk/lib/_internal/pub/lib/src/hosted_source.dart b/sdk/lib/_internal/pub/lib/src/hosted_source.dart
index 1b4ecda..17b1839 100644
--- a/sdk/lib/_internal/pub/lib/src/hosted_source.dart
+++ b/sdk/lib/_internal/pub/lib/src/hosted_source.dart
@@ -98,13 +98,10 @@
   /// from that site.
   Future<String> systemCacheDirectory(PackageId id) {
     var parsed = _parseDescription(id.description);
-    var url = _getSourceDirectory(parsed.last);
-    var urlDir = replace(url, new RegExp(r'[<>:"\\/|?*%]'), (match) {
-      return '%${match[0].codeUnitAt(0)}';
-    });
+    var dir = _getSourceDirectory(parsed.last);
 
     return new Future.value(
-        path.join(systemCacheRoot, urlDir, "${parsed.first}-${id.version}"));
+        path.join(systemCacheRoot, dir, "${parsed.first}-${id.version}"));
   }
 
   String packageName(description) => _parseDescription(description).first;
@@ -123,19 +120,21 @@
     return description;
   }
 
-  List<Package> getCachedPackages() {
+  List<Package> getCachedPackages([String url]) {
+    if (url == null) url = _defaultUrl;
+
     var cacheDir = path.join(systemCacheRoot,
-                             _getSourceDirectory(_defaultUrl));
+                             _getSourceDirectory(url));
     if (!dirExists(cacheDir)) return [];
 
     return listDir(path.join(cacheDir)).map((entry) {
       // TODO(keertip): instead of catching exception in pubspec parse with
-      // sdk dependency, fix to parse and report usage of sdk dependency. 
+      // sdk dependency, fix to parse and report usage of sdk dependency.
       // dartbug.com/10190
       try {
         return new Package.load(null, entry, systemCache.sources);
       }  on ArgumentError catch (e) {
-        log.error(e);         
+        log.error(e);
       }
     }).where((package) => package != null).toList();
   }
@@ -161,14 +160,52 @@
     // Otherwise re-throw the original exception.
     throw error;
   }
+}
 
+/// This is the modified hosted source used when pub install or update are run
+/// with "--offline". This uses the system cache to get the list of available
+/// packages and does no network access.
+class OfflineHostedSource extends HostedSource {
+  /// Gets the list of all versions of [name] that are in the system cache.
+  Future<List<Version>> getVersions(String name, description) {
+    return new Future(() {
+      var parsed = _parseDescription(description);
+      var server = parsed.last;
+      log.io("Finding versions of $name in "
+             "${systemCache.rootDir}/${_getSourceDirectory(server)}");
+      return getCachedPackages(server)
+          .where((package) => package.name == name)
+          .map((package) => package.version)
+          .toList();
+    }).then((versions) {
+      // If there are no versions in the cache, report a clearer error.
+      if (versions.isEmpty) fail('Could not find package "$name" in cache.');
+
+      return versions;
+    });
+  }
+
+  Future<bool> install(PackageId id, String destPath) {
+    // Since HostedSource returns `true` for [shouldCache], install will only
+    // be called for uncached packages.
+    throw new UnsupportedError("Cannot install packages when offline.");
+  }
+
+  Future<Pubspec> describe(PackageId id) {
+    // [getVersions()] will only return packages that are already cached.
+    // SystemCache should only call [describe()] on a package after it has
+    // failed to find it in the cache, so this code should not be reached.
+    throw new UnsupportedError("Cannot describe packages when offline.");
+  }
 }
 
 /// The URL of the default package repository.
 final _defaultUrl = "https://pub.dartlang.org";
 
 String _getSourceDirectory(String url) {
-  return url.replaceAll(new RegExp(r"^https?://"), "");
+  url = url.replaceAll(new RegExp(r"^https?://"), "");
+  return replace(url, new RegExp(r'[<>:"\\/|?*%]'),
+      (match) => '%${match[0].codeUnitAt(0)}');
 }
 
 /// Parses [description] into its server and package name components, then
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index 1620837..46e5255 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -6,6 +6,7 @@
 library pub.io;
 
 import 'dart:async';
+import 'dart:collection';
 import 'dart:io';
 import 'dart:isolate';
 import 'dart:json';
@@ -40,6 +41,103 @@
 /// for a symlink only if that symlink is unbroken and points to a file.
 bool fileExists(String file) => new File(file).existsSync();
 
+/// Returns the canonical path for [pathString]. This is the normalized,
+/// absolute path, with symlinks resolved. As in [transitiveTarget], broken or
+/// recursive symlinks will not be fully resolved.
+///
+/// This doesn't require [pathString] to point to a path that exists on the
+/// filesystem; nonexistent or unreadable path entries are treated as normal
+/// directories.
+String canonicalize(String pathString) {
+  var seen = new Set<String>();
+  var components = new Queue<String>.from(
+      path.split(path.normalize(path.absolute(pathString))));
+
+  // The canonical path, built incrementally as we iterate through [components].
+  var newPath = components.removeFirst();
+
+  // Move through the components of the path, resolving each one's symlinks as
+  // necessary. A resolved component may also add new components that need to be
+  // resolved in turn.
+  while (!components.isEmpty) {
+    seen.add(path.join(newPath, path.joinAll(components)));
+    var resolvedPath = resolveLink(
+        path.join(newPath, components.removeFirst()));
+    var relative = path.relative(resolvedPath, from: newPath);
+
+    // If the resolved path of the component relative to `newPath` is just ".",
+    // that means component was a symlink pointing to its parent directory. We
+    // can safely ignore such components.
+    if (relative == '.') continue;
+
+    var relativeComponents = new Queue<String>.from(path.split(relative));
+
+    // If the resolved path is absolute relative to `newPath`, that means it's
+    // on a different drive. We need to canonicalize the entire target of that
+    // symlink again.
+    if (path.isAbsolute(relative)) {
+      // If we've already tried to canonicalize the new path, we've encountered
+      // a symlink loop. Avoid going infinite by treating the recursive symlink
+      // as the canonical path.
+      if (seen.contains(relative)) {
+        newPath = relative;
+      } else {
+        newPath = relativeComponents.removeFirst();
+        relativeComponents.addAll(components);
+        components = relativeComponents;
+      }
+      continue;
+    }
+
+    // Pop directories off `newPath` if the component links upwards in the
+    // directory hierarchy.
+    while (relativeComponents.first == '..') {
+      newPath = path.dirname(newPath);
+      relativeComponents.removeFirst();
+    }
+
+    // If there's only one component left, [resolveLink] guarantees that it's
+    // not a link (or is a broken link). We can just add it to `newPath` and
+    // continue resolving the remaining components.
+    if (relativeComponents.length == 1) {
+      newPath = path.join(newPath, relativeComponents.single);
+      continue;
+    }
+
+    // If we've already tried to canonicalize the new path, we've encountered a
+    // symlink loop. Avoid going infinite by treating the recursive symlink as
+    // the canonical path.
+    var newSubPath = path.join(newPath, path.joinAll(relativeComponents));
+    if (seen.contains(newSubPath)) {
+      newPath = newSubPath;
+      continue;
+    }
+
+    // If there are multiple new components to resolve, add them to the
+    // beginning of the queue.
+    relativeComponents.addAll(components);
+    components = relativeComponents;
+  }
+  return newPath;
+}
+
+/// Returns the transitive target of [link] (if A links to B which links to C,
+/// this will return C). If [link] is part of a symlink loop (e.g. A links to B
+/// which links back to A), this returns the path to the first repeated link (so
+/// `transitiveTarget("A")` would return `"A"` and `transitiveTarget("A")` would
+/// return `"B"`).
+///
+/// This accepts paths to non-links or broken links, and returns them as-is.
+String resolveLink(String link) {
+  var seen = new Set<String>();
+  while (linkExists(link) && !seen.contains(link)) {
+    seen.add(link);
+    link = path.normalize(path.join(
+        path.dirname(link), new Link(link).targetSync()));
+  }
+  return link;
+}
+
 /// Reads the contents of the text file [file].
 String readTextFile(String file) =>
     new File(file).readAsStringSync(encoding: Encoding.UTF_8);
@@ -137,7 +235,7 @@
     var contents = <String>[];
 
     // Avoid recursive symlinks.
-    var resolvedPath = new File(dir).fullPathSync();
+    var resolvedPath = canonicalize(dir);
     if (listedDirectories.contains(resolvedPath)) return [];
 
     listedDirectories = new Set<String>.from(listedDirectories);
diff --git a/sdk/lib/_internal/pub/lib/src/path_source.dart b/sdk/lib/_internal/pub/lib/src/path_source.dart
index 72d4065..2b66e3b 100644
--- a/sdk/lib/_internal/pub/lib/src/path_source.dart
+++ b/sdk/lib/_internal/pub/lib/src/path_source.dart
@@ -32,18 +32,10 @@
   }
 
   bool descriptionsEqual(description1, description2) {
-    try {
-      // Compare real paths after normalizing and resolving symlinks.
-      var path1 = new File(description1["path"]).fullPathSync();
-      var path2 = new File(description2["path"]).fullPathSync();
-      return path1 == path2;
-    } on FileIOException catch (ex) {
-      // If either of the files couldn't be found, fall back to just comparing
-      // the normalized paths.
-      var path1 = path.normalize(path.absolute(description1["path"]));
-      var path2 = path.normalize(path.absolute(description2["path"]));
-      return path1 == path2;
-    }
+    // Compare real paths after normalizing and resolving symlinks.
+    var path1 = canonicalize(description1["path"]);
+    var path2 = canonicalize(description2["path"]);
+    return path1 == path2;
   }
 
   Future<bool> install(PackageId id, String destination) {
@@ -110,18 +102,17 @@
 
   /// Ensures that [description] is a valid path description. It must be a map,
   /// with a "path" key containing a path that points to an existing directory.
-  /// Throws a [FormatException] if the path is invalid.
+  /// Throws an [ApplicationException] if the path is invalid.
   void _validatePath(String name, description) {
     var dir = description["path"];
 
     if (dirExists(dir)) return;
 
     if (fileExists(dir)) {
-      throw new FormatException(
-          "Path dependency for package '$name' must refer to a "
-          "directory, not a file. Was '$dir'.");
+      fail("Path dependency for package '$name' must refer to a "
+           "directory, not a file. Was '$dir'.");
     }
 
-    throw new FormatException("Could not find package '$name' at '$dir'.");
+    fail("Could not find package '$name' at '$dir'.");
   }
 }
diff --git a/sdk/lib/_internal/pub/lib/src/system_cache.dart b/sdk/lib/_internal/pub/lib/src/system_cache.dart
index 8a51912..567803b 100644
--- a/sdk/lib/_internal/pub/lib/src/system_cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/system_cache.dart
@@ -45,11 +45,19 @@
   : _pendingInstalls = new Map<PackageId, Future<Package>>(),
     sources = new SourceRegistry();
 
-  /// Creates a system cache and registers the standard set of sources.
-  factory SystemCache.withSources(String rootDir) {
+  /// Creates a system cache and registers the standard set of sources. If
+  /// [isOffline] is `true`, then the offline hosted source will be used.
+  /// Defaults to `false`.
+  factory SystemCache.withSources(String rootDir, {bool isOffline: false}) {
     var cache = new SystemCache(rootDir);
     cache.register(new GitSource());
-    cache.register(new HostedSource());
+
+    if (isOffline) {
+      cache.register(new OfflineHostedSource());
+    } else {
+      cache.register(new HostedSource());
+    }
+
     cache.register(new PathSource());
     cache.sources.setDefault('hosted');
     return cache;
diff --git a/sdk/lib/_internal/pub/lib/src/validator/directory.dart b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
index 216f2bf..5e90437 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/directory.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
@@ -18,7 +18,9 @@
   DirectoryValidator(Entrypoint entrypoint)
     : super(entrypoint);
 
-  static final _PLURAL_NAMES = ["tools", "tests", "docs", "examples"];
+  static final _PLURAL_NAMES = [
+    "benchmarks", "docs", "examples", "tests", "tools"
+  ];
 
   Future validate() {
     return new Future.sync(() {
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index b170e83..00fafbc 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -12,6 +12,3 @@
 # Pub only runs on the standalone VM, not the browser.
 [ $runtime == drt || $runtime == dartium || $runtime == opera ]
 *: Skip
-
-[ $system == windows ]
-test/io_test: Fail # Issue 7505
diff --git a/sdk/lib/_internal/pub/test/descriptor.dart b/sdk/lib/_internal/pub/test/descriptor.dart
index 4122bbf..bccc72d 100644
--- a/sdk/lib/_internal/pub/test/descriptor.dart
+++ b/sdk/lib/_internal/pub/test/descriptor.dart
@@ -83,14 +83,6 @@
   ]);
 }
 
-/// Describes a directory for a package installed from the mock package server.
-/// This directory is of the form found in the global package cache.
-Descriptor packageCacheDir(String name, String version) {
-  return dir("$name-$version", [
-    libDir(name, '$name $version')
-  ]);
-}
-
 /// Describes a directory for a Git package. This directory is of the form
 /// found in the revision cache of the global package cache.
 Descriptor gitPackageRevisionCacheDir(String name, [int modifier]) {
@@ -137,14 +129,25 @@
 ///
 /// A package's value may also be a list of versions, in which case all
 /// versions are expected to be installed.
-Descriptor cacheDir(Map packages) {
+///
+/// If [includePubspecs] is `true`, then pubspecs will be created for each
+/// package. Defaults to `false` so that the contents of pubspecs are not
+/// validated since they will often lack the dependencies section that the
+/// real pubspec being compared against has. You usually only need to pass
+/// `true` for this if you plan to call [create] on the resulting descriptor.
+Descriptor cacheDir(Map packages, {bool includePubspecs: false}) {
   var contents = <Descriptor>[];
   packages.forEach((name, versions) {
     if (versions is! List) versions = [versions];
     for (var version in versions) {
-      contents.add(packageCacheDir(name, version));
+      var packageContents = [libDir(name, '$name $version')];
+      if (includePubspecs) {
+        packageContents.add(libPubspec(name, version));
+      }
+      contents.add(dir("$name-$version", packageContents));
     }
   });
+
   return dir(cachePath, [
     dir('hosted', [
       async(port.then((p) => dir('localhost%58$p', contents)))
diff --git a/sdk/lib/_internal/pub/test/error_group_test.dart b/sdk/lib/_internal/pub/test/error_group_test.dart
index db952c8..ff2f699 100644
--- a/sdk/lib/_internal/pub/test/error_group_test.dart
+++ b/sdk/lib/_internal/pub/test/error_group_test.dart
@@ -63,10 +63,12 @@
         "been called", () {
       completer.complete('value');
 
-      expect(() => errorGroup.registerFuture(new Future.value()),
-          throwsStateError);
-      expect(() => errorGroup.registerStream(new StreamController().stream),
-          throwsStateError);
+      completer.future.then(expectAsync1((_) {
+        expect(() => errorGroup.registerFuture(new Future.value()),
+            throwsStateError);
+        expect(() => errorGroup.registerStream(new StreamController().stream),
+            throwsStateError);
+      }));
     });
 
     test('should pass through an exception from the future if it has a '
diff --git a/sdk/lib/_internal/pub/test/install/hosted/offline_test.dart b/sdk/lib/_internal/pub/test/install/hosted/offline_test.dart
new file mode 100644
index 0000000..a39ed74
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/install/hosted/offline_test.dart
@@ -0,0 +1,66 @@
+// 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 '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+main() {
+  initConfig();
+  integration('installs a package using the cache', () {
+    // Run the server so that we know what URL to use in the system cache.
+    servePackages([]);
+
+    d.cacheDir({
+      "foo": ["1.2.2", "1.2.3"],
+      "bar": ["1.2.3"]
+    }, includePubspecs: true).create();
+
+    d.appDir([
+      dependencyMap("foo", "any"),
+      dependencyMap("bar", "any")
+    ]).create();
+
+    schedulePub(args: ['install', '--offline'],
+        output: new RegExp("Dependencies installed!\$"));
+
+    d.packagesDir({
+      "foo": "1.2.3",
+      "bar": "1.2.3"
+    }).validate();
+  });
+
+  integration('fails gracefully if a dependency is not cached', () {
+    // Run the server so that we know what URL to use in the system cache.
+    servePackages([]);
+
+    d.appDir([
+      dependencyMap("foo", "any")
+    ]).create();
+
+    schedulePub(args: ['install', '--offline'],
+        error: new RegExp('Could not find package "foo" in cache'),
+        exitCode: 1);
+  });
+
+  integration('fails gracefully no cached versions match', () {
+    // Run the server so that we know what URL to use in the system cache.
+    servePackages([]);
+
+    d.cacheDir({
+      "foo": ["1.2.2", "1.2.3"]
+    }, includePubspecs: true).create();
+
+    d.appDir([
+      dependencyMap("foo", ">2.0.0")
+    ]).create();
+
+    schedulePub(args: ['install', '--offline'],
+        error: new RegExp("Package 'foo' has no versions that match >2.0.0"),
+        exitCode: 1);
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart b/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart
index 7220cb9..053c922 100644
--- a/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/nonexistent_dir_test.dart
@@ -7,7 +7,6 @@
 import 'package:pathos/path.dart' as path;
 import 'package:scheduled_test/scheduled_test.dart';
 
-import '../../../lib/src/exit_codes.dart' as exit_codes;
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
@@ -34,6 +33,6 @@
     schedulePub(args: ['install'],
         error:
             new RegExp("Could not find package 'foo' at '$escapePath'."),
-        exitCode: exit_codes.DATA);
+        exitCode: 1);
   });
 }
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart b/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart
index 32f7180..7779467 100644
--- a/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/path_is_file_test.dart
@@ -5,7 +5,6 @@
 import 'package:pathos/path.dart' as path;
 import 'package:scheduled_test/scheduled_test.dart';
 
-import '../../../lib/src/exit_codes.dart' as exit_codes;
 import '../../descriptor.dart' as d;
 import '../../test_pub.dart';
 
@@ -38,6 +37,6 @@
     schedulePub(args: ['install'],
         error: new RegExp("Path dependency for package 'foo' must refer to a "
                           "directory, not a file. Was '$escapePath'."),
-        exitCode: exit_codes.DATA);
+        exitCode: 1);
   });
 }
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart b/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart
index 9cb3a9b..d3b75da 100644
--- a/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart
+++ b/sdk/lib/_internal/pub/test/install/path/shared_dependency_symlink_test.dart
@@ -10,10 +10,6 @@
 import '../../test_pub.dart';
 
 main() {
-  // new File().fullPathSync() does not resolve through NTFS junction points,
-  // so this feature does not work on Windows.
-  if (Platform.operatingSystem == "windows") return;
-
   initConfig();
   integration("shared dependency with symlink", () {
     d.dir("shared", [
diff --git a/sdk/lib/_internal/pub/test/install/pub_install_test.dart b/sdk/lib/_internal/pub/test/install/pub_install_test.dart
index a20f26ef..866376b 100644
--- a/sdk/lib/_internal/pub/test/install/pub_install_test.dart
+++ b/sdk/lib/_internal/pub/test/install/pub_install_test.dart
@@ -173,117 +173,35 @@
   });
 
   group('creates a packages directory in', () {
-    integration('"test/" and its subdirectories', () {
-      d.dir(appPath, [
-        d.appPubspec([]),
-        d.libDir('foo'),
-        d.dir("test", [d.dir("subtest")])
-      ]).create();
+    for (var dir in ["benchmark", "example", "test", "tool", "web"]) {
+      integration('"$dir/" and its subdirectories', () {
+        d.dir(appPath, [
+          d.appPubspec([]),
+          d.libDir('foo'),
+          d.dir(dir, [d.dir("sub${dir}")])
+        ]).create();
 
-      schedulePub(args: ['install'],
-          output: new RegExp(r"Dependencies installed!$"));
+        schedulePub(args: ['install'],
+            output: new RegExp(r"Dependencies installed!$"));
 
-      d.dir(appPath, [
-        d.dir("test", [
-          d.dir("packages", [
-            d.dir("myapp", [
-              d.file('foo.dart', 'main() => "foo";')
-            ])
-          ]),
-          d.dir("subtest", [
+        d.dir(appPath, [
+          d.dir(dir, [
             d.dir("packages", [
               d.dir("myapp", [
                 d.file('foo.dart', 'main() => "foo";')
               ])
-            ])
-          ])
-        ])
-      ]).validate();
-    });
-
-    integration('"example/" and its subdirectories', () {
-      d.dir(appPath, [
-        d.appPubspec([]),
-        d.libDir('foo'),
-        d.dir("example", [d.dir("subexample")])
-      ]).create();
-
-      schedulePub(args: ['install'],
-          output: new RegExp(r"Dependencies installed!$"));
-
-      d.dir(appPath, [
-        d.dir("example", [
-          d.dir("packages", [
-            d.dir("myapp", [
-              d.file('foo.dart', 'main() => "foo";')
-            ])
-          ]),
-          d.dir("subexample", [
-            d.dir("packages", [
-              d.dir("myapp", [
-                d.file('foo.dart', 'main() => "foo";')
+            ]),
+            d.dir("sub${dir}", [
+              d.dir("packages", [
+                d.dir("myapp", [
+                  d.file('foo.dart', 'main() => "foo";')
+                ])
               ])
             ])
           ])
-        ])
-      ]).validate();
-    });
-
-    integration('"tool/" and its subdirectories', () {
-      d.dir(appPath, [
-        d.appPubspec([]),
-        d.libDir('foo'),
-        d.dir("tool", [d.dir("subtool")])
-      ]).create();
-
-      schedulePub(args: ['install'],
-          output: new RegExp(r"Dependencies installed!$"));
-
-      d.dir(appPath, [
-        d.dir("tool", [
-          d.dir("packages", [
-            d.dir("myapp", [
-              d.file('foo.dart', 'main() => "foo";')
-            ])
-          ]),
-          d.dir("subtool", [
-            d.dir("packages", [
-              d.dir("myapp", [
-                d.file('foo.dart', 'main() => "foo";')
-              ])
-            ])
-          ])
-        ])
-      ]).validate();
-    });
-
-    integration('"web/" and its subdirectories', () {
-      d.dir(appPath, [
-        d.appPubspec([]),
-        d.libDir('foo'),
-        d.dir("web", [d.dir("subweb")])
-      ]).create();
-
-      schedulePub(args: ['install'],
-          output: new RegExp(r"Dependencies installed!$"));
-
-      d.dir(appPath, [
-        d.dir("web", [
-          d.dir("packages", [
-            d.dir("myapp", [
-              d.file('foo.dart', 'main() => "foo";')
-            ])
-          ]),
-          d.dir("subweb", [
-            d.dir("packages", [
-              d.dir("myapp", [
-                d.file('foo.dart', 'main() => "foo";')
-              ])
-            ])
-          ])
-        ])
-      ]).validate();
-    });
+        ]).validate();
+      });
+    }
 
     integration('"bin/"', () {
       d.dir(appPath, [
diff --git a/sdk/lib/_internal/pub/test/io_test.dart b/sdk/lib/_internal/pub/test/io_test.dart
index 3a0506c..6aa82bc 100644
--- a/sdk/lib/_internal/pub/test/io_test.dart
+++ b/sdk/lib/_internal/pub/test/io_test.dart
@@ -4,6 +4,7 @@
 
 library io_test;
 
+import 'dart:async';
 import 'dart:io';
 
 import 'package:pathos/path.dart' as path;
@@ -135,6 +136,154 @@
     });
   });
 
+  group('canonicalize', () {
+    test('resolves a non-link', () {
+      expect(withCanonicalTempDir((temp) {
+        var filePath = path.join(temp, 'file');
+        writeTextFile(filePath, '');
+        expect(canonicalize(filePath), equals(filePath));
+      }), completes);
+    });
+
+    test('resolves a non-existent file', () {
+      expect(withCanonicalTempDir((temp) {
+        expect(canonicalize(path.join(temp, 'nothing')),
+            equals(path.join(temp, 'nothing')));
+      }), completes);
+    });
+
+    test('resolves a symlink', () {
+      expect(withCanonicalTempDir((temp) {
+        createDir(path.join(temp, 'linked-dir'));
+        createSymlink(
+            path.join(temp, 'linked-dir'),
+            path.join(temp, 'dir'));
+        expect(
+            canonicalize(path.join(temp, 'dir')),
+            equals(path.join(temp, 'linked-dir')));
+      }), completes);
+    });
+
+    test('resolves a relative symlink', () {
+      expect(withCanonicalTempDir((temp) {
+        createDir(path.join(temp, 'linked-dir'));
+        createSymlink(
+            path.join(temp, 'linked-dir'),
+            path.join(temp, 'dir'),
+            relative: true);
+        expect(
+            canonicalize(path.join(temp, 'dir')),
+            equals(path.join(temp, 'linked-dir')));
+      }), completes);
+    });
+
+    test('resolves a single-level horizontally recursive symlink', () {
+      expect(withCanonicalTempDir((temp) {
+        var linkPath = path.join(temp, 'foo');
+        createSymlink(linkPath, linkPath);
+        expect(canonicalize(linkPath), equals(linkPath));
+      }), completes);
+    });
+
+    test('resolves a multi-level horizontally recursive symlink', () {
+      expect(withCanonicalTempDir((temp) {
+        var fooPath = path.join(temp, 'foo');
+        var barPath = path.join(temp, 'bar');
+        var bazPath = path.join(temp, 'baz');
+        createSymlink(barPath, fooPath);
+        createSymlink(bazPath, barPath);
+        createSymlink(fooPath, bazPath);
+        expect(canonicalize(fooPath), equals(fooPath));
+        expect(canonicalize(barPath), equals(barPath));
+        expect(canonicalize(bazPath), equals(bazPath));
+
+        createSymlink(fooPath, path.join(temp, 'outer'));
+        expect(canonicalize(path.join(temp, 'outer')), equals(fooPath));
+      }), completes);
+    });
+
+    test('resolves a broken symlink', () {
+      expect(withCanonicalTempDir((temp) {
+        createSymlink(path.join(temp, 'nonexistent'), path.join(temp, 'foo'));
+        expect(
+            canonicalize(path.join(temp, 'foo')),
+            equals(path.join(temp, 'nonexistent')));
+      }), completes);
+    });
+
+    test('resolves multiple nested symlinks', () {
+      expect(withCanonicalTempDir((temp) {
+        var dir1 = path.join(temp, 'dir1');
+        var dir2 = path.join(temp, 'dir2');
+        var subdir1 = path.join(dir1, 'subdir1');
+        var subdir2 = path.join(dir2, 'subdir2');
+        createDir(dir2);
+        createDir(subdir2);
+        createSymlink(dir2, dir1);
+        createSymlink(subdir2, subdir1);
+        expect(
+            canonicalize(path.join(subdir1, 'file')),
+            equals(path.join(subdir2, 'file')));
+      }), completes);
+    });
+
+    test('resolves a nested vertical symlink', () {
+      expect(withCanonicalTempDir((temp) {
+        var dir1 = path.join(temp, 'dir1');
+        var dir2 = path.join(temp, 'dir2');
+        var subdir = path.join(dir1, 'subdir');
+        createDir(dir1);
+        createDir(dir2);
+        createSymlink(dir2, subdir);
+        expect(
+            canonicalize(path.join(subdir, 'file')),
+            equals(path.join(dir2, 'file')));
+      }), completes);
+    });
+
+    test('resolves a vertically recursive symlink', () {
+      expect(withCanonicalTempDir((temp) {
+        var dir = path.join(temp, 'dir');
+        var subdir = path.join(dir, 'subdir');
+        createDir(dir);
+        createSymlink(dir, subdir);
+        expect(
+            canonicalize(path.join(temp, 'dir', 'subdir', 'subdir', 'subdir',
+                                   'subdir', 'file')),
+            equals(path.join(dir, 'file')));
+      }), completes);
+    });
+
+    test('resolves a symlink that links to a path that needs more resolving',
+        () {
+      expect(withCanonicalTempDir((temp) {
+        var dir = path.join(temp, 'dir');
+        var linkdir = path.join(temp, 'linkdir');
+        var linkfile = path.join(dir, 'link');
+        createDir(dir);
+        createSymlink(dir, linkdir);
+        createSymlink(path.join(linkdir, 'file'), linkfile);
+        expect(
+            canonicalize(linkfile),
+            equals(path.join(dir, 'file')));
+      }), completes);
+    });
+
+    test('resolves a pair of pathologically-recursive symlinks', () {
+      expect(withCanonicalTempDir((temp) {
+        var foo = path.join(temp, 'foo');
+        var subfoo = path.join(foo, 'subfoo');
+        var bar = path.join(temp, 'bar');
+        var subbar = path.join(bar, 'subbar');
+        createSymlink(subbar, foo);
+        createSymlink(subfoo, bar);
+        expect(
+            canonicalize(subfoo),
+            equals(path.join(subfoo, 'subbar', 'subfoo')));
+      }), completes);
+    });
+  });
+
   testExistencePredicate("entryExists", entryExists,
       forFile: true,
       forFileSymlink: true,
@@ -278,3 +427,7 @@
     }
   });
 }
+
+/// Like [withTempDir], but canonicalizes the path before passing it to [fn].
+Future withCanonicalTempDir(Future fn(String path)) =>
+  withTempDir((temp) => fn(canonicalize(temp)));
diff --git a/sdk/lib/_internal/pub/test/pub_test.dart b/sdk/lib/_internal/pub/test/pub_test.dart
index 36071ba..66eba69 100644
--- a/sdk/lib/_internal/pub/test/pub_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_test.dart
@@ -27,7 +27,7 @@
               [normal]    Show errors, warnings, and user messages.
               [solver]    Show steps during version resolution.
 
-    -v, --verbose         Shortcut for "--verbosity=all"
+    -v, --verbose         Shortcut for "--verbosity=all".
 
     Available commands:
       cache      Inspect the system cache.
@@ -100,6 +100,7 @@
             Install the current package's dependencies.
 
             Usage: pub install
+            --[no-]offline    Use cached packages instead of accessing the network.
             ''');
     });
 
@@ -109,9 +110,9 @@
             Publish the current package to pub.dartlang.org.
 
             Usage: pub publish [options]
-            -n, --dry-run    Validate but do not publish the package                      
-            -f, --force      Publish without confirmation if there are no errors
-                --server     The package server to which to upload this package
+            -n, --dry-run    Validate but do not publish the package.
+            -f, --force      Publish without confirmation if there are no errors.
+                --server     The package server to which to upload this package.
                              (defaults to "https://pub.dartlang.org")
             ''');
     });
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index a175c7b..e2a06f5 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -355,7 +355,7 @@
   // If the executable looks like a path, get its full path. That way we
   // can still find it when we spawn it with a different working directory.
   if (dartBin.contains(Platform.pathSeparator)) {
-    dartBin = new File(dartBin).fullPathSync();
+    dartBin = path.absolute(dartBin);
   }
 
   // Find the main pub entrypoint.
diff --git a/sdk/lib/_internal/pub/test/update/hosted/offline_test.dart b/sdk/lib/_internal/pub/test/update/hosted/offline_test.dart
new file mode 100644
index 0000000..50686d0
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/update/hosted/offline_test.dart
@@ -0,0 +1,68 @@
+// 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 '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+main() {
+  initConfig();
+  integration('updates a package using the cache', () {
+    // Run the server so that we know what URL to use in the system cache.
+    servePackages([]);
+
+    d.cacheDir({
+      "foo": ["1.2.2", "1.2.3"],
+      "bar": ["1.2.3"]
+    }, includePubspecs: true).create();
+
+    d.appDir([
+      dependencyMap("foo", "any"),
+      dependencyMap("bar", "any")
+    ]).create();
+
+    schedulePub(args: ['update', '--offline'],
+        output: new RegExp("Dependencies updated!\$"),
+        error: "Warning: Updating when offline may not update you "
+               "to the latest versions of your dependencies.");
+
+    d.packagesDir({
+      "foo": "1.2.3",
+      "bar": "1.2.3"
+    }).validate();
+  });
+
+  integration('fails gracefully if a dependency is not cached', () {
+    // Run the server so that we know what URL to use in the system cache.
+    servePackages([]);
+
+    d.appDir([
+      dependencyMap("foo", "any")
+    ]).create();
+
+    schedulePub(args: ['update', '--offline'],
+        error: new RegExp('Could not find package "foo" in cache'),
+        exitCode: 1);
+  });
+
+  integration('fails gracefully no cached versions match', () {
+    // Run the server so that we know what URL to use in the system cache.
+    servePackages([]);
+
+    d.cacheDir({
+      "foo": ["1.2.2", "1.2.3"]
+    }, includePubspecs: true).create();
+
+    d.appDir([
+      dependencyMap("foo", ">2.0.0")
+    ]).create();
+
+    schedulePub(args: ['update', '--offline'],
+        error: new RegExp("Package 'foo' has no versions that match >2.0.0"),
+        exitCode: 1);
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/validator/directory_test.dart b/sdk/lib/_internal/pub/test/validator/directory_test.dart
index e3acfb4..1b58b69 100644
--- a/sdk/lib/_internal/pub/test/validator/directory_test.dart
+++ b/sdk/lib/_internal/pub/test/validator/directory_test.dart
@@ -35,7 +35,10 @@
       'named', () {
     setUp(d.validPackage.create);
 
-    var names = ["tools", "tests", "docs", "examples", "sample", "samples"];
+    var names = [
+      "benchmarks", "docs", "examples", "sample", "samples", "tests", "tools"
+    ];
+
     for (var name in names) {
       integration('"$name"', () {
         d.dir(appPath, [d.dir(name)]).create();
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 7219719..59f0efb 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -343,7 +343,38 @@
  */
 abstract class Completer<T> {
 
-  factory Completer() => new _CompleterImpl<T>();
+  factory Completer() => new _AsyncCompleter<T>();
+
+  /**
+   * Completes the future synchronously.
+   *
+   * This constructor should be avoided unless the completion of the future is
+   * known to be the final result of another asynchronous operation. If in doubt
+   * use the default [Completer] constructor.
+   *
+   * Example:
+   *
+   *     var completer = new Completer.sync();
+   *     // The completion is the result of the asynchronous onDone event.
+   *     // No other operation is performed after the completion. It is safe
+   *     // to use the Completer.sync constructor.
+   *     stream.listen(print, onDone: () { completer.complete("done"); });
+   *
+   * Bad example. Do not use this code. Only for illustrative purposes:
+   *
+   *     var completer = new Completer.sync();
+   *     // The completion is the result of the asynchronous onDone event.
+   *     // However, there is still code executed after the completion. This
+   *     // operation is *not* safe.
+   *     stream.listen(print, onDone: () {
+   *       completer.complete("done");
+   *       foo();  // This operation follows the completion.
+   *     });
+   *
+   * *WARNING* This constructor is experimental and could disappear or change
+   * behavior.
+   */
+  factory Completer.sync() => new _SyncCompleter<T>();
 
   /** The future that will contain the result provided to this completer. */
   Future get future;
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index 3660b9f..b4f7f18 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -7,17 +7,19 @@
 deprecatedFutureValue(_FutureImpl future) =>
   future._isComplete ? future._resultOrListeners : null;
 
-class _CompleterImpl<T> implements Completer<T> {
+abstract class _Completer<T> implements Completer<T> {
   final Future<T> future;
   bool _isComplete = false;
 
-  _CompleterImpl() : future = new _FutureImpl<T>();
+  _Completer() : future = new _FutureImpl<T>();
+
+  void _setFutureValue(T value);
+  void _setFutureError(error);
 
   void complete([T value]) {
     if (_isComplete) throw new StateError("Future already completed");
     _isComplete = true;
-    _FutureImpl future = this.future;
-    future._setValue(value);
+    _setFutureValue(value);
   }
 
   void completeError(Object error, [Object stackTrace = null]) {
@@ -27,13 +29,36 @@
       // Force the stack trace onto the error, even if it already had one.
       _attachStackTrace(error, stackTrace);
     }
-    _FutureImpl future = this.future;
-    future._setError(error);
+    _setFutureError(error);
   }
 
   bool get isCompleted => _isComplete;
 }
 
+class _AsyncCompleter<T> extends _Completer<T> {
+  void _setFutureValue(T value) {
+    _FutureImpl future = this.future;
+    runAsync(() { future._setValue(value); });
+  }
+
+  void _setFutureError(error) {
+    _FutureImpl future = this.future;
+    runAsync(() { future._setError(error); });
+  }
+}
+
+class _SyncCompleter<T> extends _Completer<T> {
+  void _setFutureValue(T value) {
+    _FutureImpl future = this.future;
+    future._setValue(value);
+  }
+
+  void _setFutureError(error) {
+    _FutureImpl future = this.future;
+    future._setError(error);
+  }
+}
+
 /**
  * A listener on a future.
  *
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index d67a2c9..bd7050c 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -187,6 +187,9 @@
 
 @DocsEditable
 @DomName('WebKitAnimationEvent')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
 class AnimationEvent extends Event native "WebKitAnimationEvent" {
 
   @DomName('AnimationEvent.animationName')
@@ -982,7 +985,7 @@
 
   @DomName('CanvasRenderingContext2D.currentPath')
   @DocsEditable
-  DomPath currentPath;
+  Path currentPath;
 
   @DomName('CanvasRenderingContext2D.fillStyle')
   @DocsEditable
@@ -1826,6 +1829,22 @@
 
 
 @DocsEditable
+@DomName('WebKitCSSFilterRule')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class CssFilterRule extends CssRule native "WebKitCSSFilterRule" {
+
+  @DomName('WebKitCSSFilterRule.style')
+  @DocsEditable
+  final CssStyleDeclaration style;
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
 @DomName('CSSFontFaceLoadEvent')
 class CssFontFaceLoadEvent extends Event native "CSSFontFaceLoadEvent" {
 
@@ -1903,6 +1922,9 @@
 
 @DocsEditable
 @DomName('WebKitCSSKeyframeRule')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
 class CssKeyframeRule extends CssRule native "WebKitCSSKeyframeRule" {
 
   @DomName('WebKitCSSKeyframeRule.keyText')
@@ -1920,6 +1942,9 @@
 
 @DocsEditable
 @DomName('WebKitCSSKeyframesRule')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
 class CssKeyframesRule extends CssRule native "WebKitCSSKeyframesRule" {
 
   @DomName('WebKitCSSKeyframesRule.cssRules')
@@ -1994,6 +2019,24 @@
 
 
 @DocsEditable
+@DomName('WebKitCSSRegionRule')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class CssRegionRule extends CssRule native "WebKitCSSRegionRule" {
+
+  @DomName('WebKitCSSRegionRule.cssRules')
+  @DocsEditable
+  @Returns('_CssRuleList')
+  @Creates('_CssRuleList')
+  final List<CssRule> cssRules;
+}
+// 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('CSSRule')
 class CssRule native "CSSRule" {
 
@@ -6041,7 +6084,7 @@
 
   @DomName('Document.securityPolicy')
   @DocsEditable
-  final DomSecurityPolicy securityPolicy;
+  final SecurityPolicy securityPolicy;
 
   @JSName('selectedStylesheetSet')
   @DomName('Document.selectedStylesheetSet')
@@ -6301,7 +6344,7 @@
   @SupportedBrowser(SupportedBrowser.CHROME)
   @SupportedBrowser(SupportedBrowser.SAFARI)
   @Experimental
-  DomNamedFlowCollection getNamedFlows() native;
+  NamedFlowCollection getNamedFlows() native;
 
   @DomName('Document.webkitRegister')
   @DocsEditable
@@ -6541,7 +6584,7 @@
    * For details about CSS selector syntax, see the
    * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
    */
-  List<Element> queryAll(String selectors) {
+  ElementList queryAll(String selectors) {
     return new _FrozenElementList._wrap($dom_querySelectorAll(selectors));
   }
 }
@@ -6744,273 +6787,6 @@
 
 
 @DocsEditable
-@DomName('MimeType')
-class DomMimeType native "MimeType" {
-
-  @DomName('DOMMimeType.description')
-  @DocsEditable
-  final String description;
-
-  @DomName('DOMMimeType.enabledPlugin')
-  @DocsEditable
-  final DomPlugin enabledPlugin;
-
-  @DomName('DOMMimeType.suffixes')
-  @DocsEditable
-  final String suffixes;
-
-  @DomName('DOMMimeType.type')
-  @DocsEditable
-  final String type;
-}
-// 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('MimeTypeArray')
-class DomMimeTypeArray implements JavaScriptIndexingBehavior, List<DomMimeType> native "MimeTypeArray" {
-
-  @DomName('DOMMimeTypeArray.length')
-  @DocsEditable
-  int get length => JS("int", "#.length", this);
-
-  DomMimeType operator[](int index) => JS("DomMimeType", "#[#]", this, index);
-
-  void operator[]=(int index, DomMimeType value) {
-    throw new UnsupportedError("Cannot assign element of immutable List.");
-  }
-  // -- start List<DomMimeType> mixins.
-  // DomMimeType is the element type.
-
-  // From Iterable<DomMimeType>:
-
-  Iterator<DomMimeType> 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<DomMimeType>(this);
-  }
-
-  DomMimeType reduce(DomMimeType combine(DomMimeType value, DomMimeType element)) {
-    return IterableMixinWorkaround.reduce(this, combine);
-  }
-
-  dynamic fold(dynamic initialValue,
-               dynamic combine(dynamic previousValue, DomMimeType element)) {
-    return IterableMixinWorkaround.fold(this, initialValue, combine);
-  }
-
-  bool contains(DomMimeType element) => IterableMixinWorkaround.contains(this, element);
-
-  void forEach(void f(DomMimeType element)) => IterableMixinWorkaround.forEach(this, f);
-
-  String join([String separator = ""]) =>
-      IterableMixinWorkaround.joinList(this, separator);
-
-  Iterable map(f(DomMimeType element)) =>
-      IterableMixinWorkaround.mapList(this, f);
-
-  Iterable<DomMimeType> where(bool f(DomMimeType element)) =>
-      IterableMixinWorkaround.where(this, f);
-
-  Iterable expand(Iterable f(DomMimeType element)) =>
-      IterableMixinWorkaround.expand(this, f);
-
-  bool every(bool f(DomMimeType element)) => IterableMixinWorkaround.every(this, f);
-
-  bool any(bool f(DomMimeType element)) => IterableMixinWorkaround.any(this, f);
-
-  List<DomMimeType> toList({ bool growable: true }) =>
-      new List<DomMimeType>.from(this, growable: growable);
-
-  Set<DomMimeType> toSet() => new Set<DomMimeType>.from(this);
-
-  bool get isEmpty => this.length == 0;
-
-  Iterable<DomMimeType> take(int n) => IterableMixinWorkaround.takeList(this, n);
-
-  Iterable<DomMimeType> takeWhile(bool test(DomMimeType value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
-  }
-
-  Iterable<DomMimeType> skip(int n) => IterableMixinWorkaround.skipList(this, n);
-
-  Iterable<DomMimeType> skipWhile(bool test(DomMimeType value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
-  }
-
-  DomMimeType firstWhere(bool test(DomMimeType value), { DomMimeType orElse() }) {
-    return IterableMixinWorkaround.firstWhere(this, test, orElse);
-  }
-
-  DomMimeType lastWhere(bool test(DomMimeType value), {DomMimeType orElse()}) {
-    return IterableMixinWorkaround.lastWhereList(this, test, orElse);
-  }
-
-  DomMimeType singleWhere(bool test(DomMimeType value)) {
-    return IterableMixinWorkaround.singleWhere(this, test);
-  }
-
-  DomMimeType elementAt(int index) {
-    return this[index];
-  }
-
-  // From Collection<DomMimeType>:
-
-  void add(DomMimeType value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addAll(Iterable<DomMimeType> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  // From List<DomMimeType>:
-  void set length(int value) {
-    throw new UnsupportedError("Cannot resize immutable List.");
-  }
-
-  void clear() {
-    throw new UnsupportedError("Cannot clear immutable List.");
-  }
-
-  Iterable<DomMimeType> get reversed {
-    return IterableMixinWorkaround.reversedList(this);
-  }
-
-  void sort([int compare(DomMimeType a, DomMimeType b)]) {
-    throw new UnsupportedError("Cannot sort immutable List.");
-  }
-
-  int indexOf(DomMimeType element, [int start = 0]) =>
-      Lists.indexOf(this, element, start, this.length);
-
-  int lastIndexOf(DomMimeType element, [int start]) {
-    if (start == null) start = length - 1;
-    return Lists.lastIndexOf(this, element, start);
-  }
-
-  DomMimeType get first {
-    if (this.length > 0) return this[0];
-    throw new StateError("No elements");
-  }
-
-  DomMimeType get last {
-    if (this.length > 0) return this[this.length - 1];
-    throw new StateError("No elements");
-  }
-
-  DomMimeType get single {
-    if (length == 1) return this[0];
-    if (length == 0) throw new StateError("No elements");
-    throw new StateError("More than one element");
-  }
-
-  void insert(int index, DomMimeType element) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void insertAll(int index, Iterable<DomMimeType> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void setAll(int index, Iterable<DomMimeType> iterable) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  DomMimeType removeAt(int pos) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  DomMimeType removeLast() {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  bool remove(Object object) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeWhere(bool test(DomMimeType element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainWhere(bool test(DomMimeType element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void setRange(int start, int end, Iterable<DomMimeType> iterable, [int skipCount=0]) {
-    throw new UnsupportedError("Cannot setRange on immutable List.");
-  }
-
-  void removeRange(int start, int end) {
-    throw new UnsupportedError("Cannot removeRange on immutable List.");
-  }
-
-  void replaceRange(int start, int end, Iterable<DomMimeType> iterable) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  void fillRange(int start, int end, [DomMimeType fillValue]) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  Iterable<DomMimeType> getRange(int start, int end) =>
-    IterableMixinWorkaround.getRangeList(this, start, end);
-
-  List<DomMimeType> sublist(int start, [int end]) {
-    if (end == null) end = length;
-    return Lists.getRange(this, start, end, <DomMimeType>[]);
-  }
-
-  Map<int, DomMimeType> asMap() =>
-    IterableMixinWorkaround.asMapList(this);
-
-  String toString() {
-    StringBuffer buffer = new StringBuffer('[');
-    buffer.writeAll(this, ', ');
-    buffer.write(']');
-    return buffer.toString();
-  }
-
-  // -- end List<DomMimeType> mixins.
-
-  @DomName('DOMMimeTypeArray.item')
-  @DocsEditable
-  DomMimeType item(int index) native;
-
-  @DomName('DOMMimeTypeArray.namedItem')
-  @DocsEditable
-  DomMimeType namedItem(String name) 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('WebKitNamedFlowCollection')
-class DomNamedFlowCollection native "WebKitNamedFlowCollection" {
-
-  @DomName('DOMNamedFlowCollection.length')
-  @DocsEditable
-  final int length;
-
-  @DomName('DOMNamedFlowCollection.item')
-  @DocsEditable
-  NamedFlow item(int index) native;
-
-  @DomName('DOMNamedFlowCollection.namedItem')
-  @DocsEditable
-  NamedFlow namedItem(String name) 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('DOMParser')
 class DomParser native "DOMParser" {
 
@@ -7031,507 +6807,6 @@
 
 
 @DocsEditable
-@DomName('Path')
-class DomPath native "Path" {
-
-  @DomName('DOMPath.DOMPath')
-  @DocsEditable
-  factory DomPath([path_OR_text]) {
-    if (!?path_OR_text) {
-      return DomPath._create_1();
-    }
-    if ((path_OR_text is DomPath || path_OR_text == null)) {
-      return DomPath._create_2(path_OR_text);
-    }
-    if ((path_OR_text is String || path_OR_text == null)) {
-      return DomPath._create_3(path_OR_text);
-    }
-    throw new ArgumentError("Incorrect number or type of arguments");
-  }
-  static DomPath _create_1() => JS('DomPath', 'new Path()');
-  static DomPath _create_2(path_OR_text) => JS('DomPath', 'new Path(#)', path_OR_text);
-  static DomPath _create_3(path_OR_text) => JS('DomPath', 'new Path(#)', path_OR_text);
-
-  @DomName('DOMPath.arc')
-  @DocsEditable
-  void arc(num x, num y, num radius, num startAngle, num endAngle, bool anticlockwise) native;
-
-  @DomName('DOMPath.arcTo')
-  @DocsEditable
-  void arcTo(num x1, num y1, num x2, num y2, num radius) native;
-
-  @DomName('DOMPath.bezierCurveTo')
-  @DocsEditable
-  void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y) native;
-
-  @DomName('DOMPath.closePath')
-  @DocsEditable
-  void closePath() native;
-
-  @DomName('DOMPath.lineTo')
-  @DocsEditable
-  void lineTo(num x, num y) native;
-
-  @DomName('DOMPath.moveTo')
-  @DocsEditable
-  void moveTo(num x, num y) native;
-
-  @DomName('DOMPath.quadraticCurveTo')
-  @DocsEditable
-  void quadraticCurveTo(num cpx, num cpy, num x, num y) native;
-
-  @DomName('DOMPath.rect')
-  @DocsEditable
-  void rect(num x, num y, num width, num height) 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('Plugin')
-class DomPlugin native "Plugin" {
-
-  @DomName('DOMPlugin.description')
-  @DocsEditable
-  final String description;
-
-  @DomName('DOMPlugin.filename')
-  @DocsEditable
-  final String filename;
-
-  @DomName('DOMPlugin.length')
-  @DocsEditable
-  final int length;
-
-  @DomName('DOMPlugin.name')
-  @DocsEditable
-  final String name;
-
-  @DomName('DOMPlugin.item')
-  @DocsEditable
-  DomMimeType item(int index) native;
-
-  @DomName('DOMPlugin.namedItem')
-  @DocsEditable
-  DomMimeType namedItem(String name) 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('PluginArray')
-class DomPluginArray implements JavaScriptIndexingBehavior, List<DomPlugin> native "PluginArray" {
-
-  @DomName('DOMPluginArray.length')
-  @DocsEditable
-  int get length => JS("int", "#.length", this);
-
-  DomPlugin operator[](int index) => JS("DomPlugin", "#[#]", this, index);
-
-  void operator[]=(int index, DomPlugin value) {
-    throw new UnsupportedError("Cannot assign element of immutable List.");
-  }
-  // -- start List<DomPlugin> mixins.
-  // DomPlugin is the element type.
-
-  // From Iterable<DomPlugin>:
-
-  Iterator<DomPlugin> 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<DomPlugin>(this);
-  }
-
-  DomPlugin reduce(DomPlugin combine(DomPlugin value, DomPlugin element)) {
-    return IterableMixinWorkaround.reduce(this, combine);
-  }
-
-  dynamic fold(dynamic initialValue,
-               dynamic combine(dynamic previousValue, DomPlugin element)) {
-    return IterableMixinWorkaround.fold(this, initialValue, combine);
-  }
-
-  bool contains(DomPlugin element) => IterableMixinWorkaround.contains(this, element);
-
-  void forEach(void f(DomPlugin element)) => IterableMixinWorkaround.forEach(this, f);
-
-  String join([String separator = ""]) =>
-      IterableMixinWorkaround.joinList(this, separator);
-
-  Iterable map(f(DomPlugin element)) =>
-      IterableMixinWorkaround.mapList(this, f);
-
-  Iterable<DomPlugin> where(bool f(DomPlugin element)) =>
-      IterableMixinWorkaround.where(this, f);
-
-  Iterable expand(Iterable f(DomPlugin element)) =>
-      IterableMixinWorkaround.expand(this, f);
-
-  bool every(bool f(DomPlugin element)) => IterableMixinWorkaround.every(this, f);
-
-  bool any(bool f(DomPlugin element)) => IterableMixinWorkaround.any(this, f);
-
-  List<DomPlugin> toList({ bool growable: true }) =>
-      new List<DomPlugin>.from(this, growable: growable);
-
-  Set<DomPlugin> toSet() => new Set<DomPlugin>.from(this);
-
-  bool get isEmpty => this.length == 0;
-
-  Iterable<DomPlugin> take(int n) => IterableMixinWorkaround.takeList(this, n);
-
-  Iterable<DomPlugin> takeWhile(bool test(DomPlugin value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
-  }
-
-  Iterable<DomPlugin> skip(int n) => IterableMixinWorkaround.skipList(this, n);
-
-  Iterable<DomPlugin> skipWhile(bool test(DomPlugin value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
-  }
-
-  DomPlugin firstWhere(bool test(DomPlugin value), { DomPlugin orElse() }) {
-    return IterableMixinWorkaround.firstWhere(this, test, orElse);
-  }
-
-  DomPlugin lastWhere(bool test(DomPlugin value), {DomPlugin orElse()}) {
-    return IterableMixinWorkaround.lastWhereList(this, test, orElse);
-  }
-
-  DomPlugin singleWhere(bool test(DomPlugin value)) {
-    return IterableMixinWorkaround.singleWhere(this, test);
-  }
-
-  DomPlugin elementAt(int index) {
-    return this[index];
-  }
-
-  // From Collection<DomPlugin>:
-
-  void add(DomPlugin value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addAll(Iterable<DomPlugin> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  // From List<DomPlugin>:
-  void set length(int value) {
-    throw new UnsupportedError("Cannot resize immutable List.");
-  }
-
-  void clear() {
-    throw new UnsupportedError("Cannot clear immutable List.");
-  }
-
-  Iterable<DomPlugin> get reversed {
-    return IterableMixinWorkaround.reversedList(this);
-  }
-
-  void sort([int compare(DomPlugin a, DomPlugin b)]) {
-    throw new UnsupportedError("Cannot sort immutable List.");
-  }
-
-  int indexOf(DomPlugin element, [int start = 0]) =>
-      Lists.indexOf(this, element, start, this.length);
-
-  int lastIndexOf(DomPlugin element, [int start]) {
-    if (start == null) start = length - 1;
-    return Lists.lastIndexOf(this, element, start);
-  }
-
-  DomPlugin get first {
-    if (this.length > 0) return this[0];
-    throw new StateError("No elements");
-  }
-
-  DomPlugin get last {
-    if (this.length > 0) return this[this.length - 1];
-    throw new StateError("No elements");
-  }
-
-  DomPlugin get single {
-    if (length == 1) return this[0];
-    if (length == 0) throw new StateError("No elements");
-    throw new StateError("More than one element");
-  }
-
-  void insert(int index, DomPlugin element) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void insertAll(int index, Iterable<DomPlugin> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void setAll(int index, Iterable<DomPlugin> iterable) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  DomPlugin removeAt(int pos) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  DomPlugin removeLast() {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  bool remove(Object object) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeWhere(bool test(DomPlugin element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainWhere(bool test(DomPlugin element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void setRange(int start, int end, Iterable<DomPlugin> iterable, [int skipCount=0]) {
-    throw new UnsupportedError("Cannot setRange on immutable List.");
-  }
-
-  void removeRange(int start, int end) {
-    throw new UnsupportedError("Cannot removeRange on immutable List.");
-  }
-
-  void replaceRange(int start, int end, Iterable<DomPlugin> iterable) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  void fillRange(int start, int end, [DomPlugin fillValue]) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  Iterable<DomPlugin> getRange(int start, int end) =>
-    IterableMixinWorkaround.getRangeList(this, start, end);
-
-  List<DomPlugin> sublist(int start, [int end]) {
-    if (end == null) end = length;
-    return Lists.getRange(this, start, end, <DomPlugin>[]);
-  }
-
-  Map<int, DomPlugin> asMap() =>
-    IterableMixinWorkaround.asMapList(this);
-
-  String toString() {
-    StringBuffer buffer = new StringBuffer('[');
-    buffer.writeAll(this, ', ');
-    buffer.write(']');
-    return buffer.toString();
-  }
-
-  // -- end List<DomPlugin> mixins.
-
-  @DomName('DOMPluginArray.item')
-  @DocsEditable
-  DomPlugin item(int index) native;
-
-  @DomName('DOMPluginArray.namedItem')
-  @DocsEditable
-  DomPlugin namedItem(String name) native;
-
-  @DomName('DOMPluginArray.refresh')
-  @DocsEditable
-  void refresh(bool reload) 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('SecurityPolicy')
-class DomSecurityPolicy native "SecurityPolicy" {
-
-  @DomName('DOMSecurityPolicy.allowsEval')
-  @DocsEditable
-  final bool allowsEval;
-
-  @DomName('DOMSecurityPolicy.allowsInlineScript')
-  @DocsEditable
-  final bool allowsInlineScript;
-
-  @DomName('DOMSecurityPolicy.allowsInlineStyle')
-  @DocsEditable
-  final bool allowsInlineStyle;
-
-  @DomName('DOMSecurityPolicy.isActive')
-  @DocsEditable
-  final bool isActive;
-
-  @DomName('DOMSecurityPolicy.reportURIs')
-  @DocsEditable
-  @Returns('DomStringList')
-  @Creates('DomStringList')
-  final List<String> reportURIs;
-
-  @DomName('DOMSecurityPolicy.allowsConnectionTo')
-  @DocsEditable
-  bool allowsConnectionTo(String url) native;
-
-  @DomName('DOMSecurityPolicy.allowsFontFrom')
-  @DocsEditable
-  bool allowsFontFrom(String url) native;
-
-  @DomName('DOMSecurityPolicy.allowsFormAction')
-  @DocsEditable
-  bool allowsFormAction(String url) native;
-
-  @DomName('DOMSecurityPolicy.allowsFrameFrom')
-  @DocsEditable
-  bool allowsFrameFrom(String url) native;
-
-  @DomName('DOMSecurityPolicy.allowsImageFrom')
-  @DocsEditable
-  bool allowsImageFrom(String url) native;
-
-  @DomName('DOMSecurityPolicy.allowsMediaFrom')
-  @DocsEditable
-  bool allowsMediaFrom(String url) native;
-
-  @DomName('DOMSecurityPolicy.allowsObjectFrom')
-  @DocsEditable
-  bool allowsObjectFrom(String url) native;
-
-  @DomName('DOMSecurityPolicy.allowsPluginType')
-  @DocsEditable
-  bool allowsPluginType(String type) native;
-
-  @DomName('DOMSecurityPolicy.allowsScriptFrom')
-  @DocsEditable
-  bool allowsScriptFrom(String url) native;
-
-  @DomName('DOMSecurityPolicy.allowsStyleFrom')
-  @DocsEditable
-  bool allowsStyleFrom(String url) 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('Selection')
-class DomSelection native "Selection" {
-
-  @DomName('DOMSelection.anchorNode')
-  @DocsEditable
-  final Node anchorNode;
-
-  @DomName('DOMSelection.anchorOffset')
-  @DocsEditable
-  final int anchorOffset;
-
-  @DomName('DOMSelection.baseNode')
-  @DocsEditable
-  final Node baseNode;
-
-  @DomName('DOMSelection.baseOffset')
-  @DocsEditable
-  final int baseOffset;
-
-  @DomName('DOMSelection.extentNode')
-  @DocsEditable
-  final Node extentNode;
-
-  @DomName('DOMSelection.extentOffset')
-  @DocsEditable
-  final int extentOffset;
-
-  @DomName('DOMSelection.focusNode')
-  @DocsEditable
-  final Node focusNode;
-
-  @DomName('DOMSelection.focusOffset')
-  @DocsEditable
-  final int focusOffset;
-
-  @DomName('DOMSelection.isCollapsed')
-  @DocsEditable
-  final bool isCollapsed;
-
-  @DomName('DOMSelection.rangeCount')
-  @DocsEditable
-  final int rangeCount;
-
-  @DomName('DOMSelection.type')
-  @DocsEditable
-  final String type;
-
-  @DomName('DOMSelection.addRange')
-  @DocsEditable
-  void addRange(Range range) native;
-
-  @DomName('DOMSelection.collapse')
-  @DocsEditable
-  void collapse(Node node, int index) native;
-
-  @DomName('DOMSelection.collapseToEnd')
-  @DocsEditable
-  void collapseToEnd() native;
-
-  @DomName('DOMSelection.collapseToStart')
-  @DocsEditable
-  void collapseToStart() native;
-
-  @DomName('DOMSelection.containsNode')
-  @DocsEditable
-  bool containsNode(Node node, bool allowPartial) native;
-
-  @DomName('DOMSelection.deleteFromDocument')
-  @DocsEditable
-  void deleteFromDocument() native;
-
-  @DomName('DOMSelection.empty')
-  @DocsEditable
-  void empty() native;
-
-  @DomName('DOMSelection.extend')
-  @DocsEditable
-  void extend(Node node, int offset) native;
-
-  @DomName('DOMSelection.getRangeAt')
-  @DocsEditable
-  Range getRangeAt(int index) native;
-
-  @DomName('DOMSelection.modify')
-  @DocsEditable
-  void modify(String alter, String direction, String granularity) native;
-
-  @DomName('DOMSelection.removeAllRanges')
-  @DocsEditable
-  void removeAllRanges() native;
-
-  @DomName('DOMSelection.selectAllChildren')
-  @DocsEditable
-  void selectAllChildren(Node node) native;
-
-  @DomName('DOMSelection.setBaseAndExtent')
-  @DocsEditable
-  void setBaseAndExtent(Node baseNode, int baseOffset, Node extentNode, int extentOffset) native;
-
-  @DomName('DOMSelection.setPosition')
-  @DocsEditable
-  void setPosition(Node node, int offset) native;
-
-  @DomName('DOMSelection.toString')
-  @DocsEditable
-  String toString() 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('DOMSettableTokenList')
 class DomSettableTokenList extends DomTokenList native "DOMSettableTokenList" {
 
@@ -7935,11 +7210,32 @@
   }
 }
 
+/** 
+ * An immutable list containing HTML elements. This list contains some
+ * additional methods for ease of CSS manipulation on a group of elements.
+ */
+abstract class ElementList<T extends Element> extends ListBase<T> {
+  /**
+   * The union of all CSS classes applied to the elements in this list.
+   *
+   * This set makes it easy to add, remove or toggle (add if not present, remove
+   * if present) the classes applied to a collection of elements.
+   *
+   *     htmlList.classes.add('selected');
+   *     htmlList.classes.toggle('isOnline');
+   *     htmlList.classes.remove('selected');
+   */
+  CssClassSet get classes;
+
+  /** Replace the classes with `value` for every element in this list. */
+  set classes(Iterable<String> value);
+}
+
 // TODO(jacobr): this is an inefficient implementation but it is hard to see
 // a better option given that we cannot quite force NodeList to be an
 // ElementList as there are valid cases where a NodeList JavaScript object
 // contains Node objects that are not Elements.
-class _FrozenElementList<T extends Element> extends ListBase<T> {
+class _FrozenElementList<T extends Element> extends ListBase<T> implements ElementList {
   final List<Node> _nodeList;
 
   _FrozenElementList._wrap(this._nodeList);
@@ -7965,30 +7261,12 @@
   Element get last => _nodeList.last;
 
   Element get single => _nodeList.single;
-}
 
-class _ElementCssClassSet extends CssClassSet {
+  CssClassSet get classes => new _MultiElementCssClassSet(
+      _nodeList.where((e) => e is Element));
 
-  final Element _element;
-
-  _ElementCssClassSet(this._element);
-
-  Set<String> readClasses() {
-    var s = new LinkedHashSet<String>();
-    var classname = _element.$dom_className;
-
-    for (String name in classname.split(' ')) {
-      String trimmed = name.trim();
-      if (!trimmed.isEmpty) {
-        s.add(trimmed);
-      }
-    }
-    return s;
-  }
-
-  void writeClasses(Set<String> s) {
-    List list = new List.from(s);
-    _element.$dom_className = s.join(' ');
+  void set classes(Iterable<String> value) {
+    _nodeList.where((e) => e is Element).forEach((e) => e.classes = value);
   }
 }
 
@@ -8088,7 +7366,7 @@
    *
    *     var items = element.query('.itemClassName');
    */
-  List<Element> queryAll(String selectors) =>
+  ElementList queryAll(String selectors) =>
     new _FrozenElementList._wrap($dom_querySelectorAll(selectors));
 
   /**
@@ -13607,7 +12885,7 @@
   @DocsEditable
   void stop() native;
 }
-// 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.
 
@@ -13638,10 +12916,6 @@
   @DocsEditable
   String href;
 
-  @DomName('Location.origin')
-  @DocsEditable
-  final String origin;
-
   @DomName('Location.pathname')
   @DocsEditable
   String pathname;
@@ -13677,6 +12951,15 @@
   @DomName('Location.valueOf')
   @DocsEditable
   Object valueOf() native;
+
+
+  @DomName('Location.origin')
+  String get origin {
+    if (JS('bool', '("origin" in #)', this)) {
+      return JS('String', '#.origin', this);
+    }
+    return '${this.protocol}//${this.host}';
+  }
 }
 // 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
@@ -14939,6 +14222,252 @@
 
 
 @DocsEditable
+@DomName('MimeType')
+class MimeType native "MimeType" {
+
+  @DomName('DOMMimeType.description')
+  @DocsEditable
+  final String description;
+
+  @DomName('DOMMimeType.enabledPlugin')
+  @DocsEditable
+  final Plugin enabledPlugin;
+
+  @DomName('DOMMimeType.suffixes')
+  @DocsEditable
+  final String suffixes;
+
+  @DomName('DOMMimeType.type')
+  @DocsEditable
+  final String type;
+}
+// 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('MimeTypeArray')
+class MimeTypeArray implements JavaScriptIndexingBehavior, List<MimeType> native "MimeTypeArray" {
+
+  @DomName('DOMMimeTypeArray.length')
+  @DocsEditable
+  int get length => JS("int", "#.length", this);
+
+  MimeType operator[](int index) => JS("MimeType", "#[#]", this, index);
+
+  void operator[]=(int index, MimeType value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<MimeType> mixins.
+  // MimeType is the element type.
+
+  // From Iterable<MimeType>:
+
+  Iterator<MimeType> 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<MimeType>(this);
+  }
+
+  MimeType reduce(MimeType combine(MimeType value, MimeType element)) {
+    return IterableMixinWorkaround.reduce(this, combine);
+  }
+
+  dynamic fold(dynamic initialValue,
+               dynamic combine(dynamic previousValue, MimeType element)) {
+    return IterableMixinWorkaround.fold(this, initialValue, combine);
+  }
+
+  bool contains(MimeType element) => IterableMixinWorkaround.contains(this, element);
+
+  void forEach(void f(MimeType element)) => IterableMixinWorkaround.forEach(this, f);
+
+  String join([String separator = ""]) =>
+      IterableMixinWorkaround.joinList(this, separator);
+
+  Iterable map(f(MimeType element)) =>
+      IterableMixinWorkaround.mapList(this, f);
+
+  Iterable<MimeType> where(bool f(MimeType element)) =>
+      IterableMixinWorkaround.where(this, f);
+
+  Iterable expand(Iterable f(MimeType element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
+  bool every(bool f(MimeType element)) => IterableMixinWorkaround.every(this, f);
+
+  bool any(bool f(MimeType element)) => IterableMixinWorkaround.any(this, f);
+
+  List<MimeType> toList({ bool growable: true }) =>
+      new List<MimeType>.from(this, growable: growable);
+
+  Set<MimeType> toSet() => new Set<MimeType>.from(this);
+
+  bool get isEmpty => this.length == 0;
+
+  Iterable<MimeType> take(int n) => IterableMixinWorkaround.takeList(this, n);
+
+  Iterable<MimeType> takeWhile(bool test(MimeType value)) {
+    return IterableMixinWorkaround.takeWhile(this, test);
+  }
+
+  Iterable<MimeType> skip(int n) => IterableMixinWorkaround.skipList(this, n);
+
+  Iterable<MimeType> skipWhile(bool test(MimeType value)) {
+    return IterableMixinWorkaround.skipWhile(this, test);
+  }
+
+  MimeType firstWhere(bool test(MimeType value), { MimeType orElse() }) {
+    return IterableMixinWorkaround.firstWhere(this, test, orElse);
+  }
+
+  MimeType lastWhere(bool test(MimeType value), {MimeType orElse()}) {
+    return IterableMixinWorkaround.lastWhereList(this, test, orElse);
+  }
+
+  MimeType singleWhere(bool test(MimeType value)) {
+    return IterableMixinWorkaround.singleWhere(this, test);
+  }
+
+  MimeType elementAt(int index) {
+    return this[index];
+  }
+
+  // From Collection<MimeType>:
+
+  void add(MimeType value) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void addAll(Iterable<MimeType> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  // From List<MimeType>:
+  void set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  void clear() {
+    throw new UnsupportedError("Cannot clear immutable List.");
+  }
+
+  Iterable<MimeType> get reversed {
+    return IterableMixinWorkaround.reversedList(this);
+  }
+
+  void sort([int compare(MimeType a, MimeType b)]) {
+    throw new UnsupportedError("Cannot sort immutable List.");
+  }
+
+  int indexOf(MimeType element, [int start = 0]) =>
+      Lists.indexOf(this, element, start, this.length);
+
+  int lastIndexOf(MimeType element, [int start]) {
+    if (start == null) start = length - 1;
+    return Lists.lastIndexOf(this, element, start);
+  }
+
+  MimeType get first {
+    if (this.length > 0) return this[0];
+    throw new StateError("No elements");
+  }
+
+  MimeType get last {
+    if (this.length > 0) return this[this.length - 1];
+    throw new StateError("No elements");
+  }
+
+  MimeType get single {
+    if (length == 1) return this[0];
+    if (length == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  void insert(int index, MimeType element) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void insertAll(int index, Iterable<MimeType> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void setAll(int index, Iterable<MimeType> iterable) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  MimeType removeAt(int pos) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  MimeType removeLast() {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  bool remove(Object object) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void removeWhere(bool test(MimeType element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void retainWhere(bool test(MimeType element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void setRange(int start, int end, Iterable<MimeType> iterable, [int skipCount=0]) {
+    throw new UnsupportedError("Cannot setRange on immutable List.");
+  }
+
+  void removeRange(int start, int end) {
+    throw new UnsupportedError("Cannot removeRange on immutable List.");
+  }
+
+  void replaceRange(int start, int end, Iterable<MimeType> iterable) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  void fillRange(int start, int end, [MimeType fillValue]) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  Iterable<MimeType> getRange(int start, int end) =>
+    IterableMixinWorkaround.getRangeList(this, start, end);
+
+  List<MimeType> sublist(int start, [int end]) {
+    if (end == null) end = length;
+    return Lists.getRange(this, start, end, <MimeType>[]);
+  }
+
+  Map<int, MimeType> asMap() =>
+    IterableMixinWorkaround.asMapList(this);
+
+  String toString() {
+    StringBuffer buffer = new StringBuffer('[');
+    buffer.writeAll(this, ', ');
+    buffer.write(']');
+    return buffer.toString();
+  }
+
+  // -- end List<MimeType> mixins.
+
+  @DomName('DOMMimeTypeArray.item')
+  @DocsEditable
+  MimeType item(int index) native;
+
+  @DomName('DOMMimeTypeArray.namedItem')
+  @DocsEditable
+  MimeType namedItem(String name) 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('HTMLModElement')
 class ModElement extends Element native "HTMLModElement" {
 
@@ -15333,6 +14862,9 @@
 
 @DocsEditable
 @DomName('WebKitNamedFlow')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
 class NamedFlow extends EventTarget native "WebKitNamedFlow" {
 
   @DomName('NamedFlow.firstEmptyRegionIndex')
@@ -15384,6 +14916,30 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
+@DocsEditable
+@DomName('WebKitNamedFlowCollection')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class NamedFlowCollection native "WebKitNamedFlowCollection" {
+
+  @DomName('DOMNamedFlowCollection.length')
+  @DocsEditable
+  final int length;
+
+  @DomName('DOMNamedFlowCollection.item')
+  @DocsEditable
+  NamedFlow item(int index) native;
+
+  @DomName('DOMNamedFlowCollection.namedItem')
+  @DocsEditable
+  NamedFlow namedItem(String name) 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.
+
+
 @DomName('Navigator')
 class Navigator native "Navigator" {
 
@@ -15485,7 +15041,7 @@
 
   @DomName('Navigator.mimeTypes')
   @DocsEditable
-  final DomMimeTypeArray mimeTypes;
+  final MimeTypeArray mimeTypes;
 
   @DomName('Navigator.onLine')
   @DocsEditable
@@ -15497,7 +15053,7 @@
 
   @DomName('Navigator.plugins')
   @DocsEditable
-  final DomPluginArray plugins;
+  final PluginArray plugins;
 
   @DomName('Navigator.product')
   @DocsEditable
@@ -16864,6 +16420,65 @@
 
 
 @DocsEditable
+@DomName('Path')
+class Path native "Path" {
+
+  @DomName('DOMPath.DOMPath')
+  @DocsEditable
+  factory Path([path_OR_text]) {
+    if (!?path_OR_text) {
+      return Path._create_1();
+    }
+    if ((path_OR_text is Path || path_OR_text == null)) {
+      return Path._create_2(path_OR_text);
+    }
+    if ((path_OR_text is String || path_OR_text == null)) {
+      return Path._create_3(path_OR_text);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+  static Path _create_1() => JS('Path', 'new Path()');
+  static Path _create_2(path_OR_text) => JS('Path', 'new Path(#)', path_OR_text);
+  static Path _create_3(path_OR_text) => JS('Path', 'new Path(#)', path_OR_text);
+
+  @DomName('DOMPath.arc')
+  @DocsEditable
+  void arc(num x, num y, num radius, num startAngle, num endAngle, bool anticlockwise) native;
+
+  @DomName('DOMPath.arcTo')
+  @DocsEditable
+  void arcTo(num x1, num y1, num x2, num y2, num radius) native;
+
+  @DomName('DOMPath.bezierCurveTo')
+  @DocsEditable
+  void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y) native;
+
+  @DomName('DOMPath.closePath')
+  @DocsEditable
+  void closePath() native;
+
+  @DomName('DOMPath.lineTo')
+  @DocsEditable
+  void lineTo(num x, num y) native;
+
+  @DomName('DOMPath.moveTo')
+  @DocsEditable
+  void moveTo(num x, num y) native;
+
+  @DomName('DOMPath.quadraticCurveTo')
+  @DocsEditable
+  void quadraticCurveTo(num cpx, num cpy, num x, num y) native;
+
+  @DomName('DOMPath.rect')
+  @DocsEditable
+  void rect(num x, num y, num width, num height) 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('Performance')
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.FIREFOX)
@@ -17202,6 +16817,264 @@
 
 
 @DocsEditable
+@DomName('Plugin')
+class Plugin native "Plugin" {
+
+  @DomName('DOMPlugin.description')
+  @DocsEditable
+  final String description;
+
+  @DomName('DOMPlugin.filename')
+  @DocsEditable
+  final String filename;
+
+  @DomName('DOMPlugin.length')
+  @DocsEditable
+  final int length;
+
+  @DomName('DOMPlugin.name')
+  @DocsEditable
+  final String name;
+
+  @DomName('DOMPlugin.item')
+  @DocsEditable
+  MimeType item(int index) native;
+
+  @DomName('DOMPlugin.namedItem')
+  @DocsEditable
+  MimeType namedItem(String name) 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('PluginArray')
+class PluginArray implements JavaScriptIndexingBehavior, List<Plugin> native "PluginArray" {
+
+  @DomName('DOMPluginArray.length')
+  @DocsEditable
+  int get length => JS("int", "#.length", this);
+
+  Plugin operator[](int index) => JS("Plugin", "#[#]", this, index);
+
+  void operator[]=(int index, Plugin value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Plugin> mixins.
+  // Plugin is the element type.
+
+  // From Iterable<Plugin>:
+
+  Iterator<Plugin> 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<Plugin>(this);
+  }
+
+  Plugin reduce(Plugin combine(Plugin value, Plugin element)) {
+    return IterableMixinWorkaround.reduce(this, combine);
+  }
+
+  dynamic fold(dynamic initialValue,
+               dynamic combine(dynamic previousValue, Plugin element)) {
+    return IterableMixinWorkaround.fold(this, initialValue, combine);
+  }
+
+  bool contains(Plugin element) => IterableMixinWorkaround.contains(this, element);
+
+  void forEach(void f(Plugin element)) => IterableMixinWorkaround.forEach(this, f);
+
+  String join([String separator = ""]) =>
+      IterableMixinWorkaround.joinList(this, separator);
+
+  Iterable map(f(Plugin element)) =>
+      IterableMixinWorkaround.mapList(this, f);
+
+  Iterable<Plugin> where(bool f(Plugin element)) =>
+      IterableMixinWorkaround.where(this, f);
+
+  Iterable expand(Iterable f(Plugin element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
+  bool every(bool f(Plugin element)) => IterableMixinWorkaround.every(this, f);
+
+  bool any(bool f(Plugin element)) => IterableMixinWorkaround.any(this, f);
+
+  List<Plugin> toList({ bool growable: true }) =>
+      new List<Plugin>.from(this, growable: growable);
+
+  Set<Plugin> toSet() => new Set<Plugin>.from(this);
+
+  bool get isEmpty => this.length == 0;
+
+  Iterable<Plugin> take(int n) => IterableMixinWorkaround.takeList(this, n);
+
+  Iterable<Plugin> takeWhile(bool test(Plugin value)) {
+    return IterableMixinWorkaround.takeWhile(this, test);
+  }
+
+  Iterable<Plugin> skip(int n) => IterableMixinWorkaround.skipList(this, n);
+
+  Iterable<Plugin> skipWhile(bool test(Plugin value)) {
+    return IterableMixinWorkaround.skipWhile(this, test);
+  }
+
+  Plugin firstWhere(bool test(Plugin value), { Plugin orElse() }) {
+    return IterableMixinWorkaround.firstWhere(this, test, orElse);
+  }
+
+  Plugin lastWhere(bool test(Plugin value), {Plugin orElse()}) {
+    return IterableMixinWorkaround.lastWhereList(this, test, orElse);
+  }
+
+  Plugin singleWhere(bool test(Plugin value)) {
+    return IterableMixinWorkaround.singleWhere(this, test);
+  }
+
+  Plugin elementAt(int index) {
+    return this[index];
+  }
+
+  // From Collection<Plugin>:
+
+  void add(Plugin value) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void addAll(Iterable<Plugin> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  // From List<Plugin>:
+  void set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  void clear() {
+    throw new UnsupportedError("Cannot clear immutable List.");
+  }
+
+  Iterable<Plugin> get reversed {
+    return IterableMixinWorkaround.reversedList(this);
+  }
+
+  void sort([int compare(Plugin a, Plugin b)]) {
+    throw new UnsupportedError("Cannot sort immutable List.");
+  }
+
+  int indexOf(Plugin element, [int start = 0]) =>
+      Lists.indexOf(this, element, start, this.length);
+
+  int lastIndexOf(Plugin element, [int start]) {
+    if (start == null) start = length - 1;
+    return Lists.lastIndexOf(this, element, start);
+  }
+
+  Plugin get first {
+    if (this.length > 0) return this[0];
+    throw new StateError("No elements");
+  }
+
+  Plugin get last {
+    if (this.length > 0) return this[this.length - 1];
+    throw new StateError("No elements");
+  }
+
+  Plugin get single {
+    if (length == 1) return this[0];
+    if (length == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  void insert(int index, Plugin element) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void insertAll(int index, Iterable<Plugin> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void setAll(int index, Iterable<Plugin> iterable) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  Plugin removeAt(int pos) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  Plugin removeLast() {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  bool remove(Object object) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void removeWhere(bool test(Plugin element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void retainWhere(bool test(Plugin element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void setRange(int start, int end, Iterable<Plugin> iterable, [int skipCount=0]) {
+    throw new UnsupportedError("Cannot setRange on immutable List.");
+  }
+
+  void removeRange(int start, int end) {
+    throw new UnsupportedError("Cannot removeRange on immutable List.");
+  }
+
+  void replaceRange(int start, int end, Iterable<Plugin> iterable) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  void fillRange(int start, int end, [Plugin fillValue]) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  Iterable<Plugin> getRange(int start, int end) =>
+    IterableMixinWorkaround.getRangeList(this, start, end);
+
+  List<Plugin> sublist(int start, [int end]) {
+    if (end == null) end = length;
+    return Lists.getRange(this, start, end, <Plugin>[]);
+  }
+
+  Map<int, Plugin> asMap() =>
+    IterableMixinWorkaround.asMapList(this);
+
+  String toString() {
+    StringBuffer buffer = new StringBuffer('[');
+    buffer.writeAll(this, ', ');
+    buffer.write(']');
+    return buffer.toString();
+  }
+
+  // -- end List<Plugin> mixins.
+
+  @DomName('DOMPluginArray.item')
+  @DocsEditable
+  Plugin item(int index) native;
+
+  @DomName('DOMPluginArray.namedItem')
+  @DocsEditable
+  Plugin namedItem(String name) native;
+
+  @DomName('DOMPluginArray.refresh')
+  @DocsEditable
+  void refresh(bool reload) 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('PopStateEvent')
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.FIREFOX)
@@ -17544,6 +17417,16 @@
   @DocsEditable
   String toString() native;
 
+
+  /**
+   * Checks if createContextualFragment is supported.
+   *
+   * See also:
+   *
+   * * [createContextualFragment]
+   */
+  static bool get supportsCreateContextualFragment =>
+      JS('bool', '("createContextualFragment" in window.Range.prototype)');
 }
 // 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
@@ -18364,6 +18247,77 @@
 
 
 @DocsEditable
+@DomName('SecurityPolicy')
+class SecurityPolicy native "SecurityPolicy" {
+
+  @DomName('DOMSecurityPolicy.allowsEval')
+  @DocsEditable
+  final bool allowsEval;
+
+  @DomName('DOMSecurityPolicy.allowsInlineScript')
+  @DocsEditable
+  final bool allowsInlineScript;
+
+  @DomName('DOMSecurityPolicy.allowsInlineStyle')
+  @DocsEditable
+  final bool allowsInlineStyle;
+
+  @DomName('DOMSecurityPolicy.isActive')
+  @DocsEditable
+  final bool isActive;
+
+  @DomName('DOMSecurityPolicy.reportURIs')
+  @DocsEditable
+  @Returns('DomStringList')
+  @Creates('DomStringList')
+  final List<String> reportURIs;
+
+  @DomName('DOMSecurityPolicy.allowsConnectionTo')
+  @DocsEditable
+  bool allowsConnectionTo(String url) native;
+
+  @DomName('DOMSecurityPolicy.allowsFontFrom')
+  @DocsEditable
+  bool allowsFontFrom(String url) native;
+
+  @DomName('DOMSecurityPolicy.allowsFormAction')
+  @DocsEditable
+  bool allowsFormAction(String url) native;
+
+  @DomName('DOMSecurityPolicy.allowsFrameFrom')
+  @DocsEditable
+  bool allowsFrameFrom(String url) native;
+
+  @DomName('DOMSecurityPolicy.allowsImageFrom')
+  @DocsEditable
+  bool allowsImageFrom(String url) native;
+
+  @DomName('DOMSecurityPolicy.allowsMediaFrom')
+  @DocsEditable
+  bool allowsMediaFrom(String url) native;
+
+  @DomName('DOMSecurityPolicy.allowsObjectFrom')
+  @DocsEditable
+  bool allowsObjectFrom(String url) native;
+
+  @DomName('DOMSecurityPolicy.allowsPluginType')
+  @DocsEditable
+  bool allowsPluginType(String type) native;
+
+  @DomName('DOMSecurityPolicy.allowsScriptFrom')
+  @DocsEditable
+  bool allowsScriptFrom(String url) native;
+
+  @DomName('DOMSecurityPolicy.allowsStyleFrom')
+  @DocsEditable
+  bool allowsStyleFrom(String url) 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('SecurityPolicyViolationEvent')
 class SecurityPolicyViolationEvent extends Event native "SecurityPolicyViolationEvent" {
 
@@ -18515,6 +18469,119 @@
 
 
 @DocsEditable
+@DomName('Selection')
+class Selection native "Selection" {
+
+  @DomName('DOMSelection.anchorNode')
+  @DocsEditable
+  final Node anchorNode;
+
+  @DomName('DOMSelection.anchorOffset')
+  @DocsEditable
+  final int anchorOffset;
+
+  @DomName('DOMSelection.baseNode')
+  @DocsEditable
+  final Node baseNode;
+
+  @DomName('DOMSelection.baseOffset')
+  @DocsEditable
+  final int baseOffset;
+
+  @DomName('DOMSelection.extentNode')
+  @DocsEditable
+  final Node extentNode;
+
+  @DomName('DOMSelection.extentOffset')
+  @DocsEditable
+  final int extentOffset;
+
+  @DomName('DOMSelection.focusNode')
+  @DocsEditable
+  final Node focusNode;
+
+  @DomName('DOMSelection.focusOffset')
+  @DocsEditable
+  final int focusOffset;
+
+  @DomName('DOMSelection.isCollapsed')
+  @DocsEditable
+  final bool isCollapsed;
+
+  @DomName('DOMSelection.rangeCount')
+  @DocsEditable
+  final int rangeCount;
+
+  @DomName('DOMSelection.type')
+  @DocsEditable
+  final String type;
+
+  @DomName('DOMSelection.addRange')
+  @DocsEditable
+  void addRange(Range range) native;
+
+  @DomName('DOMSelection.collapse')
+  @DocsEditable
+  void collapse(Node node, int index) native;
+
+  @DomName('DOMSelection.collapseToEnd')
+  @DocsEditable
+  void collapseToEnd() native;
+
+  @DomName('DOMSelection.collapseToStart')
+  @DocsEditable
+  void collapseToStart() native;
+
+  @DomName('DOMSelection.containsNode')
+  @DocsEditable
+  bool containsNode(Node node, bool allowPartial) native;
+
+  @DomName('DOMSelection.deleteFromDocument')
+  @DocsEditable
+  void deleteFromDocument() native;
+
+  @DomName('DOMSelection.empty')
+  @DocsEditable
+  void empty() native;
+
+  @DomName('DOMSelection.extend')
+  @DocsEditable
+  void extend(Node node, int offset) native;
+
+  @DomName('DOMSelection.getRangeAt')
+  @DocsEditable
+  Range getRangeAt(int index) native;
+
+  @DomName('DOMSelection.modify')
+  @DocsEditable
+  void modify(String alter, String direction, String granularity) native;
+
+  @DomName('DOMSelection.removeAllRanges')
+  @DocsEditable
+  void removeAllRanges() native;
+
+  @DomName('DOMSelection.selectAllChildren')
+  @DocsEditable
+  void selectAllChildren(Node node) native;
+
+  @DomName('DOMSelection.setBaseAndExtent')
+  @DocsEditable
+  void setBaseAndExtent(Node baseNode, int baseOffset, Node extentNode, int extentOffset) native;
+
+  @DomName('DOMSelection.setPosition')
+  @DocsEditable
+  void setPosition(Node node, int offset) native;
+
+  @DomName('DOMSelection.toString')
+  @DocsEditable
+  String toString() 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('HTMLShadowElement')
 @SupportedBrowser(SupportedBrowser.CHROME, '26')
 @Experimental
@@ -18587,7 +18654,7 @@
 
   @DomName('ShadowRoot.getSelection')
   @DocsEditable
-  DomSelection getSelection() native;
+  Selection getSelection() native;
 
   static bool get supported =>
       JS('bool', '!!(Element.prototype.webkitCreateShadowRoot)');
@@ -21724,34 +21791,6 @@
 
 
 @DocsEditable
-@DomName('WebKitCSSFilterRule')
-class WebKitCssFilterRule extends CssRule native "WebKitCSSFilterRule" {
-
-  @DomName('WebKitCSSFilterRule.style')
-  @DocsEditable
-  final CssStyleDeclaration style;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
-@DomName('WebKitCSSRegionRule')
-class WebKitCssRegionRule extends CssRule native "WebKitCSSRegionRule" {
-
-  @DomName('WebKitCSSRegionRule.cssRules')
-  @DocsEditable
-  @Returns('_CssRuleList')
-  @Creates('_CssRuleList')
-  final List<CssRule> cssRules;
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
 /**
  * Use the WebSocket interface to connect to a WebSocket,
  * and to send and receive data on that WebSocket.
@@ -22725,7 +22764,7 @@
 
   @DomName('DOMWindow.getSelection')
   @DocsEditable
-  DomSelection getSelection() native;
+  Selection getSelection() native;
 
   @DomName('DOMWindow.matchMedia')
   @DocsEditable
@@ -24281,6 +24320,9 @@
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.SAFARI)
 @Experimental
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
 class _DomPoint native "WebKitPoint" {
 
   @DomName('DOMPoint.DOMPoint')
@@ -26490,78 +26532,28 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
+/** A Set that stores the CSS class names for an element. */
 abstract class CssClassSet implements Set<String> {
 
-  String toString() {
-    return readClasses().join(' ');
-  }
-
   /**
    * Adds the class [value] to the element if it is not on it, removes it if it
    * is.
    */
-  bool toggle(String value) {
-    Set<String> s = readClasses();
-    bool result = false;
-    if (s.contains(value)) {
-      s.remove(value);
-    } else {
-      s.add(value);
-      result = true;
-    }
-    writeClasses(s);
-    return result;
-  }
+  bool toggle(String value);
 
   /**
    * Returns [:true:] if classes cannot be added or removed from this
    * [:CssClassSet:].
    */
-  bool get frozen => false;
+  bool get frozen;
 
-  // interface Iterable - BEGIN
-  Iterator<String> get iterator => readClasses().iterator;
-  // interface Iterable - END
-
-  // interface Collection - BEGIN
-  void forEach(void f(String element)) {
-    readClasses().forEach(f);
-  }
-
-  String join([String separator = ""]) => readClasses().join(separator);
-
-  Iterable map(f(String element)) => readClasses().map(f);
-
-  Iterable<String> where(bool f(String element)) => readClasses().where(f);
-
-  Iterable expand(Iterable f(String element)) => readClasses().expand(f);
-
-  bool every(bool f(String element)) => readClasses().every(f);
-
-  bool any(bool f(String element)) => readClasses().any(f);
-
-  bool get isEmpty => readClasses().isEmpty;
-
-  int get length => readClasses().length;
-
-  String reduce(String combine(String value, String element)) {
-    return readClasses().reduce(combine);
-  }
-
-  dynamic fold(dynamic initialValue,
-      dynamic combine(dynamic previousValue, String element)) {
-    return readClasses().fold(initialValue, combine);
-  }
-  // interface Collection - END
-
-  // interface Set - BEGIN
   /**
    * Determine if this element contains the class [value].
    *
    * This is the Dart equivalent of jQuery's
    * [hasClass](http://api.jquery.com/hasClass/).
    */
-  bool contains(String value) => readClasses().contains(value);
+  bool contains(String value);
 
   /**
    * Add the class [value] to element.
@@ -26569,11 +26561,7 @@
    * This is the Dart equivalent of jQuery's
    * [addClass](http://api.jquery.com/addClass/).
    */
-  void add(String value) {
-    // TODO - figure out if we need to do any validation here
-    // or if the browser natively does enough.
-    _modify((s) => s.add(value));
-  }
+  void add(String value);
 
   /**
    * Remove the class [value] from element, and return true on successful
@@ -26582,13 +26570,7 @@
    * This is the Dart equivalent of jQuery's
    * [removeClass](http://api.jquery.com/removeClass/).
    */
-  bool remove(Object value) {
-    if (value is! String) return false;
-    Set<String> s = readClasses();
-    bool result = s.remove(value);
-    writeClasses(s);
-    return result;
-  }
+  bool remove(Object value);
 
   /**
    * Add all classes specified in [iterable] to element.
@@ -26596,10 +26578,7 @@
    * This is the Dart equivalent of jQuery's
    * [addClass](http://api.jquery.com/addClass/).
    */
-  void addAll(Iterable<String> iterable) {
-    // TODO - see comment above about validation.
-    _modify((s) => s.addAll(iterable));
-  }
+  void addAll(Iterable<String> iterable);
 
   /**
    * Remove all classes specified in [iterable] from element.
@@ -26607,9 +26586,7 @@
    * This is the Dart equivalent of jQuery's
    * [removeClass](http://api.jquery.com/removeClass/).
    */
-  void removeAll(Iterable<String> iterable) {
-    _modify((s) => s.removeAll(iterable));
-  }
+  void removeAll(Iterable<String> iterable);
 
   /**
    * Toggles all classes specified in [iterable] on element.
@@ -26618,59 +26595,35 @@
    * remove it if it is. This is the Dart equivalent of jQuery's
    * [toggleClass](http://api.jquery.com/toggleClass/).
    */
-  void toggleAll(Iterable<String> iterable) {
-    iterable.forEach(toggle);
+  void toggleAll(Iterable<String> iterable);
+}
+
+/**
+ * A set (union) of the CSS classes that are present in a set of elements.
+ * Implemented separately from _ElementCssClassSet for performance.
+ */
+class _MultiElementCssClassSet extends CssClassSetImpl {
+  final Iterable<Element> _elementIterable;
+  Iterable<_ElementCssClassSet> _elementCssClassSetIterable;
+
+  _MultiElementCssClassSet(this._elementIterable) {
+    _elementCssClassSetIterable = new List.from(_elementIterable).map(
+        (e) => new _ElementCssClassSet(e));
   }
 
-  void retainAll(Iterable<String> iterable) {
-    _modify((s) => s.retainAll(iterable));
+  Set<String> readClasses() {
+    var s = new LinkedHashSet<String>();
+    _elementCssClassSetIterable.forEach((e) => s.addAll(e.readClasses()));
+    return s;
   }
 
-  void removeWhere(bool test(String name)) {
-    _modify((s) => s.removeWhere(test));
+  void writeClasses(Set<String> s) {
+    var classes = new List.from(s).join(' ');
+    for (Element e in _elementIterable) {
+      e.$dom_className = classes;
+    }
   }
 
-  void retainWhere(bool test(String name)) {
-    _modify((s) => s.retainWhere(test));
-  }
-
-  bool containsAll(Iterable<String> collection) =>
-    readClasses().containsAll(collection);
-
-  Set<String> intersection(Set<String> other) =>
-    readClasses().intersection(other);
-
-  Set<String> union(Set<String> other) =>
-    readClasses().union(other);
-
-  Set<String> difference(Set<String> other) =>
-    readClasses().difference(other);
-
-  String get first => readClasses().first;
-  String get last => readClasses().last;
-  String get single => readClasses().single;
-  List<String> toList({ bool growable: true }) =>
-      readClasses().toList(growable: growable);
-  Set<String> toSet() => readClasses().toSet();
-  Iterable<String> take(int n) => readClasses().take(n);
-  Iterable<String> takeWhile(bool test(String value)) =>
-      readClasses().takeWhile(test);
-  Iterable<String> skip(int n) => readClasses().skip(n);
-  Iterable<String> skipWhile(bool test(String value)) =>
-      readClasses().skipWhile(test);
-  String firstWhere(bool test(String value), { String orElse() }) =>
-      readClasses().firstWhere(test, orElse: orElse);
-  String lastWhere(bool test(String value), {String orElse()}) =>
-      readClasses().lastWhere(test, orElse: orElse);
-  String singleWhere(bool test(String value)) =>
-      readClasses().singleWhere(test);
-  String elementAt(int index) => readClasses().elementAt(index);
-
-  void clear() {
-    _modify((s) => s.clear());
-  }
-  // interface Set - END
-
   /**
    * Helper method used to modify the set of css classes on this element.
    *
@@ -26680,25 +26633,53 @@
    *   After f returns, the modified set is written to the
    *       className property of this element.
    */
-  void _modify( f(Set<String> s)) {
-    Set<String> s = readClasses();
-    f(s);
-    writeClasses(s);
+  void modify( f(Set<String> s)) {
+    _elementCssClassSetIterable.forEach((e) => e.modify(f));
   }
 
   /**
-   * Read the class names from the Element class property,
-   * and put them into a set (duplicates are discarded).
-   * This is intended to be overridden by specific implementations.
+   * Adds the class [value] to the element if it is not on it, removes it if it
+   * is.
    */
-  Set<String> readClasses();
+  bool toggle(String value) =>
+      _modifyWithReturnValue((e) => e.toggle(value));
 
   /**
-   * Join all the elements of a set into one string and write
-   * back to the element.
-   * This is intended to be overridden by specific implementations.
+   * Remove the class [value] from element, and return true on successful
+   * removal.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [removeClass](http://api.jquery.com/removeClass/).
    */
-  void writeClasses(Set<String> s);
+  bool remove(Object value) => _modifyWithReturnValue((e) => e.remove(value));
+
+  bool _modifyWithReturnValue(f) => _elementCssClassSetIterable.fold(
+      false, (prevValue, element) => f(element) || prevValue);
+}
+
+class _ElementCssClassSet extends CssClassSetImpl {
+
+  final Element _element;
+
+  _ElementCssClassSet(this._element);
+
+  Set<String> readClasses() {
+    var s = new LinkedHashSet<String>();
+    var classname = _element.$dom_className;
+
+    for (String name in classname.split(' ')) {
+      String trimmed = name.trim();
+      if (!trimmed.isEmpty) {
+        s.add(trimmed);
+      }
+    }
+    return s;
+  }
+
+  void writeClasses(Set<String> s) {
+    List list = new List.from(s);
+    _element.$dom_className = s.join(' ');
+  }
 }
 // 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
@@ -29469,7 +29450,12 @@
   }
 
   // final String origin;
-  String get origin => _get(_ptr, 'origin');
+  String get origin {
+    if (JS('bool', '("origin" in #)', _ptr)) {
+      return JS('String', '#.origin', _ptr);
+    }
+    return '${this.protocol}//${this.host}';
+  }
 
   // String pathname;
   String get pathname => _get(_ptr, 'pathname');
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 40efe9a..3b32ec2 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -262,6 +262,9 @@
 
 @DocsEditable
 @DomName('WebKitAnimationEvent')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
 class AnimationEvent extends Event {
   AnimationEvent.internal() : super.internal();
 
@@ -1189,11 +1192,11 @@
 
   @DomName('CanvasRenderingContext2D.currentPath')
   @DocsEditable
-  DomPath get currentPath native "CanvasRenderingContext2D_currentPath_Getter";
+  Path get currentPath native "CanvasRenderingContext2D_currentPath_Getter";
 
   @DomName('CanvasRenderingContext2D.currentPath')
   @DocsEditable
-  void set currentPath(DomPath value) native "CanvasRenderingContext2D_currentPath_Setter";
+  void set currentPath(Path value) native "CanvasRenderingContext2D_currentPath_Setter";
 
   @DomName('CanvasRenderingContext2D.fillStyle')
   @DocsEditable
@@ -2208,6 +2211,26 @@
 
 
 @DocsEditable
+@DomName('WebKitCSSFilterRule')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class CssFilterRule extends CssRule {
+  CssFilterRule.internal() : super.internal();
+
+  @DomName('WebKitCSSFilterRule.style')
+  @DocsEditable
+  CssStyleDeclaration get style native "WebKitCSSFilterRule_style_Getter";
+
+}
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
 @DomName('CSSFontFaceLoadEvent')
 class CssFontFaceLoadEvent extends Event {
   CssFontFaceLoadEvent.internal() : super.internal();
@@ -2299,6 +2322,9 @@
 
 @DocsEditable
 @DomName('WebKitCSSKeyframeRule')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
 class CssKeyframeRule extends CssRule {
   CssKeyframeRule.internal() : super.internal();
 
@@ -2324,6 +2350,9 @@
 
 @DocsEditable
 @DomName('WebKitCSSKeyframesRule')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
 class CssKeyframesRule extends CssRule {
   CssKeyframesRule.internal() : super.internal();
 
@@ -2414,6 +2443,26 @@
 
 
 @DocsEditable
+@DomName('WebKitCSSRegionRule')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class CssRegionRule extends CssRule {
+  CssRegionRule.internal() : super.internal();
+
+  @DomName('WebKitCSSRegionRule.cssRules')
+  @DocsEditable
+  List<CssRule> get cssRules native "WebKitCSSRegionRule_cssRules_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('CSSRule')
 class CssRule extends NativeFieldWrapperClass1 {
   CssRule.internal();
@@ -6474,7 +6523,7 @@
 
   @DomName('Document.securityPolicy')
   @DocsEditable
-  DomSecurityPolicy get securityPolicy native "Document_securityPolicy_Getter";
+  SecurityPolicy get securityPolicy native "Document_securityPolicy_Getter";
 
   @DomName('Document.selectedStylesheetSet')
   @DocsEditable
@@ -6718,7 +6767,7 @@
   @SupportedBrowser(SupportedBrowser.CHROME)
   @SupportedBrowser(SupportedBrowser.SAFARI)
   @Experimental
-  DomNamedFlowCollection getNamedFlows() native "Document_webkitGetNamedFlows_Callback";
+  NamedFlowCollection getNamedFlows() native "Document_webkitGetNamedFlows_Callback";
 
   @DomName('Document.webkitRegister')
   @DocsEditable
@@ -6938,7 +6987,7 @@
    * For details about CSS selector syntax, see the
    * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
    */
-  List<Element> queryAll(String selectors) {
+  ElementList queryAll(String selectors) {
     return new _FrozenElementList._wrap($dom_querySelectorAll(selectors));
   }
 }
@@ -7142,285 +7191,6 @@
 
 
 @DocsEditable
-@DomName('MimeType')
-class DomMimeType extends NativeFieldWrapperClass1 {
-  DomMimeType.internal();
-
-  @DomName('DOMMimeType.description')
-  @DocsEditable
-  String get description native "DOMMimeType_description_Getter";
-
-  @DomName('DOMMimeType.enabledPlugin')
-  @DocsEditable
-  DomPlugin get enabledPlugin native "DOMMimeType_enabledPlugin_Getter";
-
-  @DomName('DOMMimeType.suffixes')
-  @DocsEditable
-  String get suffixes native "DOMMimeType_suffixes_Getter";
-
-  @DomName('DOMMimeType.type')
-  @DocsEditable
-  String get type native "DOMMimeType_type_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('MimeTypeArray')
-class DomMimeTypeArray extends NativeFieldWrapperClass1 implements List<DomMimeType> {
-  DomMimeTypeArray.internal();
-
-  @DomName('DOMMimeTypeArray.length')
-  @DocsEditable
-  int get length native "DOMMimeTypeArray_length_Getter";
-
-  DomMimeType operator[](int index) native "DOMMimeTypeArray_item_Callback";
-
-  void operator[]=(int index, DomMimeType value) {
-    throw new UnsupportedError("Cannot assign element of immutable List.");
-  }
-  // -- start List<DomMimeType> mixins.
-  // DomMimeType is the element type.
-
-  // From Iterable<DomMimeType>:
-
-  Iterator<DomMimeType> 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<DomMimeType>(this);
-  }
-
-  DomMimeType reduce(DomMimeType combine(DomMimeType value, DomMimeType element)) {
-    return IterableMixinWorkaround.reduce(this, combine);
-  }
-
-  dynamic fold(dynamic initialValue,
-               dynamic combine(dynamic previousValue, DomMimeType element)) {
-    return IterableMixinWorkaround.fold(this, initialValue, combine);
-  }
-
-  bool contains(DomMimeType element) => IterableMixinWorkaround.contains(this, element);
-
-  void forEach(void f(DomMimeType element)) => IterableMixinWorkaround.forEach(this, f);
-
-  String join([String separator = ""]) =>
-      IterableMixinWorkaround.joinList(this, separator);
-
-  Iterable map(f(DomMimeType element)) =>
-      IterableMixinWorkaround.mapList(this, f);
-
-  Iterable<DomMimeType> where(bool f(DomMimeType element)) =>
-      IterableMixinWorkaround.where(this, f);
-
-  Iterable expand(Iterable f(DomMimeType element)) =>
-      IterableMixinWorkaround.expand(this, f);
-
-  bool every(bool f(DomMimeType element)) => IterableMixinWorkaround.every(this, f);
-
-  bool any(bool f(DomMimeType element)) => IterableMixinWorkaround.any(this, f);
-
-  List<DomMimeType> toList({ bool growable: true }) =>
-      new List<DomMimeType>.from(this, growable: growable);
-
-  Set<DomMimeType> toSet() => new Set<DomMimeType>.from(this);
-
-  bool get isEmpty => this.length == 0;
-
-  Iterable<DomMimeType> take(int n) => IterableMixinWorkaround.takeList(this, n);
-
-  Iterable<DomMimeType> takeWhile(bool test(DomMimeType value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
-  }
-
-  Iterable<DomMimeType> skip(int n) => IterableMixinWorkaround.skipList(this, n);
-
-  Iterable<DomMimeType> skipWhile(bool test(DomMimeType value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
-  }
-
-  DomMimeType firstWhere(bool test(DomMimeType value), { DomMimeType orElse() }) {
-    return IterableMixinWorkaround.firstWhere(this, test, orElse);
-  }
-
-  DomMimeType lastWhere(bool test(DomMimeType value), {DomMimeType orElse()}) {
-    return IterableMixinWorkaround.lastWhereList(this, test, orElse);
-  }
-
-  DomMimeType singleWhere(bool test(DomMimeType value)) {
-    return IterableMixinWorkaround.singleWhere(this, test);
-  }
-
-  DomMimeType elementAt(int index) {
-    return this[index];
-  }
-
-  // From Collection<DomMimeType>:
-
-  void add(DomMimeType value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addAll(Iterable<DomMimeType> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  // From List<DomMimeType>:
-  void set length(int value) {
-    throw new UnsupportedError("Cannot resize immutable List.");
-  }
-
-  void clear() {
-    throw new UnsupportedError("Cannot clear immutable List.");
-  }
-
-  Iterable<DomMimeType> get reversed {
-    return IterableMixinWorkaround.reversedList(this);
-  }
-
-  void sort([int compare(DomMimeType a, DomMimeType b)]) {
-    throw new UnsupportedError("Cannot sort immutable List.");
-  }
-
-  int indexOf(DomMimeType element, [int start = 0]) =>
-      Lists.indexOf(this, element, start, this.length);
-
-  int lastIndexOf(DomMimeType element, [int start]) {
-    if (start == null) start = length - 1;
-    return Lists.lastIndexOf(this, element, start);
-  }
-
-  DomMimeType get first {
-    if (this.length > 0) return this[0];
-    throw new StateError("No elements");
-  }
-
-  DomMimeType get last {
-    if (this.length > 0) return this[this.length - 1];
-    throw new StateError("No elements");
-  }
-
-  DomMimeType get single {
-    if (length == 1) return this[0];
-    if (length == 0) throw new StateError("No elements");
-    throw new StateError("More than one element");
-  }
-
-  void insert(int index, DomMimeType element) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void insertAll(int index, Iterable<DomMimeType> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void setAll(int index, Iterable<DomMimeType> iterable) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  DomMimeType removeAt(int pos) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  DomMimeType removeLast() {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  bool remove(Object object) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeWhere(bool test(DomMimeType element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainWhere(bool test(DomMimeType element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void setRange(int start, int end, Iterable<DomMimeType> iterable, [int skipCount=0]) {
-    throw new UnsupportedError("Cannot setRange on immutable List.");
-  }
-
-  void removeRange(int start, int end) {
-    throw new UnsupportedError("Cannot removeRange on immutable List.");
-  }
-
-  void replaceRange(int start, int end, Iterable<DomMimeType> iterable) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  void fillRange(int start, int end, [DomMimeType fillValue]) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  Iterable<DomMimeType> getRange(int start, int end) =>
-    IterableMixinWorkaround.getRangeList(this, start, end);
-
-  List<DomMimeType> sublist(int start, [int end]) {
-    if (end == null) end = length;
-    return Lists.getRange(this, start, end, <DomMimeType>[]);
-  }
-
-  Map<int, DomMimeType> asMap() =>
-    IterableMixinWorkaround.asMapList(this);
-
-  String toString() {
-    StringBuffer buffer = new StringBuffer('[');
-    buffer.writeAll(this, ', ');
-    buffer.write(']');
-    return buffer.toString();
-  }
-
-  // -- end List<DomMimeType> mixins.
-
-  @DomName('DOMMimeTypeArray.item')
-  @DocsEditable
-  DomMimeType item(int index) native "DOMMimeTypeArray_item_Callback";
-
-  @DomName('DOMMimeTypeArray.namedItem')
-  @DocsEditable
-  DomMimeType namedItem(String name) native "DOMMimeTypeArray_namedItem_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('WebKitNamedFlowCollection')
-class DomNamedFlowCollection extends NativeFieldWrapperClass1 {
-  DomNamedFlowCollection.internal();
-
-  @DomName('DOMNamedFlowCollection.length')
-  @DocsEditable
-  int get length native "DOMNamedFlowCollection_length_Getter";
-
-  @DomName('DOMNamedFlowCollection.item')
-  @DocsEditable
-  NamedFlow item(int index) native "DOMNamedFlowCollection_item_Callback";
-
-  @DomName('DOMNamedFlowCollection.namedItem')
-  @DocsEditable
-  NamedFlow namedItem(String name) native "DOMNamedFlowCollection_namedItem_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('DOMParser')
 class DomParser extends NativeFieldWrapperClass1 {
   DomParser.internal();
@@ -7447,531 +7217,6 @@
 
 
 @DocsEditable
-@DomName('Path')
-class DomPath extends NativeFieldWrapperClass1 {
-  DomPath.internal();
-
-  @DomName('DOMPath.DOMPath')
-  @DocsEditable
-  factory DomPath([path_OR_text]) {
-    if (!?path_OR_text) {
-      return DomPath._create_1();
-    }
-    if ((path_OR_text is DomPath || path_OR_text == null)) {
-      return DomPath._create_2(path_OR_text);
-    }
-    if ((path_OR_text is String || path_OR_text == null)) {
-      return DomPath._create_3(path_OR_text);
-    }
-    throw new ArgumentError("Incorrect number or type of arguments");
-  }
-
-  @DocsEditable
-  static DomPath _create_1() native "DOMPath__create_1constructorCallback";
-
-  @DocsEditable
-  static DomPath _create_2(path_OR_text) native "DOMPath__create_2constructorCallback";
-
-  @DocsEditable
-  static DomPath _create_3(path_OR_text) native "DOMPath__create_3constructorCallback";
-
-  @DomName('DOMPath.arc')
-  @DocsEditable
-  void arc(num x, num y, num radius, num startAngle, num endAngle, bool anticlockwise) native "DOMPath_arc_Callback";
-
-  @DomName('DOMPath.arcTo')
-  @DocsEditable
-  void arcTo(num x1, num y1, num x2, num y2, num radius) native "DOMPath_arcTo_Callback";
-
-  @DomName('DOMPath.bezierCurveTo')
-  @DocsEditable
-  void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y) native "DOMPath_bezierCurveTo_Callback";
-
-  @DomName('DOMPath.closePath')
-  @DocsEditable
-  void closePath() native "DOMPath_closePath_Callback";
-
-  @DomName('DOMPath.lineTo')
-  @DocsEditable
-  void lineTo(num x, num y) native "DOMPath_lineTo_Callback";
-
-  @DomName('DOMPath.moveTo')
-  @DocsEditable
-  void moveTo(num x, num y) native "DOMPath_moveTo_Callback";
-
-  @DomName('DOMPath.quadraticCurveTo')
-  @DocsEditable
-  void quadraticCurveTo(num cpx, num cpy, num x, num y) native "DOMPath_quadraticCurveTo_Callback";
-
-  @DomName('DOMPath.rect')
-  @DocsEditable
-  void rect(num x, num y, num width, num height) native "DOMPath_rect_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('Plugin')
-class DomPlugin extends NativeFieldWrapperClass1 {
-  DomPlugin.internal();
-
-  @DomName('DOMPlugin.description')
-  @DocsEditable
-  String get description native "DOMPlugin_description_Getter";
-
-  @DomName('DOMPlugin.filename')
-  @DocsEditable
-  String get filename native "DOMPlugin_filename_Getter";
-
-  @DomName('DOMPlugin.length')
-  @DocsEditable
-  int get length native "DOMPlugin_length_Getter";
-
-  @DomName('DOMPlugin.name')
-  @DocsEditable
-  String get name native "DOMPlugin_name_Getter";
-
-  @DomName('DOMPlugin.item')
-  @DocsEditable
-  DomMimeType item(int index) native "DOMPlugin_item_Callback";
-
-  @DomName('DOMPlugin.namedItem')
-  @DocsEditable
-  DomMimeType namedItem(String name) native "DOMPlugin_namedItem_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('PluginArray')
-class DomPluginArray extends NativeFieldWrapperClass1 implements List<DomPlugin> {
-  DomPluginArray.internal();
-
-  @DomName('DOMPluginArray.length')
-  @DocsEditable
-  int get length native "DOMPluginArray_length_Getter";
-
-  DomPlugin operator[](int index) native "DOMPluginArray_item_Callback";
-
-  void operator[]=(int index, DomPlugin value) {
-    throw new UnsupportedError("Cannot assign element of immutable List.");
-  }
-  // -- start List<DomPlugin> mixins.
-  // DomPlugin is the element type.
-
-  // From Iterable<DomPlugin>:
-
-  Iterator<DomPlugin> 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<DomPlugin>(this);
-  }
-
-  DomPlugin reduce(DomPlugin combine(DomPlugin value, DomPlugin element)) {
-    return IterableMixinWorkaround.reduce(this, combine);
-  }
-
-  dynamic fold(dynamic initialValue,
-               dynamic combine(dynamic previousValue, DomPlugin element)) {
-    return IterableMixinWorkaround.fold(this, initialValue, combine);
-  }
-
-  bool contains(DomPlugin element) => IterableMixinWorkaround.contains(this, element);
-
-  void forEach(void f(DomPlugin element)) => IterableMixinWorkaround.forEach(this, f);
-
-  String join([String separator = ""]) =>
-      IterableMixinWorkaround.joinList(this, separator);
-
-  Iterable map(f(DomPlugin element)) =>
-      IterableMixinWorkaround.mapList(this, f);
-
-  Iterable<DomPlugin> where(bool f(DomPlugin element)) =>
-      IterableMixinWorkaround.where(this, f);
-
-  Iterable expand(Iterable f(DomPlugin element)) =>
-      IterableMixinWorkaround.expand(this, f);
-
-  bool every(bool f(DomPlugin element)) => IterableMixinWorkaround.every(this, f);
-
-  bool any(bool f(DomPlugin element)) => IterableMixinWorkaround.any(this, f);
-
-  List<DomPlugin> toList({ bool growable: true }) =>
-      new List<DomPlugin>.from(this, growable: growable);
-
-  Set<DomPlugin> toSet() => new Set<DomPlugin>.from(this);
-
-  bool get isEmpty => this.length == 0;
-
-  Iterable<DomPlugin> take(int n) => IterableMixinWorkaround.takeList(this, n);
-
-  Iterable<DomPlugin> takeWhile(bool test(DomPlugin value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
-  }
-
-  Iterable<DomPlugin> skip(int n) => IterableMixinWorkaround.skipList(this, n);
-
-  Iterable<DomPlugin> skipWhile(bool test(DomPlugin value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
-  }
-
-  DomPlugin firstWhere(bool test(DomPlugin value), { DomPlugin orElse() }) {
-    return IterableMixinWorkaround.firstWhere(this, test, orElse);
-  }
-
-  DomPlugin lastWhere(bool test(DomPlugin value), {DomPlugin orElse()}) {
-    return IterableMixinWorkaround.lastWhereList(this, test, orElse);
-  }
-
-  DomPlugin singleWhere(bool test(DomPlugin value)) {
-    return IterableMixinWorkaround.singleWhere(this, test);
-  }
-
-  DomPlugin elementAt(int index) {
-    return this[index];
-  }
-
-  // From Collection<DomPlugin>:
-
-  void add(DomPlugin value) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void addAll(Iterable<DomPlugin> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  // From List<DomPlugin>:
-  void set length(int value) {
-    throw new UnsupportedError("Cannot resize immutable List.");
-  }
-
-  void clear() {
-    throw new UnsupportedError("Cannot clear immutable List.");
-  }
-
-  Iterable<DomPlugin> get reversed {
-    return IterableMixinWorkaround.reversedList(this);
-  }
-
-  void sort([int compare(DomPlugin a, DomPlugin b)]) {
-    throw new UnsupportedError("Cannot sort immutable List.");
-  }
-
-  int indexOf(DomPlugin element, [int start = 0]) =>
-      Lists.indexOf(this, element, start, this.length);
-
-  int lastIndexOf(DomPlugin element, [int start]) {
-    if (start == null) start = length - 1;
-    return Lists.lastIndexOf(this, element, start);
-  }
-
-  DomPlugin get first {
-    if (this.length > 0) return this[0];
-    throw new StateError("No elements");
-  }
-
-  DomPlugin get last {
-    if (this.length > 0) return this[this.length - 1];
-    throw new StateError("No elements");
-  }
-
-  DomPlugin get single {
-    if (length == 1) return this[0];
-    if (length == 0) throw new StateError("No elements");
-    throw new StateError("More than one element");
-  }
-
-  void insert(int index, DomPlugin element) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void insertAll(int index, Iterable<DomPlugin> iterable) {
-    throw new UnsupportedError("Cannot add to immutable List.");
-  }
-
-  void setAll(int index, Iterable<DomPlugin> iterable) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  DomPlugin removeAt(int pos) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  DomPlugin removeLast() {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  bool remove(Object object) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void removeWhere(bool test(DomPlugin element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void retainWhere(bool test(DomPlugin element)) {
-    throw new UnsupportedError("Cannot remove from immutable List.");
-  }
-
-  void setRange(int start, int end, Iterable<DomPlugin> iterable, [int skipCount=0]) {
-    throw new UnsupportedError("Cannot setRange on immutable List.");
-  }
-
-  void removeRange(int start, int end) {
-    throw new UnsupportedError("Cannot removeRange on immutable List.");
-  }
-
-  void replaceRange(int start, int end, Iterable<DomPlugin> iterable) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  void fillRange(int start, int end, [DomPlugin fillValue]) {
-    throw new UnsupportedError("Cannot modify an immutable List.");
-  }
-
-  Iterable<DomPlugin> getRange(int start, int end) =>
-    IterableMixinWorkaround.getRangeList(this, start, end);
-
-  List<DomPlugin> sublist(int start, [int end]) {
-    if (end == null) end = length;
-    return Lists.getRange(this, start, end, <DomPlugin>[]);
-  }
-
-  Map<int, DomPlugin> asMap() =>
-    IterableMixinWorkaround.asMapList(this);
-
-  String toString() {
-    StringBuffer buffer = new StringBuffer('[');
-    buffer.writeAll(this, ', ');
-    buffer.write(']');
-    return buffer.toString();
-  }
-
-  // -- end List<DomPlugin> mixins.
-
-  @DomName('DOMPluginArray.item')
-  @DocsEditable
-  DomPlugin item(int index) native "DOMPluginArray_item_Callback";
-
-  @DomName('DOMPluginArray.namedItem')
-  @DocsEditable
-  DomPlugin namedItem(String name) native "DOMPluginArray_namedItem_Callback";
-
-  @DomName('DOMPluginArray.refresh')
-  @DocsEditable
-  void refresh(bool reload) native "DOMPluginArray_refresh_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('SecurityPolicy')
-class DomSecurityPolicy extends NativeFieldWrapperClass1 {
-  DomSecurityPolicy.internal();
-
-  @DomName('DOMSecurityPolicy.allowsEval')
-  @DocsEditable
-  bool get allowsEval native "DOMSecurityPolicy_allowsEval_Getter";
-
-  @DomName('DOMSecurityPolicy.allowsInlineScript')
-  @DocsEditable
-  bool get allowsInlineScript native "DOMSecurityPolicy_allowsInlineScript_Getter";
-
-  @DomName('DOMSecurityPolicy.allowsInlineStyle')
-  @DocsEditable
-  bool get allowsInlineStyle native "DOMSecurityPolicy_allowsInlineStyle_Getter";
-
-  @DomName('DOMSecurityPolicy.isActive')
-  @DocsEditable
-  bool get isActive native "DOMSecurityPolicy_isActive_Getter";
-
-  @DomName('DOMSecurityPolicy.reportURIs')
-  @DocsEditable
-  List<String> get reportURIs native "DOMSecurityPolicy_reportURIs_Getter";
-
-  @DomName('DOMSecurityPolicy.allowsConnectionTo')
-  @DocsEditable
-  bool allowsConnectionTo(String url) native "DOMSecurityPolicy_allowsConnectionTo_Callback";
-
-  @DomName('DOMSecurityPolicy.allowsFontFrom')
-  @DocsEditable
-  bool allowsFontFrom(String url) native "DOMSecurityPolicy_allowsFontFrom_Callback";
-
-  @DomName('DOMSecurityPolicy.allowsFormAction')
-  @DocsEditable
-  bool allowsFormAction(String url) native "DOMSecurityPolicy_allowsFormAction_Callback";
-
-  @DomName('DOMSecurityPolicy.allowsFrameFrom')
-  @DocsEditable
-  bool allowsFrameFrom(String url) native "DOMSecurityPolicy_allowsFrameFrom_Callback";
-
-  @DomName('DOMSecurityPolicy.allowsImageFrom')
-  @DocsEditable
-  bool allowsImageFrom(String url) native "DOMSecurityPolicy_allowsImageFrom_Callback";
-
-  @DomName('DOMSecurityPolicy.allowsMediaFrom')
-  @DocsEditable
-  bool allowsMediaFrom(String url) native "DOMSecurityPolicy_allowsMediaFrom_Callback";
-
-  @DomName('DOMSecurityPolicy.allowsObjectFrom')
-  @DocsEditable
-  bool allowsObjectFrom(String url) native "DOMSecurityPolicy_allowsObjectFrom_Callback";
-
-  @DomName('DOMSecurityPolicy.allowsPluginType')
-  @DocsEditable
-  bool allowsPluginType(String type) native "DOMSecurityPolicy_allowsPluginType_Callback";
-
-  @DomName('DOMSecurityPolicy.allowsScriptFrom')
-  @DocsEditable
-  bool allowsScriptFrom(String url) native "DOMSecurityPolicy_allowsScriptFrom_Callback";
-
-  @DomName('DOMSecurityPolicy.allowsStyleFrom')
-  @DocsEditable
-  bool allowsStyleFrom(String url) native "DOMSecurityPolicy_allowsStyleFrom_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('Selection')
-class DomSelection extends NativeFieldWrapperClass1 {
-  DomSelection.internal();
-
-  @DomName('DOMSelection.anchorNode')
-  @DocsEditable
-  Node get anchorNode native "DOMSelection_anchorNode_Getter";
-
-  @DomName('DOMSelection.anchorOffset')
-  @DocsEditable
-  int get anchorOffset native "DOMSelection_anchorOffset_Getter";
-
-  @DomName('DOMSelection.baseNode')
-  @DocsEditable
-  Node get baseNode native "DOMSelection_baseNode_Getter";
-
-  @DomName('DOMSelection.baseOffset')
-  @DocsEditable
-  int get baseOffset native "DOMSelection_baseOffset_Getter";
-
-  @DomName('DOMSelection.extentNode')
-  @DocsEditable
-  Node get extentNode native "DOMSelection_extentNode_Getter";
-
-  @DomName('DOMSelection.extentOffset')
-  @DocsEditable
-  int get extentOffset native "DOMSelection_extentOffset_Getter";
-
-  @DomName('DOMSelection.focusNode')
-  @DocsEditable
-  Node get focusNode native "DOMSelection_focusNode_Getter";
-
-  @DomName('DOMSelection.focusOffset')
-  @DocsEditable
-  int get focusOffset native "DOMSelection_focusOffset_Getter";
-
-  @DomName('DOMSelection.isCollapsed')
-  @DocsEditable
-  bool get isCollapsed native "DOMSelection_isCollapsed_Getter";
-
-  @DomName('DOMSelection.rangeCount')
-  @DocsEditable
-  int get rangeCount native "DOMSelection_rangeCount_Getter";
-
-  @DomName('DOMSelection.type')
-  @DocsEditable
-  String get type native "DOMSelection_type_Getter";
-
-  @DomName('DOMSelection.addRange')
-  @DocsEditable
-  void addRange(Range range) native "DOMSelection_addRange_Callback";
-
-  @DomName('DOMSelection.collapse')
-  @DocsEditable
-  void collapse(Node node, int index) native "DOMSelection_collapse_Callback";
-
-  @DomName('DOMSelection.collapseToEnd')
-  @DocsEditable
-  void collapseToEnd() native "DOMSelection_collapseToEnd_Callback";
-
-  @DomName('DOMSelection.collapseToStart')
-  @DocsEditable
-  void collapseToStart() native "DOMSelection_collapseToStart_Callback";
-
-  @DomName('DOMSelection.containsNode')
-  @DocsEditable
-  bool containsNode(Node node, bool allowPartial) native "DOMSelection_containsNode_Callback";
-
-  @DomName('DOMSelection.deleteFromDocument')
-  @DocsEditable
-  void deleteFromDocument() native "DOMSelection_deleteFromDocument_Callback";
-
-  @DomName('DOMSelection.empty')
-  @DocsEditable
-  void empty() native "DOMSelection_empty_Callback";
-
-  @DomName('DOMSelection.extend')
-  @DocsEditable
-  void extend(Node node, int offset) native "DOMSelection_extend_Callback";
-
-  @DomName('DOMSelection.getRangeAt')
-  @DocsEditable
-  Range getRangeAt(int index) native "DOMSelection_getRangeAt_Callback";
-
-  @DomName('DOMSelection.modify')
-  @DocsEditable
-  void modify(String alter, String direction, String granularity) native "DOMSelection_modify_Callback";
-
-  @DomName('DOMSelection.removeAllRanges')
-  @DocsEditable
-  void removeAllRanges() native "DOMSelection_removeAllRanges_Callback";
-
-  @DomName('DOMSelection.selectAllChildren')
-  @DocsEditable
-  void selectAllChildren(Node node) native "DOMSelection_selectAllChildren_Callback";
-
-  @DomName('DOMSelection.setBaseAndExtent')
-  @DocsEditable
-  void setBaseAndExtent(Node baseNode, int baseOffset, Node extentNode, int extentOffset) native "DOMSelection_setBaseAndExtent_Callback";
-
-  @DomName('DOMSelection.setPosition')
-  @DocsEditable
-  void setPosition(Node node, int offset) native "DOMSelection_setPosition_Callback";
-
-  @DomName('DOMSelection.toString')
-  @DocsEditable
-  String toString() native "DOMSelection_toString_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('DOMSettableTokenList')
 class DomSettableTokenList extends DomTokenList {
   DomSettableTokenList.internal() : super.internal();
@@ -8401,11 +7646,32 @@
   }
 }
 
+/** 
+ * An immutable list containing HTML elements. This list contains some
+ * additional methods for ease of CSS manipulation on a group of elements.
+ */
+abstract class ElementList<T extends Element> extends ListBase<T> {
+  /**
+   * The union of all CSS classes applied to the elements in this list.
+   *
+   * This set makes it easy to add, remove or toggle (add if not present, remove
+   * if present) the classes applied to a collection of elements.
+   *
+   *     htmlList.classes.add('selected');
+   *     htmlList.classes.toggle('isOnline');
+   *     htmlList.classes.remove('selected');
+   */
+  CssClassSet get classes;
+
+  /** Replace the classes with `value` for every element in this list. */
+  set classes(Iterable<String> value);
+}
+
 // TODO(jacobr): this is an inefficient implementation but it is hard to see
 // a better option given that we cannot quite force NodeList to be an
 // ElementList as there are valid cases where a NodeList JavaScript object
 // contains Node objects that are not Elements.
-class _FrozenElementList<T extends Element> extends ListBase<T> {
+class _FrozenElementList<T extends Element> extends ListBase<T> implements ElementList {
   final List<Node> _nodeList;
 
   _FrozenElementList._wrap(this._nodeList);
@@ -8431,30 +7697,12 @@
   Element get last => _nodeList.last;
 
   Element get single => _nodeList.single;
-}
 
-class _ElementCssClassSet extends CssClassSet {
+  CssClassSet get classes => new _MultiElementCssClassSet(
+      _nodeList.where((e) => e is Element));
 
-  final Element _element;
-
-  _ElementCssClassSet(this._element);
-
-  Set<String> readClasses() {
-    var s = new LinkedHashSet<String>();
-    var classname = _element.$dom_className;
-
-    for (String name in classname.split(' ')) {
-      String trimmed = name.trim();
-      if (!trimmed.isEmpty) {
-        s.add(trimmed);
-      }
-    }
-    return s;
-  }
-
-  void writeClasses(Set<String> s) {
-    List list = new List.from(s);
-    _element.$dom_className = s.join(' ');
+  void set classes(Iterable<String> value) {
+    _nodeList.where((e) => e is Element).forEach((e) => e.classes = value);
   }
 }
 
@@ -8554,7 +7802,7 @@
    *
    *     var items = element.query('.itemClassName');
    */
-  List<Element> queryAll(String selectors) =>
+  ElementList queryAll(String selectors) =>
     new _FrozenElementList._wrap($dom_querySelectorAll(selectors));
 
   /**
@@ -14394,12 +13642,10 @@
   void stop() native "LocalMediaStream_stop_Callback";
 
 }
-// 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.
 
-// WARNING: Do not edit - generated code.
-
 
 @DocsEditable
 @DomName('Location')
@@ -14498,6 +13744,7 @@
   @DocsEditable
   Object valueOf() native "Location_valueOf_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
@@ -15956,6 +15203,260 @@
 
 
 @DocsEditable
+@DomName('MimeType')
+class MimeType extends NativeFieldWrapperClass1 {
+  MimeType.internal();
+
+  @DomName('DOMMimeType.description')
+  @DocsEditable
+  String get description native "DOMMimeType_description_Getter";
+
+  @DomName('DOMMimeType.enabledPlugin')
+  @DocsEditable
+  Plugin get enabledPlugin native "DOMMimeType_enabledPlugin_Getter";
+
+  @DomName('DOMMimeType.suffixes')
+  @DocsEditable
+  String get suffixes native "DOMMimeType_suffixes_Getter";
+
+  @DomName('DOMMimeType.type')
+  @DocsEditable
+  String get type native "DOMMimeType_type_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('MimeTypeArray')
+class MimeTypeArray extends NativeFieldWrapperClass1 implements List<MimeType> {
+  MimeTypeArray.internal();
+
+  @DomName('DOMMimeTypeArray.length')
+  @DocsEditable
+  int get length native "DOMMimeTypeArray_length_Getter";
+
+  MimeType operator[](int index) native "DOMMimeTypeArray_item_Callback";
+
+  void operator[]=(int index, MimeType value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<MimeType> mixins.
+  // MimeType is the element type.
+
+  // From Iterable<MimeType>:
+
+  Iterator<MimeType> 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<MimeType>(this);
+  }
+
+  MimeType reduce(MimeType combine(MimeType value, MimeType element)) {
+    return IterableMixinWorkaround.reduce(this, combine);
+  }
+
+  dynamic fold(dynamic initialValue,
+               dynamic combine(dynamic previousValue, MimeType element)) {
+    return IterableMixinWorkaround.fold(this, initialValue, combine);
+  }
+
+  bool contains(MimeType element) => IterableMixinWorkaround.contains(this, element);
+
+  void forEach(void f(MimeType element)) => IterableMixinWorkaround.forEach(this, f);
+
+  String join([String separator = ""]) =>
+      IterableMixinWorkaround.joinList(this, separator);
+
+  Iterable map(f(MimeType element)) =>
+      IterableMixinWorkaround.mapList(this, f);
+
+  Iterable<MimeType> where(bool f(MimeType element)) =>
+      IterableMixinWorkaround.where(this, f);
+
+  Iterable expand(Iterable f(MimeType element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
+  bool every(bool f(MimeType element)) => IterableMixinWorkaround.every(this, f);
+
+  bool any(bool f(MimeType element)) => IterableMixinWorkaround.any(this, f);
+
+  List<MimeType> toList({ bool growable: true }) =>
+      new List<MimeType>.from(this, growable: growable);
+
+  Set<MimeType> toSet() => new Set<MimeType>.from(this);
+
+  bool get isEmpty => this.length == 0;
+
+  Iterable<MimeType> take(int n) => IterableMixinWorkaround.takeList(this, n);
+
+  Iterable<MimeType> takeWhile(bool test(MimeType value)) {
+    return IterableMixinWorkaround.takeWhile(this, test);
+  }
+
+  Iterable<MimeType> skip(int n) => IterableMixinWorkaround.skipList(this, n);
+
+  Iterable<MimeType> skipWhile(bool test(MimeType value)) {
+    return IterableMixinWorkaround.skipWhile(this, test);
+  }
+
+  MimeType firstWhere(bool test(MimeType value), { MimeType orElse() }) {
+    return IterableMixinWorkaround.firstWhere(this, test, orElse);
+  }
+
+  MimeType lastWhere(bool test(MimeType value), {MimeType orElse()}) {
+    return IterableMixinWorkaround.lastWhereList(this, test, orElse);
+  }
+
+  MimeType singleWhere(bool test(MimeType value)) {
+    return IterableMixinWorkaround.singleWhere(this, test);
+  }
+
+  MimeType elementAt(int index) {
+    return this[index];
+  }
+
+  // From Collection<MimeType>:
+
+  void add(MimeType value) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void addAll(Iterable<MimeType> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  // From List<MimeType>:
+  void set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  void clear() {
+    throw new UnsupportedError("Cannot clear immutable List.");
+  }
+
+  Iterable<MimeType> get reversed {
+    return IterableMixinWorkaround.reversedList(this);
+  }
+
+  void sort([int compare(MimeType a, MimeType b)]) {
+    throw new UnsupportedError("Cannot sort immutable List.");
+  }
+
+  int indexOf(MimeType element, [int start = 0]) =>
+      Lists.indexOf(this, element, start, this.length);
+
+  int lastIndexOf(MimeType element, [int start]) {
+    if (start == null) start = length - 1;
+    return Lists.lastIndexOf(this, element, start);
+  }
+
+  MimeType get first {
+    if (this.length > 0) return this[0];
+    throw new StateError("No elements");
+  }
+
+  MimeType get last {
+    if (this.length > 0) return this[this.length - 1];
+    throw new StateError("No elements");
+  }
+
+  MimeType get single {
+    if (length == 1) return this[0];
+    if (length == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  void insert(int index, MimeType element) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void insertAll(int index, Iterable<MimeType> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void setAll(int index, Iterable<MimeType> iterable) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  MimeType removeAt(int pos) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  MimeType removeLast() {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  bool remove(Object object) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void removeWhere(bool test(MimeType element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void retainWhere(bool test(MimeType element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void setRange(int start, int end, Iterable<MimeType> iterable, [int skipCount=0]) {
+    throw new UnsupportedError("Cannot setRange on immutable List.");
+  }
+
+  void removeRange(int start, int end) {
+    throw new UnsupportedError("Cannot removeRange on immutable List.");
+  }
+
+  void replaceRange(int start, int end, Iterable<MimeType> iterable) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  void fillRange(int start, int end, [MimeType fillValue]) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  Iterable<MimeType> getRange(int start, int end) =>
+    IterableMixinWorkaround.getRangeList(this, start, end);
+
+  List<MimeType> sublist(int start, [int end]) {
+    if (end == null) end = length;
+    return Lists.getRange(this, start, end, <MimeType>[]);
+  }
+
+  Map<int, MimeType> asMap() =>
+    IterableMixinWorkaround.asMapList(this);
+
+  String toString() {
+    StringBuffer buffer = new StringBuffer('[');
+    buffer.writeAll(this, ', ');
+    buffer.write(']');
+    return buffer.toString();
+  }
+
+  // -- end List<MimeType> mixins.
+
+  @DomName('DOMMimeTypeArray.item')
+  @DocsEditable
+  MimeType item(int index) native "DOMMimeTypeArray_item_Callback";
+
+  @DomName('DOMMimeTypeArray.namedItem')
+  @DocsEditable
+  MimeType namedItem(String name) native "DOMMimeTypeArray_namedItem_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('HTMLModElement')
 class ModElement extends _Element_Merged {
   ModElement.internal() : super.internal();
@@ -16326,6 +15827,9 @@
 
 @DocsEditable
 @DomName('WebKitNamedFlow')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
 class NamedFlow extends EventTarget {
   NamedFlow.internal() : super.internal();
 
@@ -16370,6 +15874,34 @@
 // for 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('WebKitNamedFlowCollection')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
+class NamedFlowCollection extends NativeFieldWrapperClass1 {
+  NamedFlowCollection.internal();
+
+  @DomName('DOMNamedFlowCollection.length')
+  @DocsEditable
+  int get length native "DOMNamedFlowCollection_length_Getter";
+
+  @DomName('DOMNamedFlowCollection.item')
+  @DocsEditable
+  NamedFlow item(int index) native "DOMNamedFlowCollection_item_Callback";
+
+  @DomName('DOMNamedFlowCollection.namedItem')
+  @DocsEditable
+  NamedFlow namedItem(String name) native "DOMNamedFlowCollection_namedItem_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.
+
 
 @DomName('Navigator')
 class Navigator extends NativeFieldWrapperClass1 {
@@ -16462,7 +15994,7 @@
 
   @DomName('Navigator.mimeTypes')
   @DocsEditable
-  DomMimeTypeArray get mimeTypes native "Navigator_mimeTypes_Getter";
+  MimeTypeArray get mimeTypes native "Navigator_mimeTypes_Getter";
 
   @DomName('Navigator.onLine')
   @DocsEditable
@@ -16474,7 +16006,7 @@
 
   @DomName('Navigator.plugins')
   @DocsEditable
-  DomPluginArray get plugins native "Navigator_plugins_Getter";
+  PluginArray get plugins native "Navigator_plugins_Getter";
 
   @DomName('Navigator.product')
   @DocsEditable
@@ -17957,6 +17489,75 @@
 
 
 @DocsEditable
+@DomName('Path')
+class Path extends NativeFieldWrapperClass1 {
+  Path.internal();
+
+  @DomName('DOMPath.DOMPath')
+  @DocsEditable
+  factory Path([path_OR_text]) {
+    if (!?path_OR_text) {
+      return Path._create_1();
+    }
+    if ((path_OR_text is Path || path_OR_text == null)) {
+      return Path._create_2(path_OR_text);
+    }
+    if ((path_OR_text is String || path_OR_text == null)) {
+      return Path._create_3(path_OR_text);
+    }
+    throw new ArgumentError("Incorrect number or type of arguments");
+  }
+
+  @DocsEditable
+  static Path _create_1() native "DOMPath__create_1constructorCallback";
+
+  @DocsEditable
+  static Path _create_2(path_OR_text) native "DOMPath__create_2constructorCallback";
+
+  @DocsEditable
+  static Path _create_3(path_OR_text) native "DOMPath__create_3constructorCallback";
+
+  @DomName('DOMPath.arc')
+  @DocsEditable
+  void arc(num x, num y, num radius, num startAngle, num endAngle, bool anticlockwise) native "DOMPath_arc_Callback";
+
+  @DomName('DOMPath.arcTo')
+  @DocsEditable
+  void arcTo(num x1, num y1, num x2, num y2, num radius) native "DOMPath_arcTo_Callback";
+
+  @DomName('DOMPath.bezierCurveTo')
+  @DocsEditable
+  void bezierCurveTo(num cp1x, num cp1y, num cp2x, num cp2y, num x, num y) native "DOMPath_bezierCurveTo_Callback";
+
+  @DomName('DOMPath.closePath')
+  @DocsEditable
+  void closePath() native "DOMPath_closePath_Callback";
+
+  @DomName('DOMPath.lineTo')
+  @DocsEditable
+  void lineTo(num x, num y) native "DOMPath_lineTo_Callback";
+
+  @DomName('DOMPath.moveTo')
+  @DocsEditable
+  void moveTo(num x, num y) native "DOMPath_moveTo_Callback";
+
+  @DomName('DOMPath.quadraticCurveTo')
+  @DocsEditable
+  void quadraticCurveTo(num cpx, num cpy, num x, num y) native "DOMPath_quadraticCurveTo_Callback";
+
+  @DomName('DOMPath.rect')
+  @DocsEditable
+  void rect(num x, num y, num width, num height) native "DOMPath_rect_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('Performance')
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.FIREFOX)
@@ -18318,6 +17919,272 @@
 
 
 @DocsEditable
+@DomName('Plugin')
+class Plugin extends NativeFieldWrapperClass1 {
+  Plugin.internal();
+
+  @DomName('DOMPlugin.description')
+  @DocsEditable
+  String get description native "DOMPlugin_description_Getter";
+
+  @DomName('DOMPlugin.filename')
+  @DocsEditable
+  String get filename native "DOMPlugin_filename_Getter";
+
+  @DomName('DOMPlugin.length')
+  @DocsEditable
+  int get length native "DOMPlugin_length_Getter";
+
+  @DomName('DOMPlugin.name')
+  @DocsEditable
+  String get name native "DOMPlugin_name_Getter";
+
+  @DomName('DOMPlugin.item')
+  @DocsEditable
+  MimeType item(int index) native "DOMPlugin_item_Callback";
+
+  @DomName('DOMPlugin.namedItem')
+  @DocsEditable
+  MimeType namedItem(String name) native "DOMPlugin_namedItem_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('PluginArray')
+class PluginArray extends NativeFieldWrapperClass1 implements List<Plugin> {
+  PluginArray.internal();
+
+  @DomName('DOMPluginArray.length')
+  @DocsEditable
+  int get length native "DOMPluginArray_length_Getter";
+
+  Plugin operator[](int index) native "DOMPluginArray_item_Callback";
+
+  void operator[]=(int index, Plugin value) {
+    throw new UnsupportedError("Cannot assign element of immutable List.");
+  }
+  // -- start List<Plugin> mixins.
+  // Plugin is the element type.
+
+  // From Iterable<Plugin>:
+
+  Iterator<Plugin> 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<Plugin>(this);
+  }
+
+  Plugin reduce(Plugin combine(Plugin value, Plugin element)) {
+    return IterableMixinWorkaround.reduce(this, combine);
+  }
+
+  dynamic fold(dynamic initialValue,
+               dynamic combine(dynamic previousValue, Plugin element)) {
+    return IterableMixinWorkaround.fold(this, initialValue, combine);
+  }
+
+  bool contains(Plugin element) => IterableMixinWorkaround.contains(this, element);
+
+  void forEach(void f(Plugin element)) => IterableMixinWorkaround.forEach(this, f);
+
+  String join([String separator = ""]) =>
+      IterableMixinWorkaround.joinList(this, separator);
+
+  Iterable map(f(Plugin element)) =>
+      IterableMixinWorkaround.mapList(this, f);
+
+  Iterable<Plugin> where(bool f(Plugin element)) =>
+      IterableMixinWorkaround.where(this, f);
+
+  Iterable expand(Iterable f(Plugin element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
+  bool every(bool f(Plugin element)) => IterableMixinWorkaround.every(this, f);
+
+  bool any(bool f(Plugin element)) => IterableMixinWorkaround.any(this, f);
+
+  List<Plugin> toList({ bool growable: true }) =>
+      new List<Plugin>.from(this, growable: growable);
+
+  Set<Plugin> toSet() => new Set<Plugin>.from(this);
+
+  bool get isEmpty => this.length == 0;
+
+  Iterable<Plugin> take(int n) => IterableMixinWorkaround.takeList(this, n);
+
+  Iterable<Plugin> takeWhile(bool test(Plugin value)) {
+    return IterableMixinWorkaround.takeWhile(this, test);
+  }
+
+  Iterable<Plugin> skip(int n) => IterableMixinWorkaround.skipList(this, n);
+
+  Iterable<Plugin> skipWhile(bool test(Plugin value)) {
+    return IterableMixinWorkaround.skipWhile(this, test);
+  }
+
+  Plugin firstWhere(bool test(Plugin value), { Plugin orElse() }) {
+    return IterableMixinWorkaround.firstWhere(this, test, orElse);
+  }
+
+  Plugin lastWhere(bool test(Plugin value), {Plugin orElse()}) {
+    return IterableMixinWorkaround.lastWhereList(this, test, orElse);
+  }
+
+  Plugin singleWhere(bool test(Plugin value)) {
+    return IterableMixinWorkaround.singleWhere(this, test);
+  }
+
+  Plugin elementAt(int index) {
+    return this[index];
+  }
+
+  // From Collection<Plugin>:
+
+  void add(Plugin value) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void addAll(Iterable<Plugin> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  // From List<Plugin>:
+  void set length(int value) {
+    throw new UnsupportedError("Cannot resize immutable List.");
+  }
+
+  void clear() {
+    throw new UnsupportedError("Cannot clear immutable List.");
+  }
+
+  Iterable<Plugin> get reversed {
+    return IterableMixinWorkaround.reversedList(this);
+  }
+
+  void sort([int compare(Plugin a, Plugin b)]) {
+    throw new UnsupportedError("Cannot sort immutable List.");
+  }
+
+  int indexOf(Plugin element, [int start = 0]) =>
+      Lists.indexOf(this, element, start, this.length);
+
+  int lastIndexOf(Plugin element, [int start]) {
+    if (start == null) start = length - 1;
+    return Lists.lastIndexOf(this, element, start);
+  }
+
+  Plugin get first {
+    if (this.length > 0) return this[0];
+    throw new StateError("No elements");
+  }
+
+  Plugin get last {
+    if (this.length > 0) return this[this.length - 1];
+    throw new StateError("No elements");
+  }
+
+  Plugin get single {
+    if (length == 1) return this[0];
+    if (length == 0) throw new StateError("No elements");
+    throw new StateError("More than one element");
+  }
+
+  void insert(int index, Plugin element) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void insertAll(int index, Iterable<Plugin> iterable) {
+    throw new UnsupportedError("Cannot add to immutable List.");
+  }
+
+  void setAll(int index, Iterable<Plugin> iterable) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  Plugin removeAt(int pos) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  Plugin removeLast() {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  bool remove(Object object) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void removeWhere(bool test(Plugin element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void retainWhere(bool test(Plugin element)) {
+    throw new UnsupportedError("Cannot remove from immutable List.");
+  }
+
+  void setRange(int start, int end, Iterable<Plugin> iterable, [int skipCount=0]) {
+    throw new UnsupportedError("Cannot setRange on immutable List.");
+  }
+
+  void removeRange(int start, int end) {
+    throw new UnsupportedError("Cannot removeRange on immutable List.");
+  }
+
+  void replaceRange(int start, int end, Iterable<Plugin> iterable) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  void fillRange(int start, int end, [Plugin fillValue]) {
+    throw new UnsupportedError("Cannot modify an immutable List.");
+  }
+
+  Iterable<Plugin> getRange(int start, int end) =>
+    IterableMixinWorkaround.getRangeList(this, start, end);
+
+  List<Plugin> sublist(int start, [int end]) {
+    if (end == null) end = length;
+    return Lists.getRange(this, start, end, <Plugin>[]);
+  }
+
+  Map<int, Plugin> asMap() =>
+    IterableMixinWorkaround.asMapList(this);
+
+  String toString() {
+    StringBuffer buffer = new StringBuffer('[');
+    buffer.writeAll(this, ', ');
+    buffer.write(']');
+    return buffer.toString();
+  }
+
+  // -- end List<Plugin> mixins.
+
+  @DomName('DOMPluginArray.item')
+  @DocsEditable
+  Plugin item(int index) native "DOMPluginArray_item_Callback";
+
+  @DomName('DOMPluginArray.namedItem')
+  @DocsEditable
+  Plugin namedItem(String name) native "DOMPluginArray_namedItem_Callback";
+
+  @DomName('DOMPluginArray.refresh')
+  @DocsEditable
+  void refresh(bool reload) native "DOMPluginArray_refresh_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('PopStateEvent')
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.FIREFOX)
@@ -18699,6 +18566,15 @@
   @DocsEditable
   String toString() native "Range_toString_Callback";
 
+
+  /**
+   * Checks if createContextualFragment is supported.
+   *
+   * See also:
+   *
+   * * [createContextualFragment]
+   */
+  static bool get supportsCreateContextualFragment => true;
 }
 // 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
@@ -19547,6 +19423,79 @@
 
 
 @DocsEditable
+@DomName('SecurityPolicy')
+class SecurityPolicy extends NativeFieldWrapperClass1 {
+  SecurityPolicy.internal();
+
+  @DomName('DOMSecurityPolicy.allowsEval')
+  @DocsEditable
+  bool get allowsEval native "DOMSecurityPolicy_allowsEval_Getter";
+
+  @DomName('DOMSecurityPolicy.allowsInlineScript')
+  @DocsEditable
+  bool get allowsInlineScript native "DOMSecurityPolicy_allowsInlineScript_Getter";
+
+  @DomName('DOMSecurityPolicy.allowsInlineStyle')
+  @DocsEditable
+  bool get allowsInlineStyle native "DOMSecurityPolicy_allowsInlineStyle_Getter";
+
+  @DomName('DOMSecurityPolicy.isActive')
+  @DocsEditable
+  bool get isActive native "DOMSecurityPolicy_isActive_Getter";
+
+  @DomName('DOMSecurityPolicy.reportURIs')
+  @DocsEditable
+  List<String> get reportURIs native "DOMSecurityPolicy_reportURIs_Getter";
+
+  @DomName('DOMSecurityPolicy.allowsConnectionTo')
+  @DocsEditable
+  bool allowsConnectionTo(String url) native "DOMSecurityPolicy_allowsConnectionTo_Callback";
+
+  @DomName('DOMSecurityPolicy.allowsFontFrom')
+  @DocsEditable
+  bool allowsFontFrom(String url) native "DOMSecurityPolicy_allowsFontFrom_Callback";
+
+  @DomName('DOMSecurityPolicy.allowsFormAction')
+  @DocsEditable
+  bool allowsFormAction(String url) native "DOMSecurityPolicy_allowsFormAction_Callback";
+
+  @DomName('DOMSecurityPolicy.allowsFrameFrom')
+  @DocsEditable
+  bool allowsFrameFrom(String url) native "DOMSecurityPolicy_allowsFrameFrom_Callback";
+
+  @DomName('DOMSecurityPolicy.allowsImageFrom')
+  @DocsEditable
+  bool allowsImageFrom(String url) native "DOMSecurityPolicy_allowsImageFrom_Callback";
+
+  @DomName('DOMSecurityPolicy.allowsMediaFrom')
+  @DocsEditable
+  bool allowsMediaFrom(String url) native "DOMSecurityPolicy_allowsMediaFrom_Callback";
+
+  @DomName('DOMSecurityPolicy.allowsObjectFrom')
+  @DocsEditable
+  bool allowsObjectFrom(String url) native "DOMSecurityPolicy_allowsObjectFrom_Callback";
+
+  @DomName('DOMSecurityPolicy.allowsPluginType')
+  @DocsEditable
+  bool allowsPluginType(String type) native "DOMSecurityPolicy_allowsPluginType_Callback";
+
+  @DomName('DOMSecurityPolicy.allowsScriptFrom')
+  @DocsEditable
+  bool allowsScriptFrom(String url) native "DOMSecurityPolicy_allowsScriptFrom_Callback";
+
+  @DomName('DOMSecurityPolicy.allowsStyleFrom')
+  @DocsEditable
+  bool allowsStyleFrom(String url) native "DOMSecurityPolicy_allowsStyleFrom_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('SecurityPolicyViolationEvent')
 class SecurityPolicyViolationEvent extends Event {
   SecurityPolicyViolationEvent.internal() : super.internal();
@@ -19735,6 +19684,123 @@
 
 
 @DocsEditable
+@DomName('Selection')
+class Selection extends NativeFieldWrapperClass1 {
+  Selection.internal();
+
+  @DomName('DOMSelection.anchorNode')
+  @DocsEditable
+  Node get anchorNode native "DOMSelection_anchorNode_Getter";
+
+  @DomName('DOMSelection.anchorOffset')
+  @DocsEditable
+  int get anchorOffset native "DOMSelection_anchorOffset_Getter";
+
+  @DomName('DOMSelection.baseNode')
+  @DocsEditable
+  Node get baseNode native "DOMSelection_baseNode_Getter";
+
+  @DomName('DOMSelection.baseOffset')
+  @DocsEditable
+  int get baseOffset native "DOMSelection_baseOffset_Getter";
+
+  @DomName('DOMSelection.extentNode')
+  @DocsEditable
+  Node get extentNode native "DOMSelection_extentNode_Getter";
+
+  @DomName('DOMSelection.extentOffset')
+  @DocsEditable
+  int get extentOffset native "DOMSelection_extentOffset_Getter";
+
+  @DomName('DOMSelection.focusNode')
+  @DocsEditable
+  Node get focusNode native "DOMSelection_focusNode_Getter";
+
+  @DomName('DOMSelection.focusOffset')
+  @DocsEditable
+  int get focusOffset native "DOMSelection_focusOffset_Getter";
+
+  @DomName('DOMSelection.isCollapsed')
+  @DocsEditable
+  bool get isCollapsed native "DOMSelection_isCollapsed_Getter";
+
+  @DomName('DOMSelection.rangeCount')
+  @DocsEditable
+  int get rangeCount native "DOMSelection_rangeCount_Getter";
+
+  @DomName('DOMSelection.type')
+  @DocsEditable
+  String get type native "DOMSelection_type_Getter";
+
+  @DomName('DOMSelection.addRange')
+  @DocsEditable
+  void addRange(Range range) native "DOMSelection_addRange_Callback";
+
+  @DomName('DOMSelection.collapse')
+  @DocsEditable
+  void collapse(Node node, int index) native "DOMSelection_collapse_Callback";
+
+  @DomName('DOMSelection.collapseToEnd')
+  @DocsEditable
+  void collapseToEnd() native "DOMSelection_collapseToEnd_Callback";
+
+  @DomName('DOMSelection.collapseToStart')
+  @DocsEditable
+  void collapseToStart() native "DOMSelection_collapseToStart_Callback";
+
+  @DomName('DOMSelection.containsNode')
+  @DocsEditable
+  bool containsNode(Node node, bool allowPartial) native "DOMSelection_containsNode_Callback";
+
+  @DomName('DOMSelection.deleteFromDocument')
+  @DocsEditable
+  void deleteFromDocument() native "DOMSelection_deleteFromDocument_Callback";
+
+  @DomName('DOMSelection.empty')
+  @DocsEditable
+  void empty() native "DOMSelection_empty_Callback";
+
+  @DomName('DOMSelection.extend')
+  @DocsEditable
+  void extend(Node node, int offset) native "DOMSelection_extend_Callback";
+
+  @DomName('DOMSelection.getRangeAt')
+  @DocsEditable
+  Range getRangeAt(int index) native "DOMSelection_getRangeAt_Callback";
+
+  @DomName('DOMSelection.modify')
+  @DocsEditable
+  void modify(String alter, String direction, String granularity) native "DOMSelection_modify_Callback";
+
+  @DomName('DOMSelection.removeAllRanges')
+  @DocsEditable
+  void removeAllRanges() native "DOMSelection_removeAllRanges_Callback";
+
+  @DomName('DOMSelection.selectAllChildren')
+  @DocsEditable
+  void selectAllChildren(Node node) native "DOMSelection_selectAllChildren_Callback";
+
+  @DomName('DOMSelection.setBaseAndExtent')
+  @DocsEditable
+  void setBaseAndExtent(Node baseNode, int baseOffset, Node extentNode, int extentOffset) native "DOMSelection_setBaseAndExtent_Callback";
+
+  @DomName('DOMSelection.setPosition')
+  @DocsEditable
+  void setPosition(Node node, int offset) native "DOMSelection_setPosition_Callback";
+
+  @DomName('DOMSelection.toString')
+  @DocsEditable
+  String toString() native "DOMSelection_toString_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('HTMLShadowElement')
 @SupportedBrowser(SupportedBrowser.CHROME, '26')
 @Experimental
@@ -19820,7 +19886,7 @@
 
   @DomName('ShadowRoot.getSelection')
   @DocsEditable
-  DomSelection getSelection() native "ShadowRoot_getSelection_Callback";
+  Selection getSelection() native "ShadowRoot_getSelection_Callback";
 
   static bool get supported => _Utils.shadowRootSupported(window.document);
 }
@@ -23341,40 +23407,6 @@
 
 
 @DocsEditable
-@DomName('WebKitCSSFilterRule')
-class WebKitCssFilterRule extends CssRule {
-  WebKitCssFilterRule.internal() : super.internal();
-
-  @DomName('WebKitCSSFilterRule.style')
-  @DocsEditable
-  CssStyleDeclaration get style native "WebKitCSSFilterRule_style_Getter";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
-@DomName('WebKitCSSRegionRule')
-class WebKitCssRegionRule extends CssRule {
-  WebKitCssRegionRule.internal() : super.internal();
-
-  @DomName('WebKitCSSRegionRule.cssRules')
-  @DocsEditable
-  List<CssRule> get cssRules native "WebKitCSSRegionRule_cssRules_Getter";
-
-}
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
 /**
  * Use the WebSocket interface to connect to a WebSocket,
  * and to send and receive data on that WebSocket.
@@ -24107,7 +24139,7 @@
 
   @DomName('DOMWindow.getSelection')
   @DocsEditable
-  DomSelection getSelection() native "DOMWindow_getSelection_Callback";
+  Selection getSelection() native "DOMWindow_getSelection_Callback";
 
   @DomName('DOMWindow.matchMedia')
   @DocsEditable
@@ -25717,6 +25749,9 @@
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.SAFARI)
 @Experimental
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.SAFARI)
+@Experimental
 class _DomPoint extends NativeFieldWrapperClass1 {
   _DomPoint.internal();
   factory _DomPoint(num x, num y) => _create(x, y);
@@ -28199,78 +28234,28 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
+/** A Set that stores the CSS class names for an element. */
 abstract class CssClassSet implements Set<String> {
 
-  String toString() {
-    return readClasses().join(' ');
-  }
-
   /**
    * Adds the class [value] to the element if it is not on it, removes it if it
    * is.
    */
-  bool toggle(String value) {
-    Set<String> s = readClasses();
-    bool result = false;
-    if (s.contains(value)) {
-      s.remove(value);
-    } else {
-      s.add(value);
-      result = true;
-    }
-    writeClasses(s);
-    return result;
-  }
+  bool toggle(String value);
 
   /**
    * Returns [:true:] if classes cannot be added or removed from this
    * [:CssClassSet:].
    */
-  bool get frozen => false;
+  bool get frozen;
 
-  // interface Iterable - BEGIN
-  Iterator<String> get iterator => readClasses().iterator;
-  // interface Iterable - END
-
-  // interface Collection - BEGIN
-  void forEach(void f(String element)) {
-    readClasses().forEach(f);
-  }
-
-  String join([String separator = ""]) => readClasses().join(separator);
-
-  Iterable map(f(String element)) => readClasses().map(f);
-
-  Iterable<String> where(bool f(String element)) => readClasses().where(f);
-
-  Iterable expand(Iterable f(String element)) => readClasses().expand(f);
-
-  bool every(bool f(String element)) => readClasses().every(f);
-
-  bool any(bool f(String element)) => readClasses().any(f);
-
-  bool get isEmpty => readClasses().isEmpty;
-
-  int get length => readClasses().length;
-
-  String reduce(String combine(String value, String element)) {
-    return readClasses().reduce(combine);
-  }
-
-  dynamic fold(dynamic initialValue,
-      dynamic combine(dynamic previousValue, String element)) {
-    return readClasses().fold(initialValue, combine);
-  }
-  // interface Collection - END
-
-  // interface Set - BEGIN
   /**
    * Determine if this element contains the class [value].
    *
    * This is the Dart equivalent of jQuery's
    * [hasClass](http://api.jquery.com/hasClass/).
    */
-  bool contains(String value) => readClasses().contains(value);
+  bool contains(String value);
 
   /**
    * Add the class [value] to element.
@@ -28278,11 +28263,7 @@
    * This is the Dart equivalent of jQuery's
    * [addClass](http://api.jquery.com/addClass/).
    */
-  void add(String value) {
-    // TODO - figure out if we need to do any validation here
-    // or if the browser natively does enough.
-    _modify((s) => s.add(value));
-  }
+  void add(String value);
 
   /**
    * Remove the class [value] from element, and return true on successful
@@ -28291,13 +28272,7 @@
    * This is the Dart equivalent of jQuery's
    * [removeClass](http://api.jquery.com/removeClass/).
    */
-  bool remove(Object value) {
-    if (value is! String) return false;
-    Set<String> s = readClasses();
-    bool result = s.remove(value);
-    writeClasses(s);
-    return result;
-  }
+  bool remove(Object value);
 
   /**
    * Add all classes specified in [iterable] to element.
@@ -28305,10 +28280,7 @@
    * This is the Dart equivalent of jQuery's
    * [addClass](http://api.jquery.com/addClass/).
    */
-  void addAll(Iterable<String> iterable) {
-    // TODO - see comment above about validation.
-    _modify((s) => s.addAll(iterable));
-  }
+  void addAll(Iterable<String> iterable);
 
   /**
    * Remove all classes specified in [iterable] from element.
@@ -28316,9 +28288,7 @@
    * This is the Dart equivalent of jQuery's
    * [removeClass](http://api.jquery.com/removeClass/).
    */
-  void removeAll(Iterable<String> iterable) {
-    _modify((s) => s.removeAll(iterable));
-  }
+  void removeAll(Iterable<String> iterable);
 
   /**
    * Toggles all classes specified in [iterable] on element.
@@ -28327,59 +28297,35 @@
    * remove it if it is. This is the Dart equivalent of jQuery's
    * [toggleClass](http://api.jquery.com/toggleClass/).
    */
-  void toggleAll(Iterable<String> iterable) {
-    iterable.forEach(toggle);
+  void toggleAll(Iterable<String> iterable);
+}
+
+/**
+ * A set (union) of the CSS classes that are present in a set of elements.
+ * Implemented separately from _ElementCssClassSet for performance.
+ */
+class _MultiElementCssClassSet extends CssClassSetImpl {
+  final Iterable<Element> _elementIterable;
+  Iterable<_ElementCssClassSet> _elementCssClassSetIterable;
+
+  _MultiElementCssClassSet(this._elementIterable) {
+    _elementCssClassSetIterable = new List.from(_elementIterable).map(
+        (e) => new _ElementCssClassSet(e));
   }
 
-  void retainAll(Iterable<String> iterable) {
-    _modify((s) => s.retainAll(iterable));
+  Set<String> readClasses() {
+    var s = new LinkedHashSet<String>();
+    _elementCssClassSetIterable.forEach((e) => s.addAll(e.readClasses()));
+    return s;
   }
 
-  void removeWhere(bool test(String name)) {
-    _modify((s) => s.removeWhere(test));
+  void writeClasses(Set<String> s) {
+    var classes = new List.from(s).join(' ');
+    for (Element e in _elementIterable) {
+      e.$dom_className = classes;
+    }
   }
 
-  void retainWhere(bool test(String name)) {
-    _modify((s) => s.retainWhere(test));
-  }
-
-  bool containsAll(Iterable<String> collection) =>
-    readClasses().containsAll(collection);
-
-  Set<String> intersection(Set<String> other) =>
-    readClasses().intersection(other);
-
-  Set<String> union(Set<String> other) =>
-    readClasses().union(other);
-
-  Set<String> difference(Set<String> other) =>
-    readClasses().difference(other);
-
-  String get first => readClasses().first;
-  String get last => readClasses().last;
-  String get single => readClasses().single;
-  List<String> toList({ bool growable: true }) =>
-      readClasses().toList(growable: growable);
-  Set<String> toSet() => readClasses().toSet();
-  Iterable<String> take(int n) => readClasses().take(n);
-  Iterable<String> takeWhile(bool test(String value)) =>
-      readClasses().takeWhile(test);
-  Iterable<String> skip(int n) => readClasses().skip(n);
-  Iterable<String> skipWhile(bool test(String value)) =>
-      readClasses().skipWhile(test);
-  String firstWhere(bool test(String value), { String orElse() }) =>
-      readClasses().firstWhere(test, orElse: orElse);
-  String lastWhere(bool test(String value), {String orElse()}) =>
-      readClasses().lastWhere(test, orElse: orElse);
-  String singleWhere(bool test(String value)) =>
-      readClasses().singleWhere(test);
-  String elementAt(int index) => readClasses().elementAt(index);
-
-  void clear() {
-    _modify((s) => s.clear());
-  }
-  // interface Set - END
-
   /**
    * Helper method used to modify the set of css classes on this element.
    *
@@ -28389,25 +28335,53 @@
    *   After f returns, the modified set is written to the
    *       className property of this element.
    */
-  void _modify( f(Set<String> s)) {
-    Set<String> s = readClasses();
-    f(s);
-    writeClasses(s);
+  void modify( f(Set<String> s)) {
+    _elementCssClassSetIterable.forEach((e) => e.modify(f));
   }
 
   /**
-   * Read the class names from the Element class property,
-   * and put them into a set (duplicates are discarded).
-   * This is intended to be overridden by specific implementations.
+   * Adds the class [value] to the element if it is not on it, removes it if it
+   * is.
    */
-  Set<String> readClasses();
+  bool toggle(String value) =>
+      _modifyWithReturnValue((e) => e.toggle(value));
 
   /**
-   * Join all the elements of a set into one string and write
-   * back to the element.
-   * This is intended to be overridden by specific implementations.
+   * Remove the class [value] from element, and return true on successful
+   * removal.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [removeClass](http://api.jquery.com/removeClass/).
    */
-  void writeClasses(Set<String> s);
+  bool remove(Object value) => _modifyWithReturnValue((e) => e.remove(value));
+
+  bool _modifyWithReturnValue(f) => _elementCssClassSetIterable.fold(
+      false, (prevValue, element) => f(element) || prevValue);
+}
+
+class _ElementCssClassSet extends CssClassSetImpl {
+
+  final Element _element;
+
+  _ElementCssClassSet(this._element);
+
+  Set<String> readClasses() {
+    var s = new LinkedHashSet<String>();
+    var classname = _element.$dom_className;
+
+    for (String name in classname.split(' ')) {
+      String trimmed = name.trim();
+      if (!trimmed.isEmpty) {
+        s.add(trimmed);
+      }
+    }
+    return s;
+  }
+
+  void writeClasses(Set<String> s) {
+    List list = new List.from(s);
+    _element.$dom_className = s.join(' ');
+  }
 }
 // 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
diff --git a/sdk/lib/html/html_common/css_class_set.dart b/sdk/lib/html/html_common/css_class_set.dart
new file mode 100644
index 0000000..df50d62
--- /dev/null
+++ b/sdk/lib/html/html_common/css_class_set.dart
@@ -0,0 +1,216 @@
+// 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 html_common;
+
+abstract class CssClassSetImpl implements CssClassSet {
+
+  String toString() {
+    return readClasses().join(' ');
+  }
+
+  /**
+   * Adds the class [value] to the element if it is not on it, removes it if it
+   * is.
+   */
+  bool toggle(String value) {
+    Set<String> s = readClasses();
+    bool result = false;
+    if (s.contains(value)) {
+      s.remove(value);
+    } else {
+      s.add(value);
+      result = true;
+    }
+    writeClasses(s);
+    return result;
+  }
+
+  /**
+   * Returns [:true:] if classes cannot be added or removed from this
+   * [:CssClassSet:].
+   */
+  bool get frozen => false;
+
+  // interface Iterable - BEGIN
+  Iterator<String> get iterator => readClasses().iterator;
+  // interface Iterable - END
+
+  // interface Collection - BEGIN
+  void forEach(void f(String element)) {
+    readClasses().forEach(f);
+  }
+
+  String join([String separator = ""]) => readClasses().join(separator);
+
+  Iterable map(f(String element)) => readClasses().map(f);
+
+  Iterable<String> where(bool f(String element)) => readClasses().where(f);
+
+  Iterable expand(Iterable f(String element)) => readClasses().expand(f);
+
+  bool every(bool f(String element)) => readClasses().every(f);
+
+  bool any(bool f(String element)) => readClasses().any(f);
+
+  bool get isEmpty => readClasses().isEmpty;
+
+  int get length => readClasses().length;
+
+  String reduce(String combine(String value, String element)) {
+    return readClasses().reduce(combine);
+  }
+
+  dynamic fold(dynamic initialValue,
+      dynamic combine(dynamic previousValue, String element)) {
+    return readClasses().fold(initialValue, combine);
+  }
+  // interface Collection - END
+
+  // interface Set - BEGIN
+  /**
+   * Determine if this element contains the class [value].
+   *
+   * This is the Dart equivalent of jQuery's
+   * [hasClass](http://api.jquery.com/hasClass/).
+   */
+  bool contains(String value) => readClasses().contains(value);
+
+  /**
+   * Add the class [value] to element.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [addClass](http://api.jquery.com/addClass/).
+   */
+  void add(String value) {
+    // TODO - figure out if we need to do any validation here
+    // or if the browser natively does enough.
+    modify((s) => s.add(value));
+  }
+
+  /**
+   * Remove the class [value] from element, and return true on successful
+   * removal.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [removeClass](http://api.jquery.com/removeClass/).
+   */
+  bool remove(Object value) {
+    if (value is! String) return false;
+    Set<String> s = readClasses();
+    bool result = s.remove(value);
+    writeClasses(s);
+    return result;
+  }
+
+  /**
+   * Add all classes specified in [iterable] to element.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [addClass](http://api.jquery.com/addClass/).
+   */
+  void addAll(Iterable<String> iterable) {
+    // TODO - see comment above about validation.
+    modify((s) => s.addAll(iterable));
+  }
+
+  /**
+   * Remove all classes specified in [iterable] from element.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [removeClass](http://api.jquery.com/removeClass/).
+   */
+  void removeAll(Iterable<String> iterable) {
+    modify((s) => s.removeAll(iterable));
+  }
+
+  /**
+   * Toggles all classes specified in [iterable] on element.
+   *
+   * Iterate through [iterable]'s items, and add it if it is not on it, or
+   * remove it if it is. This is the Dart equivalent of jQuery's
+   * [toggleClass](http://api.jquery.com/toggleClass/).
+   */
+  void toggleAll(Iterable<String> iterable) {
+    iterable.forEach(toggle);
+  }
+
+  void retainAll(Iterable<String> iterable) {
+    modify((s) => s.retainAll(iterable));
+  }
+
+  void removeWhere(bool test(String name)) {
+    modify((s) => s.removeWhere(test));
+  }
+
+  void retainWhere(bool test(String name)) {
+    modify((s) => s.retainWhere(test));
+  }
+
+  bool containsAll(Iterable<String> collection) =>
+    readClasses().containsAll(collection);
+
+  Set<String> intersection(Set<String> other) =>
+    readClasses().intersection(other);
+
+  Set<String> union(Set<String> other) =>
+    readClasses().union(other);
+
+  Set<String> difference(Set<String> other) =>
+    readClasses().difference(other);
+
+  String get first => readClasses().first;
+  String get last => readClasses().last;
+  String get single => readClasses().single;
+  List<String> toList({ bool growable: true }) =>
+      readClasses().toList(growable: growable);
+  Set<String> toSet() => readClasses().toSet();
+  Iterable<String> take(int n) => readClasses().take(n);
+  Iterable<String> takeWhile(bool test(String value)) =>
+      readClasses().takeWhile(test);
+  Iterable<String> skip(int n) => readClasses().skip(n);
+  Iterable<String> skipWhile(bool test(String value)) =>
+      readClasses().skipWhile(test);
+  String firstWhere(bool test(String value), { String orElse() }) =>
+      readClasses().firstWhere(test, orElse: orElse);
+  String lastWhere(bool test(String value), {String orElse()}) =>
+      readClasses().lastWhere(test, orElse: orElse);
+  String singleWhere(bool test(String value)) =>
+      readClasses().singleWhere(test);
+  String elementAt(int index) => readClasses().elementAt(index);
+
+  void clear() {
+    modify((s) => s.clear());
+  }
+  // interface Set - END
+
+  /**
+   * Helper method used to modify the set of css classes on this element.
+   *
+   *   f - callback with:
+   *   s - a Set of all the css class name currently on this element.
+   *
+   *   After f returns, the modified set is written to the
+   *       className property of this element.
+   */
+  void modify( f(Set<String> s)) {
+    Set<String> s = readClasses();
+    f(s);
+    writeClasses(s);
+  }
+
+  /**
+   * Read the class names from the Element class property,
+   * and put them into a set (duplicates are discarded).
+   * This is intended to be overridden by specific implementations.
+   */
+  Set<String> readClasses();
+
+  /**
+   * Join all the elements of a set into one string and write
+   * back to the element.
+   * This is intended to be overridden by specific implementations.
+   */
+  void writeClasses(Set<String> s);
+}
diff --git a/sdk/lib/html/html_common/html_common.dart b/sdk/lib/html/html_common/html_common.dart
index f023b30..72d5dab 100644
--- a/sdk/lib/html/html_common/html_common.dart
+++ b/sdk/lib/html/html_common/html_common.dart
@@ -1,4 +1,4 @@
-// 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.
 
@@ -10,6 +10,7 @@
 import 'metadata.dart';
 export 'metadata.dart';
 
+part 'css_class_set.dart';
 part 'device.dart';
 part 'filtered_element_list.dart';
 part 'lists.dart';
diff --git a/sdk/lib/html/html_common/html_common_dart2js.dart b/sdk/lib/html/html_common/html_common_dart2js.dart
index 1f0a19f..ed42991 100644
--- a/sdk/lib/html/html_common/html_common_dart2js.dart
+++ b/sdk/lib/html/html_common/html_common_dart2js.dart
@@ -13,6 +13,7 @@
 import 'metadata.dart';
 export 'metadata.dart';
 
+part 'css_class_set.dart';
 part 'conversions.dart';
 part 'device.dart';
 part 'filtered_element_list.dart';
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index a67b5d3..80671f8 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -464,7 +464,7 @@
  * and errors out when the request errors.
  */
 Future _completeRequest(Request request) {
-  var completer = new Completer();
+  var completer = new Completer.sync();
   // TODO: make sure that completer.complete is synchronous as transactions
   // may be committed if the result is not processed immediately.
   request.onSuccess.listen((e) {
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index 0d92e79..71b47ad 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -336,7 +336,7 @@
  * and errors out when the request errors.
  */
 Future _completeRequest(Request request) {
-  var completer = new Completer();
+  var completer = new Completer.sync();
   // TODO: make sure that completer.complete is synchronous as transactions
   // may be committed if the result is not processed immediately.
   request.onSuccess.listen((e) {
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 89af6c3..b97b458 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -228,7 +228,8 @@
     request[1] = _path;
     return _fileService.call(request).then((response) {
       if (_isErrorResponse(response)) {
-        throw _exceptionFromResponse(response, "Cannot open file '$_path'");
+        throw _exceptionFromResponse(response,
+                                     "Cannot check existence of file '$_path'");
       }
       return response;
     });
diff --git a/sdk/lib/io/http_body.dart b/sdk/lib/io/http_body.dart
index 7a8a494..1ec6d17 100644
--- a/sdk/lib/io/http_body.dart
+++ b/sdk/lib/io/http_body.dart
@@ -74,7 +74,7 @@
    * The content type e.g. application/json, application/octet-stream,
    * application/x-www-form-urlencoded, text/plain.
    */
-  String get mimeType;
+  ContentType get contentType;
 
   /**
    * A high-level type value, that reflects how the body was parsed, e.g.
@@ -143,3 +143,26 @@
    */
   HttpResponse get response;
 }
+
+
+/**
+ * A [HttpBodyFileUpload] object wraps a file upload, presenting a way for
+ * extracting filename, contentType and the data of the uploaded file.
+ */
+abstract class HttpBodyFileUpload {
+  /**
+   * The filename of the uploaded file.
+   */
+  String filename;
+
+  /**
+   * The [ContentType] of the uploaded file. For 'text/\*' and
+   * 'application/json' the [data] field will a String.
+   */
+  ContentType contentType;
+
+  /**
+   * The content of the file. Either a [String] or a [List<int>].
+   */
+  dynamic content;
+}
diff --git a/sdk/lib/io/http_body_impl.dart b/sdk/lib/io/http_body_impl.dart
index 095b74e..736e86e 100644
--- a/sdk/lib/io/http_body_impl.dart
+++ b/sdk/lib/io/http_body_impl.dart
@@ -33,59 +33,134 @@
 
   static Future<HttpBody> process(Stream<List<int>> stream,
                                   HttpHeaders headers) {
-    return stream.fold(
-        new _BufferList(),
-        (buffer, data) {
-          // TODO(ajohnsen): Add limit for POST data.
-          buffer.add(data);
-          return buffer;
-        })
-        .then((list) {
-          dynamic content = list.readBytes();
-          String type = "binary";
-          ContentType contentType = headers.contentType;
-          if (contentType == null) {
-            return new _HttpBody(null, type, content);
-          }
-          String asText(Encoding defaultEncoding) {
-            var encoding;
-            var charset = contentType.charset;
-            if (charset != null) encoding = Encoding.fromName(charset);
-            if (encoding == null) encoding = defaultEncoding;
-            return _decodeString(content, encoding);
-          }
-          switch (contentType.primaryType) {
-            case "text":
-              type = "text";
-              content = asText(Encoding.ASCII);
-              break;
+    ContentType contentType = headers.contentType;
 
-            case "application":
-              switch (contentType.subType) {
-                case "json":
-                  content = JSON.parse(asText(Encoding.UTF_8));
-                  type = "json";
-                  break;
+    Future<HttpBody> asBinary() {
+      return stream
+          .fold(new _BufferList(), (buffer, data) => buffer..add(data))
+          .then((buffer) => new _HttpBody(contentType,
+                                          "binary",
+                                          buffer.readBytes()));
+    }
 
-                default:
-                  break;
+    Future<HttpBody> asText(Encoding defaultEncoding) {
+      var encoding;
+      var charset = contentType.charset;
+      if (charset != null) encoding = Encoding.fromName(charset);
+      if (encoding == null) encoding = defaultEncoding;
+      return stream
+          .transform(new StringDecoder(encoding))
+          .fold(new StringBuffer(), (buffer, data) => buffer..write(data))
+          .then((buffer) => new _HttpBody(contentType,
+                                          "text",
+                                          buffer.toString()));
+    }
+
+    Future<HttpBody> asFormData() {
+      return stream
+          .transform(new MimeMultipartTransformer(
+                contentType.parameters['boundary']))
+          .map((HttpMultipartFormData.parse))
+          .map((multipart) {
+            var future;
+            if (multipart.isText) {
+              future = multipart
+                  .fold(new StringBuffer(), (b, s) => b..write(s))
+                  .then((b) => b.toString());
+            } else {
+              future = multipart
+                  .fold(new _BufferList(), (b, d) => b..add(d))
+                  .then((b) => b.readBytes());
+            }
+            return future.then((data) {
+              var filename =
+                  multipart.contentDisposition.parameters['filename'];
+              if (filename != null) {
+                data = new _HttpBodyFileUpload(multipart.contentType,
+                                               filename,
+                                               data);
               }
-              break;
+              return [multipart.contentDisposition.parameters['name'], data];
+            });
+          })
+          .fold([], (l, f) => l..add(f))
+          .then(Future.wait)
+          .then((parts) {
+            Map<String, dynamic> map = new Map<String, dynamic>();
+            for (var part in parts) {
+              map[part[0]] = part[1];  // Override existing entries.
+            }
+            return new _HttpBody(contentType, 'form', map);
+          });
+    }
 
-            default:
-              break;
-          }
-          return new _HttpBody(contentType.mimeType, type, content);
-        });
+    if (contentType == null) {
+      return asBinary();
+    }
+
+    switch (contentType.primaryType) {
+      case "text":
+        return asText(Encoding.ASCII);
+
+      case "application":
+        switch (contentType.subType) {
+          case "json":
+            return asText(Encoding.UTF_8)
+                .then((body) => new _HttpBody(contentType,
+                                              "json",
+                                              JSON.parse(body.body)));
+
+          case "x-www-form-urlencoded":
+            return asText(Encoding.ASCII)
+                .then((body) {
+                  var map = _HttpUtils.splitQueryString(body.body);
+                  var result = {};
+                  String parse(String s) {
+                    return _HttpUtils.decodeHttpEntityString(
+                        _HttpUtils.decodeUrlEncodedString(s));
+                  }
+                  for (var key in map.keys) {
+                    result[parse(key)] = parse(map[key]);
+                  }
+                  return new _HttpBody(contentType, "form", result);
+                });
+
+          default:
+            break;
+        }
+        break;
+
+      case "multipart":
+        switch (contentType.subType) {
+          case "form-data":
+            return asFormData();
+
+          default:
+            break;
+        }
+        break;
+
+      default:
+        break;
+    }
+
+    return asBinary();
   }
 }
 
+class _HttpBodyFileUpload implements HttpBodyFileUpload {
+  final ContentType contentType;
+  final String filename;
+  final dynamic content;
+  _HttpBodyFileUpload(this.contentType, this.filename, this.content);
+}
+
 class _HttpBody implements HttpBody {
-  final String mimeType;
+  final ContentType contentType;
   final String type;
   final dynamic body;
 
-  _HttpBody(String this.mimeType,
+  _HttpBody(ContentType this.contentType,
             String this.type,
             dynamic this.body);
 }
@@ -97,7 +172,7 @@
   final HttpResponse response;
 
   _HttpRequestBody(HttpRequest request, HttpBody body)
-      : super(body.mimeType, body.type, body.body),
+      : super(body.contentType, body.type, body.body),
         method = request.method,
         uri = request.uri,
         headers = request.headers,
@@ -109,7 +184,7 @@
   final HttpClientResponse response;
 
   _HttpClientResponseBody(HttpClientResponse response, HttpBody body)
-      : super(body.mimeType, body.type, body.body),
+      : super(body.contentType, body.type, body.body),
         this.response = response;
 
   int get statusCode => response.statusCode;
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart
index f6f756b..5983717 100644
--- a/sdk/lib/io/http_headers.dart
+++ b/sdk/lib/io/http_headers.dart
@@ -525,7 +525,7 @@
             s[index] == parameterSeparator) break;
         index++;
       }
-      return s.substring(start, index).toLowerCase();
+      return s.substring(start, index);
     }
 
     void expect(String expected) {
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 8ea7174..2f5e15a 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -381,7 +381,33 @@
 
     var cr =  _httpClient._findProxyCredentials(proxy);
     if (cr != null) {
-      return retryWithProxyCredentials(cr);
+      if (cr.scheme == _AuthenticationScheme.BASIC) {
+        return retryWithProxyCredentials(cr);
+      }
+
+      // Digest authentication only supports the MD5 algorithm.
+      if (cr.scheme == _AuthenticationScheme.DIGEST &&
+          (header.parameters["algorithm"] == null ||
+           header.parameters["algorithm"].toLowerCase() == "md5")) {
+        if (cr.nonce == null || cr.nonce == header.parameters["nonce"]) {
+          // If the nonce is not set then this is the first authenticate
+          // response for these credentials. Set up authentication state.
+          if (cr.nonce == null) {
+            cr.nonce = header.parameters["nonce"];
+            cr.algorithm = "MD5";
+            cr.qop = header.parameters["qop"];
+            cr.nonceCount = 0;
+          }
+          // Credentials where found, prepare for retrying the request.
+          return retryWithProxyCredentials(cr);
+        } else if (header.parameters["stale"] != null &&
+                   header.parameters["stale"].toLowerCase() == "true") {
+          // If stale is true retry with new nonce.
+          cr.nonce = header.parameters["nonce"];
+          // Credentials where found, prepare for retrying the request.
+          return retryWithProxyCredentials(cr);
+        }
+      }
     }
 
     // Ask for more credentials if none found.
@@ -914,6 +940,40 @@
     _responseCompleter.completeError(error);
   }
 
+  // Generate the request URI based on the method and proxy.
+  String _requestUri() {
+    // Generate the request URI starting from the path component.
+    String uriStartingFromPath() {
+      String result = uri.path;
+      if (result.length == 0) result = "/";
+      if (uri.query != "") {
+        if (uri.fragment != "") {
+          result = "${result}?${uri.query}#${uri.fragment}";
+        } else {
+          result = "${result}?${uri.query}";
+        }
+      }
+      return result;
+    }
+
+    if (_proxy.isDirect) {
+      return uriStartingFromPath();
+    } else {
+      if (method == "CONNECT") {
+        // For the connect method the request URI is the host:port of
+        // the requested destination of the tunnel (see RFC 2817
+        // section 5.2)
+        return "${uri.domain}:${uri.port}";
+      } else {
+        if (_httpClientConnection._proxyTunnel) {
+          return uriStartingFromPath();
+        } else {
+          return uri.toString();
+        }
+      }
+    }
+  }
+
   void _writeHeader() {
     var buffer = new _BufferList();
 
@@ -921,42 +981,13 @@
 
     writeCRLF() => buffer.add(const [_CharCode.CR, _CharCode.LF]);
 
-    void writePath() {
-      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}";
-        }
-      }
-      buffer.add(path.codeUnits);
-    }
-
     // Write the request method.
     buffer.add(method.codeUnits);
     writeSP();
     // Write the request URI.
-    if (_proxy.isDirect) {
-      writePath();
-    } else {
-      if (method == "CONNECT") {
-        // For the connect method the request URI is the host:port of
-        // the requested destination of the tunnel (see RFC 2817
-        // section 5.2)
-        buffer.add(uri.domain.codeUnits);
-        buffer.add(const [_CharCode.COLON]);
-        buffer.add(uri.port.toString().codeUnits);
-      } else {
-        if (_httpClientConnection._proxyTunnel) {
-          writePath();
-        } else {
-          buffer.add(uri.toString().codeUnits);
-        }
-      }
-    }
+    buffer.add(_requestUri().codeUnits);
     writeSP();
+    // Write HTTP/1.1.
     buffer.add(_Const.HTTP11);
     writeCRLF();
 
@@ -1120,7 +1151,8 @@
   _HttpClientRequest send(Uri uri, int port, String method, _Proxy proxy) {
     // Start with pausing the parser.
     _subscription.pause();
-    _Credentials cr;  // Credentials used to authorize this request.
+    _ProxyCredentials proxyCreds;  // Credentials used to authorize proxy.
+    _SiteCredentials creds;  // Credentials used to authorize this request.
     var outgoing = new _HttpOutgoing(_socket);
     // Create new request object, wrapping the outgoing connection.
     var request = new _HttpClientRequest(outgoing,
@@ -1139,9 +1171,9 @@
           _encodeString("${proxy.username}:${proxy.password}"));
       request.headers.set(HttpHeaders.PROXY_AUTHORIZATION, "Basic $auth");
     } else if (!proxy.isDirect && _httpClient._proxyCredentials.length > 0) {
-      var cr =  _httpClient._findProxyCredentials(proxy);
-      if (cr != null) {
-        cr.authorize(request);
+      proxyCreds = _httpClient._findProxyCredentials(proxy);
+      if (proxyCreds != null) {
+        proxyCreds.authorize(request);
       }
     }
     if (uri.userInfo != null && !uri.userInfo.isEmpty) {
@@ -1152,9 +1184,9 @@
       request.headers.set(HttpHeaders.AUTHORIZATION, "Basic $auth");
     } else {
       // Look for credentials.
-      cr = _httpClient._findCredentials(uri);
-      if (cr != null) {
-        cr.authorize(request);
+      creds = _httpClient._findCredentials(uri);
+      if (creds != null) {
+        creds.authorize(request);
       }
     }
     // Start sending the request (lazy, delayed until the user provides
@@ -1179,16 +1211,31 @@
                     destroy();
                   }
                 });
-                // For digest authentication check if the server
-                // requests the client to start using a new nonce.
-                if (cr != null && cr.scheme == _AuthenticationScheme.DIGEST) {
+                // For digest authentication if proxy check if the proxy
+                // requests the client to start using a new nonce for proxy
+                // authentication.
+                if (proxyCreds != null &&
+                    proxyCreds.scheme == _AuthenticationScheme.DIGEST) {
+                  var authInfo = incoming.headers["proxy-authentication-info"];
+                  if (authInfo != null && authInfo.length == 1) {
+                    var header =
+                        _HeaderValue.parse(
+                            authInfo[0], parameterSeparator: ',');
+                    var nextnonce = header.parameters["nextnonce"];
+                    if (nextnonce != null) proxyCreds.nonce = nextnonce;
+                  }
+                }
+                // For digest authentication check if the server requests the
+                // client to start using a new nonce.
+                if (creds != null &&
+                    creds.scheme == _AuthenticationScheme.DIGEST) {
                   var authInfo = incoming.headers["authentication-info"];
                   if (authInfo != null && authInfo.length == 1) {
                     var header =
                         _HeaderValue.parse(
                             authInfo[0], parameterSeparator: ',');
                     var nextnonce = header.parameters["nextnonce"];
-                    if (nextnonce != null) cr.nonce = nextnonce;
+                    if (nextnonce != null) creds.nonce = nextnonce;
                   }
                 }
                 request._onIncoming(incoming);
@@ -1354,7 +1401,7 @@
   }
 
   void addCredentials(Uri url, String realm, HttpClientCredentials cr) {
-    _credentials.add(new _Credentials(url, realm, cr));
+    _credentials.add(new _SiteCredentials(url, realm, cr));
   }
 
   set authenticateProxy(
@@ -1527,10 +1574,10 @@
     return connect(new HttpException("No proxies given"));
   }
 
-  _Credentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
+  _SiteCredentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
     // Look for credentials.
-    _Credentials cr =
-        _credentials.fold(null, (_Credentials prev, _Credentials value) {
+    _SiteCredentials cr =
+        _credentials.fold(null, (prev, value) {
           if (value.applies(url, scheme)) {
             if (prev == null) return value;
             return value.uri.path.length > prev.uri.path.length ? value : prev;
@@ -2008,8 +2055,19 @@
 }
 
 
-class _Credentials {
-  _Credentials(this.uri, this.realm, this.credentials) {
+abstract class _Credentials {
+  _HttpClientCredentials credentials;
+  String realm;
+  bool used = false;
+
+  // Digest specific fields.
+  String ha1;
+  String nonce;
+  String algorithm;
+  String qop;
+  int nonceCount;
+
+  _Credentials(this.credentials, this.realm) {
     if (credentials.scheme == _AuthenticationScheme.DIGEST) {
       // Calculate the H(A1) value once. There is no mentioning of
       // username/password encoding in RFC 2617. However there is an
@@ -2030,6 +2088,15 @@
 
   _AuthenticationScheme get scheme => credentials.scheme;
 
+  void authorize(HttpClientRequest request);
+}
+
+class _SiteCredentials extends _Credentials {
+  Uri uri;
+
+  _SiteCredentials(this.uri, realm, _HttpClientCredentials creds)
+  : super(creds, realm);
+
   bool applies(Uri uri, _AuthenticationScheme scheme) {
     if (scheme != null && credentials.scheme != scheme) return false;
     if (uri.domain != this.uri.domain) return false;
@@ -2050,38 +2117,32 @@
     credentials.authorize(this, request);
     used = true;
   }
-
-  bool used = false;
-  Uri uri;
-  String realm;
-  _HttpClientCredentials credentials;
-
-  // Digest specific fields.
-  String ha1;
-  String nonce;
-  String algorithm;
-  String qop;
-  int nonceCount;
 }
 
 
-class _ProxyCredentials {
-  _ProxyCredentials(this.host, this.port, this.realm, this.credentials);
+class _ProxyCredentials extends _Credentials {
+  String host;
+  int port;
 
-  _AuthenticationScheme get scheme => credentials.scheme;
+  _ProxyCredentials(this.host,
+                    this.port,
+                    realm,
+                    _HttpClientCredentials creds)
+  : super(creds, realm);
 
   bool applies(_Proxy proxy, _AuthenticationScheme scheme) {
     return proxy.host == host && proxy.port == port;
   }
 
   void authorize(HttpClientRequest request) {
+    // Digest credentials cannot be used without a nonce from the
+    // server.
+    if (credentials.scheme == _AuthenticationScheme.DIGEST &&
+        nonce == null) {
+      return;
+    }
     credentials.authorizeProxy(this, request);
   }
-
-  String host;
-  int port;
-  String realm;
-  _HttpClientCredentials credentials;
 }
 
 
@@ -2133,11 +2194,12 @@
 
   _AuthenticationScheme get scheme => _AuthenticationScheme.DIGEST;
 
-  String authorization(_Credentials credentials, HttpClientRequest request) {
+  String authorization(_Credentials credentials, _HttpClientRequest request) {
+    String requestUri = request._requestUri();
     MD5 hasher = new MD5();
     hasher.add(request.method.codeUnits);
     hasher.add([_CharCode.COLON]);
-    hasher.add(request.uri.path.codeUnits);
+    hasher.add(requestUri.codeUnits);
     var ha2 = CryptoUtils.bytesToHex(hasher.close());
 
     String qop;
@@ -2174,7 +2236,7 @@
     buffer.write('username="$username"');
     buffer.write(', realm="${credentials.realm}"');
     buffer.write(', nonce="${credentials.nonce}"');
-    buffer.write(', uri="${request.uri.path}"');
+    buffer.write(', uri="$requestUri"');
     buffer.write(', algorithm="${credentials.algorithm}"');
     if (qop == "auth") {
       buffer.write(', qop="$qop"');
@@ -2186,13 +2248,14 @@
   }
 
   void authorize(_Credentials credentials, HttpClientRequest request) {
-    request.headers.set(HttpHeaders.AUTHORIZATION, authorization(credentials, request));
+    request.headers.set(HttpHeaders.AUTHORIZATION,
+                        authorization(credentials, request));
   }
 
   void authorizeProxy(_ProxyCredentials credentials,
                       HttpClientRequest request) {
-    // TODO(sgjesse): Implement!!!
-    throw new UnsupportedError("Digest authentication not yet supported");
+    request.headers.set(HttpHeaders.PROXY_AUTHORIZATION,
+                        authorization(credentials, request));
   }
 
   String username;
diff --git a/sdk/lib/io/http_multipart_form_data.dart b/sdk/lib/io/http_multipart_form_data.dart
new file mode 100644
index 0000000..3c9bca4
--- /dev/null
+++ b/sdk/lib/io/http_multipart_form_data.dart
@@ -0,0 +1,73 @@
+// 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;
+
+
+/**
+ * [:HttpMultipartFormData:] class used for 'upgrading' a [MimeMultipart] by
+ * parsing it as a 'multipart/form-data' part. The following code shows how
+ * it can be used.
+ *
+ *   HttpServer server = ...;
+ *   server.listen((request) {
+ *     String boundary = request.headers.contentType.parameters['boundary'];
+ *     request
+ *         .transform(new MimeMultipartTransformer(boundary))
+ *         .map(HttpMultipartFormData.parse)
+ *         .map((HttpMultipartFormData formData) {
+ *           // form data object available here.
+ *         });
+ *
+ * [:HttpMultipartFormData:] is a Stream, serving either bytes or decoded
+ * Strings. Use [isText] or [isBinary] to see what type of data is provided.
+ */
+abstract class HttpMultipartFormData implements Stream {
+  /**
+   * The parsed [:Content-Type:] header of the [:HttpMultipartFormData:].
+   * Returns [:null:] if not present.
+   */
+  ContentType get contentType;
+
+  /**
+   * The parsed [:Content-Disposition:] header of the [:HttpMultipartFormData:].
+   * This field is always present. Use this to extract e.g. name(form field
+   * name)and filename (client provided name of uploaded file) parameters.
+   */
+  HeaderValue get contentDisposition;
+
+  /**
+   * The parsed [:Content-Transfer-Encoding:] header of the
+   * [:HttpMultipartFormData:]. This field is used to determine how to decode
+   * the data. Returns [:null:] if not present.
+   */
+  HeaderValue get contentTransferEncoding;
+
+  /**
+   * Returns [:true:] if the data is decoded as [String].
+   */
+  bool get isText;
+
+  /**
+   * Returns [:true:] if the data is raw bytes.
+   */
+  bool get isBinary;
+
+  /**
+   * Returns the value for the header named [name]. If there
+   * is no header with the provided name, [:null:] will be returned.
+   *
+   * Use this method to index other headers available in the original
+   * [MimeMultipart].
+   */
+  String value(String name);
+
+  /**
+   * Parse a [MimeMultipart] and return a [HttpMultipartFormData]. If the
+   * [:Content-Disposition:] header is missing or invalid, a [HttpException] is
+   * thrown.
+   */
+  static HttpMultipartFormData parse(MimeMultipart multipart)
+      => _HttpMultipartFormData.parse(multipart);
+}
diff --git a/sdk/lib/io/http_multipart_form_data_impl.dart b/sdk/lib/io/http_multipart_form_data_impl.dart
new file mode 100644
index 0000000..b227954
--- /dev/null
+++ b/sdk/lib/io/http_multipart_form_data_impl.dart
@@ -0,0 +1,102 @@
+// 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 _HttpMultipartFormData extends Stream implements HttpMultipartFormData {
+  final ContentType contentType;
+  final HeaderValue contentDisposition;
+  final HeaderValue contentTransferEncoding;
+
+  final MimeMultipart _mimeMultipart;
+
+  bool _isText = false;
+
+  Stream _stream;
+
+  _HttpMultipartFormData(ContentType this.contentType,
+                         HeaderValue this.contentDisposition,
+                         HeaderValue this.contentTransferEncoding,
+                         MimeMultipart this._mimeMultipart) {
+    _stream = _mimeMultipart;
+    if (contentTransferEncoding != null) {
+      // TODO(ajohnsen): Support BASE64, etc.
+      throw new HttpException("Unsupported contentTransferEncoding: "
+                              "${contentTransferEncoding.value}");
+    }
+
+    if (contentType == null ||
+        contentType.primaryType == 'text' ||
+        contentType.mimeType == 'application/json') {
+      _isText = true;
+      StringBuffer buffer = new StringBuffer();
+      Encoding encoding;
+      if (contentType != null) {
+        encoding = Encoding.fromName(contentType.charset);
+      }
+      if (encoding == null) encoding = Encoding.ISO_8859_1;
+      _stream = _stream
+          .transform(new StringDecoder(encoding))
+          .expand((data) {
+            buffer.write(data);
+            var out = _HttpUtils.decodeHttpEntityString(buffer.toString());
+            if (out != null) {
+              buffer = new StringBuffer();
+              return [out];
+            }
+            return const [];
+          });
+    }
+  }
+
+  bool get isText => _isText;
+  bool get isBinary => !_isText;
+
+  static HttpMultipartFormData parse(MimeMultipart multipart) {
+    var type;
+    var encoding;
+    var disposition;
+    var remaining = new Map<String, String>();
+    for (String key in multipart.headers.keys) {
+      switch (key) {
+        case HttpHeaders.CONTENT_TYPE:
+          type = ContentType.parse(multipart.headers[key]);
+          break;
+
+        case 'content-transfer-encoding':
+          encoding = HeaderValue.parse(multipart.headers[key]);
+          break;
+
+        case 'content-disposition':
+          disposition = HeaderValue.parse(multipart.headers[key]);
+          break;
+
+        default:
+          remaining[key] = multipart.headers[key];
+          break;
+      }
+    }
+    if (disposition == null) {
+      throw new HttpException(
+          "Mime Multipart doesn't contain a Content-Disposition header value");
+    }
+    return new _HttpMultipartFormData(type, disposition, encoding, multipart);
+  }
+
+  StreamSubscription listen(void onData(data),
+                            {void onDone(),
+                             void onError(error),
+                             bool cancelOnError}) {
+    return _stream.listen(onData,
+                          onDone: onDone,
+                          onError: onError,
+                          cancelOnError: cancelOnError);
+  }
+
+  String value(String name) {
+    return _mimeMultipart.headers[name];
+  }
+}
+
diff --git a/sdk/lib/io/http_utils.dart b/sdk/lib/io/http_utils.dart
index 8c23491..8e957bf 100644
--- a/sdk/lib/io/http_utils.dart
+++ b/sdk/lib/io/http_utils.dart
@@ -358,4 +358,41 @@
 
     return new DateTime.utc(year, month, dayOfMonth, hour, minute, second, 0);
   }
+
+  // Decode a string with HTTP entities. Returns null if the string ends in the
+  // middle of a http entity.
+  static String decodeHttpEntityString(String input) {
+    int amp = input.lastIndexOf('&');
+    if (amp < 0) return input;
+    int end = input.lastIndexOf(';');
+    if (end < amp) return null;
+
+    var buffer = new StringBuffer();
+    int offset = 0;
+
+    parse(amp, end) {
+      switch (input[amp + 1]) {
+        case '#':
+          if (input[amp + 2] == 'x') {
+            buffer.writeCharCode(
+                int.parse(input.substring(amp + 3, end), radix: 16));
+          } else {
+            buffer.writeCharCode(int.parse(input.substring(amp + 2, end)));
+          }
+          break;
+
+        default:
+          throw new HttpException('Unhandled HTTP entity token');
+      }
+    }
+
+    while ((amp = input.indexOf('&', offset)) >= 0) {
+      buffer.write(input.substring(offset, amp));
+      int end = input.indexOf(';', amp);
+      parse(amp, end);
+      offset = end + 1;
+    }
+    buffer.write(input.substring(offset));
+    return buffer.toString();
+  }
 }
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index 2d7000f..fee6a12 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -40,6 +40,8 @@
 part 'http_body_impl.dart';
 part 'http_headers.dart';
 part 'http_impl.dart';
+part 'http_multipart_form_data.dart';
+part 'http_multipart_form_data_impl.dart';
 part 'http_parser.dart';
 part 'http_session.dart';
 part 'http_utils.dart';
diff --git a/sdk/lib/io/iolib_sources.gypi b/sdk/lib/io/iolib_sources.gypi
index f2d61f5..2eab1d9 100644
--- a/sdk/lib/io/iolib_sources.gypi
+++ b/sdk/lib/io/iolib_sources.gypi
@@ -19,6 +19,8 @@
     'http_body_impl.dart',
     'http_headers.dart',
     'http_impl.dart',
+    'http_multipart_form_data.dart',
+    'http_multipart_form_data_impl.dart',
     'http_parser.dart',
     'http_session.dart',
     'http_utils.dart',
diff --git a/sdk/lib/io/mime_multipart_parser.dart b/sdk/lib/io/mime_multipart_parser.dart
index 55451e9..4bfbebe 100644
--- a/sdk/lib/io/mime_multipart_parser.dart
+++ b/sdk/lib/io/mime_multipart_parser.dart
@@ -13,11 +13,11 @@
   Map<String, String> get headers;
 }
 
-class _MimeMultipartImpl extends MimeMultipart {
+class _MimeMultipart extends MimeMultipart {
   final Map<String, String> headers;
   final Stream<List<int>> _stream;
 
-  _MimeMultipartImpl(this.headers, this._stream);
+  _MimeMultipart(this.headers, this._stream);
 
   StreamSubscription<List<int>> listen(void onData(List<int> data),
                                        {void onDone(),
@@ -64,7 +64,7 @@
 
   List<int> _boundary;
   int _state = _START;
-  int _boundaryIndex = 0;
+  int _boundaryIndex = 2;
 
   // Current index in the data buffer. If index is negative then it
   // is the index into the artificial prefix of the boundary string.
@@ -119,7 +119,7 @@
               onDone: () {
                 if (_state != _DONE) {
                   _controller.addError(
-                      new MimeParserException("Bad multipart ending"));
+                      new MimeMultipartException("Bad multipart ending"));
                 }
                 _controller.close();
               },
@@ -187,7 +187,7 @@
       }
       switch (_state) {
         case _START:
-          if (_toLowerCase(byte) == _toLowerCase(_boundary[_boundaryIndex])) {
+          if (byte == _boundary[_boundaryIndex]) {
             _boundaryIndex++;
             if (_boundaryIndex == _boundary.length) {
               _state = _FIRST_BOUNDARY_ENDING;
@@ -246,7 +246,7 @@
             _state = _HEADER_VALUE_START;
           } else {
             if (!_isTokenChar(byte)) {
-              throw new MimeParserException("Invalid header field name");
+              throw new MimeMultipartException("Invalid header field name");
             }
             _headerField.writeCharCode(_toLowerCase(byte));
           }
@@ -281,7 +281,7 @@
           } else {
             String headerField = _headerField.toString();
             String headerValue =_headerValue.toString();
-            _headers[headerField] = headerValue;
+            _headers[headerField.toLowerCase()] = headerValue;
             _headerField = new StringBuffer();
             _headerValue = new StringBuffer();
             if (byte == _CharCode.CR) {
@@ -305,7 +305,7 @@
                 _parse();
               });
           _controller.add(
-              new _MimeMultipartImpl(_headers, _multipartController.stream));
+              new _MimeMultipart(_headers, _multipartController.stream));
           _headers = null;
           _state = _CONTENT;
           contentStartIndex = _index + 1;
@@ -388,20 +388,20 @@
 
   void _expect(int val1, int val2) {
     if (val1 != val2) {
-      throw new MimeParserException("Failed to parse multipart mime 1");
+      throw new MimeMultipartException("Failed to parse multipart mime 1");
     }
   }
 
   void _expectWS(int byte) {
     if (byte != _CharCode.SP && byte != _CharCode.HT) {
-      throw new MimeParserException("Failed to parse multipart mime 2");
+      throw new MimeMultipartException("Failed to parse multipart mime 2");
     }
   }
 }
 
 
-class MimeParserException implements Exception {
-  const MimeParserException([String this.message = ""]);
-  String toString() => "MimeParserException: $message";
+class MimeMultipartException implements Exception {
+  const MimeMultipartException([String this.message = ""]);
+  String toString() => "MimeMultipartException: $message";
   final String message;
 }
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index c562e43..37ded8b 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -5744,7 +5744,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
-class _AttributeClassSet extends CssClassSet {
+class _AttributeClassSet extends CssClassSetImpl {
   final Element _element;
 
   _AttributeClassSet(this._element);
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index 3e42808..7cf7d6c 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -6485,7 +6485,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
-class _AttributeClassSet extends CssClassSet {
+class _AttributeClassSet extends CssClassSetImpl {
   final Element _element;
 
   _AttributeClassSet(this._element);
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
new file mode 100644
index 0000000..4941e73
--- /dev/null
+++ b/tests/co19/co19-analyzer.status
@@ -0,0 +1,333 @@
+# 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.
+
+[ $compiler == dartanalyzer ]
+Language/03_Overview/1_Scoping_A01_t46: fail
+Language/03_Overview/1_Scoping_A02_t07: fail
+Language/03_Overview/1_Scoping_A02_t11: fail
+Language/03_Overview/1_Scoping_A02_t12: fail
+Language/03_Overview/1_Scoping_A02_t16: fail
+Language/03_Overview/1_Scoping_A02_t28: fail
+Language/05_Variables/05_Variables_A01_t09: fail
+Language/05_Variables/05_Variables_A01_t11: fail
+Language/05_Variables/05_Variables_A05_t04: fail
+Language/06_Functions/06_Functions_A01_t10: fail
+Language/06_Functions/06_Functions_A01_t31: fail
+Language/06_Functions/2_Formal_Parameters/1_Required_Formals_A02_t06: fail
+Language/06_Functions/2_Formal_Parameters/1_Required_Formals_A02_t07: fail
+Language/06_Functions/2_Formal_Parameters/2_Optional_Formals_A03_t03: fail
+Language/06_Functions/2_Formal_Parameters_A01_t02: fail
+Language/06_Functions/2_Formal_Parameters_A01_t09: fail
+Language/06_Functions/2_Formal_Parameters_A02_t02: fail
+Language/07_Classes/07_Classes_A02_t02: fail
+Language/07_Classes/07_Classes_A02_t04: fail
+Language/07_Classes/07_Classes_A03_t02: fail
+Language/07_Classes/07_Classes_A03_t07: fail
+Language/07_Classes/07_Classes_A03_t08: fail
+Language/07_Classes/07_Classes_A09_t01: fail
+Language/07_Classes/07_Classes_A09_t02: fail
+Language/07_Classes/07_Classes_A09_t03: fail
+Language/07_Classes/07_Classes_A09_t04: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A03_t01: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A03_t02: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t02: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t03: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t04: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t05: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t06: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t07: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t08: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t09: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t10: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t11: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t12: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t13: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t14: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t15: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t16: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t17: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A04_t18: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A05_t02: fail
+Language/07_Classes/1_Instance_Methods/2_Operators_A06_t02: fail
+Language/07_Classes/1_Instance_Methods_A02_t05: fail
+Language/07_Classes/2_Getters_A04_t03: fail
+Language/07_Classes/2_Getters_A04_t04: fail
+Language/07_Classes/2_Getters_A04_t05: fail
+Language/07_Classes/2_Getters_A04_t07: fail
+Language/07_Classes/3_Setters_A03_t02: fail
+Language/07_Classes/3_Setters_A03_t04: fail
+Language/07_Classes/3_Setters_A03_t06: fail
+Language/07_Classes/3_Setters_A03_t08: fail
+Language/07_Classes/4_Abstract_Instance_Members_A04_t06: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A01_t02: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A01_t04: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t03: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t04: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t05: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t06: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t07: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t08: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A03_t11: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t13: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t15: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A05_t01: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A05_t02: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A05_t03: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t04: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t05: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t06: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t07: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t09: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A11_t12: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A14_t01: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A14_t02: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A14_t03: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A14_t04: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A14_t05: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A14_t06: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A15_t07: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A16_t01: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A16_t02: fail
+Language/07_Classes/6_Constructors/1_Generative_Constructors_A16_t07: fail
+Language/07_Classes/6_Constructors/2_Factories_A01_t05: fail
+Language/07_Classes/6_Constructors/2_Factories_A02_t01: fail
+Language/07_Classes/6_Constructors/2_Factories_A02_t02: fail
+Language/07_Classes/6_Constructors/2_Factories_A02_t03: fail
+Language/07_Classes/6_Constructors/2_Factories_A02_t04: fail
+Language/07_Classes/6_Constructors/2_Factories_A02_t05: fail
+Language/07_Classes/6_Constructors/3_Constant_Constructors_A03_t02: fail
+Language/07_Classes/6_Constructors/3_Constant_Constructors_A04_t01: fail
+Language/07_Classes/6_Constructors/3_Constant_Constructors_A04_t02: fail
+Language/07_Classes/6_Constructors/3_Constant_Constructors_A04_t03: fail
+Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t01: fail
+Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t02: fail
+Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t03: fail
+Language/07_Classes/6_Constructors_A02_t01: fail
+Language/07_Classes/7_Static_Methods_A01_t01: fail
+Language/07_Classes/9_Superclasses_A03_t01: fail
+Language/07_Classes/9_Superclasses_A03_t02: fail
+Language/08_Interfaces/5_Superinterfaces_A01_t03: fail
+Language/08_Interfaces/5_Superinterfaces_A01_t04: fail
+Language/08_Interfaces/5_Superinterfaces_A04_t03: fail
+Language/11_Expressions/01_Constants_A01_t01: fail
+Language/11_Expressions/01_Constants_A08_t02: fail
+Language/11_Expressions/01_Constants_A09_t02: fail
+Language/11_Expressions/01_Constants_A10_t03: fail
+Language/11_Expressions/01_Constants_A11_t03: fail
+Language/11_Expressions/01_Constants_A11_t04: fail
+Language/11_Expressions/01_Constants_A15_t07: fail
+Language/11_Expressions/01_Constants_A16_t01: fail
+Language/11_Expressions/01_Constants_A16_t02: fail
+Language/11_Expressions/01_Constants_A16_t03: fail
+Language/11_Expressions/01_Constants_A17_t03: fail
+Language/11_Expressions/01_Constants_A19_t04: fail
+Language/11_Expressions/01_Constants_A20_t02: fail
+Language/11_Expressions/03_Numbers_A01_t01: fail
+Language/11_Expressions/03_Numbers_A01_t02: fail
+Language/11_Expressions/03_Numbers_A01_t03: fail
+Language/11_Expressions/03_Numbers_A01_t04: fail
+Language/11_Expressions/03_Numbers_A01_t08: fail
+Language/11_Expressions/03_Numbers_A01_t10: fail
+Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t03: fail
+Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t09: fail
+Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t11: fail
+Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t14: fail
+Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t15: fail
+Language/11_Expressions/05_Strings_A02_t34: fail
+Language/11_Expressions/05_Strings_A02_t36: fail
+Language/11_Expressions/05_Strings_A02_t42: fail
+Language/11_Expressions/05_Strings_A02_t44: fail
+Language/11_Expressions/05_Strings_A02_t46: fail
+Language/11_Expressions/05_Strings_A02_t48: fail
+Language/11_Expressions/06_Lists_A01_t03: fail
+Language/11_Expressions/06_Lists_A01_t04: fail
+Language/11_Expressions/06_Lists_A03_t01: fail
+Language/11_Expressions/07_Maps_A01_t01: fail
+Language/11_Expressions/07_Maps_A02_t02: fail
+Language/11_Expressions/07_Maps_A07_t03: fail
+Language/11_Expressions/08_Throw_A06_t01: fail
+Language/11_Expressions/08_Throw_A06_t02: fail
+Language/11_Expressions/08_Throw_A06_t03: fail
+Language/11_Expressions/08_Throw_A06_t04: fail
+Language/11_Expressions/08_Throw_A06_t05: fail
+Language/11_Expressions/08_Throw_A06_t06: fail
+Language/11_Expressions/10_This_A01_t05: fail
+Language/11_Expressions/10_This_A03_t01: fail
+Language/11_Expressions/10_This_A03_t03: fail
+Language/11_Expressions/10_This_A03_t04: fail
+Language/11_Expressions/10_This_A03_t05: fail
+Language/11_Expressions/10_This_A03_t06: fail
+Language/11_Expressions/10_This_A03_t07: fail
+Language/11_Expressions/10_This_A03_t08: fail
+Language/11_Expressions/11_Instance_Creation/1_New_A01_t04: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A02_t01: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A02_t02: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A02_t03: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A02_t04: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A02_t05: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A02_t06: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A02_t07: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A03_t01: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A03_t02: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A04_t01: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A04_t03: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A04_t04: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A05_t01: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A06_t01: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A06_t02: fail
+Language/11_Expressions/11_Instance_Creation/2_Const_A10_t01: fail
+Language/11_Expressions/11_Instance_Creation_A05_t02: fail
+Language/11_Expressions/14_Function_Invocation/1_Actual_Argument_List_Evaluation_A01_t05: fail
+Language/11_Expressions/14_Function_Invocation/2_Binding_Actuals_to_Formals_A04_t01: fail
+Language/11_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t10: fail
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A01_t05: fail
+Language/11_Expressions/15_Method_Invocation/3_Static_Invocation_A01_t05: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A01_t05: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A05_t01: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A05_t02: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A05_t03: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A05_t04: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A05_t05: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A05_t06: fail
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A05_t07: fail
+Language/11_Expressions/19_Conditional_A01_t05: fail
+Language/11_Expressions/19_Conditional_A01_t06: fail
+Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t04: fail
+Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t05: fail
+Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t06: fail
+Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t07: fail
+Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t08: fail
+Language/11_Expressions/20_Logical_Boolean_Expressions_A01_t09: fail
+Language/11_Expressions/21_Bitwise_Expressions_A01_t03: fail
+Language/11_Expressions/21_Bitwise_Expressions_A01_t04: fail
+Language/11_Expressions/21_Bitwise_Expressions_A01_t05: fail
+Language/11_Expressions/21_Bitwise_Expressions_A01_t06: fail
+Language/11_Expressions/21_Bitwise_Expressions_A01_t07: fail
+Language/11_Expressions/21_Bitwise_Expressions_A01_t08: fail
+Language/11_Expressions/21_Bitwise_Expressions_A01_t09: fail
+Language/11_Expressions/21_Bitwise_Expressions_A01_t10: fail
+Language/11_Expressions/21_Bitwise_Expressions_A01_t11: fail
+Language/11_Expressions/22_Equality_A01_t03: fail
+Language/11_Expressions/22_Equality_A01_t04: fail
+Language/11_Expressions/22_Equality_A01_t07: fail
+Language/11_Expressions/22_Equality_A01_t08: fail
+Language/11_Expressions/22_Equality_A01_t11: fail
+Language/11_Expressions/22_Equality_A01_t12: fail
+Language/11_Expressions/22_Equality_A01_t15: fail
+Language/11_Expressions/22_Equality_A01_t16: fail
+Language/11_Expressions/23_Relational_Expressions_A01_t03: fail
+Language/11_Expressions/23_Relational_Expressions_A01_t04: fail
+Language/11_Expressions/23_Relational_Expressions_A01_t05: fail
+Language/11_Expressions/23_Relational_Expressions_A01_t06: fail
+Language/11_Expressions/23_Relational_Expressions_A01_t07: fail
+Language/11_Expressions/23_Relational_Expressions_A01_t08: fail
+Language/11_Expressions/23_Relational_Expressions_A01_t09: fail
+Language/11_Expressions/24_Shift_A01_t02: fail
+Language/11_Expressions/24_Shift_A01_t03: fail
+Language/11_Expressions/24_Shift_A01_t04: fail
+Language/11_Expressions/24_Shift_A01_t05: fail
+Language/11_Expressions/24_Shift_A01_t06: fail
+Language/11_Expressions/24_Shift_A01_t07: fail
+Language/11_Expressions/25_Additive_Expressions_A01_t02: fail
+Language/11_Expressions/25_Additive_Expressions_A01_t03: fail
+Language/11_Expressions/25_Additive_Expressions_A01_t05: fail
+Language/11_Expressions/25_Additive_Expressions_A01_t06: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t02: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t03: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t04: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t05: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t06: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t07: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t08: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t18: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t19: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t20: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t21: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t22: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t23: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t24: fail
+Language/11_Expressions/26_Multiplicative_Expressions_A01_t25: fail
+Language/11_Expressions/27_Unary_Expressions_A01_t08: fail
+Language/11_Expressions/28_Postfix_Expressions_A01_t06: fail
+Language/11_Expressions/28_Postfix_Expressions_A01_t09: fail
+Language/11_Expressions/28_Postfix_Expressions_A01_t10: fail
+Language/11_Expressions/28_Postfix_Expressions_A01_t11: fail
+Language/11_Expressions/29_Assignable_Expressions_A01_t10: fail
+Language/11_Expressions/29_Assignable_Expressions_A01_t11: fail
+Language/11_Expressions/29_Assignable_Expressions_A01_t12: fail
+Language/11_Expressions/29_Assignable_Expressions_A01_t13: fail
+Language/11_Expressions/29_Assignable_Expressions_A01_t15: fail
+Language/11_Expressions/29_Assignable_Expressions_A01_t16: fail
+Language/11_Expressions/30_Identifier_Reference_A01_t07: fail
+Language/11_Expressions/30_Identifier_Reference_A01_t08: fail
+Language/11_Expressions/31_Type_Test_A05_t01: fail
+Language/11_Expressions/31_Type_Test_A05_t02: fail
+Language/11_Expressions/31_Type_Test_A05_t03: fail
+Language/11_Expressions/32_Type_Cast_A04_t01: fail
+Language/11_Expressions/32_Type_Cast_A04_t02: fail
+Language/11_Expressions/33_Argument_Definition_Test_A01_t14: fail
+Language/11_Expressions/33_Argument_Definition_Test_A01_t18: fail
+Language/12_Statements/02_Expression_Statements_A01_t06: fail
+Language/12_Statements/02_Expression_Statements_A01_t07: fail
+Language/12_Statements/02_Expression_Statements_A01_t12: fail
+Language/12_Statements/03_Variable_Declaration_A04_t01: fail
+Language/12_Statements/03_Variable_Declaration_A04_t02: fail
+Language/12_Statements/03_Variable_Declaration_A04_t05: fail
+Language/12_Statements/03_Variable_Declaration_A04_t06: fail
+Language/12_Statements/03_Variable_Declaration_A04_t07: fail
+Language/12_Statements/03_Variable_Declaration_A04_t08: fail
+Language/12_Statements/04_Local_Function_Declaration_A01_t01: fail
+Language/12_Statements/04_Local_Function_Declaration_A02_t02: fail
+Language/12_Statements/05_If_A01_t01: fail
+Language/12_Statements/06_For_A01_t10: fail
+Language/12_Statements/07_While_A01_t04: fail
+Language/12_Statements/08_Do_A01_t07: fail
+Language/12_Statements/09_Switch_A01_t06: fail
+Language/12_Statements/15_Assert_A01_t03: fail
+Language/13_Libraries_and_Scripts/13_Libraries_and_Scripts_A03_t17: fail
+Language/13_Libraries_and_Scripts/1_Imports_A01_t46: fail
+Language/13_Libraries_and_Scripts/1_Imports_A02_t12: fail
+Language/13_Libraries_and_Scripts/1_Imports_A02_t15: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t02: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t05: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t07: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t08: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t09: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t10: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t22: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t25: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t27: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t28: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t29: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t30: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t42: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t45: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t48: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t49: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t50: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t62: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t65: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t68: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t69: fail
+Language/13_Libraries_and_Scripts/1_Imports_A03_t70: fail
+Language/13_Libraries_and_Scripts/1_Imports_A04_t03: fail
+Language/13_Libraries_and_Scripts/1_Imports_A05_t01: fail
+Language/13_Libraries_and_Scripts/2_Exports_A04_t02: fail
+Language/13_Libraries_and_Scripts/2_Exports_A04_t03: fail
+Language/13_Libraries_and_Scripts/2_Exports_A05_t01: fail
+Language/13_Libraries_and_Scripts/5_URIs_A01_t24: fail
+Language/13_Libraries_and_Scripts/5_URIs_A01_t25: fail
+Language/14_Types/3_Type_Declarations/1_Typedef_A07_t01: fail
+Language/14_Types/3_Type_Declarations/1_Typedef_A07_t02: fail
+Language/14_Types/3_Type_Declarations/1_Typedef_A07_t03: fail
+Language/14_Types/3_Type_Declarations/1_Typedef_A07_t04: fail
+Language/15_Reference/1_Lexical_Rules/1_Reserved_Words_A40_t04: fail
+Language/15_Reference/1_Lexical_Rules_A02_t06: fail
+LibTest/core/double/ceil_A01_t05: fail
+LibTest/core/double/floor_A01_t05: fail
+
+
+[ $runtime == drt && $compiler == none ]
+*: Skip
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 78dc0f9..b2502fa 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -560,6 +560,11 @@
 LibTest/async/Future/Future.immediateError_A01_t01: Fail # No AsyncError anymore. Issue 407
 LibTest/async/Future/catchError_A02_t01: Fail # No AsyncError anymore. Issue 407
 
+LibTest/async/Completer/complete_A01_t03: Fail # Completer is now asynchronous. Issue TODO
+LibTest/async/Completer/complete_A01_t04: Fail # Completer is now asynchronous. Issue TODO
+LibTest/async/Future/then_A01_t01: Fail # Completer is now asynchronous. Issue TODO
+LibTest/async/Future/then_A01_t04: Fail # Completer is now asynchronous. Issue TODO
+
 Language/11_Expressions/05_Strings/1_String_Interpolation_A03_t02: Fail # Issue 397
 Language/11_Expressions/05_Strings/1_String_Interpolation_A04_t02: Fail # Issue 397
 Language/11_Expressions/11_Instance_Creation/1_New_A08_t01: Fail # Issue 397
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 3e46304..9c16e3d 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -537,6 +537,11 @@
 LibTest/async/Future/Future.immediateError_A01_t01: Fail # No AsyncError anymore. Issue 407
 LibTest/async/Future/catchError_A02_t01: Fail # No AsyncError anymore. Issue 407
 
+LibTest/async/Completer/complete_A01_t03: Fail # Completer is now asynchronous. Issue TODO
+LibTest/async/Completer/complete_A01_t04: Fail # Completer is now asynchronous. Issue TODO
+LibTest/async/Future/then_A01_t01: Fail # Completer is now asynchronous. Issue TODO
+LibTest/async/Future/then_A01_t04: Fail # Completer is now asynchronous. Issue TODO
+
 Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: Fail, OK # co19 issue 409
 Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t02: Fail, OK # co19 issue 409
 Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t03: Fail, OK # co19 issue 409
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 4e265b3..99470a9 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -484,6 +484,11 @@
 LibTest/async/Future/Future.immediateError_A01_t01: Fail # No AsyncError anymore. Issue 407
 LibTest/async/Future/catchError_A02_t01: Fail # No AsyncError anymore. Issue 407
 
+LibTest/async/Completer/complete_A01_t03: Fail # Completer is now asynchronous. Issue TODO
+LibTest/async/Completer/complete_A01_t04: Fail # Completer is now asynchronous. Issue TODO
+LibTest/async/Future/then_A01_t01: Fail # Completer is now asynchronous. Issue TODO
+LibTest/async/Future/then_A01_t04: Fail # Completer is now asynchronous. Issue TODO
+
 [ $compiler == none && $runtime == vm && $checked ]
 LibTest/core/Set/intersection_A01_t01: Fail # issue 390
 LibTest/core/Set/intersection_A01_t02: Fail # issue 390
diff --git a/tests/co19/test_config.dart b/tests/co19/test_config.dart
index 1ea56de..0392975 100644
--- a/tests/co19/test_config.dart
+++ b/tests/co19/test_config.dart
@@ -14,7 +14,8 @@
       : super(configuration,
               "co19",
               new Path("tests/co19/src"),
-              ["tests/co19/co19-compiler.status",
+              ["tests/co19/co19-analyzer.status",
+               "tests/co19/co19-compiler.status",
                "tests/co19/co19-runtime.status",
                "tests/co19/co19-dart2dart.status",
                "tests/co19/co19-dart2js.status"]);
diff --git a/tests/compiler/dart2js/deprecated_features_test.dart b/tests/compiler/dart2js/deprecated_features_test.dart
index 588e77f..3ca046e 100644
--- a/tests/compiler/dart2js/deprecated_features_test.dart
+++ b/tests/compiler/dart2js/deprecated_features_test.dart
@@ -31,7 +31,7 @@
     if (uri.scheme != "main") return dummy.provider(uri);
     String source = TEST_SOURCE[uri.path];
     Expect.isNotNull(source);
-    return (new Completer<String>()..complete(source)).future;
+    return new Future<String>.value(source);
   }
 
   String code = deprecatedFutureValue(
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 1aa2277..877c3d1 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -305,7 +305,8 @@
 
   resolverVisitor() {
     Element mockElement =
-        new ElementX(buildSourceString(''), ElementKind.FUNCTION, mainApp);
+        new ElementX(buildSourceString(''), ElementKind.FUNCTION,
+            mainApp.entryCompilationUnit);
     ResolverVisitor visitor =
         new ResolverVisitor(this, mockElement,
                             new CollectingTreeElements(mockElement));
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index cd29121c..3008f2e 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -89,6 +89,10 @@
 symbol_test/02: Fail
 symbol_test/03: Fail
 
+[ $compiler == dartanalyzer ]
+int_parse_radix_test: fail
+list_insert_test: fail
+list_removeat_test: fail
 
 [ $arch == arm ]
 *: Skip
diff --git a/tests/html/element_classes_test.dart b/tests/html/element_classes_test.dart
index 83bb86c..3c628b9 100644
--- a/tests/html/element_classes_test.dart
+++ b/tests/html/element_classes_test.dart
@@ -19,6 +19,11 @@
   Element makeElementWithClasses() =>
     new Element.html('<div class="foo bar baz"></div>');
 
+  Element makeListElement() =>
+    new Element.html('<ul class="foo bar baz">'
+        '<li class="quux qux"><li class="meta">'
+        '<li class="classy lassy"><li class="qux lassy"></ul>');
+
   Set<String> makeClassSet() => makeElementWithClasses().classes;
 
   Set<String> extractClasses(Element el) {
@@ -53,9 +58,7 @@
 
   test('forEach', () {
     final classes = <String>[];
-    // TODO: Change to this when Issue 3484 is fixed.
-    //    makeClassSet().forEach(classes.add);
-    makeClassSet().forEach((c) => classes.add(c));
+    makeClassSet().forEach(classes.add);
     expect(classes, orderedEquals(['foo', 'bar', 'baz']));
   });
 
@@ -177,4 +180,141 @@
     classes.toggle('baz');
     expect(classes, orderedEquals(['foo', 'bar', 'aardvark', 'baz']));
   });
+
+  Element listElement;
+
+  ElementList listElementSetup() {
+    listElement = makeListElement();
+    document.documentElement.children.add(listElement);
+    return document.queryAll('li');
+  }
+
+  test('listClasses=', () {
+    var elements =  listElementSetup();
+    elements.classes = ['foo', 'qux'];
+    elements = document.queryAll('li');
+    for (Element e in elements) {
+      expect(e.classes, orderedEquals(['foo', 'qux']));
+      expect(extractClasses(e), orderedEquals(['foo', 'qux']));
+    }
+
+    elements.classes = [];
+    for (Element e in elements) {
+      expect(e.classes, []);
+    }
+    document.documentElement.children.remove(listElement);
+  });
+
+  test('listMap', () {
+    var elements = listElementSetup();
+    expect(elements.classes.map((c) => c.toUpperCase()).toList(),
+        unorderedEquals(['QUX', 'QUUX', 'META', 'CLASSY', 'LASSY']));
+    document.documentElement.children.remove(listElement);
+  });
+
+  test('listContains', () {
+    var elements = listElementSetup();
+    expect(elements.classes.contains('lassy'), isTrue);
+    expect(elements.classes.contains('foo'), isFalse);
+    document.documentElement.children.remove(listElement);
+  });
+
+
+  test('listAdd', () {
+    var elements =  listElementSetup();
+    elements.classes.add('lassie');
+    expect(elements.classes,
+        unorderedEquals(['lassie', 'qux', 'quux', 'meta', 'classy', 'lassy']));
+    for (Element e in elements) {
+      expect(e.classes, anyOf(unorderedEquals(['quux', 'qux', 'lassie']),
+          unorderedEquals(['meta', 'lassie']),
+          unorderedEquals(['classy', 'lassy', 'lassie']),
+          unorderedEquals(['qux', 'lassy', 'lassie'])));
+    }
+    document.documentElement.children.remove(listElement);
+  });
+
+  test('listRemove', () {
+    var elements = listElementSetup();
+    expect(elements.classes.remove('lassi'), isFalse);
+    expect(elements.classes,
+        unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy']));
+    for (Element e in elements) {
+      expect(e.classes, anyOf(unorderedEquals(['quux', 'qux']),
+          unorderedEquals(['meta']), unorderedEquals(['classy', 'lassy']),
+          unorderedEquals(['qux', 'lassy'])));
+    }
+
+    expect(elements.classes.remove('qux'), isTrue);
+    expect(elements.classes,
+        unorderedEquals(['quux', 'meta', 'classy', 'lassy']));
+    for (Element e in elements) {
+      expect(e.classes, anyOf(unorderedEquals(['quux']),
+          unorderedEquals(['meta']), unorderedEquals(['classy', 'lassy']),
+          unorderedEquals(['lassy'])));
+    }
+    document.documentElement.children.remove(listElement);
+  });
+
+  test('listToggle', () {
+    var elements = listElementSetup();
+    elements.classes.toggle('qux');
+    expect(elements.classes,
+        unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy']));
+    for (Element e in elements) {
+      expect(e.classes, anyOf(unorderedEquals(['quux']),
+          unorderedEquals(['meta', 'qux']), unorderedEquals(['classy', 'lassy',
+          'qux']), unorderedEquals(['lassy'])));
+    }
+    document.documentElement.children.remove(listElement);
+  });
+
+  test('listAddAll', () {
+    var elements = listElementSetup();
+    elements.classes.addAll(['qux', 'lassi', 'sassy']);
+    expect(elements.classes,
+        unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy', 'sassy',
+        'lassi']));
+    for (Element e in elements) {
+      expect(e.classes, anyOf(
+          unorderedEquals(['quux', 'qux', 'lassi', 'sassy']),
+          unorderedEquals(['meta', 'qux', 'lassi', 'sassy']),
+          unorderedEquals(['classy', 'lassy', 'qux', 'lassi','sassy']),
+          unorderedEquals(['lassy', 'qux', 'lassi', 'sassy'])));
+    }
+    document.documentElement.children.remove(listElement);
+  });
+
+  test('listRemoveAll', () {
+    var elements = listElementSetup();
+    elements.classes.removeAll(['qux', 'lassy', 'meta']);
+    expect(elements.classes,
+        unorderedEquals(['quux','classy']));
+    for (Element e in elements) {
+      expect(e.classes, anyOf(unorderedEquals(['quux']),
+          unorderedEquals([]), unorderedEquals(['classy'])));
+    }
+    document.documentElement.children.remove(listElement);
+  });
+
+  test('listToggleAll', () {
+    var elements = listElementSetup();
+    elements.classes.toggleAll(['qux', 'meta', 'mornin']);
+    expect(elements.classes,
+        unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy', 'mornin']));
+    for (Element e in elements) {
+      expect(e.classes, anyOf(unorderedEquals(['quux', 'meta', 'mornin']),
+          unorderedEquals(['qux', 'mornin']),
+          unorderedEquals(['classy', 'lassy', 'qux', 'mornin', 'meta']),
+          unorderedEquals(['lassy', 'mornin', 'meta'])));
+    }
+    document.documentElement.children.remove(listElement);
+  });
+
+  test('listContainsAll', () {
+    var elements = listElementSetup();
+    expect(elements.classes.containsAll(['qux', 'meta', 'mornin']), isFalse);
+    expect(elements.classes.containsAll(['qux', 'lassy', 'classy']), isTrue);
+    document.documentElement.children.remove(listElement);
+  });
 }
diff --git a/tests/html/html.status b/tests/html/html.status
index 6282522..8d10943 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -12,6 +12,8 @@
 [ $compiler == none && ($runtime == drt || $runtime == dartium) ]
 # postMessage in dartium always transfers the typed array buffer, never a view
 postmessage_structured_test/typed_arrays: Fail
+async_test: Timeout # http://dartbug.com/10470
+dom_isolates_test: Timeout # http://dartbug.com/10470
 
 [ $compiler == none && $runtime == drt && $system == windows ]
 worker_test/functional: Pass, Crash # Issue 9929.
@@ -175,6 +177,7 @@
 media_stream_test/supported_media: Fail
 mutationobserver_test/supported: Fail
 notifications_test/supported: Fail
+range_test/supported: Fail
 rtc_test/supported: Fail
 shadow_dom_test/supported: Fail
 speechrecognition_test/supported: Fail
@@ -365,4 +368,5 @@
 js_interop_2_test: Fail, OK        # Test cannot run under CSP restrictions.
 js_interop_3_test: Skip            # Test cannot run under CSP restrictions (times out).
 postmessage_structured_test: Skip  # Test cannot run under CSP restrictions (times out).
+safe_dom_test: Skip                # Test cannot run under CSP restrictions (times out).
 shadow_dom_layout_test: Fail, OK   # Test cannot run under CSP restrictions.
diff --git a/tests/html/location_test.dart b/tests/html/location_test.dart
index e1f0fb8..88e3f2d 100644
--- a/tests/html/location_test.dart
+++ b/tests/html/location_test.dart
@@ -2,6 +2,7 @@
 import '../../pkg/unittest/lib/unittest.dart';
 import '../../pkg/unittest/lib/html_config.dart';
 import 'dart:html';
+import 'dart:uri';
 
 main() {
   useHtmlConfiguration();
@@ -17,4 +18,17 @@
       var h = location.hash;
       expect(h, '#hello');
     });
+
+  test('location.origin', () {
+    var origin = window.location.origin;
+
+    // We build up the origin from Uri, then make sure that it matches.
+    var uri = new Uri(window.location.href);
+    var reconstructedOrigin = '${uri.scheme}://${uri.domain}';
+    if (uri.port != 0) {
+      reconstructedOrigin = '$reconstructedOrigin:${uri.port}';
+    }
+
+    expect(origin, reconstructedOrigin);
+  });
 }
diff --git a/tests/html/range_test.dart b/tests/html/range_test.dart
new file mode 100644
index 0000000..3792afd
--- /dev/null
+++ b/tests/html/range_test.dart
@@ -0,0 +1,29 @@
+library range_test;
+
+import 'dart:html';
+import '../../pkg/unittest/lib/unittest.dart';
+import '../../pkg/unittest/lib/html_individual_config.dart';
+
+main() {
+  useHtmlIndividualConfiguration();
+
+  group('supported', () {
+    test('supports_createContextualFragment', () {
+      expect(Range.supportsCreateContextualFragment, isTrue);
+    });
+  });
+
+  group('functional', () {
+    test('supported works', () {
+      var range = new Range();
+      range.selectNode(document.body);
+
+      var expectation = Range.supportsCreateContextualFragment ?
+          returnsNormally : throws;
+
+      expect(() {
+        range.createContextualFragment('<div></div>');
+      }, expectation);
+    });
+  });
+}
diff --git a/tests/html/safe_dom_test.dart b/tests/html/safe_dom_test.dart
new file mode 100644
index 0000000..5e7ae35
--- /dev/null
+++ b/tests/html/safe_dom_test.dart
@@ -0,0 +1,98 @@
+library safe_dom_test;
+
+import 'dart:async';
+import 'dart:html';
+import '../../pkg/unittest/lib/unittest.dart';
+import '../../pkg/unittest/lib/html_config.dart';
+
+main() {
+  useHtmlConfiguration();
+
+  // Checks to see if any illegal properties were set via script.
+  var checkerScript = '''
+  window.addEventListener('message', function(e) {
+    if (e.data == 'check_unsafe') {
+      if (window.unsafe_value) {
+        window.postMessage('unsafe_check_failed', '*');
+      } else {
+        window.postMessage('unsafe_check_passed', '*');
+      }
+      //window.alert('checking!');
+    }
+  }, false);
+  ''';
+
+  var script = new ScriptElement();
+  script.text = checkerScript;
+  document.body.append(script);
+
+  var unsafeString =
+      '<img src="_.png" onerror="javascript:window.unsafe_value=1;" crap="1"/>';
+
+  test('Safe DOM', () {
+    var fragment = createContextualFragment(unsafeString);
+
+    expect(isSafe(), completion(true),
+        reason: 'Expected no unsafe code executed.');
+  });
+
+  // Make sure that scripts did get executed, so we know our detection works.
+  test('Unsafe Execution', () {
+    var div = new DivElement();
+    div.innerHtml = unsafeString;
+    // Crashing DRT ??
+    // var fragment = createContextualFragment(unsafeString);
+    // div.append(fragment);
+    // document.body.append(div)
+
+    expect(isSafe(), completion(false),
+        reason: 'Expected unsafe code was executed.');
+  });
+
+  test('Validity', () {
+    var fragment = createContextualFragment('<span>content</span>');
+    var div = new DivElement();
+    div.append(fragment);
+
+    expect(div.nodes.length, 1);
+    expect(div.nodes[0] is SpanElement, isTrue);
+  });
+}
+
+DocumentFragment createContextualFragment(String html, [String contextTag]) {
+  var doc = document.implementation.createHtmlDocument('');
+
+  var contextElement;
+  if (contextTag != null) {
+    contextElement = doc.$dom_createElement(contextTag);
+  } else {
+    contextElement = doc.body;
+  }
+
+  if (Range.supportsCreateContextualFragment) {
+    var range = doc.$dom_createRange();
+    range.selectNode(contextElement);
+    return range.createContextualFragment(html);
+  } else {
+    contextElement.innerHtml = html;
+    var fragment = new DocumentFragment();;
+    while (contextElement.$dom_firstChild != null) {
+      fragment.append(contextElement.$dom_firstChild);
+    }
+    return fragment;
+  }
+}
+
+// Delay to wait for the image load to fail.
+const Duration imageLoadDelay = const Duration(milliseconds: 500);
+
+Future<bool> isSafe() {
+  return new Future.delayed(imageLoadDelay).then((_) {
+    window.postMessage('check_unsafe', '*');
+  }).then((_) {
+    return window.onMessage.where(
+        (e) => e.data.startsWith('unsafe_check')).first;
+  }).then((e) {
+    return e.data == 'unsafe_check_passed';
+  });
+}
diff --git a/tests/html/streams_test.dart b/tests/html/streams_test.dart
index b0feb5e..7a3b2ff 100644
--- a/tests/html/streams_test.dart
+++ b/tests/html/streams_test.dart
@@ -112,7 +112,7 @@
     helper.pulse();
     expect(callCount, 2);
 
-    var completer = new Completer<int>();
+    var completer = new Completer<int>.sync();
     subscription.pause(completer.future);
     helper.pulse();
     expect(callCount, 2);
diff --git a/tests/html/websql_test.dart b/tests/html/websql_test.dart
index cac79de..2c77b6a 100644
--- a/tests/html/websql_test.dart
+++ b/tests/html/websql_test.dart
@@ -12,7 +12,7 @@
 }
 
 Future<SqlTransaction> transaction(SqlDatabase db) {
-  final completer = new Completer<SqlTransaction>();
+  final completer = new Completer<SqlTransaction>.sync();
 
   db.transaction((SqlTransaction transaction) {
     completer.complete(transaction);
@@ -25,7 +25,7 @@
 
 Future<SqlResultSet> createTable(SqlTransaction transaction, String tableName,
     String columnName) {
-  final completer = new Completer<SqlResultSet>();
+  final completer = new Completer<SqlResultSet>.sync();
 
   final sql = 'CREATE TABLE $tableName ($columnName)';
   transaction.executeSql(sql, [],
@@ -41,7 +41,7 @@
 
 Future<SqlResultSet> insert(SqlTransaction transaction, String tableName,
     String columnName, value) {
-  final completer = new Completer<SqlResultSet>();
+  final completer = new Completer<SqlResultSet>.sync();
 
   final sql = 'INSERT INTO $tableName ($columnName) VALUES (?)';
   transaction.executeSql(sql, [value],
@@ -56,7 +56,7 @@
 }
 
 Future<SqlResultSet> queryTable(SqlTransaction transaction, String tableName) {
-  final completer = new Completer<SqlResultSet>();
+  final completer = new Completer<SqlResultSet>.sync();
 
   final sql = 'SELECT * FROM $tableName';
   transaction.executeSql(sql, [],
@@ -72,7 +72,7 @@
 
 Future<SqlResultSet> dropTable(SqlTransaction transaction, String tableName,
     [bool ignoreFailure = false]) {
-  final completer = new Completer<SqlResultSet>();
+  final completer = new Completer<SqlResultSet>.sync();
 
   final sql = 'DROP TABLE $tableName';
   transaction.executeSql(sql, [],
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 89c72e7..b0cd54b 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -36,6 +36,15 @@
 isolate2_negative_test: Pass
 compute_this_script_browser_test: Pass
 
+[ $compiler == dartanalyzer ]
+isolate2_negative_test: fail
+isolate3_negative_test: fail
+isolate_import_negative_test: fail
+isolate_negative_test: fail
+spawn_function_negative_test: fail
+spawn_uri_negative_test: fail
+spawn_uri_vm_negative_test: fail
+unresolved_ports_negative_test: fail
 
 [ $compiler == dart2js && ($runtime == d8 || $jscl) ]
 illegal_msg_stream_test: Fail # Issue 6750
diff --git a/tests/language/allocation_sinking_vm_test.dart b/tests/language/allocation_sinking_vm_test.dart
new file mode 100644
index 0000000..d7bb7b9
--- /dev/null
+++ b/tests/language/allocation_sinking_vm_test.dart
@@ -0,0 +1,132 @@
+// 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 allocation sinking optimization.
+
+import 'package:expect/expect.dart';
+
+class Point {
+  var x, y;
+
+  Point(this.x, this.y);
+
+  operator * (other) {
+    return x * other.x + y * other.y;
+  }
+}
+
+class C {
+  var p;
+  C(this.p);
+}
+
+class D {
+  var p;
+  D(this.p);
+}
+
+// Class that is used to capture materialized Point object with * operator.
+class F {
+  var p;
+  var val;
+
+  F(this.p);
+
+  operator * (other) {
+    Expect.isTrue(other is Point);
+    Expect.equals(42.0, other.x);
+    Expect.equals(0.5, other.y);
+
+    if (val == null) {
+      val = other;
+    } else {
+      Expect.isTrue(identical(val, other));
+    }
+
+    return this.p * other;
+  }
+}
+
+test1(c, x, y) {
+  var a = new Point(x - 0.5, y + 0.5);
+  var b = new Point(x + 0.5, y + 0.8);
+  var d = new Point(c.p * a, c.p * b);
+  return d * d;
+}
+
+effects() {
+  // This function should not be inlinable.
+  try { } catch (e) { }
+}
+
+testForwardingThroughEffects(c, x, y) {
+  var a = new Point(x - 0.5, y + 0.5);
+  var b = new Point(x - 0.5, y - 0.8);
+  var d = new Point(c.p * a, c.p * b);
+  // Effects can't affect neither a, b, nor d because they do not escape.
+  effects();
+  effects();
+  return ((a == null) ? 0.0 : 0.1) + (d * d);
+}
+
+testIdentity(x) {
+  var y = new Point(42.0, 0.5);
+  var z = y;
+  return x * y + x * z;
+}
+
+class PointP<T> {
+  var x, y;
+
+  PointP(this.x, this.y);
+
+  operator * (other) {
+    return x * other.x + y * other.y;
+  }
+}
+
+foo2() => new PointP<int>(1, 3) * new PointP<num>(5, 6);
+
+main() {
+  var c = new C(new Point(0.1, 0.2));
+
+  // Compute initial values.
+  final x0 = test1(c, 11.11, 22.22);
+  final y0 = testForwardingThroughEffects(c, 11.11, 22.22);
+  final z0 = testIdentity(c.p);
+
+  // Force optimization.
+  for (var i = 0; i < 10000; i++) {
+    test1(c, i.toDouble(), i.toDouble());
+    testForwardingThroughEffects(c, i.toDouble(), i.toDouble());
+    testIdentity(c.p);
+    foo2();
+  }
+
+  // Test returned value after optimization.
+  final x1 = test1(c, 11.11, 22.22);
+  final y1 = testForwardingThroughEffects(c, 11.11, 22.22);
+
+  // Test returned value after deopt.
+  final x2 = test1(new D(c.p), 11.11, 22.22);
+  final y2 = testForwardingThroughEffects(new D(c.p), 11.11, 22.22);
+
+  Expect.equals(6465, (x0 * 100).floor());
+  Expect.equals(6465, (x1 * 100).floor());
+  Expect.equals(6465, (x2 * 100).floor());
+  Expect.equals(x0, x1);
+  Expect.equals(x0, x2);
+
+  Expect.equals(6008, (y0 * 100).floor());
+  Expect.equals(6008, (y1 * 100).floor());
+  Expect.equals(6008, (y2 * 100).floor());
+  Expect.equals(y0, y1);
+  Expect.equals(y0, y2);
+
+  // Test that identity of materialized objects is preserved correctly and
+  // no copies are materialized.
+  final z1 = testIdentity(c.p);
+  final z2 = testIdentity(new F(c.p));
+  Expect.equals(z0, z1);
+  Expect.equals(z0, z2);
+}
\ No newline at end of file
diff --git a/tests/language/language.status b/tests/language/language.status
index 879ef11..6e939ca 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -555,6 +555,411 @@
 invocation_mirror_test: Fail, OK # hardcoded names.
 super_call4_test: Fail, OK # hardcoded names.
 
+[ $compiler == dartanalyzer ]
+abstract_factory_constructor_test/00: fail
+assign_instance_method_negative_test: fail
+assign_static_type_test/01: fail
+assign_static_type_test/02: fail
+assign_static_type_test/03: fail
+assign_static_type_test/04: fail
+assign_static_type_test/05: fail
+assign_static_type_test/06: fail
+bad_initializer2_negative_test: fail
+bad_named_constructor_negative_test: fail
+bad_named_parameters2_test: fail
+bad_named_parameters_test: fail
+bad_override_test/01: fail
+bad_override_test/02: fail
+bad_override_test/03: fail
+bad_override_test/04: fail
+bad_override_test/05: fail
+black_listed_test/11: fail
+body_less_constructor_wrong_arg_negative_test: fail
+built_in_identifier_prefix_test: fail
+call_constructor_on_unresolvable_class_test/01: fail
+call_constructor_on_unresolvable_class_test/02: fail
+call_constructor_on_unresolvable_class_test/03: fail
+call_constructor_on_unresolvable_class_test/07: fail
+call_non_method_field_test/01: fail
+call_non_method_field_test/02: fail
+call_nonexistent_static_test/01: fail
+call_nonexistent_static_test/02: fail
+call_nonexistent_static_test/03: fail
+call_nonexistent_static_test/04: fail
+call_nonexistent_static_test/05: fail
+call_nonexistent_static_test/06: fail
+call_nonexistent_static_test/07: fail
+call_nonexistent_static_test/08: fail
+call_nonexistent_static_test/09: fail
+call_nonexistent_static_test/10: fail
+call_through_getter_test: fail
+callable_test/00: fail
+callable_test/01: fail
+cast_test/04: fail
+cast_test/05: fail
+class_cycle_negative_test: fail
+class_cycle_test/00: fail
+class_cycle_test/01: fail
+class_cycle_test/03: fail
+class_literal_test/02: fail
+class_literal_test/05: fail
+class_literal_test/07: fail
+class_literal_test/10: fail
+class_literal_test/11: fail
+class_literal_test/12: fail
+class_literal_test/14: fail
+class_literal_test/17: fail
+class_literal_test/18: fail
+class_literal_test/19: fail
+class_literal_test/22: fail
+class_literal_test/23: fail
+class_literal_test/24: fail
+class_literal_test/27: fail
+class_literal_test/28: fail
+class_literal_test/29: fail
+closure_call_wrong_argument_count_negative_test: fail
+compile_time_constant10_test/none: fail
+compile_time_constant8_test: fail
+compile_time_constant_arguments_test/01: fail
+compile_time_constant_arguments_test/02: fail
+compile_time_constant_arguments_test/03: fail
+compile_time_constant_arguments_test/04: fail
+compile_time_constant_arguments_test/05: fail
+compile_time_constant_arguments_test/06: fail
+compile_time_constant_b_test: fail
+compile_time_constant_checked2_test/01: fail
+compile_time_constant_checked2_test/02: fail
+compile_time_constant_checked2_test/03: fail
+compile_time_constant_checked2_test/04: fail
+compile_time_constant_checked2_test/05: fail
+compile_time_constant_checked2_test/06: fail
+compile_time_constant_checked3_test/01: fail
+compile_time_constant_checked3_test/02: fail
+compile_time_constant_checked3_test/03: fail
+compile_time_constant_checked3_test/04: fail
+compile_time_constant_checked3_test/05: fail
+compile_time_constant_checked3_test/06: fail
+compile_time_constant_checked_test/01: fail
+compile_time_constant_checked_test/02: fail
+compile_time_constant_checked_test/03: fail
+compile_time_constant_d_test: fail
+compile_time_constant_e_test: fail
+compile_time_constant_test/02: fail
+const_counter_negative_test: fail
+const_factory_negative_test: fail
+const_optional_args_negative_test: fail
+const_syntax_test/06: fail
+constructor2_negative_test: fail
+constructor3_negative_test: fail
+constructor_call_wrong_argument_count_negative_test: fail
+constructor_name_test/01: fail
+constructor_name_test/02: fail
+constructor_name_test/03: fail
+constructor_negative_test: fail
+constructor_redirect1_negative_test: fail
+constructor_redirect2_negative_test: fail
+constructor_redirect2_test/02: fail
+constructor_redirect2_test/03: fail
+constructor_redirect2_test/04: fail
+constructor_redirect_test/01: fail
+constructor_return_with_arrow_negative_test: fail
+constructor_return_with_init_and_arrow_negative_test: fail
+constructor_setter_negative_test: fail
+cyclic_constructor_test/01: fail
+cyclic_type_variable_test/01: fail
+cyclic_type_variable_test/02: fail
+cyclic_type_variable_test/03: fail
+cyclic_type_variable_test/04: fail
+default_factory2_test/01: fail
+default_implementation2_test: fail
+duplicate_constructor_test/01: fail
+duplicate_export_negative_test: fail
+dynamic2_test/00: fail
+dynamic_field_test: fail
+f_bounded_quantification_test/01: fail
+f_bounded_quantification_test/02: fail
+factory2_negative_test: fail
+factory2_test: fail
+factory5_test/00: fail
+factory_negative_test: fail
+factory_redirection2_test/01: fail
+factory_redirection_test/04: fail
+factory_redirection_test/07: fail
+fauxverride_test/03: fail
+fauxverride_test/05: fail
+field_decl_missing_var_type_test/01: fail
+field_method4_negative_test: fail
+field_override_test/01: fail
+field_override_test/02: fail
+field_type_check_test/01: fail
+final_for_in_variable_test/01: fail
+final_param_negative_test: fail
+final_var_negative_test: fail
+final_variable_assignment_test/01: fail
+final_variable_assignment_test/02: fail
+final_variable_assignment_test/03: fail
+final_variable_assignment_test/04: fail
+first_class_types_constants_test: fail
+for_in2_test: fail
+function_type_alias5_test/00: fail
+function_type_alias5_test/01: fail
+function_type_alias5_test/02: fail
+getter_no_setter2_test/00: fail
+getter_no_setter2_test/02: fail
+getter_no_setter2_test/03: fail
+getter_no_setter_test/00: fail
+getter_no_setter_test/01: fail
+getter_no_setter_test/02: fail
+getters_setters2_test/01: fail
+getters_setters2_test/02: fail
+getters_setters_type_test/01: fail
+implicit_scope_test: fail
+implicit_this_test/01: fail
+implicit_this_test/04: fail
+implicit_this_test/none: fail
+import_combinators_negative_test: fail
+import_private_test/01: fail
+inst_field_initializer1_negative_test: fail
+instance_call_wrong_argument_count_negative_test: fail
+instance_method2_negative_test: fail
+instance_method_negative_test: fail
+instantiate_type_variable_negative_test: fail
+interface_cycle_negative_test: fail
+interface_inherit_field_test: fail
+interface_static_non_final_fields_negative_test: fail
+interface_test/00: fail
+internal_library_test/01: fail
+is_not_class2_negative_test: fail
+issue1363_test: fail
+library1_negative_test: fail
+library_juxtaposition_test: fail
+licm_test: fail
+list_literal1_negative_test: fail
+list_literal_syntax_test/01: fail
+list_literal_syntax_test/02: fail
+list_literal_syntax_test/03: fail
+list_literal_syntax_test/05: fail
+map_literal1_negative_test: fail
+map_literal2_test: fail
+map_literal3_test: fail
+method_override2_test/00: fail
+method_override2_test/01: fail
+method_override2_test/02: fail
+method_override2_test/03: fail
+mixin_cyclic_test/01: fail
+mixin_illegal_constructor_test/01: fail
+mixin_illegal_constructor_test/02: fail
+mixin_illegal_constructor_test/03: fail
+mixin_illegal_constructor_test/04: fail
+mixin_illegal_constructor_test/05: fail
+mixin_illegal_constructor_test/06: fail
+mixin_illegal_constructor_test/07: fail
+mixin_illegal_constructor_test/08: fail
+mixin_illegal_constructor_test/09: fail
+mixin_illegal_constructor_test/10: fail
+mixin_illegal_constructor_test/11: fail
+mixin_illegal_constructor_test/12: fail
+mixin_illegal_constructor_test/13: fail
+mixin_illegal_constructor_test/14: fail
+mixin_illegal_constructor_test/15: fail
+mixin_illegal_constructor_test/16: fail
+mixin_illegal_cycles_test/01: fail
+mixin_illegal_cycles_test/02: fail
+mixin_illegal_cycles_test/03: fail
+mixin_illegal_cycles_test/04: fail
+mixin_illegal_cycles_test/05: fail
+mixin_illegal_cycles_test/06: fail
+mixin_illegal_super_use_test/01: fail
+mixin_illegal_super_use_test/02: fail
+mixin_illegal_super_use_test/03: fail
+mixin_illegal_super_use_test/04: fail
+mixin_illegal_super_use_test/05: fail
+mixin_illegal_super_use_test/06: fail
+mixin_illegal_super_use_test/07: fail
+mixin_illegal_super_use_test/08: fail
+mixin_illegal_super_use_test/09: fail
+mixin_illegal_super_use_test/10: fail
+mixin_illegal_super_use_test/11: fail
+mixin_illegal_superclass_test/01: fail
+mixin_illegal_superclass_test/02: fail
+mixin_illegal_superclass_test/03: fail
+mixin_illegal_superclass_test/04: fail
+mixin_illegal_superclass_test/05: fail
+mixin_illegal_superclass_test/06: fail
+mixin_illegal_superclass_test/07: fail
+mixin_illegal_superclass_test/08: fail
+mixin_illegal_superclass_test/09: fail
+mixin_illegal_superclass_test/10: fail
+mixin_illegal_superclass_test/11: fail
+mixin_illegal_superclass_test/12: fail
+mixin_illegal_superclass_test/13: fail
+mixin_illegal_superclass_test/14: fail
+mixin_illegal_superclass_test/15: fail
+mixin_illegal_superclass_test/16: fail
+mixin_illegal_superclass_test/17: fail
+mixin_illegal_superclass_test/18: fail
+mixin_illegal_superclass_test/19: fail
+mixin_illegal_superclass_test/20: fail
+mixin_illegal_superclass_test/21: fail
+mixin_illegal_superclass_test/22: fail
+mixin_illegal_superclass_test/23: fail
+mixin_illegal_superclass_test/24: fail
+mixin_illegal_superclass_test/25: fail
+mixin_illegal_superclass_test/26: fail
+mixin_illegal_superclass_test/27: fail
+mixin_illegal_superclass_test/28: fail
+mixin_illegal_superclass_test/29: fail
+mixin_illegal_superclass_test/30: fail
+mixin_illegal_syntax_test/13: fail
+mixin_type_parameters_errors_test/01: fail
+mixin_type_parameters_errors_test/02: fail
+mixin_type_parameters_errors_test/03: fail
+mixin_type_parameters_errors_test/04: fail
+mixin_type_parameters_errors_test/05: fail
+named_parameters2_test: fail
+named_parameters_aggregated_test/03: fail
+named_parameters_aggregated_test/04: fail
+named_parameters_aggregated_test/05: fail
+named_parameters_type_test: fail
+new_expression_type_args_test/00: fail
+new_expression_type_args_test/01: fail
+new_expression_type_args_test/02: fail
+no_such_method_negative_test: fail
+non_const_super_negative_test: fail
+number_identifier_negative_test: fail
+override_field_method1_negative_test: fail
+override_field_method2_negative_test: fail
+override_field_method4_negative_test: fail
+override_field_method5_negative_test: fail
+override_field_test/01: fail
+override_field_test/02: fail
+override_field_test/03: fail
+override_method_with_field_test/01: fail
+override_method_with_field_test/02: fail
+parameter_initializer3_negative_test: fail
+parameter_initializer5_negative_test: fail
+positional_parameters_type_test: fail
+prefix10_negative_test: fail
+prefix11_negative_test: fail
+prefix12_negative_test: fail
+prefix1_negative_test: fail
+prefix22_test: fail
+prefix23_test: fail
+prefix2_negative_test: fail
+prefix3_negative_test: fail
+prefix4_negative_test: fail
+prefix5_negative_test: fail
+prefix6_negative_test: fail
+prefix8_negative_test: fail
+prefix9_negative_test: fail
+private_member1_negative_test: fail
+private_member2_negative_test: fail
+private_member3_negative_test: fail
+pseudo_kw_illegal_test/14: fail
+pseudo_kw_test: fail
+redirecting_factory_infinite_steps_test/01: fail
+redirecting_factory_infinite_steps_test/02: fail
+scope_negative_test: fail
+setter3_test/01: fail
+setter3_test/02: fail
+setter_declaration2_negative_test: fail
+setter_declaration_negative_test: fail
+static_call_wrong_argument_count_negative_test: fail
+static_field3_test/01: fail
+static_field3_test/02: fail
+static_field3_test/03: fail
+static_field3_test/04: fail
+static_field_test/01: fail
+static_field_test/02: fail
+static_field_test/03: fail
+static_field_test/04: fail
+static_final_field2_negative_test: fail
+static_final_field_negative_test: fail
+string_interpolate1_negative_test: fail
+string_interpolate2_negative_test: fail
+string_interpolation1_negative_test: fail
+string_interpolation2_negative_test: fail
+string_interpolation3_negative_test: fail
+string_interpolation4_negative_test: fail
+string_interpolation5_negative_test: fail
+string_interpolation6_negative_test: fail
+string_interpolation9_test/10: fail
+string_interpolation9_test/11: fail
+string_interpolation9_test/12: fail
+string_interpolation9_test/13: fail
+string_interpolation9_test/14: fail
+string_interpolation9_test/15: fail
+string_interpolation9_test/16: fail
+string_interpolation9_test/17: fail
+string_interpolation9_test/18: fail
+string_interpolation9_test/19: fail
+string_interpolation9_test/1: fail
+string_interpolation9_test/20: fail
+string_interpolation9_test/2: fail
+string_interpolation9_test/3: fail
+string_interpolation9_test/4: fail
+string_interpolation9_test/5: fail
+string_interpolation9_test/6: fail
+string_interpolation9_test/7: fail
+string_interpolation9_test/8: fail
+string_interpolation9_test/9: fail
+string_interpolation_test/01: fail
+super_call3_test/02: fail
+super_operator_index_test/01: fail
+super_operator_index_test/02: fail
+super_operator_index_test/03: fail
+super_operator_index_test/04: fail
+super_operator_index_test/05: fail
+super_operator_index_test/06: fail
+super_operator_index_test/07: fail
+syntax_test/28: fail
+syntax_test/29: fail
+syntax_test/30: fail
+syntax_test/31: fail
+syntax_test/32: fail
+syntax_test/33: fail
+ternary_test: fail
+throw7_negative_test: fail
+try_catch_on_syntax_test/01: fail
+try_catch_on_syntax_test/07: fail
+try_catch_syntax_test/08: fail
+try_catch_syntax_test/16: fail
+try_catch_syntax_test/17: fail
+type_error_test: fail
+type_parameter_test/01: fail
+type_parameter_test/02: fail
+type_parameter_test/03: fail
+type_parameter_test/04: fail
+type_variable_bounds2_test/00: fail
+type_variable_bounds2_test/01: fail
+type_variable_bounds2_test/02: fail
+type_variable_bounds2_test/03: fail
+type_variable_bounds2_test/04: fail
+type_variable_bounds2_test/06: fail
+type_variable_bounds_test/00: fail
+type_variable_bounds_test/01: fail
+type_variable_bounds_test/02: fail
+type_variable_bounds_test/03: fail
+type_variable_bounds_test/04: fail
+type_variable_bounds_test/05: fail
+type_variable_bounds_test/06: fail
+type_variable_bounds_test/07: fail
+type_variable_bounds_test/09: fail
+type_variable_bounds_test/10: fail
+type_variable_identifier_expression_negative_test: fail
+type_variable_static_context_negative_test: fail
+typed_equality_test: fail
+unary2_test: fail
+unary_test: fail
+unresolved_in_factory_negative_test: fail
+unresolved_top_level_method_negative_test: fail
+unresolved_top_level_var_negative_test: fail
+unsigned_right_shift_test/01: fail
+unsigned_right_shift_test/02: fail
+wrong_number_type_arguments_test/00: fail
+wrong_number_type_arguments_test/02: fail
+
+
 [ $arch == arm ]
 *: Skip
 
diff --git a/tests/language/load_to_load_forwarding_test.dart b/tests/language/load_to_load_forwarding_test.dart
index 6c7d8b4..cade3c6 100644
--- a/tests/language/load_to_load_forwarding_test.dart
+++ b/tests/language/load_to_load_forwarding_test.dart
@@ -35,10 +35,37 @@
   return [value1, value2];
 }
 
+// Verify that immutable and mutable VM fields (array length in this case)
+// are not confused by load forwarding even if the access the same offset
+// in the object.
+testImmutableVMFields(arr, immutable) {
+  if (immutable) {
+    return arr.length;  // Immutable length load.
+  }
+
+  if (arr.length < 2) {  // Mutable length load, should not be forwarded.
+    arr.add(null);
+  }
+
+  return arr.length;
+}
+
 main() {
+  final fixed = new List(10);
+  final growable = [];
+  testImmutableVMFields(fixed, true);
+  testImmutableVMFields(growable, false);
+  testImmutableVMFields(growable, false);
+
   for (var i = 0; i < 2000; i++) {
     Expect.listEquals([0x02010000, 0x03020100], foo(new A(0, 0)));
     Expect.listEquals([0x02010000, 0x03020100], bar(new A(0, 0), false));
     Expect.listEquals([0x04020000, 0x03020100], bar(new A(0, 0), true));
+    testImmutableVMFields(fixed, true);
   }
+
+  Expect.equals(1, testImmutableVMFields([], false));
+  Expect.equals(2, testImmutableVMFields([1], false));
+  Expect.equals(2, testImmutableVMFields([1, 2], false));
+  Expect.equals(3, testImmutableVMFields([1, 2, 3], false));
 }
\ No newline at end of file
diff --git a/tests/lib/analyzer/analyze_tests.status b/tests/lib/analyzer/analyze_tests.status
index d949e2b..949fd4f 100644
--- a/tests/lib/analyzer/analyze_tests.status
+++ b/tests/lib/analyzer/analyze_tests.status
@@ -35,3 +35,6 @@
 standalone/io/http_parser_test: Fail
 standalone/io/web_socket_protocol_processor_test: Fail
 standalone/io/url_encoding_test: Fail
+
+[ $compiler == dartanalyzer ]
+standalone/io/process_exit_negative_test: fail
diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart
index 078ee4a..7af6893 100644
--- a/tests/lib/async/future_test.dart
+++ b/tests/lib/async/future_test.dart
@@ -76,15 +76,17 @@
   final completer = new Completer<int>();
   final future = completer.future;
 
-  int value;
-  future.then((int v) { value = v; });
-  Expect.isNull(value);
+  int after;
 
-  Expect.isFalse(completer.isCompleted);
+  var port = new ReceivePort();
+  future.then((int v) { after = v; })
+    .then((_) {
+      Expect.equals(3, after);
+      port.close();
+    });
+
   completer.complete(3);
-  Expect.isTrue(completer.isCompleted);
-
-  Expect.equals(3, value);
+  Expect.isNull(after);
 }
 
 testCompleteWithSuccessHandlerAfterComplete() {
diff --git a/tests/standalone/io/http_auth_digest_test.dart b/tests/standalone/io/http_auth_digest_test.dart
index 70e1451..74e9d93 100644
--- a/tests/standalone/io/http_auth_digest_test.dart
+++ b/tests/standalone/io/http_auth_digest_test.dart
@@ -67,7 +67,7 @@
           HeaderValue header =
               HeaderValue.parse(
                   authorization, parameterSeparator: ",");
-          if (header.value == "basic") {
+          if (header.value.toLowerCase() == "basic") {
             sendUnauthorizedResponse(response);
           } else if (!useNextNonce && nonceCount == nonceStaleAfter) {
             nonce = "87654321";
@@ -78,12 +78,12 @@
             var qop = header.parameters["qop"];
             var cnonce = header.parameters["cnonce"];
             var nc = header.parameters["nc"];
-            Expect.equals("digest", header.value);
+            Expect.equals("digest", header.value.toLowerCase());
             Expect.equals("dart", header.parameters["username"]);
             Expect.equals(realm, header.parameters["realm"]);
             Expect.equals("MD5", header.parameters["algorithm"]);
             Expect.equals(nonce, header.parameters["nonce"]);
-            Expect.equals(request.uri.path, uri);
+            Expect.equals(request.uri.toString(), uri);
             if (qop != null) {
               // A server qop of auth-int is downgraded to none by the client.
               Expect.equals("auth", serverQop);
@@ -201,10 +201,17 @@
         new HttpClientDigestCredentials("dart", "password"));
 
     var futures = [];
-    for (int i = 0; i < 5; i++) {
+    for (int i = 0; i < 2; i++) {
+      String uriBase = "http://127.0.0.1:${server.port}/digest";
       futures.add(
           makeRequest(
-              Uri.parse("http://127.0.0.1:${server.port}/digest")));
+              Uri.parse(uriBase)));
+      futures.add(
+          makeRequest(
+              Uri.parse("$uriBase?querystring")));
+      futures.add(
+          makeRequest(
+              Uri.parse("$uriBase?querystring#fragment")));
     }
     Future.wait(futures).then((_) {
       server.shutdown();
diff --git a/tests/standalone/io/http_body_test.dart b/tests/standalone/io/http_body_test.dart
index cd1c4b5..a6ea742 100644
--- a/tests/standalone/io/http_body_test.dart
+++ b/tests/standalone/io/http_body_test.dart
@@ -90,7 +90,7 @@
             List<int> content,
             dynamic expectedBody,
             String type,
-            [bool shouldFail = false]) {
+            {bool shouldFail: false}) {
     HttpServer.bind("127.0.0.1", 0).then((server) {
       server.transform(new HttpBodyHandler())
           .listen((body) {
@@ -98,26 +98,52 @@
             Expect.equals(type, body.type);
             switch (type) {
               case "text":
-                Expect.equals(body.mimeType, "text/plain");
+                Expect.equals(body.contentType.mimeType, "text/plain");
                 Expect.equals(expectedBody, body.body);
                 break;
 
               case "json":
-                Expect.equals(body.mimeType, "application/json");
+                Expect.equals(body.contentType.mimeType, "application/json");
                 Expect.mapEquals(expectedBody, body.body);
                 break;
 
               case "binary":
-                Expect.equals(body.mimeType, null);
+                Expect.equals(body.contentType, null);
                 Expect.listEquals(expectedBody, body.body);
                 break;
 
+              case "form":
+                var mimeType = body.contentType.mimeType;
+                Expect.isTrue(
+                    mimeType == 'multipart/form-data' ||
+                    mimeType == 'application/x-www-form-urlencoded');
+                Expect.setEquals(expectedBody.keys.toSet(),
+                                 body.body.keys.toSet());
+                for (var key in expectedBody.keys) {
+                  if (body.body[key] is HttpBodyFileUpload) {
+                    Expect.equals(expectedBody[key]['contentType'],
+                                  body.body[key].contentType.toString());
+                    Expect.equals(expectedBody[key]['filename'],
+                                  body.body[key].filename);
+                    if (body.body[key].content is String) {
+                      Expect.equals(expectedBody[key]['content'],
+                                    body.body[key].content);
+                    } else {
+                      Expect.listEquals(expectedBody[key]['content'],
+                                        body.body[key].content);
+                    }
+                  } else {
+                    Expect.equals(expectedBody[key], body.body[key]);
+                  }
+                }
+                break;
+
               default:
                 Expect.fail("bad body type");
             }
             body.response.close();
           }, onError: (error) {
-            if (!shouldFail) Expect.fail("Error unexpected");
+            if (!shouldFail) throw error;
           });
 
       var client = new HttpClient();
@@ -160,9 +186,70 @@
        '{ bad json }'.codeUnits,
        null,
        "json",
-       true);
+       shouldFail: true);
 
   test(null, "body".codeUnits, "body".codeUnits, "binary");
+
+  test("multipart/form-data; boundary=AaB03x",
+       '''
+--AaB03x\r
+Content-Disposition: form-data; name="name"\r
+\r
+Larry\r
+--AaB03x--\r\n'''.codeUnits,
+       { "name": "Larry" },
+       "form");
+
+  test("multipart/form-data; boundary=AaB03x",
+       '''
+--AaB03x\r
+Content-Disposition: form-data; name="files"; filename="myfile"\r
+Content-Type: application/octet-stream\r
+\r
+File content\r
+--AaB03x--\r\n'''.codeUnits,
+       { "files": { 'filename': 'myfile',
+                    'contentType': 'application/octet-stream',
+                    'content': 'File content'.codeUnits} },
+       "form");
+
+  test("multipart/form-data; boundary=AaB03x",
+       '''
+--AaB03x\r
+Content-Disposition: form-data; name="files"; filename="myfile"\r
+Content-Type: application/octet-stream\r
+\r
+File content\r
+--AaB03x\r
+Content-Disposition: form-data; name="files"; filename="myfile"\r
+Content-Type: text/plain\r
+\r
+File content\r
+--AaB03x--\r\n'''.codeUnits,
+       { "files": { 'filename': 'myfile',
+                    'contentType': 'text/plain',
+                    'content': 'File content'} },
+       "form");
+
+  test("multipart/form-data; boundary=AaB03x",
+       '''
+--AaB03x\r
+Content-Disposition: form-data; name="files"; filename="myfile"\r
+Content-Type: application/json\r
+\r
+File content\r
+--AaB03x--\r\n'''.codeUnits,
+       { "files": { 'filename': 'myfile',
+                    'contentType': 'application/json',
+                    'content': 'File content'} },
+       "form");
+
+  test('application/x-www-form-urlencoded',
+       '%E5%B9%B3%3D%E4%BB%AE%E5%90%8D=%26%2324179%3B%26%2320206%3B%26%'
+       '2321517%3B&b=%26%2324179%3B%26%2320206%3B%26%2321517%3B'.codeUnits,
+       { 'b' : '平仮名',
+         '平=仮名' : '平仮名'},
+       "form");
 }
 
 void main() {
diff --git a/tests/standalone/io/http_multipart_test.dart b/tests/standalone/io/http_multipart_test.dart
new file mode 100644
index 0000000..d564fc9
--- /dev/null
+++ b/tests/standalone/io/http_multipart_test.dart
@@ -0,0 +1,201 @@
+// 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 "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:io';
+
+class FormField {
+  final String name;
+  final value;
+  final String contentType;
+  final String filename;
+
+  FormField(String this.name,
+            this.value,
+            {String this.contentType,
+             String this.filename});
+
+  bool operator==(other) {
+    if (value.length != other.value.length) return false;
+    for (int i = 0; i < value.length; i++) {
+      if (value[i] != other.value[i]) {
+        return false;
+      }
+    }
+    return name == other.name &&
+           contentType == other.contentType &&
+           filename == other.filename;
+  }
+
+  String toString() {
+    return "FormField('$name', '$value', '$contentType', '$filename')";
+  }
+}
+
+void postDataTest(List<int> message,
+                  String contentType,
+                  String boundary,
+                  List<FormField> expectedFields) {
+  HttpServer.bind("127.0.0.1", 0).then((server) {
+    server.listen((request) {
+      String boundary = request.headers.contentType.parameters['boundary'];
+      request
+          .transform(new MimeMultipartTransformer(boundary))
+          .map(HttpMultipartFormData.parse)
+          .map((multipart) {
+            var future;
+            if (multipart.isText) {
+              future = multipart
+                  .fold(new StringBuffer(), (b, s) => b..write(s))
+                  .then((b) => b.toString());
+            } else {
+              future = multipart
+                  .fold([], (b, s) => b..addAll(s));
+            }
+            return future
+                .then((data) {
+                  String contentType;
+                  if (multipart.contentType != null) {
+                    contentType = multipart.contentType.mimeType;
+                  }
+                  return new FormField(
+                      multipart.contentDisposition.parameters['name'],
+                      data,
+                      contentType: contentType,
+                      filename:
+                          multipart.contentDisposition.parameters['filename']);
+                });
+          })
+          .fold([], (l, f) => l..add(f))
+          .then(Future.wait)
+          .then((fields) {
+            Expect.listEquals(expectedFields, fields);
+            request.response.close().then((_) => server.close());
+          });
+    });
+    var client = new HttpClient();
+    client.post('127.0.0.1', server.port, '/')
+        .then((request) {
+          request.headers.set('content-type',
+                              'multipart/form-data; boundary=$boundary');
+          request.add(message);
+          return request.close();
+        })
+        .then((response) {
+          client.close();
+        });
+  });
+}
+
+void testPostData() {
+  var message = '''
+\r\n--AaB03x\r
+Content-Disposition: form-data; name="submit-name"\r
+\r
+Larry\r
+--AaB03x\r
+Content-Disposition: form-data; name="files"; filename="file1.txt"\r
+Content-Type: text/plain\r
+\r
+Content of file\r
+--AaB03x--\r\n''';
+
+
+  postDataTest(message.codeUnits,
+               'multipart/form-data',
+               'AaB03x',
+               [new FormField('submit-name', 'Larry'),
+                new FormField('files',
+                              'Content of file',
+                              contentType: 'text/plain',
+                              filename: 'file1.txt')]);
+
+  // Similar test using Chrome posting.
+  message = [
+      45, 45, 45, 45, 45, 45, 87, 101, 98, 75, 105, 116, 70, 111, 114, 109, 66,
+      111, 117, 110, 100, 97, 114, 121, 81, 83, 113, 108, 56, 107, 68, 65, 76,
+      77, 55, 116, 65, 107, 67, 49, 13, 10, 67, 111, 110, 116, 101, 110, 116,
+      45, 68, 105, 115, 112, 111, 115, 105, 116, 105, 111, 110, 58, 32, 102,
+      111, 114, 109, 45, 100, 97, 116, 97, 59, 32, 110, 97, 109, 101, 61, 34,
+      115, 117, 98, 109, 105, 116, 45, 110, 97, 109, 101, 34, 13, 10, 13, 10,
+      84, 101, 115, 116, 13, 10, 45, 45, 45, 45, 45, 45, 87, 101, 98, 75, 105,
+      116, 70, 111, 114, 109, 66, 111, 117, 110, 100, 97, 114, 121, 81, 83, 113,
+      108, 56, 107, 68, 65, 76, 77, 55, 116, 65, 107, 67, 49, 13, 10, 67, 111,
+      110, 116, 101, 110, 116, 45, 68, 105, 115, 112, 111, 115, 105, 116, 105,
+      111, 110, 58, 32, 102, 111, 114, 109, 45, 100, 97, 116, 97, 59, 32, 110,
+      97, 109, 101, 61, 34, 102, 105, 108, 101, 115, 34, 59, 32, 102, 105, 108,
+      101, 110, 97, 109, 101, 61, 34, 86, 69, 82, 83, 73, 79, 78, 34, 13, 10,
+      67, 111, 110, 116, 101, 110, 116, 45, 84, 121, 112, 101, 58, 32, 97, 112,
+      112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 111, 99, 116, 101, 116, 45,
+      115, 116, 114, 101, 97, 109, 13, 10, 13, 10, 123, 32, 10, 32, 32, 34, 114,
+      101, 118, 105, 115, 105, 111, 110, 34, 58, 32, 34, 50, 49, 56, 54, 48, 34,
+      44, 10, 32, 32, 34, 118, 101, 114, 115, 105, 111, 110, 34, 32, 58, 32, 34,
+      48, 46, 49, 46, 50, 46, 48, 95, 114, 50, 49, 56, 54, 48, 34, 44, 10, 32,
+      32, 34, 100, 97, 116, 101, 34, 32, 32, 32, 32, 58, 32, 34, 50, 48, 49, 51,
+      48, 52, 50, 51, 48, 48, 48, 52, 34, 10, 125, 13, 10, 45, 45, 45, 45, 45,
+      45, 87, 101, 98, 75, 105, 116, 70, 111, 114, 109, 66, 111, 117, 110, 100,
+      97, 114, 121, 81, 83, 113, 108, 56, 107, 68, 65, 76, 77, 55, 116, 65, 107,
+      67, 49, 45, 45, 13, 10];
+
+  var data = [
+      123, 32, 10, 32, 32, 34, 114, 101, 118, 105, 115, 105, 111, 110, 34, 58,
+      32, 34, 50, 49, 56, 54, 48, 34, 44, 10, 32, 32, 34, 118, 101, 114, 115,
+      105, 111, 110, 34, 32, 58, 32, 34, 48, 46, 49, 46, 50, 46, 48, 95, 114,
+      50, 49, 56, 54, 48, 34, 44, 10, 32, 32, 34, 100, 97, 116, 101, 34, 32, 32,
+      32, 32, 58, 32, 34, 50, 48, 49, 51, 48, 52, 50, 51, 48, 48, 48, 52, 34,
+      10, 125];
+
+  postDataTest(message,
+               'multipart/form-data',
+               '----WebKitFormBoundaryQSql8kDALM7tAkC1',
+               [new FormField('submit-name', 'Test'),
+                new FormField('files',
+                              data,
+                              contentType: 'application/octet-stream',
+                              filename: 'VERSION')]);
+
+  message = [
+      45, 45, 45, 45, 45, 45, 87, 101, 98, 75, 105, 116, 70, 111, 114, 109, 66,
+      111, 117, 110, 100, 97, 114, 121, 118, 65, 86, 122, 117, 103, 75, 77, 116,
+      90, 98, 121, 87, 111, 66, 71, 13, 10, 67, 111, 110, 116, 101, 110, 116,
+      45, 68, 105, 115, 112, 111, 115, 105, 116, 105, 111, 110, 58, 32, 102,
+      111, 114, 109, 45, 100, 97, 116, 97, 59, 32, 110, 97, 109, 101, 61, 34,
+      110, 97, 109, 101, 34, 13, 10, 13, 10, 38, 35, 49, 50, 52, 48, 50, 59, 38,
+      35, 49, 50, 52, 50, 53, 59, 38, 35, 49, 50, 51, 54, 52, 59, 38, 35, 49,
+      50, 51, 57, 52, 59, 13, 10, 45, 45, 45, 45, 45, 45, 87, 101, 98, 75, 105,
+      116, 70, 111, 114, 109, 66, 111, 117, 110, 100, 97, 114, 121, 118, 65, 86,
+      122, 117, 103, 75, 77, 116, 90, 98, 121, 87, 111, 66, 71, 45, 45, 13, 10];
+
+  postDataTest(message,
+               'multipart/form-data',
+               '----WebKitFormBoundaryvAVzugKMtZbyWoBG',
+               [new FormField('name', 'ひらがな')]);
+
+  message = [
+      45, 45, 45, 45, 45, 45, 87, 101, 98, 75, 105, 116, 70, 111, 114, 109, 66,
+      111, 117, 110, 100, 97, 114, 121, 102, 101, 48, 69, 122, 86, 49, 97, 78,
+      121, 115, 68, 49, 98, 80, 104, 13, 10, 67, 111, 110, 116, 101, 110, 116,
+      45, 68, 105, 115, 112, 111, 115, 105, 116, 105, 111, 110, 58, 32, 102,
+      111, 114, 109, 45, 100, 97, 116, 97, 59, 32, 110, 97, 109, 101, 61, 34,
+      110, 97, 109, 101, 34, 13, 10, 13, 10, 248, 118, 13, 10, 45, 45, 45, 45,
+      45, 45, 87, 101, 98, 75, 105, 116, 70, 111, 114, 109, 66, 111, 117, 110,
+      100, 97, 114, 121, 102, 101, 48, 69, 122, 86, 49, 97, 78, 121, 115, 68,
+      49, 98, 80, 104, 45, 45, 13, 10];
+
+  postDataTest(message,
+               'multipart/form-data',
+               '----WebKitFormBoundaryfe0EzV1aNysD1bPh',
+               [new FormField('name', 'øv')]);
+}
+
+
+void main() {
+  testPostData();
+}
diff --git a/tests/standalone/io/http_parser_test.dart b/tests/standalone/io/http_parser_test.dart
index 5742510..0030a7d 100644
--- a/tests/standalone/io/http_parser_test.dart
+++ b/tests/standalone/io/http_parser_test.dart
@@ -275,13 +275,13 @@
   }
 
   static void _testParseInvalidResponse(String response, [bool close = false]) {
-    _HttpParser httpParser;
-    bool errorCalled;
-    StreamController controller;
+    void testWrite(List<int> requestData, [int chunkSize = -1]) {
+      _HttpParser httpParser = new _HttpParser.responseParser();
+      StreamController controller = new StreamController();
+      bool errorCalled = false;;
 
-    void reset() {
-      httpParser = new _HttpParser.responseParser();
-      controller = new StreamController();
+      if (chunkSize == -1) chunkSize = requestData.length;
+
       var port = new ReceivePort();
       controller.stream.pipe(httpParser);
       var subscription = httpParser.listen((incoming) {
@@ -300,12 +300,8 @@
         port.close();
         Expect.isTrue(errorCalled);
       });
-      errorCalled = false;
-    }
 
-    void testWrite(List<int> requestData, [int chunkSize = -1]) {
-      if (chunkSize == -1) chunkSize = requestData.length;
-      reset();
+      errorCalled = false;
       for (int pos = 0;
            pos < requestData.length && !errorCalled;
            pos += chunkSize) {
diff --git a/tests/standalone/io/http_proxy_test.dart b/tests/standalone/io/http_proxy_test.dart
index 197b11a..abab0bb 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.dart
@@ -80,21 +80,65 @@
   HttpServer server;
   HttpClient client;
   int requestCount = 0;
+  String authScheme;
+  String realm = "test";
   String username;
   String password;
 
+  var ha1;
+  String serverAlgorithm = "MD5";
+  String serverQop = "auth";
+  Set ncs = new Set();
+
+  var nonce = "12345678";  // No need for random nonce in test.
+
   ProxyServer() : client = new HttpClient();
 
-  authenticationRequired(request) {
+  void useBasicAuthentication(String username, String password) {
+    this.username = username;
+    this.password = password;
+    authScheme = "Basic";
+  }
+
+  void useDigestAuthentication(String username, String password) {
+    this.username = username;
+    this.password = password;
+    authScheme = "Digest";
+
+    // Calculate ha1.
+    var hasher = new MD5();
+    hasher.add("${username}:${realm}:${password}".codeUnits);
+    ha1 = CryptoUtils.bytesToHex(hasher.close());
+  }
+
+  basicAuthenticationRequired(request) {
     request.fold(null, (x, y) {}).then((_) {
       var response = request.response;
       response.headers.set(HttpHeaders.PROXY_AUTHENTICATE,
-                           "Basic, realm=realm");
+                           "Basic, realm=$realm");
       response.statusCode = HttpStatus.PROXY_AUTHENTICATION_REQUIRED;
       response.close();
     });
   }
 
+  digestAuthenticationRequired(request, {stale: false}) {
+    request.fold(null, (x, y) {}).then((_) {
+      var response = request.response;
+      response.statusCode = HttpStatus.PROXY_AUTHENTICATION_REQUIRED;
+      StringBuffer authHeader = new StringBuffer();
+      authHeader.write('Digest');
+      authHeader.write(', realm="$realm"');
+      authHeader.write(', nonce="$nonce"');
+      if (stale) authHeader.write(', stale="true"');
+      if (serverAlgorithm != null) {
+        authHeader.write(', algorithm=$serverAlgorithm');
+      }
+      if (serverQop != null) authHeader.write(', qop="$serverQop"');
+      response.headers.set(HttpHeaders.PROXY_AUTHENTICATE, authHeader);
+      response.close();
+    });
+  }
+
   Future<ProxyServer> start() {
     var x = new Completer();
     HttpServer.bind("localhost", 0).then((s) {
@@ -104,20 +148,75 @@
         requestCount++;
         if (username != null && password != null) {
           if (request.headers[HttpHeaders.PROXY_AUTHORIZATION] == null) {
-            authenticationRequired(request);
+            if (authScheme == "Digest") {
+              digestAuthenticationRequired(request);
+            } else {
+              basicAuthenticationRequired(request);
+            }
             return;
           } else {
             Expect.equals(
                 1, request.headers[HttpHeaders.PROXY_AUTHORIZATION].length);
             String authorization =
               request.headers[HttpHeaders.PROXY_AUTHORIZATION][0];
-            List<String> tokens = authorization.split(" ");
-            Expect.equals("Basic", tokens[0]);
-            String auth =
-                CryptoUtils.bytesToBase64(encodeUtf8("$username:$password"));
-            if (auth != tokens[1]) {
-              authenticationRequired(request);
-              return;
+            if (authScheme == "Basic") {
+              List<String> tokens = authorization.split(" ");
+              Expect.equals("Basic", tokens[0]);
+              String auth =
+                  CryptoUtils.bytesToBase64(encodeUtf8("$username:$password"));
+              if (auth != tokens[1]) {
+                basicAuthenticationRequired(request);
+                return;
+              }
+            } else {
+              HeaderValue header =
+                  HeaderValue.parse(
+                      authorization, parameterSeparator: ",");
+              Expect.equals("Digest", header.value);
+              var uri = header.parameters["uri"];
+              var qop = header.parameters["qop"];
+              var cnonce = header.parameters["cnonce"];
+              var nc = header.parameters["nc"];
+              Expect.equals(username, header.parameters["username"]);
+              Expect.equals(realm, header.parameters["realm"]);
+              Expect.equals("MD5", header.parameters["algorithm"]);
+              Expect.equals(nonce, header.parameters["nonce"]);
+              Expect.equals(request.uri.toString(), uri);
+              if (qop != null) {
+                // A server qop of auth-int is downgraded to none by the client.
+                Expect.equals("auth", serverQop);
+                Expect.equals("auth", header.parameters["qop"]);
+                Expect.isNotNull(cnonce);
+                Expect.isNotNull(nc);
+                Expect.isFalse(ncs.contains(nc));
+                ncs.add(nc);
+              } else {
+                Expect.isNull(cnonce);
+                Expect.isNull(nc);
+              }
+              Expect.isNotNull(header.parameters["response"]);
+
+              var hasher = new MD5();
+              hasher.add("${request.method}:${uri}".codeUnits);
+              var ha2 = CryptoUtils.bytesToHex(hasher.close());
+
+              var x;
+              hasher = new MD5();
+              if (qop == null || qop == "" || qop == "none") {
+                hasher.add("$ha1:${nonce}:$ha2".codeUnits);
+              } else {
+                hasher.add(
+                    "$ha1:${nonce}:${nc}:${cnonce}:${qop}:$ha2".codeUnits);
+              }
+              Expect.equals(CryptoUtils.bytesToHex(hasher.close()),
+                            header.parameters["response"]);
+
+              // Add a bogus Proxy-Authentication-Info for testing.
+              var info = 'rspauth="77180d1ab3d6c9de084766977790f482", '
+                         'cnonce="8f971178", '
+                         'nc=000002c74, '
+                         'qop=auth';
+              request.response.headers.set("Proxy-Authentication-Info", info);
             }
           }
         }
@@ -412,10 +511,11 @@
 
 
 int testProxyAuthenticateCount = 0;
-void testProxyAuthenticate() {
+Future testProxyAuthenticate(bool useDigestAuthentication) {
+  testProxyAuthenticateCount = 0;
+  var completer = new Completer();
+
   setupProxyServer().then((proxyServer) {
-  proxyServer.username = "test";
-  proxyServer.password = "test";
   setupServer(1).then((server) {
   setupServer(1, secure: true).then((secureServer) {
     HttpClient client = new HttpClient();
@@ -423,6 +523,12 @@
     Completer step1 = new Completer();
     Completer step2 = new Completer();
 
+    if (useDigestAuthentication) {
+      proxyServer.useDigestAuthentication("dart", "password");
+    } else {
+      proxyServer.useBasicAuthentication("dart", "password");
+    }
+
     // Test with no authentication.
     client.findProxy = (Uri uri) {
       return "PROXY localhost:${proxyServer.port}";
@@ -459,15 +565,25 @@
     }
     step1.future.then((_) {
       testProxyAuthenticateCount = 0;
-      client.findProxy = (Uri uri) {
-        return "PROXY test:test@localhost:${proxyServer.port}";
-      };
+      if (useDigestAuthentication) {
+        client.findProxy = (Uri uri) => "PROXY localhost:${proxyServer.port}";
+        client.addProxyCredentials(
+            "localhost",
+            proxyServer.port,
+            "test",
+            new HttpClientDigestCredentials("dart", "password"));
+      } else {
+        client.findProxy = (Uri uri) {
+          return "PROXY dart:password@localhost:${proxyServer.port}";
+        };
+      }
 
       for (int i = 0; i < loopCount; i++) {
         test(bool secure) {
+          var path = useDigestAuthentication ? "A" : "$i";
           String url = secure
-              ? "https://localhost:${secureServer.port}/$i"
-              : "http://localhost:${server.port}/$i";
+              ? "https://localhost:${secureServer.port}/$path"
+              : "http://localhost:${server.port}/$path";
 
           client.postUrl(Uri.parse(url))
             .then((HttpClientRequest clientRequest) {
@@ -504,7 +620,7 @@
             "localhost",
             proxyServer.port,
             "realm",
-            new HttpClientBasicCredentials("test", "test"));
+            new HttpClientBasicCredentials("dart", "password"));
         return new Future.value(true);
       };
 
@@ -531,6 +647,7 @@
                   server.shutdown();
                   secureServer.shutdown();
                   client.close();
+                  completer.complete(null);
                 }
               });
             });
@@ -543,16 +660,19 @@
   });
   });
   });
+
+  return completer.future;
 }
 
 int testRealProxyDoneCount = 0;
 void testRealProxy() {
   setupServer(1).then((server) {
     HttpClient client = new HttpClient();
-     client.addProxyCredentials("localhost",
-                                8080,
-                                "test",
-                                new HttpClientBasicCredentials("test", "test"));
+     client.addProxyCredentials(
+         "localhost",
+         8080,
+         "test",
+         new HttpClientBasicCredentials("dart", "password"));
 
     List<String> proxy =
         ["PROXY localhost:8080",
@@ -593,10 +713,10 @@
     HttpClient client = new HttpClient();
 
     List<String> proxy =
-        ["PROXY test:test@localhost:8080",
-         "PROXY test:test@localhost:8080; PROXY hede.hule.hest:8080",
-         "PROXY hede.hule.hest:8080; PROXY test:test@localhost:8080",
-         "PROXY test:test@localhost:8080; DIRECT"];
+        ["PROXY dart:password@localhost:8080",
+         "PROXY dart:password@localhost:8080; PROXY hede.hule.hest:8080",
+         "PROXY hede.hule.hest:8080; PROXY dart:password@localhost:8080",
+         "PROXY dart:password@localhost:8080; DIRECT"];
 
     client.findProxy = (Uri uri) {
       // Pick the proxy configuration based on the request path.
@@ -639,7 +759,10 @@
   testProxy();
   testProxyChain();
   testProxyFromEnviroment();
-  testProxyAuthenticate();
+  // The two invocations of uses the same global variable for state -
+  // run one after the other.
+  testProxyAuthenticate(false)
+      .then((_) => testProxyAuthenticate(true));
   // This test is not normally run. It can be used for locally testing
   // with a real proxy server (e.g. Apache).
   //testRealProxy();
diff --git a/tests/standalone/io/http_server_early_client_close2_test.dart b/tests/standalone/io/http_server_early_client_close2_test.dart
new file mode 100644
index 0000000..bc8b6f6
--- /dev/null
+++ b/tests/standalone/io/http_server_early_client_close2_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+main() {
+  HttpServer.bind("127.0.0.1", 0).then((server) {
+    server.listen(
+      (request) {
+        String name = new Options().script;
+        new File(name).openRead().pipe(request.response)
+            .catchError((e) { /* ignore */ });
+      });
+
+    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";
+        socket.write(data);
+        socket.close();
+        socket.done.then((_) {
+          socket.destroy();
+          if (++count < 10) {
+            makeRequest();
+          } else {
+            server.close();
+          }
+        });
+      });
+    }
+    makeRequest();
+  });
+}
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 c4ec244..d35aaf4 100644
--- a/tests/standalone/io/http_server_early_client_close_test.dart
+++ b/tests/standalone/io/http_server_early_client_close_test.dart
@@ -125,7 +125,7 @@
           if (++count < 10) {
             makeRequest();
           } else {
-            server.close();
+            runAsync(server.close);
           }
         });
       });
diff --git a/tests/standalone/io/mime_multipart_parser_test.dart b/tests/standalone/io/mime_multipart_parser_test.dart
index 1045b5a..5a81df7 100644
--- a/tests/standalone/io/mime_multipart_parser_test.dart
+++ b/tests/standalone/io/mime_multipart_parser_test.dart
@@ -279,12 +279,8 @@
 --\r\r\r
 -\r""";
   testParse(message, "boundary", [headers, headers], [body1, body2]);
-}
 
-void testParseInvalid() {
-  String message;
-
-  // Missing initial CRLF. One body part less.
+  // Without initial CRLF.
   message = """
 --xxx\r
 \r
@@ -295,7 +291,11 @@
 \r
 Body2\r
 --xxx--\r\n""";
-  testParse(message, "xxx", null, ["\r\nBody2"]);
+  testParse(message, "xxx", null, ["\r\nBody 1", "\r\nBody2"]);
+}
+
+void testParseInvalid() {
+  String message;
 
   // Missing end boundary.
   message = """
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 98e86d9..78a9864 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -17,6 +17,8 @@
 [ $runtime == vm ]
 package/package_isolate_test: Fail # http://dartbug.com/7520.
 io/raw_server_socket_cancel_test: Pass, Fail, Timeout # Issue 8675
+io/http_server_early_client_close_test: Pass, Fail # http://dartbug.com/10408
+io/http_server_early_client_close2_test: Pass, Fail # http://dartbug.com/10408
 
 [ $runtime == vm && $checked ]
 # These tests have type errors on purpose.
@@ -36,6 +38,8 @@
 # of allowed open files ('ulimit -n' says something like 256).
 io/socket_many_connections_test: Skip
 
+debugger/basic_debugger_test: Pass, Crash # Issue 10488
+
 # These tests pass on MacOS 10.8.2 but fails on the buildbot machines
 # that are running an earlier version of MacOS. The issue is that the
 # old version of MacOS does not expand the precomposed utf-8 it gets
@@ -74,6 +78,17 @@
 
 io/process_exit_negative_test: Fail  # This is a compilation-time negative test.
 
+[ $compiler == dartanalyzer ]
+crypto/base64_test: fail
+io/file_constructor_test: fail
+io/http_date_test: fail
+io/http_headers_test: fail
+io/http_parser_test: fail
+io/process_exit_negative_test: fail
+io/url_encoding_test: fail
+io/web_socket_protocol_processor_test: fail
+
+
 [ $compiler == dart2js ]
 number_identity_test: Skip # Bigints and int/double diff. not supported.
 typed_data_test: Skip # dart:typed_data support needed.
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart
index 470d79a..3ed3e17 100644
--- a/tests/utils/dummy_compiler_test.dart
+++ b/tests/utils/dummy_compiler_test.dart
@@ -11,7 +11,6 @@
 import '../../sdk/lib/_internal/compiler/compiler.dart';
 
 Future<String> provider(Uri uri) {
-  Completer<String> completer = new Completer<String>();
   String source;
   if (uri.scheme == "main") {
     source = "main() {}";
@@ -80,8 +79,7 @@
   } else {
    throw "unexpected URI $uri";
   }
-  completer.complete(source);
-  return completer.future;
+  return new Future.value(source);
 }
 
 void handler(Uri uri, int begin, int end, String message, Diagnostic kind) {
diff --git a/tests/utils/recursive_import_test.dart b/tests/utils/recursive_import_test.dart
index 15a09be..d411707 100644
--- a/tests/utils/recursive_import_test.dart
+++ b/tests/utils/recursive_import_test.dart
@@ -61,7 +61,6 @@
 main() {
   int count = 0;
   Future<String> provider(Uri uri) {
-    Completer<String> completer = new Completer<String>();
     String source;
     if (uri.path.length > 100) {
       // Simulate an OS error.
@@ -84,8 +83,7 @@
     } else {
      throw "unexpected URI $uri";
     }
-    completer.complete(source);
-    return completer.future;
+    return new Future.value(source);
   }
 
   int warningCount = 0;
diff --git a/tools/VERSION b/tools/VERSION
index 3671ff7..49be911 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 5
-BUILD 5
+BUILD 6
 PATCH 0
diff --git a/tools/dom/scripts/dartmetadata.py b/tools/dom/scripts/dartmetadata.py
index ddb441c..3a10a55 100644
--- a/tools/dom/scripts/dartmetadata.py
+++ b/tools/dom/scripts/dartmetadata.py
@@ -14,7 +14,7 @@
 import os
 import re
 from generator import ConstantOutputOrder
-from htmlrenamer import renamed_html_members
+from htmlrenamer import renamed_html_members, html_interface_renames
 
 _logger = logging.getLogger('DartMetadata')
 
@@ -445,6 +445,10 @@
     if key in _annotations:
       annotations.extend(_annotations[key])
 
+    if (not member_name and interface_name.startswith('WebKit') and
+        interface_name not in html_interface_renames):
+      annotations.extend(_webkit_experimental_annotations)
+
     if (member_name and member_name.startswith('webkit') and
         key not in renamed_html_members):
       annotations.extend(_webkit_experimental_annotations)
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 8ab7081..9073f98 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -28,12 +28,8 @@
     'Database': 'SqlDatabase', # Avoid conflict with Index DB's Database.
     'DatabaseSync': 'SqlDatabaseSync',
     'DOMApplicationCache': 'ApplicationCache',
-    'DOMCoreException': 'DomException',
     'DOMFileSystem': 'FileSystem',
-    'DOMFormData': 'FormData',
     'DOMPoint': '_DomPoint',
-    'DOMURL': 'Url',
-    'DOMWindow': 'Window',
     'EntryCallback': '_EntryCallback',
     'EntriesCallback': '_EntriesCallback',
     'ErrorCallback': '_ErrorCallback',
@@ -59,9 +55,6 @@
     'SVGGradientElement': '_GradientElement',
     'SVGSVGElement': 'SvgSvgElement', # Manual to avoid name conflicts.
     'WebGLVertexArrayObjectOES': 'VertexArrayObject',
-    'WebKitCSSKeyframeRule': 'CssKeyframeRule',
-    'WebKitCSSKeyframesRule': 'CssKeyframesRule',
-    'WebKitCSSTransformValue': 'CssTransformValue',
     'XMLHttpRequest': 'HttpRequest',
     'XMLHttpRequestException': 'HttpRequestException',
     'XMLHttpRequestProgressEvent': 'HttpRequestProgressEvent',
@@ -649,7 +642,7 @@
       if any(interface.id in ['Element', 'Document']
              for interface in self._database.Hierarchy(interface)):
         return interface.id[len('HTML'):]
-    return self.DartifyTypeName(interface.id)
+    return self.DartifyTypeName(interface.javascript_binding_name)
 
 
   def RenameMember(self, interface_name, member_node, member, member_prefix='',
@@ -747,6 +740,7 @@
     name = re.sub(r'^SVG', '', type_name)
     name = re.sub(r'^IDB', '', name)
     name = re.sub(r'^WebGL', '', name)
+    name = re.sub(r'^WebKit', '', name)
 
     return self._CamelCaseName(name)
 
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 75a4ffe..5473635 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -55,6 +55,7 @@
     'HTMLTableElement.createTBody',
     'IDBDatabase.transaction',
     'KeyboardEvent.initKeyboardEvent',
+    'Location.origin',
     'MouseEvent.offsetX',
     'MouseEvent.offsetY',
     'Navigator.language',
diff --git a/tools/dom/src/CssClassSet.dart b/tools/dom/src/CssClassSet.dart
index acae69c..4ee943d 100644
--- a/tools/dom/src/CssClassSet.dart
+++ b/tools/dom/src/CssClassSet.dart
@@ -4,78 +4,28 @@
 
 part of html;
 
+/** A Set that stores the CSS class names for an element. */
 abstract class CssClassSet implements Set<String> {
 
-  String toString() {
-    return readClasses().join(' ');
-  }
-
   /**
    * Adds the class [value] to the element if it is not on it, removes it if it
    * is.
    */
-  bool toggle(String value) {
-    Set<String> s = readClasses();
-    bool result = false;
-    if (s.contains(value)) {
-      s.remove(value);
-    } else {
-      s.add(value);
-      result = true;
-    }
-    writeClasses(s);
-    return result;
-  }
+  bool toggle(String value);
 
   /**
    * Returns [:true:] if classes cannot be added or removed from this
    * [:CssClassSet:].
    */
-  bool get frozen => false;
+  bool get frozen;
 
-  // interface Iterable - BEGIN
-  Iterator<String> get iterator => readClasses().iterator;
-  // interface Iterable - END
-
-  // interface Collection - BEGIN
-  void forEach(void f(String element)) {
-    readClasses().forEach(f);
-  }
-
-  String join([String separator = ""]) => readClasses().join(separator);
-
-  Iterable map(f(String element)) => readClasses().map(f);
-
-  Iterable<String> where(bool f(String element)) => readClasses().where(f);
-
-  Iterable expand(Iterable f(String element)) => readClasses().expand(f);
-
-  bool every(bool f(String element)) => readClasses().every(f);
-
-  bool any(bool f(String element)) => readClasses().any(f);
-
-  bool get isEmpty => readClasses().isEmpty;
-
-  int get length => readClasses().length;
-
-  String reduce(String combine(String value, String element)) {
-    return readClasses().reduce(combine);
-  }
-
-  dynamic fold(dynamic initialValue,
-      dynamic combine(dynamic previousValue, String element)) {
-    return readClasses().fold(initialValue, combine);
-  }
-  // interface Collection - END
-
-  // interface Set - BEGIN
   /**
    * Determine if this element contains the class [value].
    *
    * This is the Dart equivalent of jQuery's
    * [hasClass](http://api.jquery.com/hasClass/).
    */
-  bool contains(String value) => readClasses().contains(value);
+  bool contains(String value);
 
   /**
    * Add the class [value] to element.
@@ -83,11 +33,7 @@
    * This is the Dart equivalent of jQuery's
    * [addClass](http://api.jquery.com/addClass/).
    */
-  void add(String value) {
-    // TODO - figure out if we need to do any validation here
-    // or if the browser natively does enough.
-    _modify((s) => s.add(value));
-  }
+  void add(String value);
 
   /**
    * Remove the class [value] from element, and return true on successful
@@ -96,13 +42,7 @@
    * This is the Dart equivalent of jQuery's
    * [removeClass](http://api.jquery.com/removeClass/).
    */
-  bool remove(Object value) {
-    if (value is! String) return false;
-    Set<String> s = readClasses();
-    bool result = s.remove(value);
-    writeClasses(s);
-    return result;
-  }
+  bool remove(Object value);
 
   /**
    * Add all classes specified in [iterable] to element.
@@ -110,10 +50,7 @@
    * This is the Dart equivalent of jQuery's
    * [addClass](http://api.jquery.com/addClass/).
    */
-  void addAll(Iterable<String> iterable) {
-    // TODO - see comment above about validation.
-    _modify((s) => s.addAll(iterable));
-  }
+  void addAll(Iterable<String> iterable);
 
   /**
    * Remove all classes specified in [iterable] from element.
@@ -121,9 +58,7 @@
    * This is the Dart equivalent of jQuery's
    * [removeClass](http://api.jquery.com/removeClass/).
    */
-  void removeAll(Iterable<String> iterable) {
-    _modify((s) => s.removeAll(iterable));
-  }
+  void removeAll(Iterable<String> iterable);
 
   /**
    * Toggles all classes specified in [iterable] on element.
@@ -132,59 +67,35 @@
    * remove it if it is. This is the Dart equivalent of jQuery's
    * [toggleClass](http://api.jquery.com/toggleClass/).
    */
-  void toggleAll(Iterable<String> iterable) {
-    iterable.forEach(toggle);
+  void toggleAll(Iterable<String> iterable);
+}
+
+/**
+ * A set (union) of the CSS classes that are present in a set of elements.
+ * Implemented separately from _ElementCssClassSet for performance.
+ */
+class _MultiElementCssClassSet extends CssClassSetImpl {
+  final Iterable<Element> _elementIterable;
+  Iterable<_ElementCssClassSet> _elementCssClassSetIterable;
+
+  _MultiElementCssClassSet(this._elementIterable) {
+    _elementCssClassSetIterable = new List.from(_elementIterable).map(
+        (e) => new _ElementCssClassSet(e));
   }
 
-  void retainAll(Iterable<String> iterable) {
-    _modify((s) => s.retainAll(iterable));
+  Set<String> readClasses() {
+    var s = new LinkedHashSet<String>();
+    _elementCssClassSetIterable.forEach((e) => s.addAll(e.readClasses()));
+    return s;
   }
 
-  void removeWhere(bool test(String name)) {
-    _modify((s) => s.removeWhere(test));
+  void writeClasses(Set<String> s) {
+    var classes = new List.from(s).join(' ');
+    for (Element e in _elementIterable) {
+      e.$dom_className = classes;
+    }
   }
 
-  void retainWhere(bool test(String name)) {
-    _modify((s) => s.retainWhere(test));
-  }
-
-  bool containsAll(Iterable<String> collection) =>
-    readClasses().containsAll(collection);
-
-  Set<String> intersection(Set<String> other) =>
-    readClasses().intersection(other);
-
-  Set<String> union(Set<String> other) =>
-    readClasses().union(other);
-
-  Set<String> difference(Set<String> other) =>
-    readClasses().difference(other);
-
-  String get first => readClasses().first;
-  String get last => readClasses().last;
-  String get single => readClasses().single;
-  List<String> toList({ bool growable: true }) =>
-      readClasses().toList(growable: growable);
-  Set<String> toSet() => readClasses().toSet();
-  Iterable<String> take(int n) => readClasses().take(n);
-  Iterable<String> takeWhile(bool test(String value)) =>
-      readClasses().takeWhile(test);
-  Iterable<String> skip(int n) => readClasses().skip(n);
-  Iterable<String> skipWhile(bool test(String value)) =>
-      readClasses().skipWhile(test);
-  String firstWhere(bool test(String value), { String orElse() }) =>
-      readClasses().firstWhere(test, orElse: orElse);
-  String lastWhere(bool test(String value), {String orElse()}) =>
-      readClasses().lastWhere(test, orElse: orElse);
-  String singleWhere(bool test(String value)) =>
-      readClasses().singleWhere(test);
-  String elementAt(int index) => readClasses().elementAt(index);
-
-  void clear() {
-    _modify((s) => s.clear());
-  }
-  // interface Set - END
-
   /**
    * Helper method used to modify the set of css classes on this element.
    *
@@ -194,23 +105,51 @@
    *   After f returns, the modified set is written to the
    *       className property of this element.
    */
-  void _modify( f(Set<String> s)) {
-    Set<String> s = readClasses();
-    f(s);
-    writeClasses(s);
+  void modify( f(Set<String> s)) {
+    _elementCssClassSetIterable.forEach((e) => e.modify(f));
   }
 
   /**
-   * Read the class names from the Element class property,
-   * and put them into a set (duplicates are discarded).
-   * This is intended to be overridden by specific implementations.
+   * Adds the class [value] to the element if it is not on it, removes it if it
+   * is.
    */
-  Set<String> readClasses();
+  bool toggle(String value) =>
+      _modifyWithReturnValue((e) => e.toggle(value));
 
   /**
-   * Join all the elements of a set into one string and write
-   * back to the element.
-   * This is intended to be overridden by specific implementations.
+   * Remove the class [value] from element, and return true on successful
+   * removal.
+   *
+   * This is the Dart equivalent of jQuery's
+   * [removeClass](http://api.jquery.com/removeClass/).
    */
-  void writeClasses(Set<String> s);
+  bool remove(Object value) => _modifyWithReturnValue((e) => e.remove(value));
+
+  bool _modifyWithReturnValue(f) => _elementCssClassSetIterable.fold(
+      false, (prevValue, element) => f(element) || prevValue);
+}
+
+class _ElementCssClassSet extends CssClassSetImpl {
+
+  final Element _element;
+
+  _ElementCssClassSet(this._element);
+
+  Set<String> readClasses() {
+    var s = new LinkedHashSet<String>();
+    var classname = _element.$dom_className;
+
+    for (String name in classname.split(' ')) {
+      String trimmed = name.trim();
+      if (!trimmed.isEmpty) {
+        s.add(trimmed);
+      }
+    }
+    return s;
+  }
+
+  void writeClasses(Set<String> s) {
+    List list = new List.from(s);
+    _element.$dom_className = s.join(' ');
+  }
 }
diff --git a/tools/dom/src/dart2js_LocationWrapper.dart b/tools/dom/src/dart2js_LocationWrapper.dart
index f430534..c943226 100644
--- a/tools/dom/src/dart2js_LocationWrapper.dart
+++ b/tools/dom/src/dart2js_LocationWrapper.dart
@@ -44,7 +44,12 @@
   }
 
   // final String origin;
-  String get origin => _get(_ptr, 'origin');
+  String get origin {
+    if (JS('bool', '("origin" in #)', _ptr)) {
+      return JS('String', '#.origin', _ptr);
+    }
+    return '${this.protocol}//${this.host}';
+  }
 
   // String pathname;
   String get pathname => _get(_ptr, 'pathname');
diff --git a/tools/dom/templates/html/impl/impl_Document.darttemplate b/tools/dom/templates/html/impl/impl_Document.darttemplate
index 73b40fa..dd42121 100644
--- a/tools/dom/templates/html/impl/impl_Document.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Document.darttemplate
@@ -32,7 +32,7 @@
    * For details about CSS selector syntax, see the
    * [CSS selector specification](http://www.w3.org/TR/css3-selectors/).
    */
-  List<Element> queryAll(String selectors) {
+  ElementList queryAll(String selectors) {
     return new _FrozenElementList._wrap($dom_querySelectorAll(selectors));
   }
 }
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 3b3ca0b..08a6b08 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -137,11 +137,32 @@
   }
 }
 
+/** 
+ * An immutable list containing HTML elements. This list contains some
+ * additional methods for ease of CSS manipulation on a group of elements.
+ */
+abstract class ElementList<T extends Element> extends ListBase<T> {
+  /**
+   * The union of all CSS classes applied to the elements in this list.
+   *
+   * This set makes it easy to add, remove or toggle (add if not present, remove
+   * if present) the classes applied to a collection of elements.
+   *
+   *     htmlList.classes.add('selected');
+   *     htmlList.classes.toggle('isOnline');
+   *     htmlList.classes.remove('selected');
+   */
+  CssClassSet get classes;
+
+  /** Replace the classes with `value` for every element in this list. */
+  set classes(Iterable<String> value);
+}
+
 // TODO(jacobr): this is an inefficient implementation but it is hard to see
 // a better option given that we cannot quite force NodeList to be an
 // ElementList as there are valid cases where a NodeList JavaScript object
 // contains Node objects that are not Elements.
-class _FrozenElementList<T extends Element> extends ListBase<T> {
+class _FrozenElementList<T extends Element> extends ListBase<T> implements ElementList {
   final List<Node> _nodeList;
 
   _FrozenElementList._wrap(this._nodeList);
@@ -167,30 +188,12 @@
   Element get last => _nodeList.last;
 
   Element get single => _nodeList.single;
-}
 
-class _ElementCssClassSet extends CssClassSet {
+  CssClassSet get classes => new _MultiElementCssClassSet(
+      _nodeList.where((e) => e is Element));
 
-  final Element _element;
-
-  _ElementCssClassSet(this._element);
-
-  Set<String> readClasses() {
-    var s = new LinkedHashSet<String>();
-    var classname = _element.$dom_className;
-
-    for (String name in classname.split(' ')) {
-      String trimmed = name.trim();
-      if (!trimmed.isEmpty) {
-        s.add(trimmed);
-      }
-    }
-    return s;
-  }
-
-  void writeClasses(Set<String> s) {
-    List list = new List.from(s);
-    _element.$dom_className = s.join(' ');
+  void set classes(Iterable<String> value) {
+    _nodeList.where((e) => e is Element).forEach((e) => e.classes = value);
   }
 }
 
@@ -289,7 +292,7 @@
    *
    *     var items = element.query('.itemClassName');
    */
-  List<Element> queryAll(String selectors) =>
+  ElementList queryAll(String selectors) =>
     new _FrozenElementList._wrap($dom_querySelectorAll(selectors));
 
   /**
diff --git a/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate b/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate
index b64989c..842b6f4 100644
--- a/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate
+++ b/tools/dom/templates/html/impl/impl_IDBFactory.darttemplate
@@ -96,7 +96,7 @@
  * and errors out when the request errors.
  */
 Future _completeRequest(Request request) {
-  var completer = new Completer();
+  var completer = new Completer.sync();
   // TODO: make sure that completer.complete is synchronous as transactions
   // may be committed if the result is not processed immediately.
   request.onSuccess.listen((e) {
diff --git a/tools/dom/templates/html/impl/impl_Location.darttemplate b/tools/dom/templates/html/impl/impl_Location.darttemplate
new file mode 100644
index 0000000..3d69c79
--- /dev/null
+++ b/tools/dom/templates/html/impl/impl_Location.darttemplate
@@ -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.
+
+part of $LIBRARYNAME;
+
+@DocsEditable
+$(ANNOTATIONS)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+$!MEMBERS
+
+$if DART2JS
+  @DomName('Location.origin')
+  String get origin {
+    if (JS('bool', '("origin" in #)', this)) {
+      return JS('String', '#.origin', this);
+    }
+    return '${this.protocol}//${this.host}';
+  }
+$endif
+}
diff --git a/tools/dom/templates/html/impl/impl_Range.darttemplate b/tools/dom/templates/html/impl/impl_Range.darttemplate
index 13ab552..1aebb9e 100644
--- a/tools/dom/templates/html/impl/impl_Range.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Range.darttemplate
@@ -10,4 +10,18 @@
   factory $CLASSNAME() => document.$dom_createRange();
 
 $!MEMBERS
+
+  /**
+   * Checks if createContextualFragment is supported.
+   *
+   * See also:
+   *
+   * * [createContextualFragment]
+   */
+$if DART2JS
+  static bool get supportsCreateContextualFragment =>
+      JS('bool', '("createContextualFragment" in window.Range.prototype)');
+$else
+  static bool get supportsCreateContextualFragment => true;
+$endif
 }
diff --git a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
index 9ab3886..8ac5997 100644
--- a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
@@ -4,7 +4,7 @@
 
 part of $LIBRARYNAME;
 
-class _AttributeClassSet extends CssClassSet {
+class _AttributeClassSet extends CssClassSetImpl {
   final Element _element;
 
   _AttributeClassSet(this._element);
diff --git a/tools/gyp/configurations_msvs.gypi b/tools/gyp/configurations_msvs.gypi
index 4a21b2f..f2d067c 100644
--- a/tools/gyp/configurations_msvs.gypi
+++ b/tools/gyp/configurations_msvs.gypi
@@ -23,6 +23,10 @@
             'LinkIncremental': '2',
             'GenerateDebugInformation': 'true',
             'StackReserveSize': '2097152',
+            'AdditionalDependencies': [
+              'advapi32.lib',
+              'shell32.lib',
+            ],
           },
         },
       },
@@ -46,6 +50,10 @@
             'OptimizeReferences': '2',
             'EnableCOMDATFolding': '2',
             'StackReserveSize': '2097152',
+            'AdditionalDependencies': [
+              'advapi32.lib',
+              'shell32.lib',
+            ],
           },
         },
       },