Index: runtime/vm/object.cc |
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
index 11de55fb370d6ae092d04b3d981a094e0e1b0343..20d7b4a4f1791a82fdb27a665a8edf9cb50bcd44 100644 |
--- a/runtime/vm/object.cc |
+++ b/runtime/vm/object.cc |
@@ -4129,23 +4129,19 @@ RawLibraryPrefix* Class::LookupLibraryPrefix(const String& name) const { |
} |
-// 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 { |
- intptr_t index = start_index; |
- Zone* zone = Thread::Current()->zone(); |
- AbstractType& type = Type::Handle(zone); |
+// 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()) { |
- canonical_types = empty_array().raw(); |
+ return AbstractType::null(); |
} |
- ASSERT(canonical_types.IsArray()); |
+ AbstractType& type = Type::Handle(zone); |
const intptr_t length = canonical_types.Length(); |
- while (index < length) { |
- type ^= canonical_types.At(index); |
+ while (*index < length) { |
+ type ^= canonical_types.At(*index); |
if (type.IsNull()) { |
break; |
} |
@@ -4154,23 +4150,58 @@ RawAbstractType* Class::LookupOrAddCanonicalType( |
ASSERT(type.IsCanonical()); |
return type.raw(); |
} |
- index++; |
+ *index = *index + 1; |
} |
+ return AbstractType::null(); |
+} |
- 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); |
+// 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(); |
} |
@@ -15793,9 +15824,14 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const { |
set_arguments(type_args); |
type = cls.CanonicalType(); // May be set while canonicalizing type args. |
if (type.IsNull()) { |
- cls.set_canonical_types(*this); |
- SetCanonical(); |
- return this->raw(); |
+ MutexLocker ml(isolate->type_canonicalization_mutex()); |
+ // Recheck if type exists. |
+ type = cls.CanonicalType(); |
+ if (type.IsNull()) { |
+ SetCanonical(); |
+ cls.set_canonical_types(*this); |
+ return this->raw(); |
+ } |
} |
} |
ASSERT(this->Equals(type)); |