[vm] Support Dart metadata on libraries and library dependencies in Dart 2 mode

Fixes https://github.com/dart-lang/sdk/issues/33774

Change-Id: I0b34cdf2bee099076e29bec6cfb849b0b250f690
Reviewed-on: https://dart-review.googlesource.com/64245
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 9770a26..46dba1a 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -7283,26 +7283,34 @@
   return metadata_values.raw();
 }
 
-RawObject* StreamingFlowGraphBuilder::EvaluateMetadata(intptr_t kernel_offset) {
+RawObject* StreamingFlowGraphBuilder::EvaluateMetadata(
+    intptr_t kernel_offset,
+    bool is_annotations_offset) {
   SetOffset(kernel_offset);
-  const Tag tag = PeekTag();
 
   ASSERT(active_class() != NULL);
 
-  if (tag == kClass) {
-    ClassHelper class_helper(this);
-    class_helper.ReadUntilExcluding(ClassHelper::kAnnotations);
-  } else if (tag == kProcedure) {
-    ProcedureHelper procedure_helper(this);
-    procedure_helper.ReadUntilExcluding(ProcedureHelper::kAnnotations);
-  } else if (tag == kField) {
-    FieldHelper field_helper(this);
-    field_helper.ReadUntilExcluding(FieldHelper::kAnnotations);
-  } else if (tag == kConstructor) {
-    ConstructorHelper constructor_helper(this);
-    constructor_helper.ReadUntilExcluding(ConstructorHelper::kAnnotations);
-  } else {
-    FATAL("No support for metadata on this type of kernel node\n");
+  // Library and LibraryDependency objects do not have a tag in kernel binary.
+  // Synthetic metadata fields corresponding to these objects keep kernel
+  // offset of annotations list instead of annotated object.
+  if (!is_annotations_offset) {
+    const Tag tag = PeekTag();
+
+    if (tag == kClass) {
+      ClassHelper class_helper(this);
+      class_helper.ReadUntilExcluding(ClassHelper::kAnnotations);
+    } else if (tag == kProcedure) {
+      ProcedureHelper procedure_helper(this);
+      procedure_helper.ReadUntilExcluding(ProcedureHelper::kAnnotations);
+    } else if (tag == kField) {
+      FieldHelper field_helper(this);
+      field_helper.ReadUntilExcluding(FieldHelper::kAnnotations);
+    } else if (tag == kConstructor) {
+      ConstructorHelper constructor_helper(this);
+      constructor_helper.ReadUntilExcluding(ConstructorHelper::kAnnotations);
+    } else {
+      FATAL("No support for metadata on this type of kernel node\n");
+    }
   }
 
   return BuildAnnotations();
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index cc258c8..c9babb5 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -275,7 +275,8 @@
   Fragment BuildStatementAt(intptr_t kernel_offset);
   RawObject* BuildParameterDescriptor(intptr_t kernel_offset);
   RawObject* BuildAnnotations();
-  RawObject* EvaluateMetadata(intptr_t kernel_offset);
+  RawObject* EvaluateMetadata(intptr_t kernel_offset,
+                              bool is_annotations_offset);
   void CollectTokenPositionsFor(
       intptr_t script_index,
       intptr_t initial_script_index,
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 57f95cc..d22bad5 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -2058,7 +2058,8 @@
   return nsm;
 }
 
-RawObject* EvaluateMetadata(const Field& metadata_field) {
+RawObject* EvaluateMetadata(const Field& metadata_field,
+                            bool is_annotations_offset) {
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
     Thread* thread = Thread::Current();
@@ -2076,7 +2077,7 @@
         ExternalTypedData::Handle(Z, metadata_field.KernelData()),
         metadata_field.KernelDataProgramOffset(), &active_class);
     return streaming_flow_graph_builder.EvaluateMetadata(
-        metadata_field.kernel_offset());
+        metadata_field.kernel_offset(), is_annotations_offset);
   } else {
     Thread* thread = Thread::Current();
     Error& error = Error::Handle();
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index 2fdace5..53d60ec 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -690,7 +690,8 @@
   intptr_t catch_try_index_;
 };
 
-RawObject* EvaluateMetadata(const Field& metadata_field);
+RawObject* EvaluateMetadata(const Field& metadata_field,
+                            bool is_annotations_offset);
 RawObject* BuildParameterDescriptor(const Function& function);
 void CollectTokenPositionsFor(const Script& script);
 
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 99aa61f..8e6e3b39 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -1304,7 +1304,10 @@
     }
       /* Falls through */
     case kAnnotations: {
-      helper_->SkipListOfExpressions();
+      annotation_count_ = helper_->ReadListLength();
+      for (intptr_t i = 0; i < annotation_count_; ++i) {
+        helper_->SkipExpression();  // read ith expression.
+      }
       if (++next_read_ == field) return;
     }
       /* Falls through */
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index eb1564d..f18a9bb 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -729,7 +729,7 @@
   };
 
   explicit LibraryDependencyHelper(KernelReaderHelper* helper)
-      : helper_(helper), next_read_(kFileOffset) {}
+      : annotation_count_(0), helper_(helper), next_read_(kFileOffset) {}
 
   void ReadUntilIncluding(Field field) {
     ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
@@ -740,6 +740,7 @@
   uint8_t flags_;
   StringIndex name_index_;
   NameIndex target_library_canonical_name_;
+  intptr_t annotation_count_;
 
  private:
   KernelReaderHelper* helper_;
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 114ae9a..31148a0 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -762,6 +762,8 @@
       Z, ScriptAt(library_helper.source_uri_index_, import_uri_index));
 
   library_helper.ReadUntilExcluding(LibraryHelper::kAnnotations);
+  intptr_t annotations_kernel_offset =
+      builder_.ReaderOffset() - correction_offset_;
   intptr_t annotation_count = builder_.ReadListLength();  // read list length.
   if (annotation_count > 0) {
     EnsurePotentialExtensionLibraries();
@@ -772,10 +774,6 @@
   }
   library_helper.SetJustRead(LibraryHelper::kAnnotations);
 
-  library_helper.ReadUntilExcluding(LibraryHelper::kDependencies);
-  LoadLibraryImportsAndExports(&library);
-  library_helper.SetJustRead(LibraryHelper::kDependencies);
-
   // Setup toplevel class (which contains library fields/procedures).
   Class& toplevel_class =
       Class::Handle(Z, Class::New(library, Symbols::TopLevel(), script,
@@ -783,6 +781,10 @@
   toplevel_class.set_is_cycle_free();
   library.set_toplevel_class(toplevel_class);
 
+  library_helper.ReadUntilExcluding(LibraryHelper::kDependencies);
+  LoadLibraryImportsAndExports(&library, toplevel_class);
+  library_helper.SetJustRead(LibraryHelper::kDependencies);
+
   const GrowableObjectArray& classes =
       GrowableObjectArray::Handle(Z, I->object_store()->pending_classes());
 
@@ -851,6 +853,12 @@
     LoadProcedure(library, toplevel_class, false, next_procedure_offset);
   }
 
+  if (FLAG_enable_mirrors && annotation_count > 0) {
+    ASSERT(annotations_kernel_offset > 0);
+    library.AddLibraryMetadata(toplevel_class, TokenPosition::kNoSource,
+                               annotations_kernel_offset);
+  }
+
   toplevel_class.SetFunctions(Array::Handle(MakeFunctionsArray()));
   classes.Add(toplevel_class, Heap::kOld);
   if (!library.Loaded()) library.SetLoaded();
@@ -858,7 +866,8 @@
   return library.raw();
 }
 
-void KernelLoader::LoadLibraryImportsAndExports(Library* library) {
+void KernelLoader::LoadLibraryImportsAndExports(Library* library,
+                                                const Class& toplevel_class) {
   GrowableObjectArray& show_list = GrowableObjectArray::Handle(Z);
   GrowableObjectArray& hide_list = GrowableObjectArray::Handle(Z);
   Array& show_names = Array::Handle(Z);
@@ -869,6 +878,11 @@
   const intptr_t deps_count = builder_.ReadListLength();
   for (intptr_t dep = 0; dep < deps_count; ++dep) {
     LibraryDependencyHelper dependency_helper(&builder_);
+
+    dependency_helper.ReadUntilExcluding(LibraryDependencyHelper::kAnnotations);
+    intptr_t annotations_kernel_offset =
+        builder_.ReaderOffset() - correction_offset_;
+
     dependency_helper.ReadUntilExcluding(LibraryDependencyHelper::kCombinators);
 
     // Ignore the dependency if the target library is invalid.
@@ -937,6 +951,11 @@
         }
       }
     }
+    if (FLAG_enable_mirrors && dependency_helper.annotation_count_ > 0) {
+      ASSERT(annotations_kernel_offset > 0);
+      ns.AddMetadata(toplevel_class, TokenPosition::kNoSource,
+                     annotations_kernel_offset);
+    }
   }
 }
 
diff --git a/runtime/vm/kernel_loader.h b/runtime/vm/kernel_loader.h
index 954ef90..bc41510 100644
--- a/runtime/vm/kernel_loader.h
+++ b/runtime/vm/kernel_loader.h
@@ -249,7 +249,8 @@
                                   const Function& function,
                                   const AbstractType& field_type);
 
-  void LoadLibraryImportsAndExports(Library* library);
+  void LoadLibraryImportsAndExports(Library* library,
+                                    const Class& toplevel_class);
 
   Library& LookupLibraryOrNull(NameIndex library);
   Library& LookupLibrary(NameIndex library);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index da966ec..cfdfcbc 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -10626,8 +10626,9 @@
 }
 
 void Library::AddLibraryMetadata(const Object& tl_owner,
-                                 TokenPosition token_pos) const {
-  AddMetadata(tl_owner, Symbols::TopLevel(), token_pos);
+                                 TokenPosition token_pos,
+                                 intptr_t kernel_offset) const {
+  AddMetadata(tl_owner, Symbols::TopLevel(), token_pos, kernel_offset);
 }
 
 RawString* Library::MakeMetadataName(const Object& obj) const {
@@ -10695,7 +10696,8 @@
   metadata = field.StaticValue();
   if (field.StaticValue() == Object::empty_array().raw()) {
     if (field.kernel_offset() > 0) {
-      metadata = kernel::EvaluateMetadata(field);
+      metadata = kernel::EvaluateMetadata(
+          field, /* is_annotations_offset = */ obj.IsLibrary());
     } else {
       metadata = Parser::ParseMetadata(field);
     }
@@ -12287,7 +12289,9 @@
   StorePointer(&raw_ptr()->metadata_field_, value.raw());
 }
 
-void Namespace::AddMetadata(const Object& owner, TokenPosition token_pos) {
+void Namespace::AddMetadata(const Object& owner,
+                            TokenPosition token_pos,
+                            intptr_t kernel_offset) {
   ASSERT(Field::Handle(metadata_field()).IsNull());
   Field& field = Field::Handle(Field::NewTopLevel(Symbols::TopLevel(),
                                                   false,  // is_final
@@ -12296,6 +12300,7 @@
   field.set_is_reflectable(false);
   field.SetFieldType(Object::dynamic_type());
   field.SetStaticValue(Array::empty_array(), true);
+  field.set_kernel_offset(kernel_offset);
   set_metadata_field(field);
 }
 
@@ -12311,7 +12316,12 @@
   Object& metadata = Object::Handle();
   metadata = field.StaticValue();
   if (field.StaticValue() == Object::empty_array().raw()) {
-    metadata = Parser::ParseMetadata(field);
+    if (field.kernel_offset() > 0) {
+      metadata =
+          kernel::EvaluateMetadata(field, /* is_annotations_offset = */ true);
+    } else {
+      metadata = Parser::ParseMetadata(field);
+    }
     if (metadata.IsArray()) {
       ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());
       field.SetStaticValue(Array::Cast(metadata), true);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 5e2b6f3..ff768b4 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3849,7 +3849,8 @@
                            TokenPosition token_pos,
                            intptr_t kernel_offset = 0) const;
   void AddLibraryMetadata(const Object& tl_owner,
-                          TokenPosition token_pos) const;
+                          TokenPosition token_pos,
+                          intptr_t kernel_offset = 0) const;
   void AddTypeParameterMetadata(const TypeParameter& param,
                                 TokenPosition token_pos) const;
   void CloneMetadataFrom(const Library& from_library,
@@ -4065,7 +4066,9 @@
   RawArray* show_names() const { return raw_ptr()->show_names_; }
   RawArray* hide_names() const { return raw_ptr()->hide_names_; }
 
-  void AddMetadata(const Object& owner, TokenPosition token_pos);
+  void AddMetadata(const Object& owner,
+                   TokenPosition token_pos,
+                   intptr_t kernel_offset = 0);
   RawObject* GetMetadata() const;
 
   static intptr_t InstanceSize() {
diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status
index 6dffcc5..4257d48 100644
--- a/tests/lib_2/lib_2_kernel.status
+++ b/tests/lib_2/lib_2_kernel.status
@@ -116,7 +116,6 @@
 mirrors/constructor_private_name_test: RuntimeError # Issue 33345 - Incorrect qualified symbol literal from kernel reader
 mirrors/constructors_test: CompileTimeError # Issue 31402 (Invocation arguments)
 mirrors/dart2js_mirrors_test: RuntimeError # 31916
-mirrors/deferred_mirrors_metadata_test: RuntimeError, CompileTimeError # Deferred loading kernel issue 28335.
 mirrors/deferred_type_test: CompileTimeError, RuntimeError
 mirrors/empty_test: Crash, RuntimeError
 mirrors/enum_test: RuntimeError # Issue 31402 (Invocation arguments)
@@ -140,7 +139,6 @@
 mirrors/library_imports_prefixed_show_hide_test: RuntimeError # Issue 33098
 mirrors/library_imports_prefixed_test: RuntimeError # Issue 33098
 mirrors/library_imports_shown_test: RuntimeError # Issue 33098
-mirrors/library_metadata_test: RuntimeError
 mirrors/load_library_test: RuntimeError
 mirrors/metadata_allowed_values_test/16: Skip # Flaky, crashes.
 mirrors/metadata_scope_test/none: RuntimeError