Version 1.3.0-dev.7.5

svn merge -c 34481 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 34484 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 34486 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

Use changes to trunk/dart/tests/language/language.status from https://codereview.chromium.org/216383004
cd trunk/dart
svn revert tests/language/language.status
wget -O diff https://codereview.chromium.org/download/issue216383004_1_10018.diff
patch -p0 < diff
rm diff

R=kasperl@google.com

Review URL: https://codereview.chromium.org//216633003

git-svn-id: http://dart.googlecode.com/svn/trunk@34497 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/lib/corelib_sources.gypi b/runtime/lib/corelib_sources.gypi
index 1b94b04..f5f68cf 100644
--- a/runtime/lib/corelib_sources.gypi
+++ b/runtime/lib/corelib_sources.gypi
@@ -34,6 +34,7 @@
     'integers_patch.dart',
     'invocation_mirror.h',
     'invocation_mirror_patch.dart',
+    'lib_prefix.dart',
     'map_patch.dart',
     'null_patch.dart',
     'object.cc',
diff --git a/runtime/lib/lib_prefix.dart b/runtime/lib/lib_prefix.dart
new file mode 100644
index 0000000..b1cac38
--- /dev/null
+++ b/runtime/lib/lib_prefix.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+import "dart:isolate";
+
+// This type corresponds to the VM-internal class LibraryPrefix.
+
+class _LibraryPrefix {
+  _load() native "LibraryPrefix_load";
+
+  loadLibrary() {
+    var completer = new Completer<bool>();
+    var port = new RawReceivePort();
+    port.handler = (_) {
+      this._load();
+      completer.complete(true);
+      port.close();
+    };
+    port.sendPort.send(1);
+    return completer.future;
+  }
+}
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 1162ab4..6da79b2 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -230,4 +230,12 @@
   return type.UserVisibleName();
 }
 
+
+DEFINE_NATIVE_ENTRY(LibraryPrefix_load, 1) {
+  const LibraryPrefix& prefix =
+      LibraryPrefix::CheckedHandle(arguments->NativeArgAt(0));
+  prefix.LoadLibrary();
+  return Bool::Get(true).raw();
+}
+
 }  // namespace dart
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 6a2bafd..e6038e0 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -347,6 +347,8 @@
   V(WeakProperty_getValue, 1)                                                  \
   V(WeakProperty_setValue, 2)                                                  \
   V(Uri_isWindowsPlatform, 0)                                                  \
+  V(LibraryPrefix_load, 1)                                                     \
+
 
 class BootstrapNatives : public AllStatic {
  public:
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 0d1e38e..8ffa3ce 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -579,6 +579,14 @@
           function.SetCode(code);
           ASSERT(CodePatcher::CodeIsPatchable(code));
         }
+        if (parsed_function->HasDeferredPrefixes()) {
+          GrowableObjectArray* prefixes = parsed_function->DeferredPrefixes();
+          LibraryPrefix& prefix = LibraryPrefix::Handle();
+          for (intptr_t i = 0; i < prefixes->Length(); i++) {
+            prefix ^= prefixes->At(i);
+            prefix.RegisterDependentCode(code);
+          }
+        }
       }
       is_compiled = true;
       done = true;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 28f5fd7..7848d34 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -4492,7 +4492,7 @@
     if (!library_prefix.IsNull()) {
       library_prefix.AddImport(import_ns);
     } else {
-      library_prefix = LibraryPrefix::New(prefix_symbol, import_ns);
+      library_prefix = LibraryPrefix::New(prefix_symbol, import_ns, false);
       library_vm.AddObject(library_prefix, prefix_symbol);
     }
   }
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 7fb08c8..771e6e8 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -125,7 +125,6 @@
 RawClass* Object::token_stream_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::script_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::library_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
-RawClass* Object::library_prefix_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::namespace_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::code_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::instructions_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
@@ -569,9 +568,6 @@
   cls = Class::New<Library>();
   library_class_ = cls.raw();
 
-  cls = Class::New<LibraryPrefix>();
-  library_prefix_class_ = cls.raw();
-
   cls = Class::New<Namespace>();
   namespace_class_ = cls.raw();
 
@@ -770,7 +766,6 @@
   SET_CLASS_NAME(token_stream, TokenStream);
   SET_CLASS_NAME(script, Script);
   SET_CLASS_NAME(library, LibraryClass);
-  SET_CLASS_NAME(library_prefix, LibraryPrefix);
   SET_CLASS_NAME(namespace, Namespace);
   SET_CLASS_NAME(code, Code);
   SET_CLASS_NAME(instructions, Instructions);
@@ -945,6 +940,9 @@
   cls = Class::New<MixinAppType>();
   object_store->set_mixin_app_type_class(cls);
 
+  cls = Class::New<LibraryPrefix>();
+  object_store->set_library_prefix_class(cls);
+
   // Pre-allocate the OneByteString class needed by the symbol table.
   cls = Class::NewStringClass(kOneByteStringCid);
   object_store->set_one_byte_string_class(cls);
@@ -1063,6 +1061,11 @@
   RegisterClass(cls, Symbols::Null(), core_lib);
   pending_classes.Add(cls);
 
+  cls = object_store->library_prefix_class();
+  ASSERT(!cls.IsNull());
+  RegisterPrivateClass(cls, Symbols::_LibraryPrefix(), core_lib);
+  pending_classes.Add(cls);
+
   cls = object_store->type_class();
   RegisterPrivateClass(cls, Symbols::Type(), core_lib);
   pending_classes.Add(cls);
@@ -1337,6 +1340,9 @@
   cls = Class::New<Instance>(kInstanceCid);
   object_store->set_object_class(cls);
 
+  cls = Class::New<LibraryPrefix>();
+  object_store->set_library_prefix_class(cls);
+
   cls = Class::New<Type>();
   object_store->set_type_class(cls);
 
@@ -2443,9 +2449,12 @@
       function ^= code.function();
       // If function uses dependent code switch it to unoptimized.
       if (function.CurrentCode() == code.raw()) {
-        ASSERT(function.HasOptimizedCode());
         ReportSwitchingCode(code);
-        function.SwitchToUnoptimizedCode();
+        if (code.is_optimized()) {
+          function.SwitchToUnoptimizedCode();
+        } else {
+          function.ClearCode();
+        }
       }
     }
   }
@@ -9113,6 +9122,9 @@
 void LibraryPrefix::AddImport(const Namespace& import) const {
   intptr_t num_current_imports = num_imports();
 
+  // Prefixes with deferred libraries can only contain one library.
+  ASSERT((num_current_imports == 0) || !is_deferred_load());
+
   // The library needs to be added to the list.
   Array& imports = Array::Handle(this->imports());
   const intptr_t length = (imports.IsNull()) ? 0 : imports.Length();
@@ -9128,6 +9140,9 @@
 
 
 RawObject* LibraryPrefix::LookupObject(const String& name) const {
+  if (!is_loaded()) {
+    return Object::null();
+  }
   Array& imports = Array::Handle(this->imports());
   Object& obj = Object::Handle();
   Namespace& import = Namespace::Handle();
@@ -9174,8 +9189,81 @@
 }
 
 
+void LibraryPrefix::set_is_loaded() const {
+  raw_ptr()->is_loaded_ = true;
+}
+
+
+void LibraryPrefix::LoadLibrary() const {
+  // Non-deferred prefixes are loaded.
+  ASSERT(is_deferred_load() || is_loaded());
+  if (is_loaded()) {
+    return;
+  }
+  InvalidateDependentCode();
+  set_is_loaded();
+}
+
+
+RawArray* LibraryPrefix::dependent_code() const {
+  return raw_ptr()->dependent_code_;
+}
+
+
+void LibraryPrefix::set_dependent_code(const Array& array) const {
+  StorePointer(&raw_ptr()->dependent_code_, array.raw());
+}
+
+
+class PrefixDependentArray : public WeakCodeReferences {
+ public:
+  explicit PrefixDependentArray(const LibraryPrefix& prefix)
+      : WeakCodeReferences(Array::Handle(prefix.dependent_code())),
+                           prefix_(prefix) {}
+
+  virtual void UpdateArrayTo(const Array& value) {
+    prefix_.set_dependent_code(value);
+  }
+
+  virtual void ReportDeoptimization(const Code& code) {
+    // This gets called when the code object is on the stack
+    // while nuking code that depends on a prefix. We don't expect
+    // this to happen, so make sure we die loudly if we find
+    // ourselves here.
+    UNIMPLEMENTED();
+  }
+
+  virtual void ReportSwitchingCode(const Code& code) {
+    if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+      OS::PrintErr("Prefix '%s': deleting code for function '%s'\n",
+        String::Handle(prefix_.name()).ToCString(),
+        Function::Handle(code.function()).ToCString());
+    }
+  }
+
+ private:
+  const LibraryPrefix& prefix_;
+  DISALLOW_COPY_AND_ASSIGN(PrefixDependentArray);
+};
+
+
+void LibraryPrefix::RegisterDependentCode(const Code& code) const {
+  ASSERT(is_deferred_load());
+  ASSERT(!is_loaded());
+  PrefixDependentArray a(*this);
+  a.Register(code);
+}
+
+
+void LibraryPrefix::InvalidateDependentCode() const {
+  PrefixDependentArray a(*this);
+  a.DisableCode();
+}
+
+
 RawLibraryPrefix* LibraryPrefix::New() {
-  ASSERT(Object::library_prefix_class() != Class::null());
+  ASSERT(Isolate::Current()->object_store()->library_prefix_class() !=
+      Class::null());
   RawObject* raw = Object::Allocate(LibraryPrefix::kClassId,
                                     LibraryPrefix::InstanceSize(),
                                     Heap::kOld);
@@ -9184,12 +9272,16 @@
 
 
 RawLibraryPrefix* LibraryPrefix::New(const String& name,
-                                     const Namespace& import) {
+                                     const Namespace& import,
+                                     bool deferred_load) {
   const LibraryPrefix& result = LibraryPrefix::Handle(LibraryPrefix::New());
   result.set_name(name);
   result.set_num_imports(0);
+  result.raw_ptr()->is_deferred_load_ = deferred_load;
+  result.raw_ptr()->is_loaded_ = !deferred_load;
   result.set_imports(Array::Handle(Array::New(kInitialSize)));
   result.AddImport(import);
+  result.set_dependent_code(Object::null_array());
   return result.raw();
 }
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 0789c0e..9d6d35a 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -447,7 +447,6 @@
   static RawClass* token_stream_class() { return token_stream_class_; }
   static RawClass* script_class() { return script_class_; }
   static RawClass* library_class() { return library_class_; }
-  static RawClass* library_prefix_class() { return library_prefix_class_; }
   static RawClass* namespace_class() { return namespace_class_; }
   static RawClass* code_class() { return code_class_; }
   static RawClass* instructions_class() { return instructions_class_; }
@@ -598,7 +597,6 @@
   static RawClass* token_stream_class_;  // Class of the TokenStream vm object.
   static RawClass* script_class_;  // Class of the Script vm object.
   static RawClass* library_class_;  // Class of the Library vm object.
-  static RawClass* library_prefix_class_;  // Class of Library prefix vm object.
   static RawClass* namespace_class_;  // Class of Namespace vm object.
   static RawClass* code_class_;  // Class of the Code vm object.
   static RawClass* instructions_class_;  // Class of the Instructions vm object.
@@ -2707,41 +2705,6 @@
 };
 
 
-class LibraryPrefix : public Object {
- public:
-  RawString* name() const { return raw_ptr()->name_; }
-  virtual RawString* DictionaryName() const { return name(); }
-
-  RawArray* imports() const { return raw_ptr()->imports_; }
-  intptr_t num_imports() const { return raw_ptr()->num_imports_; }
-
-  bool ContainsLibrary(const Library& library) const;
-  RawLibrary* GetLibrary(int index) const;
-  void AddImport(const Namespace& import) const;
-  RawObject* LookupObject(const String& name) const;
-  RawClass* LookupClass(const String& class_name) const;
-
-  static intptr_t InstanceSize() {
-    return RoundedAllocationSize(sizeof(RawLibraryPrefix));
-  }
-
-  static RawLibraryPrefix* New(const String& name, const Namespace& import);
-
- private:
-  static const int kInitialSize = 2;
-  static const int kIncrementSize = 2;
-
-  void set_name(const String& value) const;
-  void set_imports(const Array& value) const;
-  void set_num_imports(intptr_t value) const;
-
-  static RawLibraryPrefix* New();
-
-  FINAL_HEAP_OBJECT_IMPLEMENTATION(LibraryPrefix, Object);
-  friend class Class;
-};
-
-
 // A Namespace contains the names in a library dictionary, filtered by
 // the show/hide combinators.
 class Namespace : public Object {
@@ -4106,6 +4069,58 @@
 };
 
 
+class LibraryPrefix : public Instance {
+ public:
+  RawString* name() const { return raw_ptr()->name_; }
+  virtual RawString* DictionaryName() const { return name(); }
+
+  RawArray* imports() const { return raw_ptr()->imports_; }
+  intptr_t num_imports() const { return raw_ptr()->num_imports_; }
+
+  bool ContainsLibrary(const Library& library) const;
+  RawLibrary* GetLibrary(int index) const;
+  void AddImport(const Namespace& import) const;
+  RawObject* LookupObject(const String& name) const;
+  RawClass* LookupClass(const String& class_name) const;
+
+  bool is_deferred_load() const { return raw_ptr()->is_deferred_load_; }
+  bool is_loaded() const { return raw_ptr()->is_loaded_; }
+  void LoadLibrary() const;
+
+  // Return the list of code objects that were compiled when this
+  // prefix was not yet loaded. These code objects will be invalidated
+  // when the prefix is loaded.
+  RawArray* dependent_code() const;
+  void set_dependent_code(const Array& array) const;
+
+  // Add the given code object to the list of dependent ones.
+  void RegisterDependentCode(const Code& code) const;
+  void InvalidateDependentCode() const;
+
+  static intptr_t InstanceSize() {
+    return RoundedAllocationSize(sizeof(RawLibraryPrefix));
+  }
+
+  static RawLibraryPrefix* New(const String& name,
+                               const Namespace& import,
+                               bool deferred_load);
+
+ private:
+  static const int kInitialSize = 2;
+  static const int kIncrementSize = 2;
+
+  void set_name(const String& value) const;
+  void set_imports(const Array& value) const;
+  void set_num_imports(intptr_t value) const;
+  void set_is_loaded() const;
+
+  static RawLibraryPrefix* New();
+
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(LibraryPrefix, Instance);
+  friend class Class;
+};
+
+
 // AbstractType is an abstract superclass.
 // Subclasses of AbstractType are Type and TypeParameter.
 class AbstractType : public Instance {
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index c8a046c..bc9e326 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -21,6 +21,7 @@
     null_type_(Type::null()),
     function_type_(Type::null()),
     function_impl_type_(Type::null()),
+    library_prefix_class_(Class::null()),
     type_class_(Class::null()),
     number_type_(Type::null()),
     int_type_(Type::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index b5f022a..3656235 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -69,6 +69,11 @@
     function_impl_type_ = value.raw();
   }
 
+  RawClass* library_prefix_class() const { return library_prefix_class_; }
+  void set_library_prefix_class(const Class& value) {
+    library_prefix_class_ = value.raw();
+  }
+
   RawClass* type_class() const { return type_class_; }
   void set_type_class(const Class& value) { type_class_ = value.raw(); }
 
@@ -431,6 +436,7 @@
   RawType* null_type_;
   RawType* function_type_;
   RawType* function_impl_type_;
+  RawClass* library_prefix_class_;
   RawClass* type_class_;
   RawClass* type_ref_class_;
   RawClass* type_parameter_class_;
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 797b523..88f4b3c 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -127,6 +127,22 @@
 }
 
 
+void ParsedFunction::AddDeferredPrefix(const LibraryPrefix& prefix) {
+  ASSERT(prefix.is_deferred_load());
+  ASSERT(!prefix.is_loaded());
+  if (deferred_prefixes_ == NULL) {
+    deferred_prefixes_ =
+        &GrowableObjectArray::ZoneHandle(GrowableObjectArray::New());
+  }
+  for (intptr_t i = 0; i < deferred_prefixes_->Length(); i++) {
+    if (deferred_prefixes_->At(i) == prefix.raw()) {
+      return;
+    }
+  }
+  deferred_prefixes_->Add(prefix);
+}
+
+
 void ParsedFunction::AllocateVariables() {
   LocalScope* scope = node_sequence()->scope();
   const intptr_t num_fixed_params = function().num_fixed_parameters();
@@ -4945,19 +4961,32 @@
   if (url.Length() == 0) {
     ErrorMsg("library url expected");
   }
+  bool is_deferred_import = false;
+  if (is_import && (IsLiteral("deferred"))) {
+    is_deferred_import = true;
+    ConsumeToken();
+    CheckToken(Token::kAS, "'as' expected");
+  }
   String& prefix = String::Handle();
+  intptr_t prefix_pos = 0;
   if (is_import && (CurrentToken() == Token::kAS)) {
     ConsumeToken();
+    prefix_pos = TokenPos();
     prefix = ExpectIdentifier("prefix identifier expected")->raw();
   }
 
   Array& show_names = Array::Handle();
   Array& hide_names = Array::Handle();
-  if (IsLiteral("show") || IsLiteral("hide")) {
+  if (is_deferred_import || IsLiteral("show") || IsLiteral("hide")) {
     GrowableObjectArray& show_list =
         GrowableObjectArray::Handle(GrowableObjectArray::New());
     GrowableObjectArray& hide_list =
         GrowableObjectArray::Handle(GrowableObjectArray::New());
+    // Libraries imported through deferred import automatically hide
+    // the name 'loadLibrary'.
+    if (is_deferred_import) {
+      hide_list.Add(Symbols::LoadLibrary());
+    }
     for (;;) {
       if (IsLiteral("show")) {
         ConsumeToken();
@@ -4985,6 +5014,7 @@
   Library& library = Library::Handle(Library::LookupLibrary(canon_url));
   if (library.IsNull()) {
     // Call the library tag handler to load the library.
+    // TODO(hausner): do not load eagerly if import is deferred.
     CallLibraryTagHandler(Dart_kImportTag, import_pos, canon_url);
     // If the library tag handler succeded without registering the
     // library we create an empty library to import.
@@ -5010,14 +5040,25 @@
       ErrorMsg(import_pos, "private library is not accessible");
     }
     if (prefix.IsNull() || (prefix.Length() == 0)) {
+      ASSERT(!is_deferred_import);
       library_.AddImport(ns);
     } else {
       LibraryPrefix& library_prefix = LibraryPrefix::Handle();
       library_prefix = library_.LookupLocalLibraryPrefix(prefix);
       if (!library_prefix.IsNull()) {
+        // Check that prefix names of deferred import clauses are
+        // unique.
+        if (!is_deferred_import && library_prefix.is_deferred_load()) {
+          ErrorMsg(prefix_pos,
+                   "prefix '%s' already used in a deferred import clause",
+                   prefix.ToCString());
+        }
+        if (is_deferred_import) {
+          ErrorMsg(prefix_pos, "prefix of deferred import must be uniqe");
+        }
         library_prefix.AddImport(ns);
       } else {
-        library_prefix = LibraryPrefix::New(prefix, ns);
+        library_prefix = LibraryPrefix::New(prefix, ns, is_deferred_import);
         library_.AddObject(library_prefix, prefix);
       }
     }
@@ -9196,14 +9237,17 @@
                                            const String& ident) {
   TRACE_PARSER("ResolveIdentInPrefixScope");
   HANDLESCOPE(isolate());
-  Object& obj = Object::Handle(prefix.LookupObject(ident));
+  Object& obj = Object::Handle();
+  if (prefix.is_loaded()) {
+    obj = prefix.LookupObject(ident);
+  } else {
+    // Remember that this function depends on an import prefix of an
+    // unloaded deferred library.
+    parsed_function()->AddDeferredPrefix(prefix);
+  }
   if (obj.IsNull()) {
     // Unresolved prefixed primary identifier.
-    String& qualified_name = String::ZoneHandle(prefix.name());
-    qualified_name = String::Concat(qualified_name, Symbols::Dot());
-    qualified_name = String::Concat(qualified_name, ident);
-    qualified_name = Symbols::New(qualified_name);
-    return new PrimaryNode(ident_pos, qualified_name);
+    return NULL;
   } else if (obj.IsClass()) {
     const Class& cls = Class::Cast(obj);
     return new PrimaryNode(ident_pos, Class::ZoneHandle(cls.raw()));
@@ -9311,7 +9355,8 @@
 // Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and
 // finalize it according to the given type finalization mode.
 RawAbstractType* Parser::ParseType(
-    ClassFinalizer::FinalizationKind finalization) {
+    ClassFinalizer::FinalizationKind finalization,
+    bool allow_deferred_type) {
   TRACE_PARSER("ParseType");
   CheckToken(Token::kIDENT, "type name expected");
   QualIdent type_name;
@@ -9337,6 +9382,18 @@
           "using '%s' in this context is invalid",
           type_name.ident->ToCString());
     }
+    if ((type_name.lib_prefix != NULL) &&
+        type_name.lib_prefix->is_deferred_load() &&
+        !allow_deferred_type) {
+      ParseTypeArguments(ClassFinalizer::kIgnore);
+      return ClassFinalizer::NewFinalizedMalformedType(
+          Error::Handle(),  // No previous error.
+          script_,
+          type_name.ident_pos,
+          "using deferred type '%s.%s' is invalid",
+          String::Handle(type_name.lib_prefix->name()).ToCString(),
+          type_name.ident->ToCString());
+    }
   }
   Object& type_class = Object::Handle(isolate());
   // Leave type_class as null if type finalization mode is kIgnore.
@@ -9895,8 +9952,10 @@
     ErrorMsg("type name expected");
   }
   intptr_t type_pos = TokenPos();
+  // Can't allocate const objects of a deferred type.
+  const bool allow_deferred_type = !is_const;
   AbstractType& type = AbstractType::Handle(
-      ParseType(ClassFinalizer::kCanonicalizeWellFormed));
+      ParseType(ClassFinalizer::kCanonicalizeWellFormed, allow_deferred_type));
   // In case the type is malformed, throw a dynamic type error after finishing
   // parsing the instance creation expression.
   if (!type.IsMalformed() && (type.IsTypeParameter() || type.IsDynamicType())) {
@@ -10282,6 +10341,7 @@
     CloseBlock();
   } else if (IsIdentifier()) {
     QualIdent qual_ident;
+    intptr_t qual_ident_pos = TokenPos();
     ParseQualIdent(&qual_ident);
     if (qual_ident.lib_prefix == NULL) {
       if (!ResolveIdentInLocalScope(qual_ident.ident_pos,
@@ -10312,30 +10372,42 @@
       // Note: unlike in the case of an unqualified identifier, do not
       // interpret the unresolved identifier as an instance method or
       // instance getter call when compiling an instance method.
-      // TODO(hausner): Ideally we should generate the NoSuchMethodError
-      // later, when we know more about how the unresolved name is used.
-      // For example, we don't know yet whether the unresolved name
-      // refers to a getter or a setter. However, it is more awkward
-      // to distinuish four NoSuchMethodError cases all over the place
-      // in the parser. The four cases are: prefixed vs non-prefixed
-      // name, static vs dynamic context in which the unresolved name
-      // is used. We cheat a little here by looking at the next token
-      // to determine whether we have an unresolved method call or
-      // field access.
-      if (primary->IsPrimaryNode() &&
-          primary->AsPrimaryNode()->primary().IsString()) {
-        InvocationMirror::Type call_type =
-            CurrentToken() == Token::kLPAREN ?
-               InvocationMirror::kMethod : InvocationMirror::kGetter;
-        const String& unresolved_name =
-            String::Cast(primary->AsPrimaryNode()->primary());
-        primary = ThrowNoSuchMethodError(primary->token_pos(),
-                                        current_class(),
-                                        unresolved_name,
-                                        NULL,  // No arguments.
-                                        InvocationMirror::kTopLevel,
-                                        call_type,
-                                        NULL);  // No existing function.
+      if (primary == NULL) {
+        if (qual_ident.lib_prefix->is_deferred_load() &&
+            qual_ident.ident->Equals(Symbols::LoadLibrary())) {
+          // Hack Alert: recognize special 'loadLibrary' call on the
+          // prefix object. The prefix is the primary. Rewind parser and
+          // let ParseSelectors() handle the loadLibrary call.
+          SetPosition(qual_ident_pos);
+          ConsumeToken();  // Prefix name.
+          primary = new LiteralNode(qual_ident_pos, *qual_ident.lib_prefix);
+        } else {
+          // TODO(hausner): Ideally we should generate the NoSuchMethodError
+          // later, when we know more about how the unresolved name is used.
+          // For example, we don't know yet whether the unresolved name
+          // refers to a getter or a setter. However, it is more awkward
+          // to distinuish four NoSuchMethodError cases all over the place
+          // in the parser. The four cases are: prefixed vs non-prefixed
+          // name, static vs dynamic context in which the unresolved name
+          // is used. We cheat a little here by looking at the next token
+          // to determine whether we have an unresolved method call or
+          // field access.
+          String& qualified_name =
+              String::ZoneHandle(qual_ident.lib_prefix->name());
+          qualified_name = String::Concat(qualified_name, Symbols::Dot());
+          qualified_name = String::Concat(qualified_name, *qual_ident.ident);
+          qualified_name = Symbols::New(qualified_name);
+          InvocationMirror::Type call_type =
+              CurrentToken() == Token::kLPAREN ?
+                  InvocationMirror::kMethod : InvocationMirror::kGetter;
+          primary = ThrowNoSuchMethodError(qual_ident_pos,
+                                           current_class(),
+                                           qualified_name,
+                                           NULL,  // No arguments.
+                                           InvocationMirror::kTopLevel,
+                                           call_type,
+                                           NULL);  // No existing function.
+        }
       }
     }
     ASSERT(primary != NULL);
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 8760eab..587444a 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -47,6 +47,7 @@
         saved_current_context_var_(NULL),
         saved_entry_context_var_(NULL),
         expression_temp_var_(NULL),
+        deferred_prefixes_(NULL),
         first_parameter_index_(0),
         first_stack_local_index_(0),
         num_copied_params_(0),
@@ -108,6 +109,10 @@
   static LocalVariable* CreateExpressionTempVar(intptr_t token_pos);
   LocalVariable* EnsureExpressionTemp();
 
+  bool HasDeferredPrefixes() const { return deferred_prefixes_ != NULL; }
+  GrowableObjectArray* DeferredPrefixes() const { return deferred_prefixes_; }
+  void AddDeferredPrefix(const LibraryPrefix& prefix);
+
   int first_parameter_index() const { return first_parameter_index_; }
   int first_stack_local_index() const { return first_stack_local_index_; }
   int num_copied_params() const { return num_copied_params_; }
@@ -124,6 +129,7 @@
   LocalVariable* saved_current_context_var_;
   LocalVariable* saved_entry_context_var_;
   LocalVariable* expression_temp_var_;
+  GrowableObjectArray* deferred_prefixes_;
 
   int first_parameter_index_;
   int first_stack_local_index_;
@@ -356,7 +362,8 @@
   void ResolveTypeFromClass(const Class& cls,
                             ClassFinalizer::FinalizationKind finalization,
                             AbstractType* type);
-  RawAbstractType* ParseType(ClassFinalizer::FinalizationKind finalization);
+  RawAbstractType* ParseType(ClassFinalizer::FinalizationKind finalization,
+                             bool allow_deferred_type = false);
   void ParseTypeParameters(const Class& cls);
   RawTypeArguments* ParseTypeArguments(
       ClassFinalizer::FinalizationKind finalization);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index fcb27ab..5ba26e8 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -26,7 +26,6 @@
   V(TokenStream)                                                               \
   V(Script)                                                                    \
   V(Library)                                                                   \
-  V(LibraryPrefix)                                                             \
   V(Namespace)                                                                 \
   V(Code)                                                                      \
   V(Instructions)                                                              \
@@ -46,6 +45,7 @@
     V(UnhandledException)                                                      \
     V(UnwindError)                                                             \
   V(Instance)                                                                  \
+    V(LibraryPrefix)                                                           \
     V(AbstractType)                                                            \
       V(Type)                                                                  \
       V(TypeRef)                                                               \
@@ -782,19 +782,6 @@
 };
 
 
-class RawLibraryPrefix : public RawObject {
-  RAW_HEAP_OBJECT_IMPLEMENTATION(LibraryPrefix);
-
-  RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->name_); }
-  RawString* name_;               // library prefix name.
-  RawArray* imports_;             // libraries imported with this prefix.
-  RawObject** to() {
-    return reinterpret_cast<RawObject**>(&ptr()->imports_);
-  }
-  intptr_t num_imports_;          // Number of library entries in libraries_.
-};
-
-
 class RawNamespace : public RawObject {
   RAW_HEAP_OBJECT_IMPLEMENTATION(Namespace);
 
@@ -1136,6 +1123,23 @@
 };
 
 
+class RawLibraryPrefix : public RawInstance {
+  RAW_HEAP_OBJECT_IMPLEMENTATION(LibraryPrefix);
+
+  RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->name_); }
+  RawString* name_;               // Library prefix name.
+  RawArray* imports_;             // Libraries imported with this prefix.
+  RawArray* dependent_code_;      // Code that refers to deferred, unloaded
+                                  // library prefix.
+  RawObject** to() {
+    return reinterpret_cast<RawObject**>(&ptr()->dependent_code_);
+  }
+  intptr_t num_imports_;          // Number of library entries in libraries_.
+  bool is_deferred_load_;
+  bool is_loaded_;
+};
+
+
 class RawAbstractType : public RawInstance {
  protected:
   enum TypeState {
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index e917e67..db45e58 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1094,6 +1094,8 @@
 
   // Set all non object fields.
   prefix.raw_ptr()->num_imports_ = reader->ReadIntptrValue();
+  prefix.raw_ptr()->is_deferred_load_ = reader->Read<bool>();
+  prefix.raw_ptr()->is_loaded_ = reader->Read<bool>();
 
   // Set all the object fields.
   // TODO(5411462): Need to assert No GC can happen here, even though
@@ -1119,11 +1121,13 @@
   writer->WriteInlinedObjectHeader(object_id);
 
   // Write out the class and tags information.
-  writer->WriteVMIsolateObject(kLibraryPrefixCid);
+  writer->WriteIndexedObject(kLibraryPrefixCid);
   writer->WriteIntptrValue(writer->GetObjectTags(this));
 
   // Write out all non object fields.
   writer->WriteIntptrValue(ptr()->num_imports_);
+  writer->Write<bool>(ptr()->is_deferred_load_);
+  writer->Write<bool>(ptr()->is_loaded_);
 
   // Write out all the object pointer fields.
   SnapshotWriterVisitor visitor(writer);
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 29d9792..8c0a49e 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -598,7 +598,7 @@
 
 
 RawLibraryPrefix* SnapshotReader::NewLibraryPrefix() {
-  ALLOC_NEW_OBJECT(LibraryPrefix, Object::library_prefix_class());
+  ALLOC_NEW_OBJECT(LibraryPrefix, object_store()->library_prefix_class());
 }
 
 
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index df5679d..865c77e 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -66,6 +66,8 @@
   V(ClosureFunctionField, ":function")                                         \
   V(ClosureContextField, ":context")                                           \
   V(Library, "library")                                                        \
+  V(LoadLibrary, "loadLibrary")                                                \
+  V(_LibraryPrefix, "_LibraryPrefix")                                          \
   V(Native, "native")                                                          \
   V(Import, "import")                                                          \
   V(Source, "source")                                                          \
diff --git a/tests/language/deferred_constraints_type_annotation_test.dart b/tests/language/deferred_constraints_type_annotation_test.dart
index 3fbc238..043f85c 100644
--- a/tests/language/deferred_constraints_type_annotation_test.dart
+++ b/tests/language/deferred_constraints_type_annotation_test.dart
@@ -15,7 +15,7 @@
   lib.C a = null; /// type_annotation_null: static type warning
   Expect.throws(() { /// new_before_load: static type warning
     lib.C a = new lib.C(); /// new_before_load: continued
-  }, (e) => e is NoSuchMethodError); /// new_before_load: continued
+  }, (e) => e is Error); /// new_before_load: continued
 
   // In this case we do not defer C.
   lib2.C a1 = new lib2.C(); /// type_annotation_non_deferred: continued
diff --git a/tests/language/language.status b/tests/language/language.status
index 8d12238..d505b7d 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -21,16 +21,17 @@
 mixin_forwarding_constructor2_test: Fail # Issue 13641
 
 # Issue 17521
-deferred_constraints_constants_test/*: Fail, Pass
-deferred_constraints_type_annotation_test/*: Fail, Pass
-deferred_shadow_load_library_test: Fail
-deferred_closurize_load_library_test: Fail
-deferred_constraints_type_annotation_old_syntax_test/as_operation: Fail
-deferred_constraints_type_annotation_old_syntax_test/is_check: Fail
-deferred_constraints_type_annotation_old_syntax_test/catch_check: Fail
-deferred_constraints_type_annotation_old_syntax_test/new_before_load: Fail
+deferred_constraints_constants_test/default_argument2: Fail
+deferred_constraints_constants_test/metadata1: Fail
+deferred_constraints_constants_test/metadata3: Fail
+deferred_constraints_constants_test/metadata2: Fail
+
 
 # These test use the old syntax, and will be phased out.
+deferred_constraints_type_annotation_old_syntax_test/as_operation: Fail, Ok
+deferred_constraints_type_annotation_old_syntax_test/is_check: Fail, Ok
+deferred_constraints_type_annotation_old_syntax_test/catch_check: Fail, Ok
+deferred_constraints_type_annotation_old_syntax_test/new_before_load: Fail, Ok
 deferred_constraints_constants_old_syntax_test/reference1: Fail, Ok
 deferred_constraints_constants_old_syntax_test/reference2: Fail, Ok
 deferred_constraints_constants_old_syntax_test/metadata1: Fail, Ok
@@ -41,8 +42,12 @@
 deferred_constraints_constants_old_syntax_test/constructor1: Fail, Ok
 deferred_constraints_constants_old_syntax_test/constructor2: Fail, Ok
 
-[ ($compiler == none || $compiler == dart2dart)]
-# Issue 17521, 17523
+cyclic_type_test: Fail, Pass # Issue 17629
+cyclic_type2_test: Fail, Pass # Issue 17629
+least_upper_bound_expansive_test/*: Fail, Pass # Issue 17629
+
+[ ($compiler == dart2dart)]
+# Issue 17523
 deferred_constraints_type_annotation_test/as_operation: Fail
 deferred_constraints_type_annotation_test/is_check: Fail
 deferred_constraints_type_annotation_test/catch_check: Fail
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index ae0a1d3..4d091a2 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -250,7 +250,6 @@
 mirrors/mixin_application_test/01: Fail, OK # TODO(ahe): Slight broken test to ensure test coverage on dart2js.
 mirrors/intercepted_object_test: Fail, OK # TODO(ahe): Slight broken test to ensure test coverage on dart2js.
 mirrors/typedef_test/01: Fail, OK # Incorrect dart2js behavior.
-mirrors/deferred_mirrors_metadata_test: Fail # Issue 17521
 
 mirrors/generic_local_function_test: RuntimeError # Issue 14913
 mirrors/symbol_validation_test: RuntimeError # Issue 13596
diff --git a/tests/standalone/issue14236_source.dart b/tests/standalone/issue14236_source.dart
index a422cae..3182e48 100644
--- a/tests/standalone/issue14236_source.dart
+++ b/tests/standalone/issue14236_source.dart
@@ -7,8 +7,8 @@
 // The original test/main has been commented out and we have a test/main which
 // throws an error to ensure that this file is not executed as part of the
 // test.
-// 
-// When issue14236_test.dart fails, you must regenerate it using the VM 
+//
+// When issue14236_test.dart fails, you must regenerate it using the VM
 // with your changes. You should understand what in your change makes
 // regeneration of the snapshot necessary.
 // Steps for regenerating:
@@ -28,7 +28,7 @@
 }
 */
 
-test() {
+test(dummy) {
   Expect.fail("Don't expect this to run at all");
 }
 
diff --git a/tests/standalone/issue14236_test.dart b/tests/standalone/issue14236_test.dart
index cb41800..b837d0b 100644
--- a/tests/standalone/issue14236_test.dart
+++ b/tests/standalone/issue14236_test.dart
Binary files differ
diff --git a/tools/VERSION b/tools/VERSION
index c151c3b..c121fd1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
 MINOR 3
 PATCH 0
 PRERELEASE 7
-PRERELEASE_PATCH 4
+PRERELEASE_PATCH 5