Version 1.12.0-dev.5.3

Cherry-pick f3f52d4b59081e2f294126ac7f69f902968692d7 to dev
Cherry-pick b30a7a1750cd13c92781480f8708974b84385cad to dev
Cherry-pick 73cfbce0bca51c92e589fc7d85869478f044dc11 to dev
Cherry-pick b6ffeafbee0eb22de30c88d2cb1b9bcf3bfe9723 to dev
Cherry-pick a8e2180b781ad82d81206696da220a920310b5db to dev
Cherry-pick fc55f38aaf053a62d1959b09644ecff49fc35d43 to dev
Cherry-pick 56c91201c32b8213d37849e22dbabf392eef1bd6 to dev
Cherry-pick c06e66c9b92cc6a5faf6179c43fdb3a0bec6e34c to dev
Cherry-pick 532474ab358eea3b85312465f4fa60626a0b820b to dev
Cherry-pick cc981c8246e28e21fe84b8ec00b7a2eac9719102 to dev
Cherry-pick 480cd7fdc82dc861745acda57ebd9341aaf1bd80 to dev
diff --git a/DEPS b/DEPS
index 56677bd..3b2587b 100644
--- a/DEPS
+++ b/DEPS
@@ -38,7 +38,7 @@
 
   # Revisions of /third_party/* dependencies.
   "7zip_rev" : "@19997",
-  "analyzer_cli_rev" : "@c4e628a8467f75ded563f029dfb2f1738856f471",
+  "analyzer_cli_rev" : "@4281dbf08ccc20b20b795b438766b57afb16ad13",
   "args_tag": "@0.13.0",
   "async_tag": "@1.2.0",
   "barback_tag" : "@0.15.2+6",
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 3c8f1a7..d1ec86e 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -1438,7 +1438,7 @@
         String libraryFile = librarySource.fullName;
         // may be "package:" URI
         {
-          String libraryPackageUri = findAbsoluteUri(context, libraryFile);
+          String libraryPackageUri = findNonFileUri(context, libraryFile);
           if (libraryPackageUri != null) {
             _addFix_importLibrary(
                 DartFixKind.IMPORT_LIBRARY_PROJECT, libraryPackageUri);
@@ -1630,7 +1630,7 @@
         if (substringAfterLast(libFile, '/') == uriName) {
           String fixedUri;
           // may be "package:" URI
-          String libPackageUri = findAbsoluteUri(context, libFile);
+          String libPackageUri = findNonFileUri(context, libFile);
           if (libPackageUri != null) {
             fixedUri = libPackageUri;
           } else {
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index c4082fa..1af70b0 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -104,10 +104,11 @@
  *
  * Returns the absolute (non-file) URI or `null`.
  */
-String findAbsoluteUri(AnalysisContext context, String path) {
-  Source fileSource = new NonExistingSource(path, null, UriKind.FILE_URI);
+String findNonFileUri(AnalysisContext context, String path) {
+  Source fileSource =
+      new NonExistingSource(path, toUri(path), UriKind.FILE_URI);
   Uri uri = context.sourceFactory.restoreUri(fileSource);
-  if (uri == null) {
+  if (uri == null || uri.scheme == 'file') {
     return null;
   }
   return uri.toString();
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index f0692c6..13d3d99 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -4405,7 +4405,7 @@
       'my_pkg': [myPkgFolder]
     });
     context.sourceFactory = new SourceFactory(
-        [AbstractContextTest.SDK_RESOLVER, resourceResolver, pkgResolver]);
+        [AbstractContextTest.SDK_RESOLVER, pkgResolver, resourceResolver]);
     // force 'my_pkg' resolution
     addSource('/tmp/other.dart', "import 'package:my_pkg/my_lib.dart';");
   }
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart
index 11db8fe..21a5ab0 100644
--- a/runtime/lib/string_patch.dart
+++ b/runtime/lib/string_patch.dart
@@ -896,14 +896,16 @@
     List<String> result = new List<String>();
     int startIndex = 0;
     int previousIndex = 0;
+    // 'pattern' may not be implemented correctly and therefore we cannot
+    // call _substringUnhchecked unless it is a trustworthy type (e.g. String).
     while (true) {
       if (startIndex == length || !iterator.moveNext()) {
-        result.add(this._substringUnchecked(previousIndex, length));
+        result.add(this.substring(previousIndex, length));
         break;
       }
       Match match = iterator.current;
       if (match.start == length) {
-        result.add(this._substringUnchecked(previousIndex, length));
+        result.add(this.substring(previousIndex, length));
         break;
       }
       int endIndex = match.end;
@@ -911,7 +913,7 @@
         ++startIndex;  // empty match, advance and restart
         continue;
       }
-      result.add(this._substringUnchecked(previousIndex, match.start));
+      result.add(this.substring(previousIndex, match.start));
       startIndex = previousIndex = endIndex;
     }
     return result;
diff --git a/runtime/observatory/lib/src/elements/class_view.html b/runtime/observatory/lib/src/elements/class_view.html
index 200c22a..a8f8165 100644
--- a/runtime/observatory/lib/src/elements/class_view.html
+++ b/runtime/observatory/lib/src/elements/class_view.html
@@ -240,9 +240,8 @@
       </div>
     </div>
 
-    <hr>
-
     <div class="content-centered-big">
+      <hr>
       <source-inset location="{{ cls.location }}">
       </source-inset>
     </div>
diff --git a/runtime/observatory/lib/src/elements/eval_box.dart b/runtime/observatory/lib/src/elements/eval_box.dart
index 7447aca..c6fd2c5 100644
--- a/runtime/observatory/lib/src/elements/eval_box.dart
+++ b/runtime/observatory/lib/src/elements/eval_box.dart
@@ -24,7 +24,7 @@
 
   void updateLineMode(Event e, var detail, Node target) {
     lineMode = (e.target as InputElement).value;
-    if (lineMode == '1-line') {
+    if (lineMode == '1-line' && text != null) {
       text = text.replaceAll('\n', ' ');
     }
   }
diff --git a/runtime/observatory/lib/src/elements/eval_box.html b/runtime/observatory/lib/src/elements/eval_box.html
index ad9045a..f01a995 100644
--- a/runtime/observatory/lib/src/elements/eval_box.html
+++ b/runtime/observatory/lib/src/elements/eval_box.html
@@ -11,10 +11,13 @@
         font: 400 16px 'Montserrat', sans-serif;
       }
       .bigtextbox {
+        flex-grow: 1;
         font: 400 16px 'Montserrat', sans-serif;
       }
       .button {
         font: 400 16px 'Montserrat', sans-serif;
+        margin-left: 0.5em;
+        margin-right: 0.5em;
       }
       .radios {
         display: inline;
@@ -64,7 +67,7 @@
         <input class="textbox" type="text" value="{{ text }}">
       </template>
       <template if="{{ lineMode == 'N-line' }}">
-        <textarea class="bigtextbox" rows="5" cols="80"
+        <textarea class="bigtextbox"
                   value="{{ text }}"></textarea>
       </template>
 
diff --git a/runtime/observatory/lib/src/elements/field_view.html b/runtime/observatory/lib/src/elements/field_view.html
index 3e16d1b..d32cab0 100644
--- a/runtime/observatory/lib/src/elements/field_view.html
+++ b/runtime/observatory/lib/src/elements/field_view.html
@@ -24,6 +24,7 @@
 
     <div class="content">
       <h1>
+        field
         <template if="{{ field.isStatic }}">static</template>
         <template if="{{ field.isFinal }}">final</template>
         <template if="{{ field.isConst }}">const</template>
@@ -83,6 +84,15 @@
         </template>
       </div>
     </div>
+
+    <div class="content-centered-big">
+      <hr>
+      <script-inset script="{{ field.location.script }}"
+                    startPos="{{ field.location.tokenPos }}"
+                    endPos="{{ field.location.tokenPos }}">
+      </script-inset>
+    </div>
+
     <view-footer></view-footer>
   </template>
 </polymer-element>
diff --git a/runtime/observatory/lib/src/elements/isolate_view.dart b/runtime/observatory/lib/src/elements/isolate_view.dart
index fc6116b..de8487c 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.dart
+++ b/runtime/observatory/lib/src/elements/isolate_view.dart
@@ -79,6 +79,7 @@
 @CustomTag('isolate-view')
 class IsolateViewElement extends ObservatoryElement {
   @published Isolate isolate;
+  @published Library rootLibrary;
   Timer _updateTimer;
   TagProfileChart tagProfileChart = new TagProfileChart();
   IsolateViewElement.created() : super.created();
@@ -106,6 +107,7 @@
     if (isolate.topFrame != null) {
       isolate.topFrame.function.load();
     }
+    isolate.rootLibrary.load().then((lib) => rootLibrary = lib);
   }
 
   @override
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index 014c191..46b49ee 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -140,6 +140,13 @@
     <div class="content">
       <eval-box callback="{{ evaluate }}"></eval-box>
     </div>
+
+    <div class="content-centered-big">
+      <hr>
+      <script-inset script="{{ rootLibrary.rootScript }}">
+      </script-inset>
+    </div>
+
     <view-footer></view-footer>
   </template>
 </polymer-element>
diff --git a/runtime/observatory/lib/src/elements/library_view.html b/runtime/observatory/lib/src/elements/library_view.html
index a898ebb..408916d 100644
--- a/runtime/observatory/lib/src/elements/library_view.html
+++ b/runtime/observatory/lib/src/elements/library_view.html
@@ -149,6 +149,12 @@
       </template>
     </div>
 
+    <div class="content-centered-big">
+      <hr>
+      <script-inset script="{{ library.rootScript }}">
+      </script-inset>
+    </div>
+
     <view-footer></view-footer>
  </template>
 </polymer-element>
diff --git a/runtime/observatory/lib/src/elements/ports.html b/runtime/observatory/lib/src/elements/ports.html
index 70aac0b..d5b3152 100644
--- a/runtime/observatory/lib/src/elements/ports.html
+++ b/runtime/observatory/lib/src/elements/ports.html
@@ -24,7 +24,7 @@
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
     </nav-bar>
     <div class="content">
-      <h1>Ports</h1>
+      <h1>Ports ({{ports.length}})</h1>
       <hr>
       <div class="memberList">
         <template repeat="{{ port in ports }}">
diff --git a/runtime/observatory/lib/src/elements/script_inset.dart b/runtime/observatory/lib/src/elements/script_inset.dart
index 66b125c..3aeaf67 100644
--- a/runtime/observatory/lib/src/elements/script_inset.dart
+++ b/runtime/observatory/lib/src/elements/script_inset.dart
@@ -11,6 +11,7 @@
 import 'package:observatory/service.dart';
 import 'package:observatory/utils.dart';
 import 'package:polymer/polymer.dart';
+import 'package:logging/logging.dart';
 
 const nbsp = "\u00A0";
 
@@ -98,6 +99,52 @@
   }
 }
 
+class LibraryAnnotation extends Annotation {
+  Library target;
+  LibraryAnnotation(this.target);
+
+  void applyStyleTo(element) {
+    if (element == null) {
+      return;  // TODO(rmacnak): Handling overlapping annotations.
+    }
+    element.style.fontWeight = "bold";
+    element.title = "library ${target.uri}";
+
+    addInfoBox(element, () {
+      var details = table();
+      var r = row();
+      r.append(cell("Library"));
+      r.append(cell(serviceRef(target)));
+      details.append(r);
+
+      return details;
+    });
+  }
+}
+
+class PartAnnotation extends Annotation {
+  Script part;
+  PartAnnotation(this.part);
+
+  void applyStyleTo(element) {
+    if (element == null) {
+      return;  // TODO(rmacnak): Handling overlapping annotations.
+    }
+    element.style.fontWeight = "bold";
+    element.title = "script ${part.uri}";
+
+    addInfoBox(element, () {
+      var details = table();
+      var r = row();
+      r.append(cell("Script"));
+      r.append(cell(serviceRef(part)));
+      details.append(r);
+
+      return details;
+    });
+  }
+}
+
 class LocalVariableAnnotation extends Annotation {
   final value;
 
@@ -169,6 +216,7 @@
       columnStop = 0;
       return;
     }
+
     Script script = location.script;
     line = script.tokenToLine(location.tokenPos);
     columnStart = script.tokenToCol(location.tokenPos);
@@ -455,9 +503,9 @@
 
     if (!inDebuggerContext && script.library != null) {
       loadDeclarationsOfLibrary(script.library);
-
-      // Add fields before functions so they beat out conflicting
-      // implicit g/setters.
+      addLibraryAnnotations();
+      addDependencyAnnotations();
+      addPartAnnotations();
       addClassAnnotations();
       addFieldAnnotations();
       addFunctionAnnotations();
@@ -500,6 +548,106 @@
     });
   }
 
+  void addLibraryAnnotations() {
+    for (ScriptLine line in script.lines) {
+      // TODO(rmacnak): Use a real scanner.
+      var pattern = new RegExp("library ${script.library.name}");
+      var match = pattern.firstMatch(line.text);
+      if (match != null) {
+        var anno = new LibraryAnnotation(script.library);
+        anno.line = line.line;
+        anno.columnStart = match.start + 8;
+        anno.columnStop = match.end;
+        annotations.add(anno);
+      }
+      // TODO(rmacnak): Use a real scanner.
+      pattern = new RegExp("part of ${script.library.name}");
+      match = pattern.firstMatch(line.text);
+      if (match != null) {
+        var anno = new LibraryAnnotation(script.library);
+        anno.line = line.line;
+        anno.columnStart = match.start + 8;
+        anno.columnStop = match.end;
+        annotations.add(anno);
+      }
+    }
+  }
+
+  Library resolveDependency(String relativeUri) {
+    var targetUri = Uri.parse(script.library.uri).resolve(relativeUri);
+    for (Library l in script.isolate.libraries) {
+      if (targetUri.toString() == l.uri) {
+        return l;
+      }
+    }
+    Logger.root.info("Could not resolve library dependency: $relativeUri");
+    return null;
+  }
+
+  void addDependencyAnnotations() {
+    // TODO(rmacnak): Use a real scanner.
+    var patterns = [
+      new RegExp("import '(.*)'"),
+      new RegExp('import "(.*)"'),
+      new RegExp("export '(.*)'"),
+      new RegExp('export "(.*)"'),
+    ];
+    for (ScriptLine line in script.lines) {
+      for (var pattern in patterns) {
+        var match = pattern.firstMatch(line.text);
+        if (match != null) {
+          Library target = resolveDependency(match[1]);
+          if (target != null) {
+            var anno = new LibraryAnnotation(target);
+            anno.line = line.line;
+            anno.columnStart = match.start + 8;
+            anno.columnStop = match.end - 1;
+            annotations.add(anno);
+          }
+        }
+      }
+    }
+  }
+
+  Script resolvePart(String relativeUri) {
+    var rootUri = Uri.parse(script.library.uri);
+    if (rootUri.scheme == 'dart') {
+      // The relative paths from dart:* libraries to their parts are not valid.
+      rootUri = new Uri.directory(script.library.uri);
+    }
+    var targetUri = rootUri.resolve(relativeUri);
+    for (Script s in script.library.scripts) {
+      if (targetUri.toString() == s.uri) {
+        return s;
+      }
+    }
+    Logger.root.info("Could not resolve part: $relativeUri");
+    return null;
+  }
+
+  void addPartAnnotations() {
+    // TODO(rmacnak): Use a real scanner.
+    var patterns = [
+      new RegExp("part '(.*)'"),
+      new RegExp('part "(.*)"'),
+    ];
+    for (ScriptLine line in script.lines) {
+      for (var pattern in patterns) {
+        var match = pattern.firstMatch(line.text);
+        if (match != null) {
+          Script part = resolvePart(match[1]);
+          if (part != null) {
+            var anno = new PartAnnotation(part);
+            anno.line = line.line;
+            anno.columnStart = match.start + 6;
+            anno.columnStop = match.end - 1;
+            annotations.add(anno);
+          }
+        }
+      }
+    }
+  }
+
   void addClassAnnotations() {
     for (var cls in script.library.classes) {
       if ((cls.location != null) && (cls.location.script == script)) {
@@ -525,13 +673,23 @@
 
   void addFunctionAnnotations() {
     for (var func in script.library.functions) {
-      if ((func.location != null) && (func.location.script == script)) {
+      if ((func.location != null) &&
+          (func.location.script == script) &&
+          (func.kind != FunctionKind.kImplicitGetterFunction) &&
+          (func.kind != FunctionKind.kImplicitSetterFunction)) {
+        // We annotate a field declaration with the field instead of the
+        // implicit getter or setter.
         annotations.add(new FunctionDeclarationAnnotation(func));
       }
     }
     for (var cls in script.library.classes) {
       for (var func in cls.functions) {
-        if ((func.location != null) && (func.location.script == script)) {
+        if ((func.location != null) &&
+            (func.location.script == script) &&
+            (func.kind != FunctionKind.kImplicitGetterFunction) &&
+            (func.kind != FunctionKind.kImplicitSetterFunction)) {
+          // We annotate a field declaration with the field instead of the
+          // implicit getter or setter.
           annotations.add(new FunctionDeclarationAnnotation(func));
         }
       }
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 1c6fc0f..2e69952 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -1951,6 +1951,13 @@
     return isolate._eval(this, expression);
   }
 
+  Script get rootScript {
+    for (Script script in scripts) {
+      if (script.uri == uri) return script;
+    }
+    return null;
+  }
+
   String toString() => "Library($uri)";
 }
 
@@ -3149,8 +3156,16 @@
     if (address == 0) {
       return;
     }
-
-    jumpTarget = instructionsByAddressOffset[address - startAddress];
+    var relativeAddress = address - startAddress;
+    if (relativeAddress < 0) {
+      Logger.root.warning('Bad address resolving jump target $relativeAddress');
+      return;
+    }
+    if (relativeAddress >= instructionsByAddressOffset.length) {
+      Logger.root.warning('Bad address resolving jump target $relativeAddress');
+      return;
+    }
+    jumpTarget = instructionsByAddressOffset[relativeAddress];
   }
 }
 
@@ -3350,7 +3365,7 @@
       var pcOffset = 0;
       if (disassembly[i] != '') {
         // Not a code comment, extract address.
-        address = int.parse(disassembly[i]);
+        address = int.parse(disassembly[i], radix:16);
         pcOffset = address - startAddress;
       }
       var instruction = new CodeInstruction(address, pcOffset, machine, human);
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index cc6612e..0d49310 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -306,6 +306,13 @@
 #define Pu64 PRIu64
 #define Px64 PRIx64
 
+// Zero-padded pointer
+#if defined(ARCH_IS_32_BIT)
+#define Pp "08" PRIxPTR
+#else
+#define Pp "016" PRIxPTR
+#endif
+
 
 // Suffixes for 64-bit integer literals.
 #ifdef _MSC_VER
diff --git a/runtime/vm/disassembler.cc b/runtime/vm/disassembler.cc
index 80e1ff6..1a92450 100644
--- a/runtime/vm/disassembler.cc
+++ b/runtime/vm/disassembler.cc
@@ -46,12 +46,11 @@
                                                  char* human_buffer,
                                                  intptr_t human_size,
                                                  uword pc) {
-  uint8_t* pc_ptr = reinterpret_cast<uint8_t*>(pc);
   // Instructions are represented as three consecutive values in a JSON array.
   // All three are strings. The first is the address of the instruction,
   // the second is the hex string of the code, and the final is a human
   // readable string.
-  jsarr_.AddValueF("%p", pc_ptr);
+  jsarr_.AddValueF("%" Pp "", pc);
   jsarr_.AddValue(hex_buffer);
   jsarr_.AddValue(human_buffer);
 }
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index dba7e42..9f43a38 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -878,7 +878,7 @@
 int DisassemblerX64::JumpConditionalShort(uint8_t* data) {
   uint8_t cond = *data & 0x0F;
   uint8_t b = *(data + 1);
-  uint8_t* dest = data + static_cast<uint8_t>(b) + 2;
+  uint8_t* dest = data + static_cast<int8_t>(b) + 2;
   const char* mnem = conditional_code_suffix[cond];
   AppendToBuffer("j%s ", mnem);
   AppendAddressToBuffer(dest);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 4351b1d..38c5c6b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -15604,6 +15604,7 @@
       return this->raw();
     }
     ASSERT(this->Equals(type));
+    ASSERT(type.IsCanonical());
     return type.raw();
   }
 
@@ -15625,6 +15626,7 @@
     }
     ASSERT(type.IsFinalized());
     if (this->Equals(type)) {
+      ASSERT(type.IsCanonical());
       return type.raw();
     }
     index++;
@@ -15653,6 +15655,7 @@
     }
     ASSERT(type.IsFinalized());
     if (this->Equals(type)) {
+      ASSERT(type.IsCanonical());
       return type.raw();
     }
     index++;
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 419cd4e..fed3ae5 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -10568,7 +10568,8 @@
 AstNode* Parser::CreateAssignmentNode(AstNode* original,
                                       AstNode* rhs,
                                       const String* left_ident,
-                                      intptr_t left_pos) {
+                                      intptr_t left_pos,
+                                      bool is_compound /* = false */) {
   AstNode* result = original->MakeAssignmentNode(rhs);
   if (result == NULL) {
     String& name = String::ZoneHandle(Z);
@@ -10606,17 +10607,18 @@
   // normally: a op= b ==> a = a op b
   // however:  a ??= b ==> a ?? (a = b)
   // Therefore, we need to transform a = (a ?? b) into a ?? (a = b)
-  if (rhs->IsBinaryOpNode() &&
+  if (is_compound &&
+      rhs->IsBinaryOpNode() &&
       (rhs->AsBinaryOpNode()->kind() == Token::kIFNULL)) {
     BinaryOpNode* ifnull = rhs->AsBinaryOpNode();
     AstNode* modified_assign =
-        CreateAssignmentNode(ifnull->left(),
+        CreateAssignmentNode(original,
                              ifnull->right(),
                              left_ident,
                              left_pos);
     result = new(Z) BinaryOpNode(rhs->token_pos(),
                                  Token::kIFNULL,
-                                 original,
+                                 ifnull->left(),
                                  modified_assign);
   }
   return result;
@@ -10658,7 +10660,7 @@
         right_expr =
             ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
         AstNode* assign_expr =
-            CreateAssignmentNode(expr, right_expr, expr_ident, expr_pos);
+            CreateAssignmentNode(expr, right_expr, expr_ident, expr_pos, true);
         ASSERT(assign_expr != NULL);
         let_expr->AddNode(assign_expr);
         expr = let_expr;
@@ -10771,7 +10773,7 @@
     AstNode* assigned_value =
         ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
     AstNode* assign_expr =
-        CreateAssignmentNode(expr, assigned_value, expr_ident, expr_pos);
+        CreateAssignmentNode(expr, assigned_value, expr_ident, expr_pos, true);
     ASSERT(assign_expr != NULL);
     let_expr->AddNode(assign_expr);
     return let_expr;
@@ -10872,7 +10874,8 @@
         binary_op,
         expr,
         new(Z) LiteralNode(op_pos, Smi::ZoneHandle(Z, Smi::New(1))));
-    AstNode* store = CreateAssignmentNode(expr, add, expr_ident, expr_pos);
+    AstNode* store =
+        CreateAssignmentNode(expr, add, expr_ident, expr_pos, true);
     ASSERT(store != NULL);
     let_expr->AddNode(store);
     expr = let_expr;
@@ -11589,7 +11592,8 @@
         binary_op,
         new(Z) LoadLocalNode(expr_pos, temp),
         new(Z) LiteralNode(expr_pos, Smi::ZoneHandle(Z, Smi::New(1))));
-    AstNode* store = CreateAssignmentNode(expr, add, expr_ident, expr_pos);
+    AstNode* store =
+        CreateAssignmentNode(expr, add, expr_ident, expr_pos, true);
     ASSERT(store != NULL);
     // The result is a pair of the (side effects of the) store followed by
     // the (value of the) initial value temp variable load.
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 2e74b1c..5199cb6 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -799,7 +799,8 @@
   AstNode* CreateAssignmentNode(AstNode* original,
                                 AstNode* rhs,
                                 const String* left_ident,
-                                intptr_t left_pos);
+                                intptr_t left_pos,
+                                bool is_compound = false);
   AstNode* InsertClosureCallNodes(AstNode* condition);
 
   ConstructorCallNode* CreateConstructorCallNode(
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 9a12d08..0cff97a 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -209,10 +209,14 @@
                         Snapshot::Kind kind) {
   ASSERT(reader != NULL);
 
+  // Determine if the type class of this type is in the full snapshot.
+  bool typeclass_is_in_fullsnapshot = reader->Read<bool>();
+
   // Allocate type object.
   Type& type = Type::ZoneHandle(reader->zone(), NEW_OBJECT(Type));
   bool is_canonical = RawObject::IsCanonical(tags);
-  bool defer_canonicalization = is_canonical && (kind != Snapshot::kFull);
+  bool defer_canonicalization = is_canonical &&
+      (kind != Snapshot::kFull && typeclass_is_in_fullsnapshot);
   reader->AddBackRef(object_id, &type, kIsDeserialized, defer_canonicalization);
 
   // Set all non object fields.
@@ -257,6 +261,14 @@
   writer->WriteIndexedObject(kTypeCid);
   writer->WriteTags(writer->GetObjectTags(this));
 
+  // Write out typeclass_is_in_fullsnapshot first as this will
+  // help the reader decide on how to canonicalize the type object.
+  intptr_t tags = writer->GetObjectTags(ptr()->type_class_);
+  bool typeclass_is_in_fullsnapshot =
+      (ClassIdTag::decode(tags) == kClassCid) &&
+      Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(ptr()->type_class_));
+  writer->Write<bool>(typeclass_is_in_fullsnapshot);
+
   // Write out all the non object pointer fields.
   writer->Write<int32_t>(ptr()->token_pos_);
   writer->Write<int8_t>(ptr()->type_state_);
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 907e805..4b92acd 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -1168,41 +1168,36 @@
     BackRefNode& backref = (*backward_references_)[i];
     if (backref.defer_canonicalization()) {
       Object* objref = backref.reference();
-      bool needs_patching = false;
       // Object should either be an abstract type or a type argument.
       if (objref->IsType()) {
         typeobj ^= objref->raw();
         newobj = typeobj.Canonicalize();
-        if ((newobj.raw() != typeobj.raw()) && !typeobj.IsRecursive()) {
-          needs_patching = true;
-        } else {
-          // Set Canonical bit.
-          objref->SetCanonical();
-        }
       } else {
         ASSERT(objref->IsTypeArguments());
         typeargs ^= objref->raw();
         newobj = typeargs.Canonicalize();
-        if ((newobj.raw() != typeargs.raw()) && !typeargs.IsRecursive()) {
-          needs_patching = true;
-        } else {
-          // Set Canonical bit.
-          objref->SetCanonical();
-        }
       }
-      if (needs_patching) {
+      if (newobj.raw() != objref->raw()) {
         ZoneGrowableArray<intptr_t>* patches = backref.patch_records();
         ASSERT(newobj.IsCanonical());
         ASSERT(patches != NULL);
+        // First we replace the back ref table with the canonical object.
+        *objref = newobj.raw();
+        // Now we go over all the patch records and patch the canonical object.
         for (intptr_t j = 0; j < patches->length(); j+=2) {
           NoSafepointScope no_safepoint;
           intptr_t patch_object_id = (*patches)[j];
           intptr_t patch_offset = (*patches)[j + 1];
           Object* target = GetBackRef(patch_object_id);
-          RawObject** rawptr =
-              reinterpret_cast<RawObject**>(target->raw()->ptr());
-          target->StorePointer((rawptr + patch_offset), newobj.raw());
+          // We should not backpatch an object that is canonical.
+          if (!target->IsCanonical()) {
+            RawObject** rawptr =
+                reinterpret_cast<RawObject**>(target->raw()->ptr());
+            target->StorePointer((rawptr + patch_offset), newobj.raw());
+          }
         }
+      } else {
+        ASSERT(objref->IsCanonical());
       }
     }
   }
diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart
index 3290682..e89acc6f 100644
--- a/sdk/lib/collection/iterable.dart
+++ b/sdk/lib/collection/iterable.dart
@@ -103,16 +103,16 @@
 
   bool get isNotEmpty => !isEmpty;
 
-  Iterable<E> take(int n) {
-    return new TakeIterable<E>(this, n);
+  Iterable<E> take(int count) {
+    return new TakeIterable<E>(this, count);
   }
 
   Iterable<E> takeWhile(bool test(E value)) {
     return new TakeWhileIterable<E>(this, test);
   }
 
-  Iterable<E> skip(int n) {
-    return new SkipIterable<E>(this, n);
+  Iterable<E> skip(int count) {
+    return new SkipIterable<E>(this, count);
   }
 
   Iterable<E> skipWhile(bool test(E value)) {
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 3de39bc..78efa1b 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -392,8 +392,8 @@
    *
    * The `count` must not be negative.
    */
-  Iterable<E> take(int n) {
-    return new TakeIterable<E>(this, n);
+  Iterable<E> take(int count) {
+    return new TakeIterable<E>(this, count);
   }
 
   /**
@@ -422,8 +422,8 @@
    *
    * The `count` must not be negative.
    */
-  Iterable<E> skip(int n) {
-    return new SkipIterable<E>(this, n);
+  Iterable<E> skip(int count) {
+    return new SkipIterable<E>(this, count);
   }
 
   /**
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index d6e6134..a539fa1 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -393,12 +393,14 @@
 string_interpolate1_negative_test: CompileTimeError
 string_interpolate2_negative_test: CompileTimeError
 string_interpolate_test: StaticWarning
+string_interpolation_and_buffer_test: StaticWarning
 string_interpolation1_negative_test: CompileTimeError
 string_interpolation2_negative_test: CompileTimeError
 string_interpolation3_negative_test: CompileTimeError
 string_interpolation4_negative_test: CompileTimeError
 string_interpolation5_negative_test: CompileTimeError
 string_interpolation6_negative_test: CompileTimeError
+string_split_test: StaticWarning
 string_test: StaticWarning
 string_unicode1_negative_test: CompileTimeError
 string_unicode2_negative_test: CompileTimeError
diff --git a/tests/language/nullaware_opt_test.dart b/tests/language/nullaware_opt_test.dart
index 5446171..e83757a 100644
--- a/tests/language/nullaware_opt_test.dart
+++ b/tests/language/nullaware_opt_test.dart
@@ -53,6 +53,12 @@
   Expect.equals(201, e.f);
 
   var x = 5 ?? bomb();
+  Expect.equals(5, x);
+
+  var y;
+  x = y ?? 1;
+  Expect.equals(1, x);
+  Expect.equals(null, y);
 }
 
 // Check that instructions without result do not crash.
diff --git a/tests/language/string_interpolation_and_buffer.dart b/tests/language/string_interpolation_and_buffer_test.dart
similarity index 85%
rename from tests/language/string_interpolation_and_buffer.dart
rename to tests/language/string_interpolation_and_buffer_test.dart
index ddcdd4e..5006d6e 100644
--- a/tests/language/string_interpolation_and_buffer.dart
+++ b/tests/language/string_interpolation_and_buffer_test.dart
@@ -5,6 +5,8 @@
 // Test to ensure that StringBuffer and string interpolation behaves
 // the same and fail fast.
 
+import "package:expect/expect.dart";
+
 class ToStringWrapper {
   final value;
 
@@ -15,9 +17,17 @@
 
 wrap(value) => new ToStringWrapper(value);
 
+final bool checkedMode = computeCheckedMode();
+bool computeCheckedMode() {
+  try {
+    int x = "foo";
+  } on Error {
+    return true;
+  }
+  return false;
+}
+
 main() {
-  bool checkedMode = false;
-  assert(checkedMode = true);
   interpolate(object) {
     var result;
     if (checkedMode && object != null) {
@@ -25,6 +35,8 @@
         result = '${wrap(object)}';
       } on TypeError {
         return 'Error';
+      } on ArgumentError {
+        return 'Error';  // Checked mode.
       }
     } else {
       try {
@@ -44,6 +56,8 @@
         sb = new StringBuffer()..write(wrap(object));
       } on TypeError {
         return 'Error';
+      } on ArgumentError {
+        return 'Error';  // Checked mode.
       }
     } else {
       try {
@@ -63,6 +77,8 @@
         sb = new StringBuffer(wrap(object));
       } on TypeError {
         return 'Error';
+      } on ArgumentError {
+        return 'Error';  // Checked mode.
       }
     } else {
       try {
diff --git a/tests/language/string_split_test.dart b/tests/language/string_split_test.dart
new file mode 100644
index 0000000..56189cc
--- /dev/null
+++ b/tests/language/string_split_test.dart
@@ -0,0 +1,29 @@
+// 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.
+// Issue 24043.
+
+import "package:expect/expect.dart";
+
+class EvilMatch implements Match {
+  int get start => 100000000;
+  int get end => 3;
+}
+
+class EvilIterator implements Iterator {
+  bool moveNext() => true;
+  EvilMatch get current => new EvilMatch();
+}
+
+class EvilIterable extends Iterable {
+  Iterator get iterator => new EvilIterator();
+}
+
+class EvilPattern implements Pattern {
+  Iterable allMatches(String s) => new EvilIterable();
+}
+
+void main() {
+  Expect.throws(() => "foo".split(new EvilPattern())[0].length,
+      (e) => e is RangeError);
+}
diff --git a/tools/VERSION b/tools/VERSION
index d45b9a4..3f0c944 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
 MINOR 12
 PATCH 0
 PRERELEASE 5
-PRERELEASE_PATCH 2
+PRERELEASE_PATCH 3