| // Copyright (c) 2018, 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. | 
 |  | 
 | #include "vm/compiler/frontend/constant_reader.h" | 
 |  | 
 | #include "vm/object_store.h" | 
 |  | 
 | namespace dart { | 
 | namespace kernel { | 
 |  | 
 | #define Z (zone_) | 
 | #define H (translation_helper_) | 
 |  | 
 | // Note: If changing how the constants are saved in the binary (and thus how | 
 | // they are read here) be aware that there's also some reading going on in | 
 | // KernelLoader::ReadVMAnnotations which then also has to be updated! | 
 |  | 
 | ConstantReader::ConstantReader(KernelReaderHelper* helper, | 
 |                                ActiveClass* active_class) | 
 |     : helper_(helper), | 
 |       zone_(helper->zone_), | 
 |       translation_helper_(helper->translation_helper_), | 
 |       active_class_(active_class), | 
 |       result_(Object::Handle(zone_)) {} | 
 |  | 
 | bool ConstantReader::IsPragmaInstanceConstant( | 
 |     intptr_t constant_index, | 
 |     intptr_t* pragma_name_constant_index, | 
 |     intptr_t* pragma_options_constant_index) { | 
 |   KernelReaderHelper reader(Z, &H, H.constants_table(), 0); | 
 |   NavigateToIndex(&reader, constant_index); | 
 |  | 
 |   if (reader.ReadByte() == kInstanceConstant) { | 
 |     NameIndex index = reader.ReadCanonicalNameReference(); | 
 |     if (H.IsRoot(index) || | 
 |         !H.StringEquals(H.CanonicalNameString(index), "pragma")) { | 
 |       return false; | 
 |     } | 
 |     index = H.CanonicalNameParent(index); | 
 |     if (H.IsRoot(index) || | 
 |         !H.StringEquals(H.CanonicalNameString(index), "dart:core")) { | 
 |       return false; | 
 |     } | 
 |     const intptr_t num_type_args = reader.ReadUInt(); | 
 |     if (num_type_args != 0) return false; | 
 |  | 
 |     const intptr_t num_fields = reader.ReadUInt(); | 
 |     if (num_fields != 2) return false; | 
 |  | 
 |     const NameIndex field0_name = reader.ReadCanonicalNameReference(); | 
 |     if (H.IsRoot(field0_name) || | 
 |         !H.StringEquals(H.CanonicalNameString(field0_name), "name")) { | 
 |       return false; | 
 |     } | 
 |     const intptr_t name_index = reader.ReadUInt(); | 
 |     if (pragma_name_constant_index != nullptr) { | 
 |       *pragma_name_constant_index = name_index; | 
 |     } | 
 |  | 
 |     const NameIndex field1_name = reader.ReadCanonicalNameReference(); | 
 |     if (H.IsRoot(field1_name) || | 
 |         !H.StringEquals(H.CanonicalNameString(field1_name), "options")) { | 
 |       return false; | 
 |     } | 
 |     const intptr_t options_index = reader.ReadUInt(); | 
 |     if (pragma_options_constant_index != nullptr) { | 
 |       *pragma_options_constant_index = options_index; | 
 |     } | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | bool ConstantReader::IsStringConstant(intptr_t constant_index, | 
 |                                       const char* name) { | 
 |   KernelReaderHelper reader(Z, &H, H.constants_table(), 0); | 
 |   NavigateToIndex(&reader, constant_index); | 
 |  | 
 |   if (reader.ReadByte() == kStringConstant) { | 
 |     const StringIndex index = reader.ReadStringReference(); | 
 |     return H.StringEquals(index, name); | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | bool ConstantReader::GetStringConstant(intptr_t constant_index, | 
 |                                        String* out_value) { | 
 |   KernelReaderHelper reader(Z, &H, H.constants_table(), 0); | 
 |   NavigateToIndex(&reader, constant_index); | 
 |  | 
 |   if (reader.ReadByte() == kStringConstant) { | 
 |     const StringIndex index = reader.ReadStringReference(); | 
 |     *out_value = H.DartSymbolPlain(index).ptr(); | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | InstancePtr ConstantReader::ReadConstantInitializer() { | 
 |   Tag tag = helper_->ReadTag();  // read tag. | 
 |   switch (tag) { | 
 |     case kSomething: | 
 |       return ReadConstantExpression(); | 
 |     default: | 
 |       const auto& script = Script::Handle(Z, Script()); | 
 |       H.ReportError(script, TokenPosition::kNoSource, | 
 |                     "Not a constant expression: unexpected kernel tag %s (%d)", | 
 |                     Reader::TagName(tag), tag); | 
 |   } | 
 |   return Instance::RawCast(result_.ptr()); | 
 | } | 
 |  | 
 | InstancePtr ConstantReader::ReadConstantExpression() { | 
 |   Tag tag = helper_->ReadTag();  // read tag. | 
 |   switch (tag) { | 
 |     case kConstantExpression: | 
 |       helper_->ReadPosition(); | 
 |       helper_->SkipDartType(); | 
 |       result_ = ReadConstant(helper_->ReadUInt()); | 
 |       break; | 
 |     case kFileUriConstantExpression: | 
 |       helper_->ReadPosition(); | 
 |       helper_->ReadUInt(); | 
 |       helper_->SkipDartType(); | 
 |       result_ = ReadConstant(helper_->ReadUInt()); | 
 |       break; | 
 |     case kInvalidExpression: { | 
 |       helper_->ReadPosition();  // Skip position. | 
 |       const String& message = H.DartString(helper_->ReadStringReference()); | 
 |       const auto& script = Script::Handle(Z, Script()); | 
 |       // Invalid expression message has pointer to the source code, no need to | 
 |       // report it twice. | 
 |       H.ReportError(script, TokenPosition::kNoSource, "%s", | 
 |                     message.ToCString()); | 
 |       break; | 
 |     } | 
 |     default: | 
 |       const auto& script = Script::Handle(Z, Script()); | 
 |       H.ReportError(script, TokenPosition::kNoSource, | 
 |                     "Not a constant expression: unexpected kernel tag %s (%d)", | 
 |                     Reader::TagName(tag), tag); | 
 |   } | 
 |   return Instance::RawCast(result_.ptr()); | 
 | } | 
 |  | 
 | ObjectPtr ConstantReader::ReadAnnotations() { | 
 |   intptr_t list_length = helper_->ReadListLength();  // read list length. | 
 |   const auto& metadata_values = | 
 |       Array::Handle(Z, ImmutableArray::New(list_length, H.allocation_space())); | 
 |   Instance& value = Instance::Handle(Z); | 
 |   for (intptr_t i = 0; i < list_length; ++i) { | 
 |     // This will read the expression. | 
 |     value = ReadConstantExpression(); | 
 |     metadata_values.SetAt(i, value); | 
 |   } | 
 |   return H.Canonicalize(metadata_values); | 
 | } | 
 |  | 
 | InstancePtr ConstantReader::ReadConstant(intptr_t constant_index) { | 
 |   ASSERT(!H.constants().IsNull()); | 
 |   ASSERT(!H.constants_table().IsNull());  // raw bytes | 
 |  | 
 |   // For kernel-level cache (in contrast with script-level caching), | 
 |   // we need to access the raw constants array inside the shared | 
 |   // KernelProgramInfo directly, so that all scripts will see the | 
 |   // results after new insertions. These accesses at kernel-level | 
 |   // must be locked since mutator and background compiler can | 
 |   // access the array at the same time. | 
 |   { | 
 |     SafepointMutexLocker ml( | 
 |         H.thread()->isolate_group()->kernel_constants_mutex()); | 
 |     const auto& constants_array = | 
 |         Array::Handle(Z, H.GetKernelProgramInfo().constants()); | 
 |     ASSERT(constant_index < constants_array.Length()); | 
 |     result_ = constants_array.At(constant_index); | 
 |   } | 
 |  | 
 |   // On miss, evaluate, and insert value. | 
 |   if (result_.ptr() == Object::sentinel().ptr()) { | 
 |     LeaveCompilerScope cs(H.thread()); | 
 |     result_ = ReadConstantInternal(constant_index); | 
 |     SafepointMutexLocker ml( | 
 |         H.thread()->isolate_group()->kernel_constants_mutex()); | 
 |     const auto& constants_array = | 
 |         Array::Handle(Z, H.GetKernelProgramInfo().constants()); | 
 |     ASSERT(constant_index < constants_array.Length()); | 
 |     constants_array.SetAt(constant_index, result_); | 
 |   } | 
 |   return Instance::RawCast(result_.ptr()); | 
 | } | 
 |  | 
 | bool ConstantReader::IsInstanceConstant(intptr_t constant_index, | 
 |                                         const Class& clazz) { | 
 |   // Get reader directly into raw bytes of constant table/constant mapping. | 
 |   KernelReaderHelper reader(Z, &H, H.constants_table(), 0); | 
 |   NavigateToIndex(&reader, constant_index); | 
 |  | 
 |   // Peek for an instance of the given clazz. | 
 |   if (reader.ReadByte() == kInstanceConstant) { | 
 |     const NameIndex index = reader.ReadCanonicalNameReference(); | 
 |     return H.LookupClassByKernelClass(index) == clazz.ptr(); | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | intptr_t ConstantReader::NumConstants() { | 
 |   ASSERT(!H.constants_table().IsNull()); | 
 |   KernelReaderHelper reader(Z, &H, H.constants_table(), 0); | 
 |   return NumConstants(&reader); | 
 | } | 
 |  | 
 | intptr_t ConstantReader::NumConstants(KernelReaderHelper* reader) { | 
 |   // Get reader directly into raw bytes of constant table/constant mapping. | 
 |   // Get the length of the constants (at the end of the mapping). | 
 |   reader->SetOffset(reader->ReaderSize() - 4); | 
 |   return reader->ReadUInt32(); | 
 | } | 
 |  | 
 | intptr_t ConstantReader::NavigateToIndex(KernelReaderHelper* reader, | 
 |                                          intptr_t constant_index) { | 
 |   const intptr_t num_constants = NumConstants(reader); | 
 |  | 
 |   // Get the binary offset of the constant at the wanted index. | 
 |   reader->SetOffset(reader->ReaderSize() - 4 - (num_constants * 4) + | 
 |                     (constant_index * 4)); | 
 |   const intptr_t constant_offset = reader->ReadUInt32(); | 
 |  | 
 |   reader->SetOffset(constant_offset); | 
 |  | 
 |   return constant_offset; | 
 | } | 
 |  | 
 | InstancePtr ConstantReader::ReadConstantInternal(intptr_t constant_index) { | 
 |   // Get reader directly into raw bytes of constant table/constant mapping. | 
 |   KernelReaderHelper reader(Z, &H, H.constants_table(), 0); | 
 |   const intptr_t constant_offset = NavigateToIndex(&reader, constant_index); | 
 |  | 
 |   // No function types returned as part of any types built should reference | 
 |   // free parent type args, ensured by clearing the enclosing function type. | 
 |   ActiveEnclosingFunctionScope scope(active_class_, nullptr); | 
 |   // Construct constant from raw bytes. | 
 |   Instance& instance = Instance::Handle(Z); | 
 |   const intptr_t constant_tag = reader.ReadByte(); | 
 |   switch (constant_tag) { | 
 |     case kNullConstant: | 
 |       instance = Instance::null(); | 
 |       break; | 
 |     case kBoolConstant: | 
 |       instance = reader.ReadByte() == 1 ? Object::bool_true().ptr() | 
 |                                         : Object::bool_false().ptr(); | 
 |       break; | 
 |     case kIntConstant: { | 
 |       uint8_t payload = 0; | 
 |       Tag integer_tag = reader.ReadTag(&payload);  // read tag. | 
 |       switch (integer_tag) { | 
 |         case kBigIntLiteral: { | 
 |           reader.ReadPosition(); | 
 |           const String& value = H.DartString(reader.ReadStringReference()); | 
 |           instance = Integer::New(value, Heap::kOld); | 
 |           break; | 
 |         } | 
 |         case kSpecializedIntLiteral: { | 
 |           reader.ReadPosition(); | 
 |           const int64_t value = | 
 |               static_cast<int32_t>(payload) - SpecializedIntLiteralBias; | 
 |           instance = Integer::New(value, Heap::kOld); | 
 |           break; | 
 |         } | 
 |         case kNegativeIntLiteral: { | 
 |           reader.ReadPosition(); | 
 |           const int64_t value = -static_cast<int64_t>(reader.ReadUInt()); | 
 |           instance = Integer::New(value, Heap::kOld); | 
 |           break; | 
 |         } | 
 |         case kPositiveIntLiteral: { | 
 |           reader.ReadPosition(); | 
 |           const int64_t value = reader.ReadUInt(); | 
 |           instance = Integer::New(value, Heap::kOld); | 
 |           break; | 
 |         } | 
 |         default: | 
 |           const auto& script = Script::Handle(Z, Script()); | 
 |           H.ReportError( | 
 |               script, TokenPosition::kNoSource, | 
 |               "Cannot lazily read integer: unexpected kernel tag %s (%d)", | 
 |               Reader::TagName(integer_tag), integer_tag); | 
 |       } | 
 |       break; | 
 |     } | 
 |     case kDoubleConstant: | 
 |       instance = Double::New(reader.ReadDouble(), Heap::kOld); | 
 |       break; | 
 |     case kStringConstant: | 
 |       instance = H.DartSymbolPlain(reader.ReadStringReference()).ptr(); | 
 |       break; | 
 |     case kSymbolConstant: { | 
 |       Library& library = Library::Handle(Z); | 
 |       library = Library::InternalLibrary(); | 
 |       const auto& symbol_class = | 
 |           Class::Handle(Z, library.LookupClass(Symbols::Symbol())); | 
 |       const auto& symbol_name_field = Field::Handle( | 
 |           Z, symbol_class.LookupInstanceFieldAllowPrivate(Symbols::_name())); | 
 |       ASSERT(!symbol_name_field.IsNull()); | 
 |       const NameIndex index = reader.ReadCanonicalNameReference(); | 
 |       if (index == -1) { | 
 |         library = Library::null(); | 
 |       } else { | 
 |         library = H.LookupLibraryByKernelLibrary(index); | 
 |       } | 
 |       const String& symbol = | 
 |           H.DartIdentifier(library, reader.ReadStringReference()); | 
 |       instance = Instance::New(symbol_class, Heap::kOld); | 
 |       instance.SetField(symbol_name_field, symbol); | 
 |       break; | 
 |     } | 
 |     case kListConstant: { | 
 |       const auto& list_class = Class::Handle( | 
 |           Z, H.isolate_group()->object_store()->immutable_array_class()); | 
 |       ASSERT(!list_class.IsNull()); | 
 |       ASSERT(list_class.is_finalized()); | 
 |       // Build type from the raw bytes (needs temporary translator). | 
 |       TypeTranslator type_translator(&reader, this, active_class_, | 
 |                                      /* finalize = */ true, | 
 |                                      /* in_constant_context = */ true); | 
 |       auto& type_arguments = | 
 |           TypeArguments::Handle(Z, TypeArguments::New(1, Heap::kOld)); | 
 |       AbstractType& type = type_translator.BuildType(); | 
 |       type_arguments.SetTypeAt(0, type); | 
 |       // Instantiate class. | 
 |       type_arguments = | 
 |           list_class.GetInstanceTypeArguments(H.thread(), type_arguments); | 
 |       // Fill array with constant elements. | 
 |       const intptr_t length = reader.ReadUInt(); | 
 |       const Array& array = | 
 |           Array::Handle(Z, ImmutableArray::New(length, Heap::kOld)); | 
 |       array.SetTypeArguments(type_arguments); | 
 |       Instance& constant = Instance::Handle(Z); | 
 |       for (intptr_t j = 0; j < length; ++j) { | 
 |         // Recurse into lazily evaluating all "sub" constants | 
 |         // needed to evaluate the current constant. | 
 |         const intptr_t entry_index = reader.ReadUInt(); | 
 |         ASSERT(entry_index < constant_offset);  // DAG! | 
 |         constant = ReadConstant(entry_index); | 
 |         array.SetAt(j, constant); | 
 |       } | 
 |       instance = array.ptr(); | 
 |       break; | 
 |     } | 
 |     case kMapConstant: { | 
 |       const auto& map_class = Class::Handle( | 
 |           Z, H.isolate_group()->object_store()->const_map_impl_class()); | 
 |       ASSERT(!map_class.IsNull()); | 
 |       ASSERT(map_class.is_finalized()); | 
 |  | 
 |       // Build types from the raw bytes (needs temporary translator). | 
 |       TypeTranslator type_translator(&reader, this, active_class_, | 
 |                                      /* finalize = */ true, | 
 |                                      /* in_constant_context = */ true); | 
 |       auto& type_arguments = | 
 |           TypeArguments::Handle(Z, TypeArguments::New(2, Heap::kOld)); | 
 |       AbstractType& type = type_translator.BuildType(); | 
 |       type_arguments.SetTypeAt(0, type); | 
 |       type = type_translator.BuildType().ptr(); | 
 |       type_arguments.SetTypeAt(1, type); | 
 |  | 
 |       // Instantiate class. | 
 |       type_arguments = | 
 |           map_class.GetInstanceTypeArguments(H.thread(), type_arguments); | 
 |  | 
 |       // Fill map with constant elements. | 
 |       const auto& map = Map::Handle(Z, ConstMap::NewUninitialized(Heap::kOld)); | 
 |       ASSERT_EQUAL(map.GetClassId(), kConstMapCid); | 
 |       map.SetTypeArguments(type_arguments); | 
 |       const intptr_t length = reader.ReadUInt(); | 
 |       const intptr_t used_data = (length << 1); | 
 |       map.set_used_data(used_data); | 
 |  | 
 |       const auto& data = Array::Handle(Z, Array::New(used_data)); | 
 |       map.set_data(data); | 
 |  | 
 |       map.set_deleted_keys(0); | 
 |       map.ComputeAndSetHashMask(); | 
 |  | 
 |       Instance& constant = Instance::Handle(Z); | 
 |       for (intptr_t j = 0; j < used_data; ++j) { | 
 |         // Recurse into lazily evaluating all "sub" constants | 
 |         // needed to evaluate the current constant. | 
 |         const intptr_t entry_index = reader.ReadUInt(); | 
 |         ASSERT(entry_index < constant_offset);  // DAG! | 
 |         constant = ReadConstant(entry_index); | 
 |         data.SetAt(j, constant); | 
 |       } | 
 |  | 
 |       instance = map.ptr(); | 
 |       break; | 
 |     } | 
 |     case kRecordConstant: { | 
 |       const intptr_t num_positional = reader.ReadListLength(); | 
 |       intptr_t num_named = 0; | 
 |       const Array* field_names = &Array::empty_array(); | 
 |       { | 
 |         AlternativeReadingScope alt(&reader.reader_); | 
 |         for (intptr_t j = 0; j < num_positional; ++j) { | 
 |           reader.ReadUInt(); | 
 |         } | 
 |         num_named = reader.ReadListLength(); | 
 |         if (num_named > 0) { | 
 |           auto& names = Array::Handle(Z, Array::New(num_named)); | 
 |           for (intptr_t j = 0; j < num_named; ++j) { | 
 |             String& name = H.DartSymbolObfuscate(reader.ReadStringReference()); | 
 |             names.SetAt(j, name); | 
 |             reader.ReadUInt(); | 
 |           } | 
 |           names.MakeImmutable(); | 
 |           field_names = &names; | 
 |         } | 
 |       } | 
 |       const intptr_t num_fields = num_positional + num_named; | 
 |       const RecordShape shape = | 
 |           RecordShape::Register(H.thread(), num_fields, *field_names); | 
 |       const auto& record = Record::Handle(Z, Record::New(shape)); | 
 |       intptr_t pos = 0; | 
 |       for (intptr_t j = 0; j < num_positional; ++j) { | 
 |         const intptr_t entry_index = reader.ReadUInt(); | 
 |         ASSERT(entry_index < constant_offset);  // DAG! | 
 |         instance = ReadConstant(entry_index); | 
 |         record.SetFieldAt(pos++, instance); | 
 |       } | 
 |       reader.ReadListLength(); | 
 |       for (intptr_t j = 0; j < num_named; ++j) { | 
 |         reader.ReadStringReference(); | 
 |         const intptr_t entry_index = reader.ReadUInt(); | 
 |         ASSERT(entry_index < constant_offset);  // DAG! | 
 |         instance = ReadConstant(entry_index); | 
 |         record.SetFieldAt(pos++, instance); | 
 |       } | 
 |       instance = record.ptr(); | 
 |       break; | 
 |     } | 
 |     case kSetConstant: { | 
 |       const auto& set_class = Class::Handle( | 
 |           Z, H.isolate_group()->object_store()->const_set_impl_class()); | 
 |       ASSERT(!set_class.IsNull()); | 
 |       ASSERT(set_class.is_finalized()); | 
 |  | 
 |       // Build types from the raw bytes (needs temporary translator). | 
 |       TypeTranslator type_translator(&reader, this, active_class_, | 
 |                                      /* finalize = */ true, | 
 |                                      /* in_constant_context = */ true); | 
 |       auto& type_arguments = | 
 |           TypeArguments::Handle(Z, TypeArguments::New(1, Heap::kOld)); | 
 |       AbstractType& type = type_translator.BuildType(); | 
 |       type_arguments.SetTypeAt(0, type); | 
 |  | 
 |       // Instantiate class. | 
 |       type_arguments = | 
 |           set_class.GetInstanceTypeArguments(H.thread(), type_arguments); | 
 |  | 
 |       // Fill set with constant elements. | 
 |       const auto& set = Set::Handle(Z, ConstSet::NewUninitialized(Heap::kOld)); | 
 |       ASSERT_EQUAL(set.GetClassId(), kConstSetCid); | 
 |       set.SetTypeArguments(type_arguments); | 
 |       const intptr_t length = reader.ReadUInt(); | 
 |       const intptr_t used_data = length; | 
 |       set.set_used_data(used_data); | 
 |  | 
 |       const auto& data = Array::Handle(Z, Array::New(used_data)); | 
 |       set.set_data(data); | 
 |  | 
 |       set.set_deleted_keys(0); | 
 |       set.ComputeAndSetHashMask(); | 
 |  | 
 |       Instance& constant = Instance::Handle(Z); | 
 |       for (intptr_t j = 0; j < used_data; ++j) { | 
 |         // Recurse into lazily evaluating all "sub" constants | 
 |         // needed to evaluate the current constant. | 
 |         const intptr_t entry_index = reader.ReadUInt(); | 
 |         ASSERT(entry_index < constant_offset);  // DAG! | 
 |         constant = ReadConstant(entry_index); | 
 |         data.SetAt(j, constant); | 
 |       } | 
 |  | 
 |       instance = set.ptr(); | 
 |       break; | 
 |     } | 
 |     case kInstanceConstant: { | 
 |       const NameIndex index = reader.ReadCanonicalNameReference(); | 
 |       const auto& klass = Class::Handle(Z, H.LookupClassByKernelClass(index)); | 
 |       if (!klass.is_declaration_loaded()) { | 
 |         FATAL( | 
 |             "Trying to evaluate an instance constant whose references class " | 
 |             "%s is not loaded yet.", | 
 |             klass.ToCString()); | 
 |       } | 
 |       const auto& obj = | 
 |           Object::Handle(Z, klass.EnsureIsAllocateFinalized(H.thread())); | 
 |       ASSERT(obj.IsNull()); | 
 |       ASSERT(klass.is_enum_class() || klass.is_const()); | 
 |       instance = Instance::New(klass, Heap::kOld); | 
 |       // Build type from the raw bytes (needs temporary translator). | 
 |       TypeTranslator type_translator(&reader, this, active_class_, | 
 |                                      /* finalize = */ true, | 
 |                                      /* in_constant_context = */ true); | 
 |       const intptr_t number_of_type_arguments = reader.ReadUInt(); | 
 |       if (klass.NumTypeArguments() > 0) { | 
 |         auto& type_arguments = TypeArguments::Handle( | 
 |             Z, TypeArguments::New(number_of_type_arguments, Heap::kOld)); | 
 |         for (intptr_t j = 0; j < number_of_type_arguments; ++j) { | 
 |           type_arguments.SetTypeAt(j, type_translator.BuildType()); | 
 |         } | 
 |         // Instantiate class. | 
 |         type_arguments = | 
 |             klass.GetInstanceTypeArguments(H.thread(), type_arguments); | 
 |         instance.SetTypeArguments(type_arguments); | 
 |       } else { | 
 |         ASSERT(number_of_type_arguments == 0); | 
 |       } | 
 |       // Set the fields. | 
 |       const intptr_t number_of_fields = reader.ReadUInt(); | 
 |       Field& field = Field::Handle(Z); | 
 |       Instance& constant = Instance::Handle(Z); | 
 |       for (intptr_t j = 0; j < number_of_fields; ++j) { | 
 |         field = H.LookupFieldByKernelField(reader.ReadCanonicalNameReference()); | 
 |         // Recurse into lazily evaluating all "sub" constants | 
 |         // needed to evaluate the current constant. | 
 |         const intptr_t entry_index = reader.ReadUInt(); | 
 |         ASSERT(entry_index < constant_offset);  // DAG! | 
 |         constant = ReadConstant(entry_index); | 
 |         instance.SetField(field, constant); | 
 |       } | 
 |       break; | 
 |     } | 
 |     case kInstantiationConstant: { | 
 |       // Recurse into lazily evaluating the "sub" constant | 
 |       // needed to evaluate the current constant. | 
 |       const intptr_t entry_index = reader.ReadUInt(); | 
 |       ASSERT(entry_index < constant_offset);  // DAG! | 
 |       const auto& constant = Instance::Handle(Z, ReadConstant(entry_index)); | 
 |       ASSERT(!constant.IsNull()); | 
 |  | 
 |       // Build type from the raw bytes (needs temporary translator). | 
 |       TypeTranslator type_translator(&reader, this, active_class_, | 
 |                                      /* finalize = */ true, | 
 |                                      /* in_constant_context = */ true); | 
 |       const intptr_t number_of_type_arguments = reader.ReadUInt(); | 
 |       ASSERT(number_of_type_arguments > 0); | 
 |       auto& type_arguments = TypeArguments::Handle( | 
 |           Z, TypeArguments::New(number_of_type_arguments, Heap::kOld)); | 
 |       for (intptr_t j = 0; j < number_of_type_arguments; ++j) { | 
 |         type_arguments.SetTypeAt(j, type_translator.BuildType()); | 
 |       } | 
 |       type_arguments = type_arguments.Canonicalize(Thread::Current()); | 
 |       // Make a copy of the old closure, and set delayed type arguments. | 
 |       Closure& closure = Closure::Handle(Z, Closure::RawCast(constant.ptr())); | 
 |       Function& function = Function::Handle(Z, closure.function()); | 
 |       const auto& type_arguments2 = | 
 |           TypeArguments::Handle(Z, closure.instantiator_type_arguments()); | 
 |       // The function type arguments are used for type parameters from enclosing | 
 |       // closures. Though inner closures cannot be constants. We should | 
 |       // therefore see `null here. | 
 |       ASSERT(closure.function_type_arguments() == TypeArguments::null()); | 
 |       Object& context = Object::Handle(Z, closure.RawContext()); | 
 |       instance = Closure::New(type_arguments2, Object::null_type_arguments(), | 
 |                               type_arguments, function, context, Heap::kOld); | 
 |       break; | 
 |     } | 
 |     case kStaticTearOffConstant: | 
 |     case kConstructorTearOffConstant: | 
 |     case kRedirectingFactoryTearOffConstant: { | 
 |       const NameIndex index = reader.ReadCanonicalNameReference(); | 
 |       Function& function = Function::Handle(Z); | 
 |       if (H.IsConstructor(index)) { | 
 |         function = H.LookupConstructorByKernelConstructor(index); | 
 |       } else { | 
 |         function = H.LookupStaticMethodByKernelProcedure(index); | 
 |       } | 
 |       function = function.ImplicitClosureFunction(); | 
 |       instance = function.ImplicitStaticClosure(); | 
 |       break; | 
 |     } | 
 |     case kTypeLiteralConstant: { | 
 |       // Build type from the raw bytes (needs temporary translator). | 
 |       // Const canonical type erasure is not applied to constant type literals. | 
 |       // However, CFE must ensure that constant type literals can be | 
 |       // canonicalized to an identical representant independently of the null | 
 |       // safety mode currently in use (sound or unsound) or migration state of | 
 |       // the declaring library (legacy or opted-in). | 
 |       TypeTranslator type_translator(&reader, this, active_class_, | 
 |                                      /* finalize = */ true, | 
 |                                      /* in_constant_context = */ true); | 
 |       instance = type_translator.BuildType().ptr(); | 
 |       break; | 
 |     } | 
 |     default: | 
 |       // We should never see unevaluated constants (kUnevaluatedConstant) in | 
 |       // the constant table, they should have been fully evaluated before we | 
 |       // get them. | 
 |       const auto& script = Script::Handle(Z, Script()); | 
 |       H.ReportError(script, TokenPosition::kNoSource, | 
 |                     "Cannot lazily read constant: unexpected kernel tag (%" Pd | 
 |                     ")", | 
 |                     constant_tag); | 
 |   } | 
 |   return H.Canonicalize(instance); | 
 | } | 
 |  | 
 | }  // namespace kernel | 
 | }  // namespace dart |