Index: runtime/vm/object.cc |
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
index ad7b37ae34434626c45ade692961e4d8114c090a..aff8c27b7190f99c7f0094bd05b33f405c5da505 100644 |
--- a/runtime/vm/object.cc |
+++ b/runtime/vm/object.cc |
@@ -42,6 +42,7 @@ |
#include "vm/thread_registry.h" |
#include "vm/timeline.h" |
#include "vm/timer.h" |
+#include "vm/type_table.h" |
#include "vm/unicode.h" |
#include "vm/verified_memory.h" |
#include "vm/weak_code.h" |
@@ -1146,12 +1147,16 @@ NOT_IN_PRODUCT( |
GrowableObjectArray::type_arguments_offset()); |
cls.set_num_type_arguments(1); |
- // canonical_type_arguments_ are Smi terminated. |
- // Last element contains the count of used slots. |
+ // Initialize hash set for canonical_type_. |
+ const intptr_t kInitialCanonicalTypeSize = 16; |
+ array = HashTables::New<CanonicalTypeSet>( |
+ kInitialCanonicalTypeSize, Heap::kOld); |
+ object_store->set_canonical_types(array); |
+ |
+ // Initialize hash set for canonical_type_arguments_. |
const intptr_t kInitialCanonicalTypeArgumentsSize = 4; |
- array = Array::New(kInitialCanonicalTypeArgumentsSize + 1); |
- array.SetAt(kInitialCanonicalTypeArgumentsSize, |
- Smi::Handle(zone, Smi::New(0))); |
+ array = HashTables::New<CanonicalTypeArgumentsSet>( |
+ kInitialCanonicalTypeArgumentsSize, Heap::kOld); |
object_store->set_canonical_type_arguments(array); |
// Setup type class early in the process. |
@@ -3632,96 +3637,26 @@ void Class::set_constants(const Array& value) const { |
} |
-RawObject* Class::canonical_types() const { |
- return raw_ptr()->canonical_types_; |
+RawType* Class::canonical_type() const { |
+ return raw_ptr()->canonical_type_; |
} |
-void Class::set_canonical_types(const Object& value) const { |
+void Class::set_canonical_type(const Type& value) const { |
ASSERT(!value.IsNull()); |
- StorePointer(&raw_ptr()->canonical_types_, value.raw()); |
+ StorePointer(&raw_ptr()->canonical_type_, value.raw()); |
} |
RawType* Class::CanonicalType() const { |
- if (!IsGeneric() && !IsClosureClass()) { |
- return reinterpret_cast<RawType*>(raw_ptr()->canonical_types_); |
- } |
- Array& types = Array::Handle(); |
- types ^= canonical_types(); |
- if (!types.IsNull() && (types.Length() > 0)) { |
- return reinterpret_cast<RawType*>(types.At(0)); |
- } |
- return reinterpret_cast<RawType*>(Object::null()); |
+ return raw_ptr()->canonical_type_; |
} |
void Class::SetCanonicalType(const Type& type) const { |
- ASSERT(type.IsCanonical()); |
- if (!IsGeneric() && !IsClosureClass()) { |
- ASSERT((canonical_types() == Object::null()) || |
- (canonical_types() == type.raw())); // Set during own finalization. |
- set_canonical_types(type); |
- } else { |
- Array& types = Array::Handle(); |
- types ^= canonical_types(); |
- ASSERT(!types.IsNull() && (types.Length() > 1)); |
- ASSERT((types.At(0) == Object::null()) || (types.At(0) == type.raw())); |
- types.SetAt(0, type); |
- // Makes sure that 'canonical_types' has not changed. |
- ASSERT(types.raw() == canonical_types()); |
- } |
-} |
- |
- |
-intptr_t Class::FindCanonicalTypeIndex(const AbstractType& needle) const { |
- Thread* thread = Thread::Current(); |
- if (EnsureIsFinalized(thread) != Error::null()) { |
- return -1; |
- } |
- if (needle.raw() == CanonicalType()) { |
- // For a generic type or signature type, there exists another index with the |
- // same type. It will never be returned by this function. |
- return 0; |
- } |
- REUSABLE_OBJECT_HANDLESCOPE(thread); |
- Object& types = thread->ObjectHandle(); |
- types = canonical_types(); |
- if (types.IsNull()) { |
- return -1; |
- } |
- const intptr_t len = Array::Cast(types).Length(); |
- REUSABLE_ABSTRACT_TYPE_HANDLESCOPE(thread); |
- AbstractType& type = thread->AbstractTypeHandle(); |
- for (intptr_t i = 0; i < len; i++) { |
- type ^= Array::Cast(types).At(i); |
- if (needle.raw() == type.raw()) { |
- return i; |
- } |
- } |
- // No type found. |
- return -1; |
-} |
- |
- |
-RawAbstractType* Class::CanonicalTypeFromIndex(intptr_t idx) const { |
- AbstractType& type = AbstractType::Handle(); |
- if (idx == 0) { |
- type = CanonicalType(); |
- if (!type.IsNull()) { |
- return type.raw(); |
- } |
- } |
- Object& types = Object::Handle(canonical_types()); |
- if (types.IsNull() || !types.IsArray()) { |
- return Type::null(); |
- } |
- if ((idx < 0) || (idx >= Array::Cast(types).Length())) { |
- return Type::null(); |
- } |
- type ^= Array::Cast(types).At(idx); |
- ASSERT(!type.IsNull()); |
- return type.raw(); |
+ ASSERT((canonical_type() == Object::null()) || |
+ (canonical_type() == type.raw())); // Set during own finalization. |
+ set_canonical_type(type); |
} |
@@ -4293,84 +4228,6 @@ RawLibraryPrefix* Class::LookupLibraryPrefix(const String& name) const { |
} |
-// Returns AbstractType::null() if type not found. Modifies index to the last |
-// position looked up. |
-RawAbstractType* Class::LookupCanonicalType( |
- Zone* zone, const AbstractType& lookup_type, intptr_t* index) const { |
- Array& canonical_types = Array::Handle(zone); |
- canonical_types ^= this->canonical_types(); |
- if (canonical_types.IsNull()) { |
- return AbstractType::null(); |
- } |
- AbstractType& type = Type::Handle(zone); |
- const intptr_t length = canonical_types.Length(); |
- while (*index < length) { |
- type ^= canonical_types.At(*index); |
- if (type.IsNull()) { |
- break; |
- } |
- ASSERT(type.IsFinalized()); |
- if (lookup_type.Equals(type)) { |
- ASSERT(type.IsCanonical()); |
- return type.raw(); |
- } |
- *index = *index + 1; |
- } |
- return AbstractType::null(); |
-} |
- |
- |
-// Canonicalizing the type arguments may have changed the index, may have |
-// grown the table, or may even have canonicalized this type. Therefore |
-// conrtinue search for canonical type at the last index visited. |
-RawAbstractType* Class::LookupOrAddCanonicalType( |
- const AbstractType& lookup_type, intptr_t start_index) const { |
- Thread* thread = Thread::Current(); |
- Zone* zone = thread->zone(); |
- Isolate* isolate = thread->isolate(); |
- AbstractType& type = Type::Handle(zone); |
- intptr_t index = start_index; |
- type ^= LookupCanonicalType(zone, lookup_type, &index); |
- |
- if (!type.IsNull()) { |
- return type.raw(); |
- } |
- { |
- SafepointMutexLocker ml(isolate->type_canonicalization_mutex()); |
- // Lookup again, in case the canonicalization array changed. |
- Array& canonical_types = Array::Handle(zone); |
- canonical_types ^= this->canonical_types(); |
- if (canonical_types.IsNull()) { |
- canonical_types = empty_array().raw(); |
- } |
- const intptr_t length = canonical_types.Length(); |
- // Start looking after previously looked up last position ('length'). |
- type ^= LookupCanonicalType(zone, lookup_type, &index); |
- if (!type.IsNull()) { |
- return type.raw(); |
- } |
- |
- // 'lookup_type' is not canonicalized yet. |
- lookup_type.SetCanonical(); |
- |
- // The type needs to be added to the list. Grow the list if it is full. |
- if (index >= length) { |
- ASSERT((index == length) || ((index == 1) && (length == 0))); |
- const intptr_t new_length = (length > 64) ? |
- (length + 64) : |
- ((length == 0) ? 2 : (length * 2)); |
- const Array& new_canonical_types = Array::Handle( |
- zone, Array::Grow(canonical_types, new_length, Heap::kOld)); |
- new_canonical_types.SetAt(index, lookup_type); |
- this->set_canonical_types(new_canonical_types); |
- } else { |
- canonical_types.SetAt(index, lookup_type); |
- } |
- } |
- return lookup_type.raw(); |
-} |
- |
- |
const char* Class::ToCString() const { |
const Library& lib = Library::Handle(library()); |
const char* library_name = lib.IsNull() ? "" : lib.ToCString(); |
@@ -4648,15 +4505,16 @@ static uint32_t CombineHashes(uint32_t hash, uint32_t other_hash) { |
} |
-static uint32_t FinalizeHash(uint32_t hash) { |
+static uint32_t FinalizeHash(uint32_t hash, intptr_t hashbits) { |
hash += hash << 3; |
hash ^= hash >> 11; // Logical shift, unsigned hash. |
hash += hash << 15; |
- return hash; |
+ hash &= ((static_cast<intptr_t>(1) << hashbits) - 1); |
+ return (hash == 0) ? 1 : hash; |
} |
-intptr_t TypeArguments::Hash() const { |
+intptr_t TypeArguments::ComputeHash() const { |
if (IsNull()) return 0; |
const intptr_t num_types = Length(); |
if (IsRaw(0, num_types)) return 0; |
@@ -4668,7 +4526,9 @@ intptr_t TypeArguments::Hash() const { |
// purposes only) while a type argument is still temporarily null. |
result = CombineHashes(result, type.IsNull() ? 0 : type.Hash()); |
} |
- return FinalizeHash(result); |
+ result = FinalizeHash(result, kHashBits); |
+ SetHash(result); |
+ return result; |
} |
@@ -5119,6 +4979,7 @@ RawTypeArguments* TypeArguments::New(intptr_t len, Heap::Space space) { |
result ^= raw; |
// Length must be set before we start storing into the array. |
result.SetLength(len); |
+ result.SetHash(0); |
} |
// The zero array should have been initialized. |
ASSERT(Object::zero_array().raw() != Array::null()); |
@@ -5144,99 +5005,6 @@ void TypeArguments::SetLength(intptr_t value) const { |
} |
-static void GrowCanonicalTypeArguments(Thread* thread, const Array& table) { |
- Isolate* isolate = thread->isolate(); |
- Zone* zone = thread->zone(); |
- // Last element of the array is the number of used elements. |
- const intptr_t table_size = table.Length() - 1; |
- const intptr_t new_table_size = table_size * 2; |
- Array& new_table = Array::Handle(zone, Array::New(new_table_size + 1)); |
- // Copy all elements from the original table to the newly allocated |
- // array. |
- TypeArguments& element = TypeArguments::Handle(zone); |
- Object& new_element = Object::Handle(zone); |
- for (intptr_t i = 0; i < table_size; i++) { |
- element ^= table.At(i); |
- if (!element.IsNull()) { |
- const intptr_t hash = element.Hash(); |
- ASSERT(Utils::IsPowerOfTwo(new_table_size)); |
- intptr_t index = hash & (new_table_size - 1); |
- new_element = new_table.At(index); |
- while (!new_element.IsNull()) { |
- index = (index + 1) & (new_table_size - 1); // Move to next element. |
- new_element = new_table.At(index); |
- } |
- new_table.SetAt(index, element); |
- } |
- } |
- // Copy used count. |
- new_element = table.At(table_size); |
- new_table.SetAt(new_table_size, new_element); |
- // Remember the new table now. |
- isolate->object_store()->set_canonical_type_arguments(new_table); |
-} |
- |
- |
-static void InsertIntoCanonicalTypeArguments(Thread* thread, |
- const Array& table, |
- const TypeArguments& arguments, |
- intptr_t index) { |
- Zone* zone = thread->zone(); |
- arguments.SetCanonical(); // Mark object as being canonical. |
- table.SetAt(index, arguments); // Remember the new element. |
- // Update used count. |
- // Last element of the array is the number of used elements. |
- const intptr_t table_size = table.Length() - 1; |
- const intptr_t used_elements = |
- Smi::Value(Smi::RawCast(table.At(table_size))) + 1; |
- const Smi& used = Smi::Handle(zone, Smi::New(used_elements)); |
- table.SetAt(table_size, used); |
- |
-#ifdef DEBUG |
- // Verify that there are no duplicates. |
- // Duplicates could appear if hash values are not kept constant across |
- // snapshots, e.g. if class ids are not preserved by the snapshots. |
- TypeArguments& other_arguments = TypeArguments::Handle(); |
- for (intptr_t i = 0; i < table_size; i++) { |
- if ((i != index) && (table.At(i) != TypeArguments::null())) { |
- other_arguments ^= table.At(i); |
- if (arguments.Equals(other_arguments)) { |
- // Recursive types may be equal, but have different hashes. |
- ASSERT(arguments.IsRecursive()); |
- ASSERT(other_arguments.IsRecursive()); |
- ASSERT(arguments.Hash() != other_arguments.Hash()); |
- } |
- } |
- } |
-#endif |
- |
- // Rehash if table is 75% full. |
- if (used_elements > ((table_size / 4) * 3)) { |
- GrowCanonicalTypeArguments(thread, table); |
- } |
-} |
- |
- |
-static intptr_t FindIndexInCanonicalTypeArguments( |
- Zone* zone, |
- const Array& table, |
- const TypeArguments& arguments, |
- intptr_t hash) { |
- // Last element of the array is the number of used elements. |
- const intptr_t table_size = table.Length() - 1; |
- ASSERT(Utils::IsPowerOfTwo(table_size)); |
- intptr_t index = hash & (table_size - 1); |
- |
- TypeArguments& current = TypeArguments::Handle(zone); |
- current ^= table.At(index); |
- while (!current.IsNull() && !current.Equals(arguments)) { |
- index = (index + 1) & (table_size - 1); // Move to next element. |
- current ^= table.At(index); |
- } |
- return index; // Index of element if found or slot into which to add it. |
-} |
- |
- |
RawTypeArguments* TypeArguments::CloneUnfinalized() const { |
if (IsNull() || IsFinalized()) { |
return raw(); |
@@ -5291,15 +5059,14 @@ RawTypeArguments* TypeArguments::Canonicalize(TrailPtr trail) const { |
Zone* zone = thread->zone(); |
Isolate* isolate = thread->isolate(); |
ObjectStore* object_store = isolate->object_store(); |
- Array& table = Array::Handle(zone, |
- object_store->canonical_type_arguments()); |
- // Last element of the array is the number of used elements. |
- const intptr_t num_used = |
- Smi::Value(Smi::RawCast(table.At(table.Length() - 1))); |
- const intptr_t hash = Hash(); |
- intptr_t index = FindIndexInCanonicalTypeArguments(zone, table, *this, hash); |
TypeArguments& result = TypeArguments::Handle(zone); |
- result ^= table.At(index); |
+ { |
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex()); |
+ CanonicalTypeArgumentsSet table(zone, |
+ object_store->canonical_type_arguments()); |
+ result ^= table.GetOrNull(CanonicalTypeArgumentsKey(*this)); |
+ object_store->set_canonical_type_arguments(table.Release()); |
+ } |
if (result.IsNull()) { |
// Canonicalize each type argument. |
AbstractType& type_arg = AbstractType::Handle(zone); |
@@ -5313,21 +5080,18 @@ RawTypeArguments* TypeArguments::Canonicalize(TrailPtr trail) const { |
} |
SetTypeAt(i, type_arg); |
} |
- // Canonicalization of a recursive type may change its hash. |
- intptr_t canonical_hash = hash; |
+ // Canonicalization of a type argument of a recursive type argument vector |
+ // may change the hash of the vector, so recompute. |
if (IsRecursive()) { |
- canonical_hash = Hash(); |
- } |
- // Canonicalization of the type argument's own type arguments may add an |
- // entry to the table, or even grow the table, and thereby change the |
- // previously calculated index. |
- table = object_store->canonical_type_arguments(); |
- if ((canonical_hash != hash) || |
- (Smi::Value(Smi::RawCast(table.At(table.Length() - 1))) != num_used)) { |
- index = FindIndexInCanonicalTypeArguments( |
- zone, table, *this, canonical_hash); |
- result ^= table.At(index); |
+ ComputeHash(); |
} |
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex()); |
+ CanonicalTypeArgumentsSet table( |
+ zone, object_store->canonical_type_arguments()); |
+ // Since we canonicalized some type arguments above we need to lookup |
+ // in the table again to make sure we don't already have an equivalent |
+ // canonical entry. |
+ result ^= table.GetOrNull(CanonicalTypeArgumentsKey(*this)); |
if (result.IsNull()) { |
// Make sure we have an old space object and add it to the table. |
if (this->IsNew()) { |
@@ -5336,8 +5100,12 @@ RawTypeArguments* TypeArguments::Canonicalize(TrailPtr trail) const { |
result ^= this->raw(); |
} |
ASSERT(result.IsOld()); |
- InsertIntoCanonicalTypeArguments(thread, table, result, index); |
+ result.SetCanonical(); // Mark object as being canonical. |
+ // Now add this TypeArgument into the canonical list of type arguments. |
+ bool present = table.Insert(result); |
+ ASSERT(!present); |
} |
+ object_store->set_canonical_type_arguments(table.Release()); |
} |
ASSERT(result.Equals(*this)); |
ASSERT(!result.IsNull()); |
@@ -5368,12 +5136,13 @@ const char* TypeArguments::ToCString() const { |
if (IsNull()) { |
return "NULL TypeArguments"; |
} |
- const char* prev_cstr = "TypeArguments:"; |
+ Zone* zone = Thread::Current()->zone(); |
+ const char* prev_cstr = OS::SCreate( |
+ zone, "TypeArguments: (%" Pd ")", Smi::Value(raw_ptr()->hash_)); |
for (int i = 0; i < Length(); i++) { |
- const AbstractType& type_at = AbstractType::Handle(TypeAt(i)); |
+ const AbstractType& type_at = AbstractType::Handle(zone, TypeAt(i)); |
const char* type_cstr = type_at.IsNull() ? "null" : type_at.ToCString(); |
- char* chars = OS::SCreate(Thread::Current()->zone(), |
- "%s [%s]", prev_cstr, type_cstr); |
+ char* chars = OS::SCreate(zone, "%s [%s]", prev_cstr, type_cstr); |
prev_cstr = chars; |
} |
return prev_cstr; |
@@ -9475,8 +9244,6 @@ class LibraryUrlTraits { |
return Library::Cast(key).UrlHash(); |
} |
}; |
- |
- |
typedef UnorderedHashSet<LibraryUrlTraits> LibraryLoadErrorSet; |
@@ -15444,7 +15211,7 @@ uword Instance::ComputeCanonicalTableHash() const { |
*reinterpret_cast<RawObject**>(this_addr + offset)); |
hash = CombineHashes(hash, value); |
} |
- return FinalizeHash(hash); |
+ return FinalizeHash(hash, (kBitsPerWord - 1)); |
} |
@@ -17224,19 +16991,23 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const { |
Thread* thread = Thread::Current(); |
Zone* zone = thread->zone(); |
Isolate* isolate = thread->isolate(); |
- AbstractType& type = Type::Handle(zone); |
- const Class& cls = Class::Handle(zone, type_class()); |
+ |
// Since void is a keyword, we never have to canonicalize the void type after |
// it is canonicalized once by the vm isolate. The parser does the mapping. |
- ASSERT((cls.raw() != Object::void_class()) || |
+ ASSERT((type_class() != Object::void_class()) || |
(isolate == Dart::vm_isolate())); |
+ |
// Since dynamic is not a keyword, the parser builds a type that requires |
// canonicalization. |
- if ((cls.raw() == Object::dynamic_class()) && |
+ if ((type_class() == Object::dynamic_class()) && |
(isolate != Dart::vm_isolate())) { |
ASSERT(Object::dynamic_type().IsCanonical()); |
return Object::dynamic_type().raw(); |
} |
+ |
+ AbstractType& type = Type::Handle(zone); |
+ const Class& cls = Class::Handle(zone, type_class()); |
+ |
// Fast canonical lookup/registry for simple types. |
if (!cls.IsGeneric() && !cls.IsClosureClass() && !cls.IsTypedefClass()) { |
ASSERT(!IsFunctionType()); |
@@ -17254,12 +17025,13 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const { |
set_arguments(type_args); |
type = cls.CanonicalType(); // May be set while canonicalizing type args. |
if (type.IsNull()) { |
- MutexLocker ml(isolate->type_canonicalization_mutex()); |
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex()); |
// Recheck if type exists. |
type = cls.CanonicalType(); |
if (type.IsNull()) { |
+ ComputeHash(); |
SetCanonical(); |
- cls.set_canonical_types(*this); |
+ cls.set_canonical_type(*this); |
return this->raw(); |
} |
} |
@@ -17269,73 +17041,76 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const { |
return type.raw(); |
} |
- Array& canonical_types = Array::Handle(zone); |
- canonical_types ^= cls.canonical_types(); |
- if (canonical_types.IsNull()) { |
- canonical_types = empty_array().raw(); |
- } |
- intptr_t length = canonical_types.Length(); |
- // Linear search to see whether this type is already present in the |
- // list of canonicalized types. |
- // TODO(asiva): Try to re-factor this lookup code to make sharing |
- // easy between the 4 versions of this loop. |
- intptr_t index = 1; // Slot 0 is reserved for CanonicalType(). |
- while (index < length) { |
- type ^= canonical_types.At(index); |
- if (type.IsNull()) { |
- break; |
- } |
- ASSERT(type.IsFinalized()); |
- if (this->Equals(type)) { |
- ASSERT(type.IsCanonical()); |
- return type.raw(); |
- } |
- index++; |
- } |
- // The type was not found in the table. It is not canonical yet. |
- |
- // Canonicalize the type arguments. |
- TypeArguments& type_args = TypeArguments::Handle(zone, arguments()); |
- // In case the type is first canonicalized at runtime, its type argument |
- // vector may be longer than necessary. This is not an issue. |
- ASSERT(type_args.IsNull() || (type_args.Length() >= cls.NumTypeArguments())); |
- type_args = type_args.Canonicalize(trail); |
- if (IsCanonical()) { |
- // Canonicalizing type_args canonicalized this type as a side effect. |
- ASSERT(IsRecursive()); |
- // Cycles via typedefs are detected and disallowed, but a function type can |
- // be recursive due to a cycle in its type arguments. |
- return this->raw(); |
+ ObjectStore* object_store = isolate->object_store(); |
+ { |
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex()); |
+ CanonicalTypeSet table(zone, object_store->canonical_types()); |
+ type ^= table.GetOrNull(CanonicalTypeKey(*this)); |
+ object_store->set_canonical_types(table.Release()); |
} |
- set_arguments(type_args); |
- ASSERT(type_args.IsNull() || type_args.IsOld()); |
- |
- // In case of a function type, replace the actual function by a signature |
- // function. |
- if (IsFunctionType()) { |
- const Function& fun = Function::Handle(zone, signature()); |
- if (!fun.IsSignatureFunction()) { |
- Function& sig_fun = Function::Handle(zone, |
- Function::NewSignatureFunction(cls, TokenPosition::kNoSource)); |
- type = fun.result_type(); |
- type = type.Canonicalize(trail); |
- sig_fun.set_result_type(type); |
- const intptr_t num_params = fun.NumParameters(); |
- sig_fun.set_num_fixed_parameters(fun.num_fixed_parameters()); |
- sig_fun.SetNumOptionalParameters(fun.NumOptionalParameters(), |
- fun.HasOptionalPositionalParameters()); |
- sig_fun.set_parameter_types(Array::Handle(Array::New(num_params, |
- Heap::kOld))); |
- for (intptr_t i = 0; i < num_params; i++) { |
- type = fun.ParameterTypeAt(i); |
+ if (type.IsNull()) { |
+ // The type was not found in the table. It is not canonical yet. |
+ |
+ // Canonicalize the type arguments. |
+ TypeArguments& type_args = TypeArguments::Handle(zone, arguments()); |
+ // In case the type is first canonicalized at runtime, its type argument |
+ // vector may be longer than necessary. This is not an issue. |
+ ASSERT(type_args.IsNull() || |
+ (type_args.Length() >= cls.NumTypeArguments())); |
+ type_args = type_args.Canonicalize(trail); |
+ if (IsCanonical()) { |
+ // Canonicalizing type_args canonicalized this type as a side effect. |
+ ASSERT(IsRecursive()); |
+ // Cycles via typedefs are detected and disallowed, but a function type |
+ // can be recursive due to a cycle in its type arguments. |
+ return this->raw(); |
+ } |
+ set_arguments(type_args); |
+ ASSERT(type_args.IsNull() || type_args.IsOld()); |
+ |
+ // In case of a function type, replace the actual function by a signature |
+ // function. |
+ if (IsFunctionType()) { |
+ const Function& fun = Function::Handle(zone, signature()); |
+ if (!fun.IsSignatureFunction()) { |
+ Function& sig_fun = Function::Handle( |
+ zone, |
+ Function::NewSignatureFunction(cls, TokenPosition::kNoSource)); |
+ type = fun.result_type(); |
type = type.Canonicalize(trail); |
- sig_fun.SetParameterTypeAt(i, type); |
+ sig_fun.set_result_type(type); |
+ const intptr_t num_params = fun.NumParameters(); |
+ sig_fun.set_num_fixed_parameters(fun.num_fixed_parameters()); |
+ sig_fun.SetNumOptionalParameters(fun.NumOptionalParameters(), |
+ fun.HasOptionalPositionalParameters()); |
+ sig_fun.set_parameter_types(Array::Handle(Array::New(num_params, |
+ Heap::kOld))); |
+ for (intptr_t i = 0; i < num_params; i++) { |
+ type = fun.ParameterTypeAt(i); |
+ type = type.Canonicalize(trail); |
+ sig_fun.SetParameterTypeAt(i, type); |
+ } |
+ sig_fun.set_parameter_names(Array::Handle(zone, fun.parameter_names())); |
+ set_signature(sig_fun); |
} |
- sig_fun.set_parameter_names(Array::Handle(zone, fun.parameter_names())); |
- set_signature(sig_fun); |
} |
+ |
+ // Check to see if the type got added to canonical list as part of the |
+ // type arguments canonicalization. |
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex()); |
+ CanonicalTypeSet table(zone, object_store->canonical_types()); |
+ type ^= table.GetOrNull(CanonicalTypeKey(*this)); |
+ if (type.IsNull()) { |
+ // Add this Type into the canonical list of types. |
+ type ^= raw(); |
+ ASSERT(type.IsOld()); |
+ type.SetCanonical(); // Mark object as being canonical. |
+ bool present = table.Insert(type); |
+ ASSERT(!present); |
+ } |
+ object_store->set_canonical_types(table.Release()); |
} |
- return cls.LookupOrAddCanonicalType(*this, index); |
+ return type.raw(); |
} |
@@ -17376,7 +17151,7 @@ RawString* Type::EnumerateURIs() const { |
} |
-intptr_t Type::Hash() const { |
+intptr_t Type::ComputeHash() const { |
ASSERT(IsFinalized()); |
uint32_t result = 1; |
if (IsMalformed()) return result; |
@@ -17400,7 +17175,9 @@ intptr_t Type::Hash() const { |
} |
} |
} |
- return FinalizeHash(result); |
+ result = FinalizeHash(result, kHashBits); |
+ SetHash(result); |
+ return result; |
} |
@@ -17442,6 +17219,7 @@ RawType* Type::New(const Object& clazz, |
result.set_unresolved_class(clazz); |
} |
result.set_arguments(arguments); |
+ result.SetHash(0); |
result.set_token_pos(token_pos); |
result.StoreNonPointer(&result.raw_ptr()->type_state_, RawType::kAllocated); |
return result.raw(); |
@@ -17621,7 +17399,7 @@ intptr_t TypeRef::Hash() const { |
// Do not calculate the hash of the referenced type to avoid divergence. |
const uint32_t result = |
Class::Handle(AbstractType::Handle(type()).type_class()).id(); |
- return FinalizeHash(result); |
+ return FinalizeHash(result, kHashBits); |
} |
@@ -17869,13 +17647,15 @@ RawString* TypeParameter::EnumerateURIs() const { |
} |
-intptr_t TypeParameter::Hash() const { |
+intptr_t TypeParameter::ComputeHash() const { |
ASSERT(IsFinalized()); |
uint32_t result = Class::Handle(parameterized_class()).id(); |
// No need to include the hash of the bound, since the type parameter is fully |
// identified by its class and index. |
result = CombineHashes(result, index()); |
- return FinalizeHash(result); |
+ result = FinalizeHash(result, kHashBits); |
+ SetHash(result); |
+ return result; |
} |
@@ -17897,6 +17677,7 @@ RawTypeParameter* TypeParameter::New(const Class& parameterized_class, |
result.set_index(index); |
result.set_name(name); |
result.set_bound(bound); |
+ result.SetHash(0); |
result.set_token_pos(token_pos); |
result.StoreNonPointer(&result.raw_ptr()->type_state_, |
RawTypeParameter::kAllocated); |
@@ -18133,13 +17914,15 @@ RawString* BoundedType::EnumerateURIs() const { |
} |
-intptr_t BoundedType::Hash() const { |
+intptr_t BoundedType::ComputeHash() const { |
uint32_t result = AbstractType::Handle(type()).Hash(); |
// No need to include the hash of the bound, since the bound is defined by the |
// type parameter (modulo instantiation state). |
result = CombineHashes(result, |
TypeParameter::Handle(type_parameter()).Hash()); |
- return FinalizeHash(result); |
+ result = FinalizeHash(result, kHashBits); |
+ SetHash(result); |
+ return result; |
} |
@@ -18157,6 +17940,7 @@ RawBoundedType* BoundedType::New(const AbstractType& type, |
const BoundedType& result = BoundedType::Handle(BoundedType::New()); |
result.set_type(type); |
result.set_bound(bound); |
+ result.SetHash(0); |
result.set_type_parameter(type_parameter); |
return result.raw(); |
} |
@@ -19694,10 +19478,9 @@ class StringHasher : ValueObject { |
// Return a non-zero hash of at most 'bits' bits. |
intptr_t Finalize(int bits) { |
ASSERT(1 <= bits && bits <= (kBitsPerWord - 1)); |
- hash_ = FinalizeHash(hash_); |
- hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1); |
+ hash_ = FinalizeHash(hash_, bits); |
ASSERT(hash_ <= static_cast<uint32_t>(kMaxInt32)); |
- return hash_ == 0 ? 1 : hash_; |
+ return hash_; |
} |
private: |
uint32_t hash_; |
@@ -19730,7 +19513,7 @@ void StringHasher::Add(const String& str, intptr_t begin_index, intptr_t len) { |
intptr_t String::Hash(const String& str, intptr_t begin_index, intptr_t len) { |
StringHasher hasher; |
hasher.Add(str, begin_index, len); |
- return hasher.Finalize(String::kHashBits); |
+ return hasher.Finalize(kHashBits); |
} |
@@ -19745,7 +19528,7 @@ intptr_t String::HashConcat(const String& str1, const String& str2) { |
StringHasher hasher; |
hasher.Add(str1, 0, len1); |
hasher.Add(str2, 0, str2.Length()); |
- return hasher.Finalize(String::kHashBits); |
+ return hasher.Finalize(kHashBits); |
} |
} |
@@ -19777,7 +19560,7 @@ intptr_t String::Hash(const uint16_t* characters, intptr_t len) { |
while (i < len) { |
hasher.Add(Utf16::Next(characters, &i, len)); |
} |
- return hasher.Finalize(String::kHashBits); |
+ return hasher.Finalize(kHashBits); |
} |
@@ -21474,7 +21257,7 @@ uword Array::ComputeCanonicalTableHash() const { |
value = reinterpret_cast<uword>(At(i)); |
hash = CombineHashes(hash, value); |
} |
- return FinalizeHash(hash); |
+ return FinalizeHash(hash, kHashBits); |
} |
@@ -22131,7 +21914,7 @@ uword TypedData::ComputeCanonicalTableHash() const { |
for (intptr_t i = 0; i < len; i++) { |
hash = CombineHashes(len, GetUint8(i)); |
} |
- return FinalizeHash(hash); |
+ return FinalizeHash(hash, kHashBits); |
} |