Revert "[VM/nnbd] Canonicalize TypeParameter objects in the VM."
This reverts commit 6a98e2719e.
Reason for revert: Unexpected test failures
Original change's description:
> [VM/nnbd] Canonicalize TypeParameter objects in the VM.
>
> Prior to this CL, type parameters were all assumed canonical, even duplicate ones.
>
> Per a new convention introduced in this CL, the type parameter array in generic classes and generic functions contains canonical type parameters. As these type parameters get cloned with a different nullability, they are inserted in a new hash table of canonical type parameters.
>
> This fixes performance issue https://github.com/dart-lang/sdk/issues/41421
>
> Change-Id: I9086158fa6b6261e9997bb50edec6d7c54abbfa1
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/148223
> Commit-Queue: Régis Crelier <regis@google.com>
> Reviewed-by: Ryan Macnak <rmacnak@google.com>
TBR=rmacnak@google.com,alexmarkov@google.com,asiva@google.com,regis@google.com
Change-Id: I0ca3b6b66e2281c285eba6b564f78c0e6b2f2217
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/150265
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Régis Crelier <regis@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
6a98e2719e
commit
c48263e901
@@ -300,13 +300,13 @@ void ClassFinalizer::VerifyBootstrapClasses() {
|
||||
}
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
void ClassFinalizer::FinalizeTypeParameters(const Class& cls) {
|
||||
void ClassFinalizer::FinalizeTypeParameters(const Class& cls,
|
||||
PendingTypes* pending_types) {
|
||||
if (FLAG_trace_type_finalization) {
|
||||
THR_Print("Finalizing type parameters of '%s'\n",
|
||||
String::Handle(cls.Name()).ToCString());
|
||||
}
|
||||
// The type parameter bounds are not finalized here.
|
||||
const intptr_t offset = cls.NumTypeArguments() - cls.NumTypeParameters();
|
||||
const TypeArguments& type_parameters =
|
||||
TypeArguments::Handle(cls.type_parameters());
|
||||
if (!type_parameters.IsNull()) {
|
||||
@@ -314,14 +314,9 @@ void ClassFinalizer::FinalizeTypeParameters(const Class& cls) {
|
||||
const intptr_t num_types = type_parameters.Length();
|
||||
for (intptr_t i = 0; i < num_types; i++) {
|
||||
type_parameter ^= type_parameters.TypeAt(i);
|
||||
if (!type_parameter.IsFinalized()) {
|
||||
type_parameter.set_index(type_parameter.index() + offset);
|
||||
type_parameter.SetIsFinalized();
|
||||
}
|
||||
if (!type_parameter.IsCanonical()) {
|
||||
// The declaration of a type parameter is canonical.
|
||||
type_parameter.SetCanonical();
|
||||
}
|
||||
type_parameter ^=
|
||||
FinalizeType(cls, type_parameter, kFinalize, pending_types);
|
||||
type_parameters.SetTypeAt(i, type_parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -430,7 +425,7 @@ intptr_t ClassFinalizer::ExpandAndFinalizeTypeArguments(
|
||||
Class& type_class = Class::Handle(zone, type.type_class());
|
||||
type_class.EnsureDeclarationLoaded();
|
||||
if (!type_class.is_type_finalized()) {
|
||||
FinalizeTypeParameters(type_class);
|
||||
FinalizeTypeParameters(type_class, pending_types);
|
||||
}
|
||||
|
||||
// The finalized type argument vector needs num_type_arguments types.
|
||||
@@ -564,7 +559,7 @@ void ClassFinalizer::FinalizeTypeArguments(const Class& cls,
|
||||
TrailPtr trail) {
|
||||
ASSERT(arguments.Length() >= cls.NumTypeArguments());
|
||||
if (!cls.is_type_finalized()) {
|
||||
FinalizeTypeParameters(cls);
|
||||
FinalizeTypeParameters(cls, pending_types);
|
||||
}
|
||||
AbstractType& super_type = AbstractType::Handle(cls.super_type());
|
||||
if (!super_type.IsNull()) {
|
||||
@@ -682,7 +677,8 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const Class& cls,
|
||||
ASSERT((pending_types == NULL) || (finalization < kCanonicalize));
|
||||
if (type.IsFinalized()) {
|
||||
// Ensure type is canonical if canonicalization is requested.
|
||||
if ((finalization >= kCanonicalize) && !type.IsCanonical()) {
|
||||
if ((finalization >= kCanonicalize) && !type.IsCanonical() &&
|
||||
type.IsType()) {
|
||||
return type.Canonicalize();
|
||||
}
|
||||
return type.raw();
|
||||
@@ -735,7 +731,8 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const Class& cls,
|
||||
type_parameter.index());
|
||||
}
|
||||
|
||||
return type_parameter.Canonicalize();
|
||||
// We do not canonicalize type parameters.
|
||||
return type_parameter.raw();
|
||||
}
|
||||
|
||||
// At this point, we can only have a Type.
|
||||
@@ -848,12 +845,7 @@ void ClassFinalizer::FinalizeSignature(const Class& cls,
|
||||
if (!type_param.IsFinalized()) {
|
||||
type_param.set_index(num_parent_type_params + i);
|
||||
type_param.SetIsFinalized();
|
||||
// The declaration of a type parameter is canonical.
|
||||
type_param.SetCanonical();
|
||||
}
|
||||
}
|
||||
for (intptr_t i = 0; i < num_type_params; i++) {
|
||||
type_param ^= type_params.TypeAt(i);
|
||||
type = type_param.bound();
|
||||
finalized_type = FinalizeType(cls, type, finalization);
|
||||
if (finalized_type.raw() != type.raw()) {
|
||||
@@ -1594,7 +1586,6 @@ void ClassFinalizer::RemapClassIds(intptr_t* old_to_new_cid) {
|
||||
// Usages of canonical hash codes are:
|
||||
//
|
||||
// * ObjectStore::canonical_types()
|
||||
// * ObjectStore::canonical_type_parameters()
|
||||
// * ObjectStore::canonical_type_arguments()
|
||||
// * Class::constants()
|
||||
//
|
||||
@@ -1663,33 +1654,6 @@ void ClassFinalizer::RehashTypes() {
|
||||
}
|
||||
object_store->set_canonical_types(types_table.Release());
|
||||
|
||||
// Rehash the canonical TypeParameters table.
|
||||
Array& typeparams_array = Array::Handle(Z);
|
||||
GrowableObjectArray& typeparams =
|
||||
GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
|
||||
TypeParameter& typeparam = TypeParameter::Handle(Z);
|
||||
{
|
||||
CanonicalTypeParameterSet typeparams_table(
|
||||
Z, object_store->canonical_type_parameters());
|
||||
typeparams_array = HashTables::ToArray(typeparams_table, false);
|
||||
for (intptr_t i = 0; i < typeparams_array.Length(); i++) {
|
||||
typeparam ^= typeparams_array.At(i);
|
||||
typeparams.Add(typeparam);
|
||||
}
|
||||
typeparams_table.Release();
|
||||
}
|
||||
|
||||
dict_size = Utils::RoundUpToPowerOfTwo(typeparams.Length() * 4 / 3);
|
||||
typeparams_array =
|
||||
HashTables::New<CanonicalTypeParameterSet>(dict_size, Heap::kOld);
|
||||
CanonicalTypeParameterSet typeparams_table(Z, typeparams_array.raw());
|
||||
for (intptr_t i = 0; i < typeparams.Length(); i++) {
|
||||
typeparam ^= typeparams.At(i);
|
||||
bool present = typeparams_table.Insert(typeparam);
|
||||
ASSERT(!present);
|
||||
}
|
||||
object_store->set_canonical_type_parameters(typeparams_table.Release());
|
||||
|
||||
// Rehash the canonical TypeArguments table.
|
||||
Array& typeargs_array = Array::Handle(Z);
|
||||
GrowableObjectArray& typeargs =
|
||||
|
||||
@@ -79,7 +79,8 @@ class ClassFinalizer : public AllStatic {
|
||||
|
||||
private:
|
||||
static void AllocateEnumValues(const Class& enum_cls);
|
||||
static void FinalizeTypeParameters(const Class& cls);
|
||||
static void FinalizeTypeParameters(const Class& cls,
|
||||
PendingTypes* pending_types = NULL);
|
||||
static intptr_t ExpandAndFinalizeTypeArguments(const Class& cls,
|
||||
const AbstractType& type,
|
||||
PendingTypes* pending_types);
|
||||
|
||||
@@ -3498,28 +3498,19 @@ class TypeRefDeserializationCluster : public DeserializationCluster {
|
||||
class TypeParameterSerializationCluster : public SerializationCluster {
|
||||
public:
|
||||
TypeParameterSerializationCluster() : SerializationCluster("TypeParameter") {}
|
||||
|
||||
~TypeParameterSerializationCluster() {}
|
||||
|
||||
void Trace(Serializer* s, ObjectPtr object) {
|
||||
TypeParameterPtr type = TypeParameter::RawCast(object);
|
||||
if (type->ptr()->IsCanonical()) {
|
||||
canonical_objects_.Add(type);
|
||||
} else {
|
||||
objects_.Add(type);
|
||||
}
|
||||
|
||||
objects_.Add(type);
|
||||
ASSERT(!type->ptr()->IsCanonical());
|
||||
PushFromTo(type);
|
||||
}
|
||||
|
||||
void WriteAlloc(Serializer* s) {
|
||||
s->WriteCid(kTypeParameterCid);
|
||||
intptr_t count = canonical_objects_.length();
|
||||
s->WriteUnsigned(count);
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
TypeParameterPtr type = canonical_objects_[i];
|
||||
s->AssignRef(type);
|
||||
}
|
||||
count = objects_.length();
|
||||
const intptr_t count = objects_.length();
|
||||
s->WriteUnsigned(count);
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
TypeParameterPtr type = objects_[i];
|
||||
@@ -3528,21 +3519,7 @@ class TypeParameterSerializationCluster : public SerializationCluster {
|
||||
}
|
||||
|
||||
void WriteFill(Serializer* s) {
|
||||
intptr_t count = canonical_objects_.length();
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
TypeParameterPtr type = canonical_objects_[i];
|
||||
AutoTraceObject(type);
|
||||
WriteFromTo(type);
|
||||
s->Write<int32_t>(type->ptr()->parameterized_class_id_);
|
||||
s->WriteTokenPosition(type->ptr()->token_pos_);
|
||||
s->Write<int16_t>(type->ptr()->index_);
|
||||
const uint8_t combined =
|
||||
(type->ptr()->flags_ << 4) | type->ptr()->nullability_;
|
||||
ASSERT(type->ptr()->flags_ == (combined >> 4));
|
||||
ASSERT(type->ptr()->nullability_ == (combined & 0xf));
|
||||
s->Write<uint8_t>(combined);
|
||||
}
|
||||
count = objects_.length();
|
||||
const intptr_t count = objects_.length();
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
TypeParameterPtr type = objects_[i];
|
||||
AutoTraceObject(type);
|
||||
@@ -3559,7 +3536,6 @@ class TypeParameterSerializationCluster : public SerializationCluster {
|
||||
}
|
||||
|
||||
private:
|
||||
GrowableArray<TypeParameterPtr> canonical_objects_;
|
||||
GrowableArray<TypeParameterPtr> objects_;
|
||||
};
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
@@ -3570,17 +3546,9 @@ class TypeParameterDeserializationCluster : public DeserializationCluster {
|
||||
~TypeParameterDeserializationCluster() {}
|
||||
|
||||
void ReadAlloc(Deserializer* d) {
|
||||
canonical_start_index_ = d->next_index();
|
||||
PageSpace* old_space = d->heap()->old_space();
|
||||
intptr_t count = d->ReadUnsigned();
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
d->AssignRef(
|
||||
AllocateUninitialized(old_space, TypeParameter::InstanceSize()));
|
||||
}
|
||||
canonical_stop_index_ = d->next_index();
|
||||
|
||||
start_index_ = d->next_index();
|
||||
count = d->ReadUnsigned();
|
||||
PageSpace* old_space = d->heap()->old_space();
|
||||
const intptr_t count = d->ReadUnsigned();
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
d->AssignRef(
|
||||
AllocateUninitialized(old_space, TypeParameter::InstanceSize()));
|
||||
@@ -3589,26 +3557,10 @@ class TypeParameterDeserializationCluster : public DeserializationCluster {
|
||||
}
|
||||
|
||||
void ReadFill(Deserializer* d) {
|
||||
for (intptr_t id = canonical_start_index_; id < canonical_stop_index_;
|
||||
id++) {
|
||||
TypeParameterPtr type = static_cast<TypeParameterPtr>(d->Ref(id));
|
||||
bool is_canonical = true;
|
||||
Deserializer::InitializeHeader(
|
||||
type, kTypeParameterCid, TypeParameter::InstanceSize(), is_canonical);
|
||||
ReadFromTo(type);
|
||||
type->ptr()->parameterized_class_id_ = d->Read<int32_t>();
|
||||
type->ptr()->token_pos_ = d->ReadTokenPosition();
|
||||
type->ptr()->index_ = d->Read<int16_t>();
|
||||
const uint8_t combined = d->Read<uint8_t>();
|
||||
type->ptr()->flags_ = combined >> 4;
|
||||
type->ptr()->nullability_ = combined & 0xf;
|
||||
}
|
||||
|
||||
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
||||
TypeParameterPtr type = static_cast<TypeParameterPtr>(d->Ref(id));
|
||||
bool is_canonical = false;
|
||||
Deserializer::InitializeHeader(
|
||||
type, kTypeParameterCid, TypeParameter::InstanceSize(), is_canonical);
|
||||
Deserializer::InitializeHeader(type, kTypeParameterCid,
|
||||
TypeParameter::InstanceSize());
|
||||
ReadFromTo(type);
|
||||
type->ptr()->parameterized_class_id_ = d->Read<int32_t>();
|
||||
type->ptr()->token_pos_ = d->ReadTokenPosition();
|
||||
@@ -3624,13 +3576,6 @@ class TypeParameterDeserializationCluster : public DeserializationCluster {
|
||||
Code& stub = Code::Handle(zone);
|
||||
|
||||
if (Snapshot::IncludesCode(kind)) {
|
||||
for (intptr_t id = canonical_start_index_; id < canonical_stop_index_;
|
||||
id++) {
|
||||
type_param ^= refs.At(id);
|
||||
stub = type_param.type_test_stub();
|
||||
type_param.SetTypeTestingStub(
|
||||
stub); // Update type_test_stub_entry_point_
|
||||
}
|
||||
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
||||
type_param ^= refs.At(id);
|
||||
stub = type_param.type_test_stub();
|
||||
@@ -3638,12 +3583,6 @@ class TypeParameterDeserializationCluster : public DeserializationCluster {
|
||||
stub); // Update type_test_stub_entry_point_
|
||||
}
|
||||
} else {
|
||||
for (intptr_t id = canonical_start_index_; id < canonical_stop_index_;
|
||||
id++) {
|
||||
type_param ^= refs.At(id);
|
||||
stub = TypeTestingStubGenerator::DefaultCodeForType(type_param);
|
||||
type_param.SetTypeTestingStub(stub);
|
||||
}
|
||||
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
||||
type_param ^= refs.At(id);
|
||||
stub = TypeTestingStubGenerator::DefaultCodeForType(type_param);
|
||||
@@ -3651,10 +3590,6 @@ class TypeParameterDeserializationCluster : public DeserializationCluster {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
intptr_t canonical_start_index_;
|
||||
intptr_t canonical_stop_index_;
|
||||
};
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
@@ -384,7 +384,6 @@ void Precompiler::DoCompileAll() {
|
||||
DropFields();
|
||||
TraceTypesFromRetainedClasses();
|
||||
DropTypes();
|
||||
DropTypeParameters();
|
||||
DropTypeArguments();
|
||||
|
||||
// Clear these before dropping classes as they may hold onto otherwise
|
||||
@@ -1784,45 +1783,6 @@ void Precompiler::DropTypes() {
|
||||
object_store->set_canonical_types(types_table.Release());
|
||||
}
|
||||
|
||||
void Precompiler::DropTypeParameters() {
|
||||
ObjectStore* object_store = I->object_store();
|
||||
GrowableObjectArray& retained_typeparams =
|
||||
GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
|
||||
Array& typeparams_array = Array::Handle(Z);
|
||||
TypeParameter& typeparam = TypeParameter::Handle(Z);
|
||||
// First drop all the type parameters that are not referenced.
|
||||
{
|
||||
CanonicalTypeParameterSet typeparams_table(
|
||||
Z, object_store->canonical_type_parameters());
|
||||
typeparams_array = HashTables::ToArray(typeparams_table, false);
|
||||
for (intptr_t i = 0; i < typeparams_array.Length(); i++) {
|
||||
typeparam ^= typeparams_array.At(i);
|
||||
bool retain = typeparams_to_retain_.HasKey(&typeparam);
|
||||
if (retain) {
|
||||
retained_typeparams.Add(typeparam);
|
||||
} else {
|
||||
typeparam.ClearCanonical();
|
||||
dropped_typeparam_count_++;
|
||||
}
|
||||
}
|
||||
typeparams_table.Release();
|
||||
}
|
||||
|
||||
// Now construct a new type parameter table and save in the object store.
|
||||
const intptr_t dict_size =
|
||||
Utils::RoundUpToPowerOfTwo(retained_typeparams.Length() * 4 / 3);
|
||||
typeparams_array =
|
||||
HashTables::New<CanonicalTypeParameterSet>(dict_size, Heap::kOld);
|
||||
CanonicalTypeParameterSet typeparams_table(Z, typeparams_array.raw());
|
||||
bool present;
|
||||
for (intptr_t i = 0; i < retained_typeparams.Length(); i++) {
|
||||
typeparam ^= retained_typeparams.At(i);
|
||||
present = typeparams_table.Insert(typeparam);
|
||||
ASSERT(!present);
|
||||
}
|
||||
object_store->set_canonical_type_parameters(typeparams_table.Release());
|
||||
}
|
||||
|
||||
void Precompiler::DropTypeArguments() {
|
||||
ObjectStore* object_store = I->object_store();
|
||||
Array& typeargs_array = Array::Handle(Z);
|
||||
|
||||
@@ -149,26 +149,6 @@ class AbstractTypeKeyValueTrait {
|
||||
|
||||
typedef DirectChainedHashMap<AbstractTypeKeyValueTrait> AbstractTypeSet;
|
||||
|
||||
class TypeParameterKeyValueTrait {
|
||||
public:
|
||||
// Typedefs needed for the DirectChainedHashMap template.
|
||||
typedef const TypeParameter* Key;
|
||||
typedef const TypeParameter* Value;
|
||||
typedef const TypeParameter* Pair;
|
||||
|
||||
static Key KeyOf(Pair kv) { return kv; }
|
||||
|
||||
static Value ValueOf(Pair kv) { return kv; }
|
||||
|
||||
static inline intptr_t Hashcode(Key key) { return key->Hash(); }
|
||||
|
||||
static inline bool IsKeyEqual(Pair pair, Key key) {
|
||||
return pair->raw() == key->raw();
|
||||
}
|
||||
};
|
||||
|
||||
typedef DirectChainedHashMap<TypeParameterKeyValueTrait> TypeParameterSet;
|
||||
|
||||
class TypeArgumentsKeyValueTrait {
|
||||
public:
|
||||
// Typedefs needed for the DirectChainedHashMap template.
|
||||
@@ -290,7 +270,6 @@ class Precompiler : public ValueObject {
|
||||
void DropFields();
|
||||
void TraceTypesFromRetainedClasses();
|
||||
void DropTypes();
|
||||
void DropTypeParameters();
|
||||
void DropTypeArguments();
|
||||
void DropMetadata();
|
||||
void DropLibraryEntries();
|
||||
@@ -330,7 +309,6 @@ class Precompiler : public ValueObject {
|
||||
intptr_t dropped_class_count_;
|
||||
intptr_t dropped_typearg_count_;
|
||||
intptr_t dropped_type_count_;
|
||||
intptr_t dropped_typeparam_count_;
|
||||
intptr_t dropped_library_count_;
|
||||
|
||||
compiler::ObjectPoolBuilder global_object_pool_builder_;
|
||||
@@ -344,7 +322,6 @@ class Precompiler : public ValueObject {
|
||||
ClassSet classes_to_retain_;
|
||||
TypeArgumentsSet typeargs_to_retain_;
|
||||
AbstractTypeSet types_to_retain_;
|
||||
TypeParameterSet typeparams_to_retain_;
|
||||
InstanceSet consts_to_retain_;
|
||||
TableSelectorSet seen_table_selectors_;
|
||||
Error& error_;
|
||||
|
||||
@@ -671,7 +671,6 @@ void BytecodeReaderHelper::ReadTypeParametersDeclaration(
|
||||
nullability, TokenPosition::kNoSource);
|
||||
parameter.set_index(offset + i);
|
||||
parameter.SetIsFinalized();
|
||||
parameter.SetCanonical();
|
||||
type_parameters.SetTypeAt(i, parameter);
|
||||
}
|
||||
|
||||
|
||||
+5
-107
@@ -1661,12 +1661,6 @@ ErrorPtr Object::Init(Isolate* isolate,
|
||||
Heap::kOld);
|
||||
object_store->set_canonical_types(array);
|
||||
|
||||
// Initialize hash set for canonical type parameters.
|
||||
const intptr_t kInitialCanonicalTypeParameterSize = 4;
|
||||
array = HashTables::New<CanonicalTypeParameterSet>(
|
||||
kInitialCanonicalTypeParameterSize, Heap::kOld);
|
||||
object_store->set_canonical_type_parameters(array);
|
||||
|
||||
// Initialize hash set for canonical_type_arguments_.
|
||||
const intptr_t kInitialCanonicalTypeArgumentsSize = 4;
|
||||
array = HashTables::New<CanonicalTypeArgumentsSet>(
|
||||
@@ -4894,8 +4888,9 @@ TypePtr Class::DeclarationType() const {
|
||||
}
|
||||
// For efficiency, the runtimeType intrinsic returns the type cached by
|
||||
// DeclarationType without checking its nullability. Therefore, we
|
||||
// consistently cache the kNonNullable version of the type.
|
||||
// The exception is type Null which is stored as kNullable.
|
||||
// consistently cache the kLegacy version of a type, unless the non-nullable
|
||||
// experiment is enabled, in which case we store the kNonNullable version.
|
||||
// In either cases, the exception is type Null which is stored as kNullable.
|
||||
Type& type =
|
||||
Type::Handle(Type::New(*this, TypeArguments::Handle(type_parameters()),
|
||||
token_pos(), Nullability::kNonNullable));
|
||||
@@ -7934,13 +7929,11 @@ FunctionPtr Function::InstantiateSignatureFrom(
|
||||
cls = type_param.parameterized_class();
|
||||
param_name = type_param.name();
|
||||
ASSERT(type_param.IsFinalized());
|
||||
ASSERT(type_param.IsCanonical());
|
||||
type_param = TypeParameter::New(
|
||||
cls, sig, type_param.index(), param_name, type,
|
||||
type_param.IsGenericCovariantImpl(), type_param.nullability(),
|
||||
type_param.token_pos());
|
||||
type_param.SetIsFinalized();
|
||||
type_param.SetCanonical();
|
||||
if (instantiated_type_params.IsNull()) {
|
||||
instantiated_type_params = TypeArguments::New(type_params.Length());
|
||||
for (intptr_t j = 0; j < i; ++j) {
|
||||
@@ -19268,6 +19261,7 @@ TypePtr Type::ToNullability(Nullability value, Heap::Space space) const {
|
||||
ASSERT(!type.IsCanonical());
|
||||
type ^= type.Canonicalize();
|
||||
}
|
||||
// TODO(regis): Should we link canonical types of different nullability?
|
||||
return type.raw();
|
||||
}
|
||||
|
||||
@@ -20116,11 +20110,7 @@ TypeParameterPtr TypeParameter::ToNullability(Nullability value,
|
||||
type_parameter.SetHash(0);
|
||||
type_parameter.SetTypeTestingStub(Code::Handle(
|
||||
TypeTestingStubGenerator::DefaultCodeForType(type_parameter)));
|
||||
if (IsCanonical()) {
|
||||
// Object::Clone does not clone canonical bit.
|
||||
ASSERT(!type_parameter.IsCanonical());
|
||||
type_parameter ^= type_parameter.Canonicalize();
|
||||
}
|
||||
// TODO(regis): Should we link type parameters of different nullability?
|
||||
return type_parameter.raw();
|
||||
}
|
||||
|
||||
@@ -20306,90 +20296,6 @@ AbstractTypePtr TypeParameter::InstantiateFrom(
|
||||
// not only happens at run time, but also during type finalization.
|
||||
}
|
||||
|
||||
AbstractTypePtr TypeParameter::Canonicalize(TrailPtr trail) const {
|
||||
ASSERT(IsFinalized());
|
||||
if (IsCanonical()) {
|
||||
return this->raw();
|
||||
}
|
||||
Thread* thread = Thread::Current();
|
||||
Zone* zone = thread->zone();
|
||||
Isolate* isolate = thread->isolate();
|
||||
|
||||
const Class& cls = Class::Handle(zone, parameterized_class());
|
||||
const Function& function = Function::Handle(
|
||||
zone, cls.IsNull() ? parameterized_function() : Function::null());
|
||||
const TypeArguments& type_params = TypeArguments::Handle(
|
||||
zone, cls.IsNull() ? function.type_parameters() : cls.type_parameters());
|
||||
const intptr_t offset =
|
||||
cls.IsNull() ? function.NumParentTypeParameters()
|
||||
: (cls.NumTypeArguments() - cls.NumTypeParameters());
|
||||
TypeParameter& type_parameter = TypeParameter::Handle(zone);
|
||||
type_parameter ^= type_params.TypeAt(index() - offset);
|
||||
ASSERT(!type_parameter.IsNull());
|
||||
if (type_parameter.nullability() == nullability()) {
|
||||
ASSERT(this->Equals(type_parameter));
|
||||
ASSERT(type_parameter.IsCanonical());
|
||||
ASSERT(type_parameter.IsOld());
|
||||
return type_parameter.raw();
|
||||
}
|
||||
|
||||
ObjectStore* object_store = isolate->object_store();
|
||||
{
|
||||
SafepointMutexLocker ml(isolate->group()->type_canonicalization_mutex());
|
||||
CanonicalTypeParameterSet table(zone,
|
||||
object_store->canonical_type_parameters());
|
||||
type_parameter ^= table.GetOrNull(CanonicalTypeParameterKey(*this));
|
||||
if (type_parameter.IsNull()) {
|
||||
// The type parameter was not found in the table. It is not canonical yet.
|
||||
// Add this type parameter into the canonical list of type parameters.
|
||||
if (this->IsNew()) {
|
||||
type_parameter ^= Object::Clone(*this, Heap::kOld);
|
||||
} else {
|
||||
type_parameter = this->raw();
|
||||
}
|
||||
ASSERT(type_parameter.IsOld());
|
||||
type_parameter.SetCanonical(); // Mark object as being canonical.
|
||||
bool present = table.Insert(type_parameter);
|
||||
ASSERT(!present);
|
||||
}
|
||||
object_store->set_canonical_type_parameters(table.Release());
|
||||
}
|
||||
return type_parameter.raw();
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
bool TypeParameter::CheckIsCanonical(Thread* thread) const {
|
||||
Zone* zone = thread->zone();
|
||||
Isolate* isolate = thread->isolate();
|
||||
|
||||
const Class& cls = Class::Handle(zone, parameterized_class());
|
||||
const Function& function = Function::Handle(
|
||||
zone, cls.IsNull() ? parameterized_function() : Function::null());
|
||||
const TypeArguments& type_params = TypeArguments::Handle(
|
||||
zone, cls.IsNull() ? function.type_parameters() : cls.type_parameters());
|
||||
const intptr_t offset =
|
||||
cls.IsNull() ? function.NumParentTypeParameters()
|
||||
: (cls.NumTypeArguments() - cls.NumTypeParameters());
|
||||
TypeParameter& type_parameter = TypeParameter::Handle(zone);
|
||||
type_parameter ^= type_params.TypeAt(index() - offset);
|
||||
ASSERT(!type_parameter.IsNull());
|
||||
if (type_parameter.nullability() == nullability()) {
|
||||
ASSERT(type_parameter.IsCanonical());
|
||||
return (raw() == type_parameter.raw());
|
||||
}
|
||||
|
||||
ObjectStore* object_store = isolate->object_store();
|
||||
{
|
||||
SafepointMutexLocker ml(isolate->group()->type_canonicalization_mutex());
|
||||
CanonicalTypeParameterSet table(zone,
|
||||
object_store->canonical_type_parameters());
|
||||
type_parameter ^= table.GetOrNull(CanonicalTypeParameterKey(*this));
|
||||
object_store->set_canonical_type_parameters(table.Release());
|
||||
}
|
||||
return (raw() == type_parameter.raw());
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
void TypeParameter::EnumerateURIs(URIs* uris) const {
|
||||
Thread* thread = Thread::Current();
|
||||
Zone* zone = thread->zone();
|
||||
@@ -24366,14 +24272,6 @@ void DumpTypeTable(Isolate* isolate) {
|
||||
table.Release();
|
||||
}
|
||||
|
||||
void DumpTypeParameterTable(Isolate* isolate) {
|
||||
OS::PrintErr("canonical type parameters (cloned from declarations):\n");
|
||||
CanonicalTypeParameterSet table(
|
||||
isolate->object_store()->canonical_type_parameters());
|
||||
table.Dump();
|
||||
table.Release();
|
||||
}
|
||||
|
||||
void DumpTypeArgumentsTable(Isolate* isolate) {
|
||||
OS::PrintErr("canonical type arguments:\n");
|
||||
CanonicalTypeArgumentsSet table(
|
||||
|
||||
+7
-2
@@ -1097,6 +1097,9 @@ class Class : public Object {
|
||||
intptr_t NumTypeParameters() const {
|
||||
return NumTypeParameters(Thread::Current());
|
||||
}
|
||||
static intptr_t type_parameters_offset() {
|
||||
return OFFSET_OF(ClassLayout, type_parameters_);
|
||||
}
|
||||
|
||||
// Return a TypeParameter if the type_name is a type parameter of this class.
|
||||
// Return null otherwise.
|
||||
@@ -8173,10 +8176,12 @@ class TypeParameter : public AbstractType {
|
||||
intptr_t num_free_fun_type_params,
|
||||
Heap::Space space,
|
||||
TrailPtr trail = nullptr) const;
|
||||
virtual AbstractTypePtr Canonicalize(TrailPtr trail = nullptr) const;
|
||||
virtual AbstractTypePtr Canonicalize(TrailPtr trail = nullptr) const {
|
||||
return raw();
|
||||
}
|
||||
#if defined(DEBUG)
|
||||
// Check if type parameter is canonical.
|
||||
virtual bool CheckIsCanonical(Thread* thread) const;
|
||||
virtual bool CheckIsCanonical(Thread* thread) const { return true; }
|
||||
#endif // DEBUG
|
||||
virtual void EnumerateURIs(URIs* uris) const;
|
||||
|
||||
|
||||
@@ -130,7 +130,6 @@ class ObjectPointerVisitor;
|
||||
RW(Class, weak_property_class) \
|
||||
RW(Array, symbol_table) \
|
||||
RW(Array, canonical_types) \
|
||||
RW(Array, canonical_type_parameters) \
|
||||
RW(Array, canonical_type_arguments) \
|
||||
RW(Library, async_library) \
|
||||
RW(Library, builtin_library) \
|
||||
|
||||
@@ -229,7 +229,6 @@ TypeParameterPtr TypeParameter::ReadFrom(SnapshotReader* reader,
|
||||
// Allocate type parameter object.
|
||||
TypeParameter& type_parameter =
|
||||
TypeParameter::ZoneHandle(reader->zone(), TypeParameter::New());
|
||||
bool is_canonical = ObjectLayout::IsCanonical(tags);
|
||||
reader->AddBackRef(object_id, &type_parameter, kIsDeserialized);
|
||||
|
||||
// Set all non object fields.
|
||||
@@ -257,10 +256,6 @@ TypeParameterPtr TypeParameter::ReadFrom(SnapshotReader* reader,
|
||||
code = TypeTestingStubGenerator::DefaultCodeForType(type_parameter);
|
||||
type_parameter.SetTypeTestingStub(code);
|
||||
|
||||
if (is_canonical) {
|
||||
type_parameter ^= type_parameter.Canonicalize();
|
||||
}
|
||||
|
||||
return type_parameter.raw();
|
||||
}
|
||||
|
||||
|
||||
+1
-24
@@ -312,25 +312,21 @@ void Symbols::Compact() {
|
||||
// 1. Drop the tables and do a full garbage collection.
|
||||
object_store->set_symbol_table(Object::empty_array());
|
||||
object_store->set_canonical_types(Object::empty_array());
|
||||
object_store->set_canonical_type_parameters(Object::empty_array());
|
||||
object_store->set_canonical_type_arguments(Object::empty_array());
|
||||
thread->heap()->CollectAllGarbage();
|
||||
|
||||
// 2. Walk the heap to find surviving canonical objects.
|
||||
GrowableArray<String*> symbols;
|
||||
GrowableArray<class Type*> types;
|
||||
GrowableArray<class TypeParameter*> type_params;
|
||||
GrowableArray<class TypeArguments*> type_args;
|
||||
class SymbolCollector : public ObjectVisitor {
|
||||
public:
|
||||
SymbolCollector(Thread* thread,
|
||||
GrowableArray<String*>* symbols,
|
||||
GrowableArray<class Type*>* types,
|
||||
GrowableArray<class TypeParameter*>* type_params,
|
||||
GrowableArray<class TypeArguments*>* type_args)
|
||||
: symbols_(symbols),
|
||||
types_(types),
|
||||
type_params_(type_params),
|
||||
type_args_(type_args),
|
||||
zone_(thread->zone()) {}
|
||||
|
||||
@@ -340,9 +336,6 @@ void Symbols::Compact() {
|
||||
symbols_->Add(&String::Handle(zone_, String::RawCast(obj)));
|
||||
} else if (obj->IsType()) {
|
||||
types_->Add(&Type::Handle(zone_, Type::RawCast(obj)));
|
||||
} else if (obj->IsTypeParameter()) {
|
||||
type_params_->Add(
|
||||
&TypeParameter::Handle(zone_, TypeParameter::RawCast(obj)));
|
||||
} else if (obj->IsTypeArguments()) {
|
||||
type_args_->Add(
|
||||
&TypeArguments::Handle(zone_, TypeArguments::RawCast(obj)));
|
||||
@@ -353,14 +346,13 @@ void Symbols::Compact() {
|
||||
private:
|
||||
GrowableArray<String*>* symbols_;
|
||||
GrowableArray<class Type*>* types_;
|
||||
GrowableArray<class TypeParameter*>* type_params_;
|
||||
GrowableArray<class TypeArguments*>* type_args_;
|
||||
Zone* zone_;
|
||||
};
|
||||
|
||||
{
|
||||
HeapIterationScope iteration(thread);
|
||||
SymbolCollector visitor(thread, &symbols, &types, &type_params, &type_args);
|
||||
SymbolCollector visitor(thread, &symbols, &types, &type_args);
|
||||
iteration.IterateObjects(&visitor);
|
||||
}
|
||||
|
||||
@@ -395,21 +387,6 @@ void Symbols::Compact() {
|
||||
object_store->set_canonical_types(table.Release());
|
||||
}
|
||||
|
||||
{
|
||||
Array& array =
|
||||
Array::Handle(zone, HashTables::New<CanonicalTypeParameterSet>(
|
||||
type_params.length() * 4 / 3, Heap::kOld));
|
||||
CanonicalTypeParameterSet table(zone, array.raw());
|
||||
for (intptr_t i = 0; i < type_params.length(); i++) {
|
||||
class TypeParameter& type_param = *type_params[i];
|
||||
ASSERT(type_param.IsTypeParameter());
|
||||
ASSERT(type_param.IsCanonical());
|
||||
bool present = table.Insert(type_param);
|
||||
ASSERT(!present);
|
||||
}
|
||||
object_store->set_canonical_type_parameters(table.Release());
|
||||
}
|
||||
|
||||
{
|
||||
Array& array =
|
||||
Array::Handle(zone, HashTables::New<CanonicalTypeArgumentsSet>(
|
||||
|
||||
@@ -50,46 +50,6 @@ class CanonicalTypeTraits {
|
||||
};
|
||||
typedef UnorderedHashSet<CanonicalTypeTraits> CanonicalTypeSet;
|
||||
|
||||
class CanonicalTypeParameterKey {
|
||||
public:
|
||||
explicit CanonicalTypeParameterKey(const TypeParameter& key) : key_(key) {}
|
||||
bool Matches(const TypeParameter& arg) const { return key_.Equals(arg); }
|
||||
uword Hash() const { return key_.Hash(); }
|
||||
const TypeParameter& key_;
|
||||
|
||||
private:
|
||||
DISALLOW_ALLOCATION();
|
||||
};
|
||||
|
||||
// Traits for looking up Canonical TypeParameter based on its hash.
|
||||
class CanonicalTypeParameterTraits {
|
||||
public:
|
||||
static const char* Name() { return "CanonicalTypeParameterTraits"; }
|
||||
static bool ReportStats() { return false; }
|
||||
|
||||
// Called when growing the table.
|
||||
static bool IsMatch(const Object& a, const Object& b) {
|
||||
ASSERT(a.IsTypeParameter() && b.IsTypeParameter());
|
||||
const TypeParameter& arg1 = TypeParameter::Cast(a);
|
||||
const TypeParameter& arg2 = TypeParameter::Cast(b);
|
||||
return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
|
||||
}
|
||||
static bool IsMatch(const CanonicalTypeParameterKey& a, const Object& b) {
|
||||
ASSERT(b.IsTypeParameter());
|
||||
return a.Matches(TypeParameter::Cast(b));
|
||||
}
|
||||
static uword Hash(const Object& key) {
|
||||
ASSERT(key.IsTypeParameter());
|
||||
return TypeParameter::Cast(key).Hash();
|
||||
}
|
||||
static uword Hash(const CanonicalTypeParameterKey& key) { return key.Hash(); }
|
||||
static ObjectPtr NewKey(const CanonicalTypeParameterKey& obj) {
|
||||
return obj.key_.raw();
|
||||
}
|
||||
};
|
||||
typedef UnorderedHashSet<CanonicalTypeParameterTraits>
|
||||
CanonicalTypeParameterSet;
|
||||
|
||||
class CanonicalTypeArgumentsKey {
|
||||
public:
|
||||
explicit CanonicalTypeArgumentsKey(const TypeArguments& key) : key_(key) {}
|
||||
|
||||
Reference in New Issue
Block a user