[vm] Fix @pragma detection in KernelLoader.

Change-Id: If09f26a27f84bbed4841eb6d868aea38af564e4a
Cq-Include-Trybots: luci.dart.try:vm-kernel-win-release-x64-try,vm-kernel-optcounter-threshold-linux-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-win-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/68362
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index c688a31..41d2016 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1567,7 +1567,7 @@
     objects_.Add(info);
 
     RawObject** from = info->from();
-    RawObject** to = info->to();
+    RawObject** to = info->to_snapshot(s->kind());
     for (RawObject** p = from; p <= to; p++) {
       s->Push(*p);
     }
@@ -1588,7 +1588,7 @@
     for (intptr_t i = 0; i < count; i++) {
       RawKernelProgramInfo* info = objects_[i];
       RawObject** from = info->from();
-      RawObject** to = info->to();
+      RawObject** to = info->to_snapshot(s->kind());
       for (RawObject** p = from; p <= to; p++) {
         s->WriteRef(*p);
       }
@@ -1627,10 +1627,14 @@
                                      KernelProgramInfo::InstanceSize(),
                                      is_vm_object);
       RawObject** from = info->from();
-      RawObject** to = info->to();
+      RawObject** to = info->to_snapshot(d->kind());
+      RawObject** end = info->to();
       for (RawObject** p = from; p <= to; p++) {
         *p = d->ReadRef();
       }
+      for (RawObject** p = to + 1; p <= end; p++) {
+        *p = Object::null();
+      }
     }
   }
 };
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 5595412..ac2c227 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -182,7 +182,8 @@
       external_name_class_(Class::Handle(Z)),
       external_name_field_(Field::Handle(Z)),
       potential_natives_(GrowableObjectArray::Handle(Z)),
-      potential_extension_libraries_(GrowableObjectArray::Handle(Z)) {
+      potential_extension_libraries_(GrowableObjectArray::Handle(Z)),
+      pragma_class_(Class::Handle(Z)) {
   if (!program->is_single_program()) {
     FATAL(
         "Trying to load a concatenated dill file at a time where that is "
@@ -283,6 +284,12 @@
       Z,
       reader.ExternalDataFromTo(reader.offset(), reader.offset() + end_offset));
 
+  // Create a view of the constants table. The trailing ComponentIndex is
+  // negligible in size.
+  const ExternalTypedData& constants_table = ExternalTypedData::Handle(
+      Z, reader.ExternalDataFromTo(program_->constant_table_offset(),
+                                   program_->kernel_data_size()));
+
   // Copy the canonical names into the VM's heap.  Encode them as unsigned, so
   // the parent indexes are adjusted when extracted.
   reader.set_offset(program_->name_table_offset());
@@ -303,8 +310,9 @@
       Z, reader.ExternalDataFromTo(program_->metadata_mappings_offset(),
                                    program_->string_table_offset()));
 
-  kernel_program_info_ = KernelProgramInfo::New(
-      offsets, data, names, metadata_payloads, metadata_mappings, scripts);
+  kernel_program_info_ =
+      KernelProgramInfo::New(offsets, data, names, metadata_payloads,
+                             metadata_mappings, constants_table, scripts);
 
   H.InitFromKernelProgramInfo(kernel_program_info_);
 
@@ -335,7 +343,8 @@
       external_name_class_(Class::Handle(Z)),
       external_name_field_(Field::Handle(Z)),
       potential_natives_(GrowableObjectArray::Handle(Z)),
-      potential_extension_libraries_(GrowableObjectArray::Handle(Z)) {
+      potential_extension_libraries_(GrowableObjectArray::Handle(Z)),
+      pragma_class_(Class::Handle(Z)) {
   ASSERT(T.active_class_ == &active_class_);
   T.finalize_ = false;
 
@@ -588,6 +597,7 @@
     //     c) update all scripts with the constants array
     ASSERT(kernel_program_info_.constants() == Array::null());
     kernel_program_info_.set_constants(constants);
+    kernel_program_info_.set_constants_table(ExternalTypedData::Handle(Z));
 
     NameIndex main = program_->main_method();
     if (main == -1) {
@@ -1335,7 +1345,6 @@
   *is_potential_native = false;
   *has_pragma_annotation = false;
   String& detected_name = String::Handle(Z);
-  Class& pragma_class = Class::Handle(Z, I->object_store()->pragma_class());
   for (intptr_t i = 0; i < annotation_count; ++i) {
     const intptr_t tag = helper_.PeekTag();
     if (tag == kConstructorInvocation || tag == kConstConstructorInvocation) {
@@ -1361,10 +1370,8 @@
         // constants in the annotation list to later.
         *is_potential_native = true;
 
-        if (program_ == nullptr) {
-          helper_.SkipExpression();
-          continue;
-        }
+        ASSERT(kernel_program_info_.constants_table() !=
+               ExternalTypedData::null());
 
         // For pragma annotations, we seek into the constants table and peek
         // into the Kernel representation of the constant.
@@ -1376,13 +1383,16 @@
 
         const intptr_t offset_in_constant_table = helper_.ReadUInt();
 
-        AlternativeReadingScope scope(&helper_.reader_,
-                                      program_->constant_table_offset());
+        AlternativeReadingScope scope(
+            &helper_.reader_,
+            &ExternalTypedData::Handle(Z,
+                                       kernel_program_info_.constants_table()),
+            0);
 
         // Seek into the position within the constant table where we can inspect
         // this constant's Kernel representation.
         helper_.ReadUInt();  // skip constant table size
-        helper_.SetOffset(helper_.ReaderOffset() + offset_in_constant_table);
+        helper_.SkipBytes(offset_in_constant_table);
         uint8_t tag = helper_.ReadTag();
         if (tag == kInstanceConstant) {
           *has_pragma_annotation =
@@ -1396,6 +1406,9 @@
         // Obtain `dart:_internal::ExternalName.name`.
         EnsureExternalClassIsLookedUp();
 
+        // Obtain `dart:_internal::pragma`.
+        EnsurePragmaClassIsLookedUp();
+
         const intptr_t constant_table_index = helper_.ReadUInt();
         const Object& constant =
             Object::Handle(constant_table.GetOrDie(constant_table_index));
@@ -1404,7 +1417,7 @@
               Instance::Handle(Instance::RawCast(constant.raw()));
           *native_name =
               String::RawCast(instance.GetField(external_name_field_));
-        } else if (constant.clazz() == pragma_class.raw()) {
+        } else if (constant.clazz() == pragma_class_.raw()) {
           *has_pragma_annotation = true;
         }
         ASSERT(constant_table.Release().raw() == constant_table_array.raw());
diff --git a/runtime/vm/kernel_loader.h b/runtime/vm/kernel_loader.h
index 8a24d34..671e71b 100644
--- a/runtime/vm/kernel_loader.h
+++ b/runtime/vm/kernel_loader.h
@@ -273,6 +273,15 @@
     }
   }
 
+  void EnsurePragmaClassIsLookedUp() {
+    if (pragma_class_.IsNull()) {
+      const Library& internal_lib =
+          Library::Handle(zone_, dart::Library::InternalLibrary());
+      pragma_class_ = internal_lib.LookupClass(Symbols::Pragma());
+      ASSERT(!pragma_class_.IsNull());
+    }
+  }
+
   void EnsurePotentialNatives() {
     potential_natives_ = kernel_program_info_.potential_natives();
     if (potential_natives_.IsNull()) {
@@ -317,6 +326,8 @@
   GrowableObjectArray& potential_natives_;
   GrowableObjectArray& potential_extension_libraries_;
 
+  Class& pragma_class_;
+
   Mapping<Library> libraries_;
   Mapping<Class> classes_;
 
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 6ba5988..b9f0f7b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -12508,6 +12508,7 @@
     const TypedData& canonical_names,
     const ExternalTypedData& metadata_payloads,
     const ExternalTypedData& metadata_mappings,
+    const ExternalTypedData& constants_table,
     const Array& scripts) {
   const KernelProgramInfo& info =
       KernelProgramInfo::Handle(KernelProgramInfo::New());
@@ -12519,6 +12520,7 @@
   info.StorePointer(&info.raw_ptr()->metadata_mappings_,
                     metadata_mappings.raw());
   info.StorePointer(&info.raw_ptr()->scripts_, scripts.raw());
+  info.StorePointer(&info.raw_ptr()->constants_table_, constants_table.raw());
   return info.raw();
 }
 
@@ -12536,6 +12538,11 @@
   StorePointer(&raw_ptr()->constants_, constants.raw());
 }
 
+void KernelProgramInfo::set_constants_table(
+    const ExternalTypedData& value) const {
+  StorePointer(&raw_ptr()->constants_table_, value.raw());
+}
+
 void KernelProgramInfo::set_potential_natives(
     const GrowableObjectArray& candidates) const {
   StorePointer(&raw_ptr()->potential_natives_, candidates.raw());
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 85af75f..d4e3f63 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4106,6 +4106,7 @@
                                    const TypedData& canonical_names,
                                    const ExternalTypedData& metadata_payload,
                                    const ExternalTypedData& metadata_mappings,
+                                   const ExternalTypedData& constants_table,
                                    const Array& scripts);
 
   static intptr_t InstanceSize() {
@@ -4126,6 +4127,12 @@
     return raw_ptr()->metadata_mappings_;
   }
 
+  RawExternalTypedData* constants_table() const {
+    return raw_ptr()->constants_table_;
+  }
+
+  void set_constants_table(const ExternalTypedData& value) const;
+
   RawArray* scripts() const { return raw_ptr()->scripts_; }
 
   RawArray* constants() const { return raw_ptr()->constants_; }
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 52c0f09..ab1af6d 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1239,7 +1239,12 @@
   RawArray* scripts_;
   RawArray* constants_;
   RawGrowableObjectArray* potential_natives_;
-  VISIT_TO(RawObject*, potential_natives_);
+  RawExternalTypedData* constants_table_;
+  VISIT_TO(RawObject*, constants_table_);
+
+  RawObject** to_snapshot(Snapshot::Kind kind) {
+    return reinterpret_cast<RawObject**>(&ptr()->potential_natives_);
+  }
 };
 
 class RawCode : public RawObject {
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 2609707..7d6bc72 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1334,7 +1334,8 @@
   reader->AddBackRef(object_id, &info, kIsDeserialized);
 
   // Set all the object fields.
-  READ_OBJECT_FIELDS(info, info.raw()->from(), info.raw()->to(), kAsReference);
+  READ_OBJECT_FIELDS(info, info.raw()->from(), info.raw()->to_snapshot(kind),
+                     kAsReference);
   return info.raw();
 }
 
@@ -1354,7 +1355,7 @@
 
   // Write out all the object pointer fields.
   SnapshotWriterVisitor visitor(writer, kAsReference);
-  visitor.VisitPointers(from(), to());
+  visitor.VisitPointers(from(), to_snapshot(kind));
 }
 
 RawCode* Code::ReadFrom(SnapshotReader* reader,