Index: runtime/vm/object.cc |
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
index 6a0e0a5777a7f68a97603e0f9f57866a3a068b2d..f15e90183ecf79dcb5204610397ed563338bca63 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. |
@@ -14412,49 +14510,51 @@ 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(); |
+ result ^= cls.LookupCanonicalInstance(zone, *this, &index); |
+ if (!result.IsNull()) { |
+ 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(); |
+ } |
} |
- index++; |
+ |
+ // The value needs to be added to the list. Grow the list if |
+ // it is full. |
+ result ^= this->raw(); |
+ if (result.IsNew() || |
+ (result.InVMHeap() && (isolate != Dart::vm_isolate()))) { |
+ /** |
+ * When a snapshot is generated on a 64 bit architecture and then read |
+ * into a 32 bit architecture, values which are Smi on the 64 bit |
+ * architecture could potentially be converted to Mint objects, however |
+ * since Smi values do not have any notion of canonical bits we lose |
+ * that information when the object becomes a Mint. |
+ * Some of these values could be literal values and end up in the |
+ * VM isolate heap. Later when these values are referenced in a |
+ * constant list we try to ensure that all the objects in the list |
+ * are canonical and try to canonicalize them. When these Mint objects |
+ * are encountered they do not have the canonical bit set and |
+ * canonicalizing them won't work as the VM heap is read only now. |
+ * In these cases we clone the object into the isolate and then |
+ * canonicalize it. |
+ */ |
+ // Create a canonical object in old space. |
+ result ^= Object::Clone(result, Heap::kOld); |
+ } |
+ ASSERT(result.IsOld()); |
+ |
+ result.SetCanonical(); |
+ cls.InsertCanonicalConstant(index, result); |
+ return result.raw(); |
} |
- // The value needs to be added to the list. Grow the list if |
- // it is full. |
- result ^= this->raw(); |
- if (result.IsNew() || |
- (result.InVMHeap() && (isolate != Dart::vm_isolate()))) { |
- /** |
- * When a snapshot is generated on a 64 bit architecture and then read |
- * into a 32 bit architecture, values which are Smi on the 64 bit |
- * architecture could potentially be converted to Mint objects, however |
- * since Smi values do not have any notion of canonical bits we lose |
- * that information when the object becomes a Mint. |
- * Some of these values could be literal values and end up in the |
- * VM isolate heap. Later when these values are referenced in a |
- * constant list we try to ensure that all the objects in the list |
- * are canonical and try to canonicalize them. When these Mint objects |
- * are encountered they do not have the canonical bit set and |
- * canonicalizing them won't work as the VM heap is read only now. |
- * In these cases we clone the object into the isolate and then |
- * canonicalize it. |
- */ |
- // Create a canonical object in old space. |
- result ^= Object::Clone(result, Heap::kOld); |
- } |
- ASSERT(result.IsOld()); |
- cls.InsertCanonicalConstant(index, result); |
- result.SetCanonical(); |
- return result.raw(); |
} |
@@ -17659,31 +17759,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(); |
+ canonical_value ^= cls.LookupCanonicalMint(zone, value, &index); |
+ if (!canonical_value.IsNull()) { |
+ 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(); |
+ } |
} |
- index++; |
+ canonical_value = Mint::New(value, Heap::kOld); |
+ 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(); |
} |
- // 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(); |
} |
@@ -17807,30 +17909,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(); |
+ |
+ canonical_value ^= cls.LookupCanonicalDouble(zone, value, &index); |
+ if (!canonical_value.IsNull()) { |
+ 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(); |
+ } |
} |
- index++; |
+ canonical_value = Double::New(value, Heap::kOld); |
+ 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(); |
} |
- // 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(); |
} |
@@ -18111,31 +18219,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(); |
} |