Index: runtime/vm/object.cc |
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
index 2c6422e7d0e5d68d8799ed3ba5034b6b3bc99174..073514a4b1362b3220da0381e63129c4a86aa9b1 100644 |
--- a/runtime/vm/object.cc |
+++ b/runtime/vm/object.cc |
@@ -992,10 +992,12 @@ void Object::InitOnce(Isolate* isolate) { |
// An object visitor which will mark all visited objects. This is used to |
-// premark all objects in the vm_isolate_ heap. |
-class PremarkingVisitor : public ObjectVisitor { |
+// premark all objects in the vm_isolate_ heap. Also precalculates hash |
+// codes so that we can get the identity hash code of objects in the read- |
+// only VM isolate. |
+class FinalizeVMIsolateVisitor : public ObjectVisitor { |
public: |
- PremarkingVisitor() {} |
+ FinalizeVMIsolateVisitor() : counter_(1337) {} |
void VisitObject(RawObject* obj) { |
// Free list elements should never be marked. |
@@ -1005,8 +1007,33 @@ class PremarkingVisitor : public ObjectVisitor { |
if (!obj->IsFreeListElement()) { |
ASSERT(obj->IsVMHeapObject()); |
obj->SetMarkBitUnsynchronized(); |
+ if (obj->IsStringInstance()) { |
+ RawString* str = reinterpret_cast<RawString*>(obj); |
+ intptr_t hash = String::Hash(str); |
+ String::SetCachedHash(str, hash); |
+ } |
+#if defined(HASH_IN_OBJECT_HEADER) |
+ // These objects end up in the read-only VM isolate which is shared |
+ // between isolates, so we have to prepopulate them with identity hash |
+ // codes, since we can't add hash codes later. |
+ if (Object::GetCachedHash(obj) == 0) { |
+ // Some classes have identity hash codes that depend on their contents, |
+ // not per object. |
+ ASSERT(!obj->IsStringInstance()); |
+ if (!obj->IsMint() && !obj->IsDouble() && !obj->IsBigint() && |
+ !obj->IsRawNull() && !obj->IsBool()) { |
+ counter_ += 2011; // The year Dart was announced and a prime. |
+ counter_ &= 0x3fffffff; |
+ if (counter_ == 0) counter_++; |
+ Object::SetCachedHash(obj, counter_); |
+ } |
+ } |
+#endif |
} |
} |
+ |
+ private: |
+ int counter_; |
}; |
@@ -1086,7 +1113,7 @@ void Object::FinalizeVMIsolate(Isolate* isolate) { |
{ |
ASSERT(isolate == Dart::vm_isolate()); |
WritableVMIsolateScope scope(Thread::Current()); |
- PremarkingVisitor premarker; |
+ FinalizeVMIsolateVisitor premarker; |
ASSERT(isolate->heap()->UsedInWords(Heap::kNew) == 0); |
isolate->heap()->IterateOldObjectsNoImagePages(&premarker); |
// Make the VM isolate read-only again after setting all objects as marked. |
@@ -1121,13 +1148,15 @@ void Object::MakeUnusedSpaceTraversable(const Object& obj, |
reinterpret_cast<RawTypedData*>(RawObject::FromAddr(addr)); |
uword new_tags = RawObject::ClassIdTag::update(kTypedDataInt8ArrayCid, 0); |
new_tags = RawObject::SizeTag::update(leftover_size, new_tags); |
- uword tags = raw->ptr()->tags_; |
- uword old_tags; |
+ uint32_t tags = raw->ptr()->tags_; |
+ uint32_t old_tags; |
// TODO(iposva): Investigate whether CompareAndSwapWord is necessary. |
do { |
old_tags = tags; |
- tags = AtomicOperations::CompareAndSwapWord(&raw->ptr()->tags_, |
- old_tags, new_tags); |
+ // We can't use obj.CompareAndSwapTags here because we don't have a |
+ // handle for the new object. |
+ tags = AtomicOperations::CompareAndSwapUint32(&raw->ptr()->tags_, |
+ old_tags, new_tags); |
} while (tags != old_tags); |
intptr_t leftover_len = (leftover_size - TypedData::InstanceSize(0)); |
@@ -1139,13 +1168,12 @@ void Object::MakeUnusedSpaceTraversable(const Object& obj, |
RawObject* raw = reinterpret_cast<RawObject*>(RawObject::FromAddr(addr)); |
uword new_tags = RawObject::ClassIdTag::update(kInstanceCid, 0); |
new_tags = RawObject::SizeTag::update(leftover_size, new_tags); |
- uword tags = raw->ptr()->tags_; |
- uword old_tags; |
+ uint32_t tags = raw->ptr()->tags_; |
+ uint32_t old_tags; |
// TODO(iposva): Investigate whether CompareAndSwapWord is necessary. |
do { |
old_tags = tags; |
- tags = AtomicOperations::CompareAndSwapWord(&raw->ptr()->tags_, |
- old_tags, new_tags); |
+ tags = obj.CompareAndSwapTags(old_tags, new_tags); |
} while (tags != old_tags); |
} |
} |
@@ -1867,12 +1895,15 @@ void Object::InitializeObject(uword address, |
*reinterpret_cast<uword*>(cur) = initial_value; |
cur += kWordSize; |
} |
- uword tags = 0; |
+ uint32_t tags = 0; |
ASSERT(class_id != kIllegalCid); |
tags = RawObject::ClassIdTag::update(class_id, tags); |
tags = RawObject::SizeTag::update(size, tags); |
tags = RawObject::VMHeapObjectTag::update(is_vm_object, tags); |
reinterpret_cast<RawObject*>(address)->tags_ = tags; |
+#if defined(HASH_IN_OBJECT_HEADER) |
+ reinterpret_cast<RawObject*>(address)->hash_ = 0; |
+#endif |
ASSERT(is_vm_object == RawObject::IsVMHeapObject(tags)); |
} |
@@ -20207,6 +20238,35 @@ static intptr_t HashImpl(const T* characters, intptr_t len) { |
} |
+intptr_t String::Hash(RawString* raw) { |
+ StringHasher hasher; |
+ uword length = Smi::Value(raw->ptr()->length_); |
+ if (raw->IsOneByteString() || raw->IsExternalOneByteString()) { |
+ const uint8_t* data; |
+ if (raw->IsOneByteString()) { |
+ data = reinterpret_cast<RawOneByteString*>(raw)->ptr()->data(); |
+ } else { |
+ ASSERT(raw->IsExternalOneByteString()); |
+ RawExternalOneByteString* str = |
+ reinterpret_cast<RawExternalOneByteString*>(raw); |
+ data = str->ptr()->external_data_->data(); |
+ } |
+ return String::Hash(data, length); |
+ } else { |
+ const uint16_t* data; |
+ if (raw->IsTwoByteString()) { |
+ data = reinterpret_cast<RawTwoByteString*>(raw)->ptr()->data(); |
+ } else { |
+ ASSERT(raw->IsExternalTwoByteString()); |
+ RawExternalTwoByteString* str = |
+ reinterpret_cast<RawExternalTwoByteString*>(raw); |
+ data = str->ptr()->external_data_->data(); |
+ } |
+ return String::Hash(data, length); |
+ } |
+} |
+ |
+ |
intptr_t String::Hash(const char* characters, intptr_t len) { |
return HashImpl(characters, len); |
} |
@@ -21027,11 +21087,11 @@ RawString* String::MakeExternal(void* array, |
// Update the class information of the object. |
const intptr_t class_id = kExternalOneByteStringCid; |
- uword tags = raw_ptr()->tags_; |
- uword old_tags; |
+ uint32_t tags = raw_ptr()->tags_; |
+ uint32_t old_tags; |
do { |
old_tags = tags; |
- uword new_tags = RawObject::SizeTag::update(used_size, old_tags); |
+ uint32_t new_tags = RawObject::SizeTag::update(used_size, old_tags); |
new_tags = RawObject::ClassIdTag::update(class_id, new_tags); |
tags = CompareAndSwapTags(old_tags, new_tags); |
} while (tags != old_tags); |
@@ -21064,11 +21124,11 @@ RawString* String::MakeExternal(void* array, |
// Update the class information of the object. |
const intptr_t class_id = kExternalTwoByteStringCid; |
- uword tags = raw_ptr()->tags_; |
- uword old_tags; |
+ uint32_t tags = raw_ptr()->tags_; |
+ uint32_t old_tags; |
do { |
old_tags = tags; |
- uword new_tags = RawObject::SizeTag::update(used_size, old_tags); |
+ uint32_t new_tags = RawObject::SizeTag::update(used_size, old_tags); |
new_tags = RawObject::ClassIdTag::update(class_id, new_tags); |
tags = CompareAndSwapTags(old_tags, new_tags); |
} while (tags != old_tags); |
@@ -21956,11 +22016,11 @@ void Array::MakeImmutable() const { |
if (IsImmutable()) return; |
ASSERT(!IsCanonical()); |
NoSafepointScope no_safepoint; |
- uword tags = raw_ptr()->tags_; |
- uword old_tags; |
+ uint32_t tags = raw_ptr()->tags_; |
+ uint32_t old_tags; |
do { |
old_tags = tags; |
- uword new_tags = |
+ uint32_t new_tags = |
RawObject::ClassIdTag::update(kImmutableArrayCid, old_tags); |
tags = CompareAndSwapTags(old_tags, new_tags); |
} while (tags != old_tags); |
@@ -22002,6 +22062,7 @@ RawArray* Array::Grow(const Array& source, |
RawArray* Array::MakeArray(const GrowableObjectArray& growable_array) { |
ASSERT(!growable_array.IsNull()); |
+ ASSERT(growable_array.IsGrowableObjectArray()); |
intptr_t used_len = growable_array.Length(); |
// Get the type arguments and prepare to copy them. |
const TypeArguments& type_arguments = |
@@ -22014,6 +22075,7 @@ RawArray* Array::MakeArray(const GrowableObjectArray& growable_array) { |
intptr_t capacity_len = growable_array.Capacity(); |
Zone* zone = Thread::Current()->zone(); |
const Array& array = Array::Handle(zone, growable_array.data()); |
+ ASSERT(array.IsArray()); |
array.SetTypeArguments(type_arguments); |
intptr_t capacity_size = Array::InstanceSize(capacity_len); |
intptr_t used_size = Array::InstanceSize(used_len); |
@@ -22027,10 +22089,10 @@ RawArray* Array::MakeArray(const GrowableObjectArray& growable_array) { |
// Update the size in the header field and length of the array object. |
uword tags = array.raw_ptr()->tags_; |
ASSERT(kArrayCid == RawObject::ClassIdTag::decode(tags)); |
- uword old_tags; |
+ uint32_t old_tags; |
do { |
old_tags = tags; |
- uword new_tags = RawObject::SizeTag::update(used_size, old_tags); |
+ uint32_t new_tags = RawObject::SizeTag::update(used_size, old_tags); |
tags = array.CompareAndSwapTags(old_tags, new_tags); |
} while (tags != old_tags); |
// TODO(22501): For the heap to remain walkable by the sweeper, it must |