Chromium Code Reviews| Index: runtime/vm/object.cc |
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
| index 0c959cd387390bde40cf85246db640950a0f51b3..28c9aaf91a141b60bdc2e5144e81734108c996f0 100644 |
| --- a/runtime/vm/object.cc |
| +++ b/runtime/vm/object.cc |
| @@ -4217,6 +4217,104 @@ const char* Class::ToCString() const { |
| } |
| +// Returns an instance of Double or Double::null(). |
| +// 'index' points to either: |
| +// - constants_list_ position of found element, or |
| +// - constants_list_ position where new canonical can be inserted. |
| +RawDouble* Class::LookupCanonicalDouble( |
| + Zone* zone, double value, intptr_t* index) const { |
| + ASSERT(this->raw() == Isolate::Current()->object_store()->double_class()); |
| + const Array& constants = Array::Handle(zone, this->constants()); |
| + const intptr_t constants_len = constants.Length(); |
| + // Linear search to see whether this value is already present in the |
| + // list of canonicalized constants. |
| + Double& canonical_value = Double::Handle(zone); |
| + while (*index < constants_len) { |
| + canonical_value ^= constants.At(*index); |
| + if (canonical_value.IsNull()) { |
| + break; |
| + } |
| + if (canonical_value.BitwiseEqualsToDouble(value)) { |
| + ASSERT(canonical_value.IsCanonical()); |
| + return canonical_value.raw(); |
| + } |
| + *index = *index + 1; |
| + } |
| + return Double::null(); |
| +} |
| + |
| + |
| +RawMint* Class::LookupCanonicalMint( |
| + Zone* zone, int64_t value, intptr_t* index) const { |
| + ASSERT(this->raw() == Isolate::Current()->object_store()->mint_class()); |
| + const Array& constants = Array::Handle(zone, this->constants()); |
| + const intptr_t constants_len = constants.Length(); |
| + // Linear search to see whether this value is already present in the |
| + // list of canonicalized constants. |
| + Mint& canonical_value = Mint::Handle(zone); |
| + while (*index < constants_len) { |
| + canonical_value ^= constants.At(*index); |
| + if (canonical_value.IsNull()) { |
| + break; |
| + } |
| + if (canonical_value.value() == value) { |
| + ASSERT(canonical_value.IsCanonical()); |
| + return canonical_value.raw(); |
| + } |
| + *index = *index + 1; |
| + } |
| + return Mint::null(); |
| +} |
| + |
| + |
| +RawBigint* Class::LookupCanonicalBigint(Zone* zone, |
| + const Bigint& value, |
| + intptr_t* index) const { |
| + ASSERT(this->raw() == Isolate::Current()->object_store()->bigint_class()); |
| + const Array& constants = Array::Handle(zone, this->constants()); |
| + const intptr_t constants_len = constants.Length(); |
| + // Linear search to see whether this value is already present in the |
| + // list of canonicalized constants. |
| + Bigint& canonical_value = Bigint::Handle(zone); |
| + while (*index < constants_len) { |
| + canonical_value ^= constants.At(*index); |
| + if (canonical_value.IsNull()) { |
| + break; |
| + } |
| + if (canonical_value.Equals(value)) { |
| + ASSERT(canonical_value.IsCanonical()); |
| + return canonical_value.raw(); |
| + } |
| + *index = *index + 1; |
| + } |
| + return Bigint::null(); |
| +} |
| + |
| + |
| +RawInstance* Class::LookupCanonicalInstance(Zone* zone, |
| + const Instance& value, |
| + intptr_t* index) const { |
| + ASSERT(this->raw() == value.clazz()); |
| + const Array& constants = Array::Handle(zone, this->constants()); |
| + const intptr_t constants_len = constants.Length(); |
| + // Linear search to see whether this value is already present in the |
| + // list of canonicalized constants. |
| + Instance& canonical_value = Instance::Handle(zone); |
| + while (*index < constants_len) { |
| + canonical_value ^= constants.At(*index); |
| + if (canonical_value.IsNull()) { |
| + break; |
| + } |
| + if (value.CanonicalizeEquals(canonical_value)) { |
| + ASSERT(canonical_value.IsCanonical()); |
| + return canonical_value.raw(); |
| + } |
| + *index = *index + 1; |
| + } |
| + return Instance::null(); |
| +} |
| + |
| + |
| void Class::InsertCanonicalConstant(intptr_t index, |
| const Instance& constant) const { |
| // The constant needs to be added to the list. Grow the list if it is full. |
| @@ -14356,21 +14454,10 @@ RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const { |
| Isolate* isolate = thread->isolate(); |
| Instance& result = Instance::Handle(zone); |
| const Class& cls = Class::Handle(zone, this->clazz()); |
| - Array& constants = Array::Handle(zone, cls.constants()); |
| - const intptr_t constants_len = constants.Length(); |
| - // Linear search to see whether this value is already present in the |
| - // list of canonicalized constants. |
| intptr_t index = 0; |
| - while (index < constants_len) { |
| - result ^= constants.At(index); |
| - if (result.IsNull()) { |
| - break; |
| - } |
| - if (this->CanonicalizeEquals(result)) { |
| - ASSERT(result.IsCanonical()); |
| - return result.raw(); |
| - } |
| - index++; |
| + result ^= cls.LookupCanonicalInstance(zone, *this, &index); |
| + if (!result.IsNull()) { |
| + return result.raw(); |
| } |
| // The value needs to be added to the list. Grow the list if |
| // it is full. |
| @@ -14396,9 +14483,20 @@ RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const { |
| result ^= Object::Clone(result, Heap::kOld); |
| } |
|
siva
2016/03/02 19:12:07
As discussed offline this piece of code could move
|
| ASSERT(result.IsOld()); |
| - cls.InsertCanonicalConstant(index, result); |
| - result.SetCanonical(); |
| - return result.raw(); |
| + { |
| + SafepointMutexLocker ml(isolate->constant_canonicalization_mutex()); |
| + // Retry lookup. |
| + { |
| + Instance& temp_result = Instance::Handle(zone, |
| + cls.LookupCanonicalInstance(zone, *this, &index)); |
| + if (!temp_result.IsNull()) { |
| + return temp_result.raw(); |
| + } |
| + } |
| + result.SetCanonical(); |
| + cls.InsertCanonicalConstant(index, result); |
| + return result.raw(); |
| + } |
| } |
| @@ -17603,31 +17701,33 @@ RawMint* Mint::New(int64_t val, Heap::Space space) { |
| RawMint* Mint::NewCanonical(int64_t value) { |
| // Do not allocate a Mint if Smi would do. |
| ASSERT(!Smi::IsValid(value)); |
| - const Class& cls = |
| - Class::Handle(Isolate::Current()->object_store()->mint_class()); |
| - const Array& constants = Array::Handle(cls.constants()); |
| - const intptr_t constants_len = constants.Length(); |
| - // Linear search to see whether this value is already present in the |
| - // list of canonicalized constants. |
| - Mint& canonical_value = Mint::Handle(); |
| + Thread* thread = Thread::Current(); |
| + Zone* zone = thread->zone(); |
| + Isolate* isolate = thread->isolate(); |
| + const Class& cls = Class::Handle(zone, isolate->object_store()->mint_class()); |
| + Mint& canonical_value = Mint::Handle(zone); |
| intptr_t index = 0; |
| - while (index < constants_len) { |
| - canonical_value ^= constants.At(index); |
| - if (canonical_value.IsNull()) { |
| - break; |
| - } |
| - if (canonical_value.value() == value) { |
| - ASSERT(canonical_value.IsCanonical()); |
| - return canonical_value.raw(); |
| - } |
| - index++; |
| + canonical_value ^= cls.LookupCanonicalMint(zone, value, &index); |
| + if (!canonical_value.IsNull()) { |
| + return canonical_value.raw(); |
| } |
| - // The value needs to be added to the constants list. Grow the list if |
| - // it is full. |
| canonical_value = Mint::New(value, Heap::kOld); |
| - cls.InsertCanonicalConstant(index, canonical_value); |
| - canonical_value.SetCanonical(); |
| - return canonical_value.raw(); |
| + { |
| + SafepointMutexLocker ml(isolate->constant_canonicalization_mutex()); |
| + // Retry lookup. |
| + { |
| + const Mint& result = |
| + Mint::Handle(zone, cls.LookupCanonicalMint(zone, value, &index)); |
| + if (!result.IsNull()) { |
| + return result.raw(); |
| + } |
| + } |
| + canonical_value.SetCanonical(); |
| + // The value needs to be added to the constants list. Grow the list if |
| + // it is full. |
| + cls.InsertCanonicalConstant(index, canonical_value); |
| + return canonical_value.raw(); |
| + } |
| } |
| @@ -17751,30 +17851,36 @@ RawDouble* Double::New(const String& str, Heap::Space space) { |
| RawDouble* Double::NewCanonical(double value) { |
| - const Class& cls = |
| - Class::Handle(Isolate::Current()->object_store()->double_class()); |
| - const Array& constants = Array::Handle(cls.constants()); |
| - const intptr_t constants_len = constants.Length(); |
| + Thread* thread = Thread::Current(); |
| + Zone* zone = thread->zone(); |
| + Isolate* isolate = thread->isolate(); |
| + const Class& cls = Class::Handle(isolate->object_store()->double_class()); |
| // Linear search to see whether this value is already present in the |
| // list of canonicalized constants. |
| - Double& canonical_value = Double::Handle(); |
| + Double& canonical_value = Double::Handle(zone); |
| intptr_t index = 0; |
| - while (index < constants_len) { |
| - canonical_value ^= constants.At(index); |
| - if (canonical_value.IsNull()) { |
| - break; |
| - } |
| - if (canonical_value.BitwiseEqualsToDouble(value)) { |
| - return canonical_value.raw(); |
| - } |
| - index++; |
| + |
| + canonical_value ^= cls.LookupCanonicalDouble(zone, value, &index); |
| + if (!canonical_value.IsNull()) { |
| + return canonical_value.raw(); |
| } |
| - // The value needs to be added to the constants list. Grow the list if |
| - // it is full. |
| canonical_value = Double::New(value, Heap::kOld); |
| - cls.InsertCanonicalConstant(index, canonical_value); |
| - canonical_value.SetCanonical(); |
| - return canonical_value.raw(); |
| + { |
| + SafepointMutexLocker ml(isolate->constant_canonicalization_mutex()); |
| + // Retry lookup. |
| + { |
| + const Double& result = |
| + Double::Handle(zone, cls.LookupCanonicalDouble(zone, value, &index)); |
| + if (!result.IsNull()) { |
| + return result.raw(); |
| + } |
| + } |
| + canonical_value.SetCanonical(); |
| + // The value needs to be added to the constants list. Grow the list if |
| + // it is full. |
| + cls.InsertCanonicalConstant(index, canonical_value); |
| + return canonical_value.raw(); |
| + } |
| } |
| @@ -18055,31 +18161,35 @@ RawBigint* Bigint::NewFromCString(const char* str, Heap::Space space) { |
| RawBigint* Bigint::NewCanonical(const String& str) { |
| + Thread* thread = Thread::Current(); |
| + Zone* zone = thread->zone(); |
| + Isolate* isolate = thread->isolate(); |
| const Bigint& value = Bigint::Handle( |
| - Bigint::NewFromCString(str.ToCString(), Heap::kOld)); |
| + zone, Bigint::NewFromCString(str.ToCString(), Heap::kOld)); |
| const Class& cls = |
| - Class::Handle(Isolate::Current()->object_store()->bigint_class()); |
| - const Array& constants = Array::Handle(cls.constants()); |
| - const intptr_t constants_len = constants.Length(); |
| - // Linear search to see whether this value is already present in the |
| - // list of canonicalized constants. |
| - Bigint& canonical_value = Bigint::Handle(); |
| + Class::Handle(zone, isolate->object_store()->bigint_class()); |
| intptr_t index = 0; |
| - while (index < constants_len) { |
| - canonical_value ^= constants.At(index); |
| - if (canonical_value.IsNull()) { |
| - break; |
| - } |
| - if (canonical_value.Equals(value)) { |
| - return canonical_value.raw(); |
| + const Bigint& canonical_value = |
| + Bigint::Handle(zone, cls.LookupCanonicalBigint(zone, value, &index)); |
| + if (!canonical_value.IsNull()) { |
| + return canonical_value.raw(); |
| + } |
| + { |
| + SafepointMutexLocker ml(isolate->constant_canonicalization_mutex()); |
| + // Retry lookup. |
| + { |
| + const Bigint& result = |
| + Bigint::Handle(zone, cls.LookupCanonicalBigint(zone, value, &index)); |
| + if (!result.IsNull()) { |
| + return result.raw(); |
| + } |
| } |
| - index++; |
| + value.SetCanonical(); |
| + // The value needs to be added to the constants list. Grow the list if |
| + // it is full. |
| + cls.InsertCanonicalConstant(index, value); |
| + return value.raw(); |
| } |
| - // The value needs to be added to the constants list. Grow the list if |
| - // it is full. |
| - cls.InsertCanonicalConstant(index, value); |
| - value.SetCanonical(); |
| - return value.raw(); |
| } |