Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Unified Diff: runtime/vm/object.cc

Issue 1754813004: Add thread safe constant canonicalization. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Move allocation Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/object.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
}
« no previous file with comments | « runtime/vm/object.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698