| Index: runtime/vm/object.cc
|
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
|
| index 52c92e2face95c1fb801fa3d09b2d09cd3cd95a8..17db59f3253d45a396459a2b1715f6140a850f6e 100644
|
| --- a/runtime/vm/object.cc
|
| +++ b/runtime/vm/object.cc
|
| @@ -992,10 +992,17 @@ 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()
|
| +#if defined(HASH_IN_OBJECT_HEADER)
|
| + : counter_(1337)
|
| +#endif
|
| + {
|
| + }
|
|
|
| void VisitObject(RawObject* obj) {
|
| // Free list elements should never be marked.
|
| @@ -1005,8 +1012,35 @@ 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:
|
| +#if defined(HASH_IN_OBJECT_HEADER)
|
| + int32_t counter_;
|
| +#endif
|
| };
|
|
|
|
|
| @@ -1086,7 +1120,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 +1155,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 +1175,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 +1902,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));
|
| }
|
|
|
| @@ -20339,6 +20377,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);
|
| }
|
| @@ -21159,11 +21226,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);
|
| @@ -21196,11 +21263,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);
|
| @@ -22088,11 +22155,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);
|
| @@ -22157,6 +22224,7 @@ RawArray* Array::MakeFixedLength(const GrowableObjectArray& growable_array,
|
| }
|
| intptr_t capacity_len = growable_array.Capacity();
|
| 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);
|
| @@ -22170,10 +22238,10 @@ RawArray* Array::MakeFixedLength(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
|
|
|