Version 1.9.0-dev.10.4

svn merge -c 44263 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44265 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44267 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44287 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44288 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44290 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44295 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44297 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44299 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44300 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44301 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44302 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44303 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@44314 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analysis_server/lib/src/get_handler.dart b/pkg/analysis_server/lib/src/get_handler.dart
index aa4c2a2..d4f6a7a 100644
--- a/pkg/analysis_server/lib/src/get_handler.dart
+++ b/pkg/analysis_server/lib/src/get_handler.dart
@@ -686,8 +686,8 @@
     implicitNames.sort();
 
     _overlayContents.clear();
-    context.visitContentCache((Source source, int stamp, String contents) {
-      _overlayContents[source.fullName] = contents;
+    context.visitContentCache((String fullName, int stamp, String contents) {
+      _overlayContents[fullName] = contents;
     });
 
     void _writeFiles(
@@ -887,14 +887,13 @@
         buffer.write('<table border="1">');
         _overlayContents.clear();
         ContentCache overlayState = analysisServer.overlayState;
-        overlayState.accept((Source source, int stamp, String contents) {
-          String fileName = source.fullName;
+        overlayState.accept((String fullName, int stamp, String contents) {
           buffer.write('<tr>');
           String link =
-              makeLink(OVERLAY_PATH, {PATH_PARAM: fileName}, fileName);
+              makeLink(OVERLAY_PATH, {PATH_PARAM: fullName}, fullName);
           DateTime time = new DateTime.fromMillisecondsSinceEpoch(stamp);
           _writeRow(buffer, [link, time]);
-          _overlayContents[fileName] = contents;
+          _overlayContents[fullName] = contents;
         });
         int count = _overlayContents.length;
         buffer.write('<tr><td colspan="2">Total: $count entries.</td></tr>');
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 2fdf505..4a45619 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -1189,12 +1189,6 @@
           _updateEndOld = endOffsetOld;
           _updateEndNew = endOffsetNew;
           _updateDelta = newUnit.length - _oldUnit.length;
-          // A comment change.
-          if (firstPair.kind == _TokenDifferenceKind.COMMENT) {
-            bool success = _resolveComment(newUnit, firstPair);
-            logger.log('Comment change: $success');
-            return success;
-          }
           // A Dart documentation comment change.
           if (firstPair.kind == _TokenDifferenceKind.COMMENT_DOC) {
             bool success = _resolveCommentDoc(newUnit, firstPair);
@@ -1254,6 +1248,13 @@
             logger.log('Failure: no enclosing function body or executable.');
             return false;
           }
+          // fail if a comment change outside the bodies
+          if (firstPair.kind == _TokenDifferenceKind.COMMENT) {
+            if (beginOffsetOld <= oldNode.offset || beginOffsetNew <= newNode.offset) {
+              logger.log('Failure: comment outside a function body.');
+              return false;
+            }
+          }
         }
         logger.log(() => 'oldNode: $oldNode');
         logger.log(() => 'newNode: $newNode');
@@ -1315,28 +1316,6 @@
   }
 
   /**
-   * Attempts to resolve a comment change.
-   * Returns `true` if success.
-   */
-  bool _resolveComment(CompilationUnit newUnit, _TokenPair firstPair) {
-    Token oldToken = firstPair.oldToken;
-    Token newToken = firstPair.newToken;
-    CommentToken newComments = newToken.precedingComments;
-    // update token references
-    _updateOffset = oldToken.offset - 1;
-    _shiftTokens(firstPair.oldToken);
-    _setPrecedingComments(oldToken, newComments);
-    // update elements
-    IncrementalResolver incrementalResolver = new IncrementalResolver(
-        _unitElement, _updateOffset, _updateEndOld, _updateEndNew);
-    incrementalResolver._updateElementNameOffsets();
-    incrementalResolver._shiftEntryErrors();
-    _updateEntry();
-    // OK
-    return true;
-  }
-
-  /**
    * Attempts to resolve a documentation comment change.
    * Returns `true` if success.
    */
@@ -1390,24 +1369,8 @@
       token.precedingComments = comment;
     } else if (token is KeywordTokenWithComment) {
       token.precedingComments = comment;
-    } else if (token is KeywordToken) {
-      KeywordTokenWithComment newToken =
-          new KeywordTokenWithComment(token.keyword, token.offset, comment);
-      token.previous.setNext(newToken);
-      newToken.setNext(token.next);
-      if (_oldUnit.beginToken == token) {
-        _oldUnit.beginToken = newToken;
-      }
     } else if (token is StringTokenWithComment) {
       token.precedingComments = comment;
-    } else if (token is StringToken) {
-      StringTokenWithComment newToken = new StringTokenWithComment(
-          token.type, token.value(), token.offset, comment);
-      token.previous.setNext(newToken);
-      newToken.setNext(token.next);
-      if (_oldUnit.beginToken == token) {
-        _oldUnit.beginToken = newToken;
-      }
     } else if (token is TokenWithComment) {
       token.precedingComments = comment;
     } else {
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index e491d91..e918ed8 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -2444,6 +2444,12 @@
         // class that was parsed.
         _parseClassDeclaration(commentAndMetadata, getAndAdvance());
         return null;
+      } else if (_matchesKeyword(Keyword.ENUM)) {
+        _reportErrorForToken(ParserErrorCode.ENUM_IN_CLASS, _peek());
+        // TODO(brianwilkerson) We don't currently have any way to capture the
+        // enum that was parsed.
+        _parseEnumDeclaration(commentAndMetadata);
+        return null;
       } else if (_isOperator(_currentToken)) {
         //
         // We appear to have found an operator declaration without the
@@ -9320,6 +9326,9 @@
   static const ParserErrorCode EMPTY_ENUM_BODY = const ParserErrorCode(
       'EMPTY_ENUM_BODY', "An enum must declare at least one constant name");
 
+  static const ParserErrorCode ENUM_IN_CLASS = const ParserErrorCode(
+      'ENUM_IN_CLASS', "Enums cannot be declared inside classes");
+
   static const ParserErrorCode EQUALITY_CANNOT_BE_EQUALITY_OPERAND =
       const ParserErrorCode('EQUALITY_CANNOT_BE_EQUALITY_OPERAND',
           "Equality expression cannot be operand of another equality expression.");
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 805897f..d0b5dde 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -22,86 +22,78 @@
 import 'source_io.dart' show FileBasedSource;
 
 /**
- * A function that is used to handle [ContentCache] entries.
+ * A function that is used to visit [ContentCache] entries.
  */
-typedef void ContentCacheVisitor(Source source, int stamp, String contents);
+typedef void ContentCacheVisitor(String fullPath, int stamp, String contents);
 
 /**
- * Instances of class `ContentCache` hold content used to override the default content of a
- * [Source].
+ * A cache used to override the default content of a [Source].
  */
 class ContentCache {
   /**
-   * A table mapping sources to the contents of those sources. This is used to override the default
-   * contents of a source.
+   * A table mapping the full path of sources to the contents of those sources.
+   * This is used to override the default contents of a source.
    */
-  HashMap<Source, String> _contentMap = new HashMap<Source, String>();
+  HashMap<String, String> _contentMap = new HashMap<String, String>();
 
   /**
-   * A table mapping sources to the modification stamps of those sources. This is used when the
-   * default contents of a source has been overridden.
+   * A table mapping the full path of sources to the modification stamps of
+   * those sources. This is used when the default contents of a source has been
+   * overridden.
    */
-  HashMap<Source, int> _stampMap = new HashMap<Source, int>();
+  HashMap<String, int> _stampMap = new HashMap<String, int>();
 
   /**
    * Visit all entries of this cache.
    */
   void accept(ContentCacheVisitor visitor) {
-    _contentMap.forEach((Source source, String contents) {
-      int stamp = _stampMap[source];
-      visitor(source, stamp, contents);
+    _contentMap.forEach((String fullPath, String contents) {
+      int stamp = _stampMap[fullPath];
+      visitor(fullPath, stamp, contents);
     });
   }
 
   /**
-   * Return the contents of the given source, or `null` if this cache does not override the
-   * contents of the source.
-   *
-   * <b>Note:</b> This method is not intended to be used except by
-   * [AnalysisContext.getContents].
-   *
-   * @param source the source whose content is to be returned
-   * @return the contents of the given source
-   */
-  String getContents(Source source) => _contentMap[source];
-
-  /**
-   * Return the modification stamp of the given source, or `null` if this cache does not
+   * Return the contents of the given [source], or `null` if this cache does not
    * override the contents of the source.
    *
    * <b>Note:</b> This method is not intended to be used except by
-   * [AnalysisContext.getModificationStamp].
-   *
-   * @param source the source whose modification stamp is to be returned
-   * @return the modification stamp of the given source
+   * [AnalysisContext.getContents].
    */
-  int getModificationStamp(Source source) => _stampMap[source];
+  String getContents(Source source) => _contentMap[source.fullName];
 
   /**
-   * Set the contents of the given source to the given contents. This has the effect of overriding
-   * the default contents of the source. If the contents are `null` the override is removed so
-   * that the default contents will be returned.
+   * Return the modification stamp of the given [source], or `null` if this
+   * cache does not override the contents of the source.
    *
-   * @param source the source whose contents are being overridden
-   * @param contents the new contents of the source
-   * @return the original cached contents or `null` if none
+   * <b>Note:</b> This method is not intended to be used except by
+   * [AnalysisContext.getModificationStamp].
+   */
+  int getModificationStamp(Source source) => _stampMap[source.fullName];
+
+  /**
+   * Set the contents of the given [source] to the given [contents]. This has
+   * the effect of overriding the default contents of the source. If the
+   * contents are `null` the override is removed so that the default contents
+   * will be returned.
    */
   String setContents(Source source, String contents) {
+    String fullName = source.fullName;
     if (contents == null) {
-      _stampMap.remove(source);
-      return _contentMap.remove(source);
+      _stampMap.remove(fullName);
+      return _contentMap.remove(fullName);
     } else {
       int newStamp = JavaSystem.currentTimeMillis();
-      int oldStamp = _stampMap[source];
-      _stampMap[source] = newStamp;
+      int oldStamp = _stampMap[fullName];
+      _stampMap[fullName] = newStamp;
       // Occasionally, if this method is called in rapid succession, the
       // timestamps are equal. Guard against this by artificially incrementing
       // the new timestamp.
       if (newStamp == oldStamp) {
-        _stampMap[source] = newStamp + 1;
+        _stampMap[fullName] = newStamp + 1;
       }
-      String oldContent = _contentMap[source];
-      _contentMap[source] = contents;
+      String oldContent = _contentMap[fullName];
+      _contentMap[fullName] = contents;
       return oldContent;
     }
   }
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index c65b545..3eb51e3 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -2843,7 +2843,7 @@
 ''');
   }
 
-  void test_endOfLineComment_header_add() {
+  void test_endOfLineComment_outBody_add() {
     _resolveUnit(r'''
 main() {
   Object x;
@@ -2856,10 +2856,10 @@
   Object x;
   x.foo();
 }
-''');
+''', expectedSuccess: false);
   }
 
-  void test_endOfLineComment_header_remove() {
+  void test_endOfLineComment_outBody_remove() {
     _resolveUnit(r'''
 // 000
 main() {
@@ -2872,10 +2872,10 @@
   Object x;
   x.foo();
 }
-''');
+''', expectedSuccess: false);
   }
 
-  void test_endOfLineComment_header_update() {
+  void test_endOfLineComment_outBody_update() {
     _resolveUnit(r'''
 // 000
 main() {
@@ -2889,7 +2889,7 @@
   Object x;
   x.foo();
 }
-''');
+''', expectedSuccess: false);
   }
 
   void test_endOfLineComment_localFunction_inTopLevelVariable() {
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 524d0511..78c7934 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -917,6 +917,16 @@
     ], "enum E {}", [ParserErrorCode.EMPTY_ENUM_BODY]);
   }
 
+  void test_enumInClass() {
+    ParserTestCase.parseCompilationUnit(r'''
+class Foo {
+  enum Bar {
+    Bar1, Bar2, Bar3
+  }
+}
+''', [ParserErrorCode.ENUM_IN_CLASS]);
+  }
+
   void test_equalityCannotBeEqualityOperand_eq_eq() {
     ParserTestCase.parseExpression(
         "1 == 2 == 3", [ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND]);
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 1490ada..c2863c5 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -659,7 +659,8 @@
         _makeVariableInitializer(handler, js.number(rethrowLabel)));
     variables.add(_makeVariableInitializer(currentError, null));
     if (analysis.hasFinally || (isAsyncStar && analysis.hasYield)) {
-      variables.add(_makeVariableInitializer(next, null));
+      variables.add(_makeVariableInitializer(next,
+          new js.ArrayInitializer(<js.Expression>[])));
     }
     if (analysis.hasThis && !isSyncStar) {
       // Sync* functions must remember `this` on the level of the outer
@@ -1416,7 +1417,7 @@
     } else {
       // The handler is reset as the first thing in the finally block.
       addStatement(
-          js.js.statement("# = [#];", [next, js.number(afterFinallyLabel)]));
+          js.js.statement("#.push(#);", [next, js.number(afterFinallyLabel)]));
       addGoto(finallyLabel);
     }
 
@@ -1440,8 +1441,9 @@
       if (node.finallyPart != null) {
         // The error has been caught, so after the finally, continue after the
         // try.
-        addStatement(js.js.statement("# = [#];",
-                                     [next, js.number(afterFinallyLabel)]));
+        addStatement(
+            js.js.statement("#.push(#);",
+                            [next, js.number(afterFinallyLabel)]));
         addGoto(finallyLabel);
       } else {
         addGoto(afterFinallyLabel);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 7914cef..718a227 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -6084,6 +6084,21 @@
 }
 
 
+bool Function::IsImplicitStaticClosureFunction(RawFunction* func) {
+  NoGCScope no_gc;
+  uint32_t kind_tag = func->ptr()->kind_tag_;
+  if (KindBits::decode(kind_tag) != RawFunction::kClosureFunction) {
+    return false;
+  }
+  if (!StaticBit::decode(kind_tag)) {
+    return false;
+  }
+  RawClosureData* data = reinterpret_cast<RawClosureData*>(func->ptr()->data_);
+  RawFunction* parent_function = data->ptr()->parent_function_;
+  return (parent_function->ptr()->data_ == reinterpret_cast<RawObject*>(func));
+}
+
+
 RawFunction* Function::New() {
   ASSERT(Object::function_class() != Class::null());
   RawObject* raw = Object::Allocate(Function::kClassId,
@@ -6383,10 +6398,15 @@
 
 RawInstance* Function::ImplicitStaticClosure() const {
   if (implicit_static_closure() == Instance::null()) {
-    ObjectStore* object_store = Isolate::Current()->object_store();
-    const Context& context = Context::Handle(object_store->empty_context());
-    const Instance& closure =
-        Instance::Handle(Closure::New(*this, context, Heap::kOld));
+    Isolate* isolate = Isolate::Current();
+    ObjectStore* object_store = isolate->object_store();
+    const Context& context = Context::Handle(isolate,
+                                             object_store->empty_context());
+    Instance& closure =
+        Instance::Handle(isolate, Closure::New(*this, context, Heap::kOld));
+    const char* error_str = NULL;
+    closure ^= closure.CheckAndCanonicalize(&error_str);
+    ASSERT(!closure.IsNull());
     set_implicit_static_closure(closure);
   }
   return implicit_static_closure();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 806dbe3..b4002ce 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2135,6 +2135,7 @@
   bool IsImplicitStaticClosureFunction() const {
     return is_static() && IsImplicitClosureFunction();
   }
+  bool static IsImplicitStaticClosureFunction(RawFunction* func);
 
   // Returns true if this function represents an implicit instance closure
   // function.
@@ -2377,6 +2378,7 @@
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(Function, Object);
   friend class Class;
+  friend class SnapshotWriter;
   friend class Parser;  // For set_eval_script.
   // RawFunction::VisitFunctionPointers accesses the private constructor of
   // Function.
@@ -7335,8 +7337,13 @@
     // Indicates this class cannot be extended by dart code.
     return -kWordSize;
   }
+  static RawFunction* GetFunction(RawObject* obj) {
+    return *(reinterpret_cast<RawFunction**>(
+        reinterpret_cast<intptr_t>(obj->ptr()) + function_offset()));
+  }
 
   friend class Class;
+  friend class SnapshotWriter;
 };
 
 
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 9d145bb..f4a537f 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -542,7 +542,9 @@
   friend class Array;
   friend class ByteBuffer;
   friend class Code;
+  friend class Closure;
   friend class FreeListElement;
+  friend class Function;
   friend class GCMarker;
   friend class ExternalTypedData;
   friend class ForwardList;
@@ -566,6 +568,7 @@
   friend class TypedData;
   friend class TypedDataView;
   friend class WeakProperty;  // StorePointer
+  friend class Instance;  // StorePointer
 
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(RawObject);
@@ -685,6 +688,8 @@
   RawObject** to() {
     return reinterpret_cast<RawObject**>(&ptr()->source_class_);
   }
+
+  friend class Function;
 };
 
 
@@ -772,6 +777,8 @@
   RawObject** to() {
     return reinterpret_cast<RawObject**>(&ptr()->closure_);
   }
+
+  friend class Function;
 };
 
 
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 9420790..a3544ad 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -237,6 +237,46 @@
 }
 
 
+RawObject* SnapshotReader::ReadStaticImplicitClosure(intptr_t object_id,
+                                                     intptr_t class_header) {
+  ASSERT(kind_ == Snapshot::kMessage);
+
+  // First create a function object and associate it with the specified
+  // 'object_id'.
+  Function& func = Function::ZoneHandle(isolate(), Function::null());
+  AddBackRef(object_id, &func, kIsDeserialized);
+
+  // Read the library/class/function information and lookup the function.
+  str_ ^= ReadObjectImpl();
+  library_ = Library::LookupLibrary(str_);
+  if (library_.IsNull() || !library_.Loaded()) {
+    SetReadException("Invalid Library object found in message.");
+  }
+  str_ ^= ReadObjectImpl();
+  if (str_.Equals(Symbols::TopLevel())) {
+    str_ ^= ReadObjectImpl();
+    func = library_.LookupFunctionAllowPrivate(str_);
+  } else {
+    cls_ = library_.LookupClassAllowPrivate(str_);
+    if (cls_.IsNull()) {
+      OS::Print("Name of class not found %s\n", str_.ToCString());
+      SetReadException("Invalid Class object found in message.");
+    }
+    cls_.EnsureIsFinalized(isolate());
+    str_ ^= ReadObjectImpl();
+    func = cls_.LookupFunctionAllowPrivate(str_);
+  }
+  if (func.IsNull()) {
+    SetReadException("Invalid function object found in message.");
+  }
+  func = func.ImplicitClosureFunction();
+  ASSERT(!func.IsNull());
+
+  // Return the associated implicit static closure.
+  return func.ImplicitStaticClosure();
+}
+
+
 RawObject* SnapshotReader::ReadObjectImpl() {
   int64_t value = Read<int64_t>();
   if ((value & kSmiTagMask) == kSmiTag) {
@@ -312,7 +352,8 @@
   // Since we are only reading an object reference, If it is an instance kind
   // then we only need to figure out the class of the object and allocate an
   // instance of it. The individual fields will be read later.
-  if (SerializedHeaderData::decode(class_header) == kInstanceObjectId) {
+  intptr_t header_id = SerializedHeaderData::decode(class_header);
+  if (header_id == kInstanceObjectId) {
     Instance& result = Instance::ZoneHandle(isolate(), Instance::null());
     AddBackRef(object_id, &result, kIsNotDeserialized);
 
@@ -326,6 +367,12 @@
       result ^= Object::Allocate(cls_.id(), instance_size, HEAP_SPACE(kind_));
     }
     return result.raw();
+  } else if (header_id == kStaticImplicitClosureObjectId) {
+    // We skip the tags that have been written as the implicit static
+    // closure is going to be created in this isolate or the canonical
+    // version already created in the isolate will be used.
+    ReadTags();
+    return ReadStaticImplicitClosure(object_id, class_header);
   }
   ASSERT((class_header & kSmiTagMask) != kSmiTag);
 
@@ -937,7 +984,8 @@
   // Read the class header information and lookup the class.
   intptr_t class_header = Read<int32_t>();
   intptr_t tags = ReadTags();
-  if (SerializedHeaderData::decode(class_header) == kInstanceObjectId) {
+  intptr_t header_id = SerializedHeaderData::decode(class_header);
+  if (header_id == kInstanceObjectId) {
     // Object is regular dart instance.
     Instance* result = reinterpret_cast<Instance*>(GetBackRef(object_id));
     intptr_t instance_size = 0;
@@ -1002,6 +1050,11 @@
       ASSERT(!result->IsNull());
     }
     return result->raw();
+  } else if (header_id == kStaticImplicitClosureObjectId) {
+    // We do not use the tags as the implicit static closure
+    // is going to be created in this isolate or the canonical
+    // version already created in the isolate will be used.
+    return ReadStaticImplicitClosure(object_id, class_header);
   }
   ASSERT((class_header & kSmiTagMask) != kSmiTag);
   intptr_t class_id = LookupInternalClass(class_header);
@@ -1215,10 +1268,10 @@
     WriteInstanceRef(raw, cls);
     return;
   }
-  // Object is being referenced, add it to the forward ref list and mark
-  // it so that future references to this object in the snapshot will use
-  // this object id. Mark it as not having been serialized yet so that we
-  // will serialize the object when we go through the forward list.
+  // Add object to the forward ref list and mark it so that future references
+  // to this object in the snapshot will use this object id. Mark it as having
+  // been serialized so that we do not serialize the object when we go through
+  // the forward list.
   forward_list_.MarkAndAddObject(raw, kIsSerialized);
   switch (class_id) {
 #define SNAPSHOT_WRITE(clazz)                                                  \
@@ -1592,6 +1645,29 @@
 }
 
 
+void SnapshotWriter::WriteStaticImplicitClosure(intptr_t object_id,
+                                                RawFunction* func,
+                                                intptr_t tags) {
+  // Write out the serialization header value for this object.
+  WriteInlinedObjectHeader(object_id);
+
+  // Indicate this is a static implicit closure object.
+  Write<int32_t>(SerializedHeaderData::encode(kStaticImplicitClosureObjectId));
+
+  // Write out the tags.
+  WriteTags(tags);
+
+  // Write out the library url, class name and signature function name.
+  RawClass* cls = GetFunctionOwner(func);
+  ASSERT(cls != Class::null());
+  RawLibrary* library = cls->ptr()->library_;
+  ASSERT(library != Library::null());
+  WriteObjectImpl(library->ptr()->url_);
+  WriteObjectImpl(cls->ptr()->name_);
+  WriteObjectImpl(func->ptr()->name_);
+}
+
+
 void SnapshotWriter::ArrayWriteTo(intptr_t object_id,
                                   intptr_t array_kind,
                                   intptr_t tags,
@@ -1625,34 +1701,63 @@
 }
 
 
-void SnapshotWriter::CheckIfSerializable(RawClass* cls) {
+RawFunction* SnapshotWriter::IsSerializableClosure(RawClass* cls,
+                                                   RawObject* obj) {
   if (Class::IsSignatureClass(cls)) {
-    // We do not allow closure objects in an isolate message.
-    Isolate* isolate = Isolate::Current();
-    HANDLESCOPE(isolate);
+    // 'obj' is a closure as its class is a signature class, extract
+    // the function object to check if this closure can be sent in an
+    // isolate message.
+    RawFunction* func = Closure::GetFunction(obj);
+    // We only allow closure of top level methods or static functions in a
+    // class to be sent in isolate messages.
+    if (can_send_any_object() &&
+        Function::IsImplicitStaticClosureFunction(func)) {
+      return func;
+    }
+    // Not a closure of a top level method or static function, throw an
+    // exception as we do not allow these objects to be serialized.
+    HANDLESCOPE(isolate());
+
+    const Class& clazz = Class::Handle(isolate(), cls);
+    const Function& errorFunc = Function::Handle(isolate(), func);
+    ASSERT(!errorFunc.IsNull());
+
+    // All other closures are errors.
     const char* format = "Illegal argument in isolate message"
-                         " : (object is a closure - %s %s)";
+        " : (object is a closure - %s %s)";
     UnmarkAll();  // Unmark objects now as we are about to print stuff.
-    const Class& clazz = Class::Handle(isolate, cls);
-    const Function& func = Function::Handle(isolate,
-                                            clazz.signature_function());
-    ASSERT(!func.IsNull());
     intptr_t len = OS::SNPrint(NULL, 0, format,
-                               clazz.ToCString(), func.ToCString()) + 1;
-    char* chars = isolate->current_zone()->Alloc<char>(len);
-    OS::SNPrint(chars, len, format, clazz.ToCString(), func.ToCString());
+                               clazz.ToCString(), errorFunc.ToCString()) + 1;
+    char* chars = isolate()->current_zone()->Alloc<char>(len);
+    OS::SNPrint(chars, len, format, clazz.ToCString(), errorFunc.ToCString());
     SetWriteException(Exceptions::kArgument, chars);
   }
+  return Function::null();
+}
+
+
+RawClass* SnapshotWriter::GetFunctionOwner(RawFunction* func) {
+  RawObject* owner = func->ptr()->owner_;
+  uword tags = GetObjectTags(owner);
+  intptr_t class_id = RawObject::ClassIdTag::decode(tags);
+  if (class_id == kClassCid) {
+    return reinterpret_cast<RawClass*>(owner);
+  }
+  ASSERT(class_id == kPatchClassCid);
+  return reinterpret_cast<RawPatchClass*>(owner)->ptr()->patched_class_;
+}
+
+
+void SnapshotWriter::CheckForNativeFields(RawClass* cls) {
   if (cls->ptr()->num_native_fields_ != 0) {
     // We do not allow objects with native fields in an isolate message.
-    Isolate* isolate = Isolate::Current();
-    HANDLESCOPE(Isolate::Current());
+    HANDLESCOPE(isolate());
     const char* format = "Illegal argument in isolate message"
                          " : (object extends NativeWrapper - %s)";
     UnmarkAll();  // Unmark objects now as we are about to print stuff.
-    const Class& clazz = Class::Handle(isolate, cls);
+    const Class& clazz = Class::Handle(isolate(), cls);
     intptr_t len = OS::SNPrint(NULL, 0, format, clazz.ToCString()) + 1;
-    char* chars = isolate->current_zone()->Alloc<char>(len);
+    char* chars = isolate()->current_zone()->Alloc<char>(len);
     OS::SNPrint(chars, len, format, clazz.ToCString());
     SetWriteException(Exceptions::kArgument, chars);
   }
@@ -1673,11 +1778,20 @@
                                    RawObject* raw,
                                    RawClass* cls,
                                    intptr_t tags) {
-  // First check if object is a closure or has native fields.
-  CheckIfSerializable(cls);
+  // Check if the instance has native fields and throw an exception if it does.
+  CheckForNativeFields(cls);
+
+  // Check if object is a closure that is serializable, if the object is a
+  // closure that is not serializable this will throw an exception.
+  RawFunction* func = IsSerializableClosure(cls, raw);
+  if (func != Function::null()) {
+    WriteStaticImplicitClosure(object_id, func, tags);
+    return;
+  }
 
   // Object is regular dart instance.
-  intptr_t next_field_offset =
+  intptr_t next_field_offset = Class::IsSignatureClass(cls) ?
+      Closure::InstanceSize() :
       cls->ptr()->next_field_offset_in_words_ << kWordSizeLog2;
   ASSERT(next_field_offset > 0);
 
@@ -1713,8 +1827,25 @@
 
 
 void SnapshotWriter::WriteInstanceRef(RawObject* raw, RawClass* cls) {
-  // First check if object is a closure or has native fields.
-  CheckIfSerializable(cls);
+  // Check if the instance has native fields and throw an exception if it does.
+  CheckForNativeFields(cls);
+
+  // Check if object is a closure that is serializable, if the object is a
+  // closure that is not serializable this will throw an exception.
+  RawFunction* func = IsSerializableClosure(cls, raw);
+  if (func != Function::null()) {
+    // Add object to the forward ref list and mark it so that future references
+    // to this object in the snapshot will use this object id. Mark it as having
+    // been serialized so that we do not serialize the object when we go through
+    // the forward list.
+    forward_list_.MarkAndAddObject(raw, kIsSerialized);
+    uword tags = raw->ptr()->tags_;
+    ASSERT(SerializedHeaderTag::decode(tags) == kObjectId);
+    intptr_t object_id = SerializedHeaderData::decode(tags);
+    tags = forward_list_.NodeForObjectId(object_id)->tags();
+    WriteStaticImplicitClosure(object_id, func, tags);
+    return;
+  }
 
   // Object is being referenced, add it to the forward ref list and mark
   // it so that future references to this object in the snapshot will use
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 9440e1a..a30b64e 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -347,6 +347,7 @@
   RawObject* AllocateUninitialized(intptr_t class_id, intptr_t size);
 
   RawClass* ReadClassId(intptr_t object_id);
+  RawObject* ReadStaticImplicitClosure(intptr_t object_id, intptr_t cls_header);
   RawObject* ReadObjectImpl();
   RawObject* ReadObjectImpl(intptr_t header);
   RawObject* ReadObjectRef();
@@ -611,6 +612,9 @@
 
   void WriteObjectRef(RawObject* raw);
   void WriteClassId(RawClass* cls);
+  void WriteStaticImplicitClosure(intptr_t object_id,
+                                  RawFunction* func,
+                                  intptr_t tags);
   void WriteObjectImpl(RawObject* raw);
   void WriteInlinedObject(RawObject* raw);
   void WriteForwardedObjects();
@@ -620,7 +624,9 @@
                     RawSmi* length,
                     RawTypeArguments* type_arguments,
                     RawObject* data[]);
-  void CheckIfSerializable(RawClass* cls);
+  RawFunction* IsSerializableClosure(RawClass* cls, RawObject* obj);
+  RawClass* GetFunctionOwner(RawFunction* func);
+  void CheckForNativeFields(RawClass* cls);
   void SetWriteException(Exceptions::ExceptionType type, const char* msg);
   void WriteInstance(intptr_t object_id,
                      RawObject* raw,
diff --git a/runtime/vm/snapshot_ids.h b/runtime/vm/snapshot_ids.h
index a7282f7..dc1500e 100644
--- a/runtime/vm/snapshot_ids.h
+++ b/runtime/vm/snapshot_ids.h
@@ -22,7 +22,7 @@
   // Object id has been optimized away; reader should use next available id.
   kOmittedObjectId,
 
-  kClassIdsOffset = kDoubleObject,
+  kClassIdsOffset = kOmittedObjectId,
 
   // The class ids of predefined classes are included in this list
   // at an offset of kClassIdsOffset.
@@ -42,6 +42,7 @@
   kArrayType,
 
   kInstanceObjectId,
+  kStaticImplicitClosureObjectId,
   kMaxPredefinedObjectIds,
   kInvalidIndex = -1,
 };
diff --git a/sdk/lib/_internal/compiler/js_lib/js_array.dart b/sdk/lib/_internal/compiler/js_lib/js_array.dart
index a170af2..981cbd2 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_array.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_array.dart
@@ -554,7 +554,7 @@
 
   Set<E> toSet() => new Set<E>.from(this);
 
-  Iterator<E> get iterator => new ListIterator<E>(this);
+  Iterator<E> get iterator => new ArrayIterator<E>(this);
 
   int get hashCode => Primitives.objectHashCode(this);
 
@@ -589,7 +589,47 @@
  * Dummy subclasses that allow the backend to track more precise
  * information about arrays through their type. The CPA type inference
  * relies on the fact that these classes do not override [] nor []=.
+ *
+ * These classes are really a fiction, and can have no methods, since
+ * getInterceptor always returns JSArray.  We should consider pushing the
+ * 'isGrowable' and 'isMutable' checks into the getInterceptor implementation so
+ * these classes can have specialized implementations. Doing so will challenge
+ * many assuptions in the JS backend.
  */
 class JSMutableArray<E> extends JSArray<E> implements JSMutableIndexable {}
 class JSFixedArray<E> extends JSMutableArray<E> {}
 class JSExtendableArray<E> extends JSMutableArray<E> {}
+
+
+/// An [Iterator] that iterates a JSArray.
+///
+class ArrayIterator<E> implements Iterator<E> {
+  final JSArray<E> _iterable;
+  final int _length;
+  int _index;
+  E _current;
+
+  ArrayIterator(JSArray<E> iterable)
+      : _iterable = iterable, _length = iterable.length, _index = 0;
+
+  E get current => _current;
+
+  bool moveNext() {
+    int length = _iterable.length;
+
+    // We have to do the length check even on fixed length Arrays.  If we can
+    // inline moveNext() we might be able to GVN the length and eliminate this
+    // check on known fixed length JSArray.
+    if (_length != length) {
+      throw new ConcurrentModificationError(_iterable);
+    }
+
+    if (_index >= length) {
+      _current = null;
+      return false;
+    }
+    _current = _iterable[_index];
+    _index++;
+    return true;
+  }
+}
diff --git a/tests/compiler/dart2js/async_await_js_transform_test.dart b/tests/compiler/dart2js/async_await_js_transform_test.dart
index ab94a56..c301f6a 100644
--- a/tests/compiler/dart2js/async_await_js_transform_test.dart
+++ b/tests/compiler/dart2js/async_await_js_transform_test.dart
@@ -82,7 +82,7 @@
     return 4;
   }""", """
 function(b) {
-  var __goto = 0, __completer = new Completer(), __returnValue, __handler = 2, __currentError, __next, __helper;
+  var __goto = 0, __completer = new Completer(), __returnValue, __handler = 2, __currentError, __next = [], __helper;
   function __body(__errorCode, __result) {
     if (__errorCode === 1) {
       __currentError = __result;
@@ -118,7 +118,7 @@
           case 13:
             // returning from await.
             __helper = __result;
-            __next = [12];
+            __next.push(12);
             // goto finally
             __goto = 11;
             break;
@@ -149,7 +149,7 @@
             // after while
           case 6:
             // break __outer
-            __next = [5];
+            __next.push(5);
             // goto finally
             __goto = 4;
             break;
@@ -708,7 +708,7 @@
 }
 """, """
 function(c, i) {
-  var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, __next, x, y, __error, __error1;
+  var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, __next = [], x, y, __error, __error1;
   function __body(__errorCode, __result) {
     if (__errorCode === 1) {
       __currentError = __result;
@@ -763,7 +763,7 @@
         case 15:
           // join
           x = __result;
-          __next = [13];
+          __next.push(13);
           // goto finally
           __goto = 12;
           break;
@@ -772,7 +772,7 @@
           __handler = 10;
           __error1 = __currentError;
           y.x = foo(__error1);
-          __next = [13];
+          __next.push(13);
           // goto finally
           __goto = 12;
           break;
diff --git a/tests/isolate/function_send1_test.dart b/tests/isolate/function_send1_test.dart
new file mode 100644
index 0000000..073ed76
--- /dev/null
+++ b/tests/isolate/function_send1_test.dart
@@ -0,0 +1,118 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:isolate";
+import "dart:async";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+void toplevel(port, message) { port.send("toplevel:$message"); }
+Function createFuncToplevel() => (p, m) { p.send(m); };
+class C {
+  Function initializer;
+  Function body;
+  C() : initializer = ((p, m) { throw "initializer"; }) {
+    body = (p, m) { throw "body"; };
+  }
+  static void staticFunc(port, message) { port.send("static:$message"); }
+  static Function createFuncStatic() => (p, m) { throw "static expr"; };
+  void instanceMethod(p, m) { throw "instanceMethod"; }
+  Function createFuncMember() => (p, m) { throw "instance expr"; };
+  void call(n, p) { throw "C"; }
+}
+
+class Callable {
+  void call(p, m) { p.send(["callable", m]); }
+}
+
+
+void main() {
+  asyncStart();
+
+  // top-level functions, static functions, closures, instance methods
+  // or function expressions are not sendable to an isolate spawned using
+  // spawnUri.
+  testUnsendable("toplevel", toplevel);
+  testUnsendable("static", C.staticFunc);
+  var c = new C();
+  testUnsendable("instance method", c.instanceMethod);
+  testUnsendable("static context expression", createFuncToplevel());
+  testUnsendable("static context expression", C.createFuncStatic());
+  testUnsendable("initializer context expression", c.initializer);
+  testUnsendable("constructor context expression", c.body);
+  testUnsendable("instance method context expression", c.createFuncMember());
+  testUnsendable("toplevel", toplevel.call);
+  testUnsendable("static", C.staticFunc.call);
+  testUnsendable("callable object", new Callable().call);
+
+  asyncEnd();
+  return;
+}
+
+// Create a receive port that expects exactly one message.
+// Pass the message to `callback` and return the sendPort.
+SendPort singleMessagePort(callback) {
+  var p;
+  p = new RawReceivePort((v) { p.close(); callback(v); });
+  return p.sendPort;
+}
+
+// A singleMessagePort that expects the message to be a specific value.
+SendPort expectMessagePort(message) {
+  asyncStart();
+  return singleMessagePort((v) {
+    Expect.equals(message, v);
+    asyncEnd();
+  });
+}
+
+// Creates a new isolate and a pair of ports that expect a single message
+// to be sent to the other isolate and back to the callback function.
+Future<SendPort> echoPort(callback(value)) {
+  Completer completer = new Completer<SendPort>();
+  SendPort replyPort = singleMessagePort(callback);
+  RawReceivePort initPort;
+  initPort = new RawReceivePort((p) {
+    completer.complete(p);
+    initPort.close();
+  });
+  return Isolate.spawn(_echo, [replyPort, initPort.sendPort])
+                .then((isolate) => completer.future);
+}
+
+void _echo(msg) {
+  var replyPort = msg[0];
+  RawReceivePort requestPort;
+  requestPort = new RawReceivePort((msg) {
+    replyPort.send(msg);
+    requestPort.close();  // Single echo only.
+  });
+  msg[1].send(requestPort.sendPort);
+}
+
+// Creates other isolate that waits for a single message, `msg`, on the returned
+// port, and executes it as `msg[0](msg[1],msg[2])` in the other isolate.
+Future<SendPort> callPort() {
+  Completer completer = new Completer<SendPort>();
+  SendPort initPort = singleMessagePort(completer.complete);
+  return Isolate.spawn(_call, initPort)
+                .then((_) => completer.future);
+}
+
+void _call(initPort) {
+  initPort.send(singleMessagePort(callFunc));
+}
+
+void testUnsendable(name, func) {
+  asyncStart();
+  Isolate.spawnUri(Uri.parse("function_send_test.dart"), [], func)
+    .then((v) => throw "allowed spawn direct?", onError: (e,s){ asyncEnd(); });
+  asyncStart();
+  Isolate.spawnUri(Uri.parse("function_send_test.dart"), [], [func])
+    .then((v) => throw "allowed spawn wrapped?", onError: (e,s){ asyncEnd(); });
+}
+
+void callFunc(message) {
+  message[0](message[1], message[2]);
+}
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 8f9e66f..30a218e 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -21,11 +21,9 @@
 handle_error_test: Fail   # Not implemented yet
 handle_error2_test: Fail  # Not implemented yet
 handle_error3_test: Fail  # Not implemented yet
-function_send_test: Fail   # Not implemented yet
 
 message3_test/constList_identical: RuntimeError # Issue 21816
 message3_test/constMap: RuntimeError  # Issue 21816
-message3_test/fun: RuntimeError  # Issue 21585
 message3_test/constInstance: RuntimeError # Issue 21816
 message3_test/byteBuffer: Crash # Issue 21818
 message3_test/int32x4: Crash # Issue 21818
@@ -53,6 +51,7 @@
 issue_21398_parent_isolate_test: SkipByDesign # Test uses a ".dart" URI.
 issue_21398_parent_isolate1_test: SkipByDesign # Test uses a ".dart" URI.
 issue_21398_parent_isolate2_test: SkipByDesign # Test uses a ".dart" URI.
+function_send1_test: SkipByDesign   # Test uses a ".dart" URI.
 message3_test/constList: RuntimeError # Issue 21817
 message3_test/constList_identical: RuntimeError # Issue 21817
 message3_test/constMap: RuntimeError  # Issue 21817
@@ -100,6 +99,7 @@
 spawn_uri_nested_vm_test: Skip # Issue 14479: This test is timing out.
 
 [ $compiler == none && ( $runtime == dartium || $runtime == drt || $runtime == ContentShellOnAndroid) ]
+message_enum_test: Fail, OK # Issue 13921 Dom isolates don't support spawnFunction
 compile_time_error_test/none: Fail, OK # Issue 13921 Dom isolates don't support spawnFunction
 isolate_import_test/none: Fail, OK # Issue 13921 Dom isolates don't support spawnFunction
 issue_21398_parent_isolate_test: Fail, OK # Issue 13921 Dom isolates don't support spawnFunction
@@ -112,6 +112,7 @@
 spawn_uri_missing_from_isolate_test: RuntimeError # Issue 17649
 spawn_uri_missing_test: SkipSlow # Times out.
 isolate_current_test: Fail, OK # Issue 13921 Dom isolates don't support spawnFunction
+function_send_test: Fail, OK  # 13921 Dom isolates don't support spawnFunction
 
 [ $compiler == dartanalyzer || $compiler == dart2analyzer ]
 browser/typed_data_message_test: StaticWarning
diff --git a/tests/language/async_throw_in_catch_test.dart b/tests/language/async_throw_in_catch_test.dart
index 1cb741e..b3ecbab 100644
--- a/tests/language/async_throw_in_catch_test.dart
+++ b/tests/language/async_throw_in_catch_test.dart
@@ -404,6 +404,40 @@
   tracer.trace("h");
 }
 
+foo17(Tracer tracer) async {
+  try {
+    tracer.trace("a");
+  } finally {
+    try {
+      tracer.trace("b");
+      throw "Error";
+    } catch (error) {
+      await new Future.value(3);  /// forceAwait: continued
+      Expect.equals("Error", error);
+      tracer.trace("c");
+    } finally {
+      tracer.trace("d");
+    }
+    tracer.trace("e");
+  }
+  tracer.trace("f");
+}
+
+foo18(Tracer tracer) async {
+  try {
+      tracer.trace("a");
+  } finally {
+    try {
+      tracer.trace("b");
+    } finally {
+      await new Future.value(3);  /// forceAwait: continued
+      tracer.trace("c");
+    }
+    tracer.trace("d");
+  }
+  tracer.trace("e");
+}
+
 runTest(expectedTrace, fun, [expectedError]) async {
   Tracer tracer = new Tracer(expectedTrace);
   try {
@@ -433,6 +467,8 @@
   await runTest("abcdefgX", foo14, "Error3");
   await runTest("abcdefg", foo15);
   await runTest("abcdfg", foo16);
+  await runTest("abcdef", foo17);
+  await runTest("abcde", foo18);
 }
 
 void main() {
diff --git a/tools/VERSION b/tools/VERSION
index 8c63f7d..9f2b03f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
 MINOR 9
 PATCH 0
 PRERELEASE 10
-PRERELEASE_PATCH 3
+PRERELEASE_PATCH 4