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(); |
} |