f98a2138b7
When uploading CLs, the presubmit checks verify that the lines in the diff are formatted correctly according to `git cl format runtime`. However, when `buildtools/<os>-<arch>/clang/bin/clang-format` is updated, it does not force reformatting of files that would be reformatted. This leads to two issues: * Inconsistent style within the code base and within a single file. * Spurious reformatting in CLs when (1) clang-format is used on the whole file, or (2) the diff lines overlap. `clang-format` doesn't change that frequently, so in general this is not a large issue, but I've seen a bit too many "spurious formatting, please revert" comments on CLs recently. This CL formats the runtime to be in line with the current pinned `clang-format`: ``` $ find runtime/ -iname *.h -o -iname *.cc | xargs buildtools/mac-arm64/clang/bin/clang-format -i ``` `git cl format` (which only formats changed lines, and does so with `clang-format`) seems to not agree with itself, or clang-format, or cpplint in a handful of places. This CL adds `// clang-format off` for these. (See previous patchsets for the specific instances.) TEST=A variety of bots including GCC, MacOS and Windows. Change-Id: I470892e898971899fda14bb3b8f2c8efefd67686 Cq-Include-Trybots: luci.dart.try:vm-gcc-linux-try,vm-ffi-qemu-linux-release-riscv64-try,vm-ffi-qemu-linux-release-arm-try,vm-aot-win-debug-x64-try,vm-win-debug-x64c-try,vm-mac-debug-x64-try,vm-mac-debug-arm64-try,vm-aot-linux-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/362780 Reviewed-by: Ryan Macnak <rmacnak@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
610 lines
24 KiB
C++
610 lines
24 KiB
C++
// 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
|