Commit 0f81f7e6 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

[oilpan] HeapHashMap support for incremental marking

Bug: chromium:757440
Change-Id: Id7056e254e7aed6c99cb12ae24bfb9359c39f53f
Reviewed-on: https://chromium-review.googlesource.com/840844Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#526699}
parent 73bfaf0d
......@@ -78,6 +78,9 @@ class ExpectWriteBarrierFires : public IncrementalMarkingScope {
CallbackStack::Item* item = marking_stack_->Pop();
T* obj = reinterpret_cast<T*>(item->Object());
auto pos = std::find(objects_.begin(), objects_.end(), obj);
// The following check makes sure that there are no unexpected objects on
// the marking stack. If it fails then the write barrier fired for an
// unexpected object.
EXPECT_NE(objects_.end(), pos);
objects_.erase(pos);
}
......@@ -852,6 +855,88 @@ TEST(IncrementalMarkingTest, HeapTerminatedArrayBuilder) {
}
}
// =============================================================================
// HeapHashMap support. ========================================================
// =============================================================================
TEST(IncrementalMarkingTest, HeapHashMapInsertMember) {
Object* obj1 = Object::Create();
Object* obj2 = Object::Create();
HeapHashMap<Member<Object>, Member<Object>> map;
{
ExpectWriteBarrierFires<Object> scope(ThreadState::Current(), {obj1, obj2});
map.insert(obj1, obj2);
}
}
TEST(IncrementalMarkingTest, HeapHashMapSetMember) {
Object* obj1 = Object::Create();
Object* obj2 = Object::Create();
HeapHashMap<Member<Object>, Member<Object>> map;
{
ExpectWriteBarrierFires<Object> scope(ThreadState::Current(), {obj1, obj2});
map.Set(obj1, obj2);
}
}
TEST(IncrementalMarkingTest, HeapHashMapSetMemberOnlyValue) {
Object* obj1 = Object::Create();
Object* obj2 = Object::Create();
Object* obj3 = Object::Create();
HeapHashMap<Member<Object>, Member<Object>> map;
map.insert(obj1, obj2);
{
// Only |obj3| is newly added to |map|, so we only expect the barrier to
// fire on this one.
ExpectWriteBarrierFires<Object> scope(ThreadState::Current(), {obj3});
map.Set(obj1, obj3);
EXPECT_FALSE(HeapObjectHeader::FromPayload(obj1)->IsMarked());
EXPECT_FALSE(HeapObjectHeader::FromPayload(obj2)->IsMarked());
}
}
TEST(IncrementalMarkingTest, HeapHashMapIteratorChangeKey) {
Object* obj1 = Object::Create();
Object* obj2 = Object::Create();
Object* obj3 = Object::Create();
HeapHashMap<Member<Object>, Member<Object>> map;
map.insert(obj1, obj2);
{
ExpectWriteBarrierFires<Object> scope(ThreadState::Current(), {obj3});
auto it = map.find(obj1);
EXPECT_NE(map.end(), it);
it->key = obj3;
}
}
TEST(IncrementalMarkingTest, HeapHashMapIteratorChangeValue) {
Object* obj1 = Object::Create();
Object* obj2 = Object::Create();
Object* obj3 = Object::Create();
HeapHashMap<Member<Object>, Member<Object>> map;
map.insert(obj1, obj2);
{
ExpectWriteBarrierFires<Object> scope(ThreadState::Current(), {obj3});
auto it = map.find(obj1);
EXPECT_NE(map.end(), it);
it->value = obj3;
}
}
TEST(IncrementalMarkingTest, HeapHashMapCopyMember) {
Object* obj1 = Object::Create();
Object* obj2 = Object::Create();
HeapHashMap<Member<Object>, Member<Object>> map1;
map1.insert(obj1, obj2);
{
ExpectWriteBarrierFires<Object> scope(ThreadState::Current(), {obj1, obj2});
EXPECT_TRUE(map1.Contains(obj1));
HeapHashMap<Member<Object>, Member<Object>> map2(map1);
EXPECT_TRUE(map1.Contains(obj1));
EXPECT_TRUE(map2.Contains(obj1));
}
}
} // namespace incremental_marking_test
} // namespace blink
......
......@@ -13,7 +13,7 @@
#include "platform/wtf/HashTraits.h"
namespace WTF {
template <typename P, typename Allocator>
template <typename P, typename Traits, typename Allocator>
class ConstructTraits;
} // namespace WTF
......@@ -268,7 +268,7 @@ class Member : public MemberBase<T, TracenessMemberConfiguration::kTraced> {
#endif // BUILDFLAG(BLINK_HEAP_INCREMENTAL_MARKING)
}
template <typename P, typename Allocator>
template <typename P, typename Traits, typename Allocator>
friend class WTF::ConstructTraits;
};
......@@ -582,8 +582,8 @@ struct IsTraceable<blink::TraceWrapperMember<T>> {
static const bool value = true;
};
template <typename T, typename Allocator>
class ConstructTraits<blink::Member<T>, Allocator> {
template <typename T, typename Traits, typename Allocator>
class ConstructTraits<blink::Member<T>, Traits, Allocator> {
STATIC_ONLY(ConstructTraits);
public:
......
......@@ -14,7 +14,7 @@ namespace WTF {
// ConstructTraits is used to construct elements in WTF collections. All
// in-place constructions that may assign Oilpan objects must be dispatched
// through ConstructAndNotifyElement.
template <typename T, typename Allocator>
template <typename T, typename Traits, typename Allocator>
class ConstructTraits {
STATIC_ONLY(ConstructTraits);
......@@ -24,14 +24,14 @@ class ConstructTraits {
template <typename... Args>
static T* ConstructAndNotifyElement(void* location, Args&&... args) {
T* object = new (NotNull, location) T(std::forward<Args>(args)...);
Allocator::template NotifyNewObject<T, VectorTraits<T>>(object);
Allocator::template NotifyNewObject<T, Traits>(object);
return object;
}
// After constructing elements using memcopy or memmove (or similar)
// |NotifyNewElements| needs to be called to propagate that information.
static void NotifyNewElements(T* array, size_t len) {
Allocator::template NotifyNewObjects<T, VectorTraits<T>>(array, len);
Allocator::template NotifyNewObjects<T, Traits>(array, len);
}
};
......
......@@ -499,7 +499,7 @@ inline void Deque<T, inlineCapacity, Allocator>::push_back(U&& value) {
end_ = 0;
else
++end_;
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
new_element, std::forward<U>(value));
}
......@@ -511,7 +511,7 @@ inline void Deque<T, inlineCapacity, Allocator>::push_front(U&& value) {
start_ = buffer_.capacity() - 1;
else
--start_;
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
&buffer_.Buffer()[start_], std::forward<U>(value));
}
......@@ -524,7 +524,7 @@ inline void Deque<T, inlineCapacity, Allocator>::emplace_back(Args&&... args) {
end_ = 0;
else
++end_;
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
new_element, std::forward<Args>(args)...);
}
......@@ -536,7 +536,7 @@ inline void Deque<T, inlineCapacity, Allocator>::emplace_front(Args&&... args) {
start_ = buffer_.capacity() - 1;
else
--start_;
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
&buffer_.Buffer()[start_], std::forward<Args>(args)...);
}
......
......@@ -21,9 +21,10 @@
#ifndef WTF_HashMap_h
#define WTF_HashMap_h
#include <initializer_list>
#include "platform/wtf/ConstructTraits.h"
#include "platform/wtf/HashTable.h"
#include "platform/wtf/allocator/PartitionAllocator.h"
#include <initializer_list>
namespace WTF {
......@@ -310,7 +311,7 @@ struct HashMapValueTraits : KeyValuePairHashTraits<KeyTraits, MappedTraits> {
}
};
template <typename ValueTraits, typename HashFunctions>
template <typename ValueTraits, typename HashFunctions, typename Allocator>
struct HashMapTranslator {
STATIC_ONLY(HashMapTranslator);
template <typename T>
......@@ -523,12 +524,13 @@ template <typename T,
typename V,
typename W,
typename X,
typename Y>
typename Allocator>
template <typename IncomingKeyType, typename IncomingMappedType>
typename HashMap<T, U, V, W, X, Y>::AddResult
HashMap<T, U, V, W, X, Y>::InlineAdd(IncomingKeyType&& key,
IncomingMappedType&& mapped) {
return impl_.template insert<HashMapTranslator<ValueTraits, HashFunctions>>(
typename HashMap<T, U, V, W, X, Allocator>::AddResult
HashMap<T, U, V, W, X, Allocator>::InlineAdd(IncomingKeyType&& key,
IncomingMappedType&& mapped) {
return impl_.template insert<
HashMapTranslator<ValueTraits, HashFunctions, Allocator>>(
std::forward<IncomingKeyType>(key),
std::forward<IncomingMappedType>(mapped));
}
......
......@@ -523,29 +523,32 @@ std::ostream& operator<<(std::ostream& stream,
using std::swap;
template <typename T, typename Allocator, bool enterGCForbiddenScope>
template <typename T,
typename Allocator,
typename Traits,
bool enterGCForbiddenScope>
struct Mover {
STATIC_ONLY(Mover);
static void Move(T&& from, T& to) {
to.~T();
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(&to,
std::move(from));
ConstructTraits<T, Traits, Allocator>::ConstructAndNotifyElement(
&to, std::move(from));
}
};
template <typename T, typename Allocator>
struct Mover<T, Allocator, true> {
template <typename T, typename Allocator, typename Traits>
struct Mover<T, Allocator, Traits, true> {
STATIC_ONLY(Mover);
static void Move(T&& from, T& to) {
to.~T();
Allocator::EnterGCForbiddenScope();
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(&to,
std::move(from));
ConstructTraits<T, Traits, Allocator>::ConstructAndNotifyElement(
&to, std::move(from));
Allocator::LeaveGCForbiddenScope();
}
};
template <typename HashFunctions, typename Allocator>
template <typename HashFunctions, typename Traits, typename Allocator>
class IdentityHashTranslator {
STATIC_ONLY(IdentityHashTranslator);
......@@ -561,7 +564,7 @@ class IdentityHashTranslator {
template <typename T, typename U, typename V>
static void Translate(T& location, U&&, V&& value) {
location = std::forward<V>(value);
ConstructTraits<T, Allocator>::NotifyNewElements(&location, 1);
ConstructTraits<T, Traits, Allocator>::NotifyNewElements(&location, 1);
}
};
......@@ -685,7 +688,7 @@ class HashTable final
typedef Value ValueType;
typedef Extractor ExtractorType;
typedef KeyTraits KeyTraitsType;
typedef IdentityHashTranslator<HashFunctions, Allocator>
typedef IdentityHashTranslator<HashFunctions, Traits, Allocator>
IdentityTranslatorType;
typedef HashTableAddResult<HashTable, ValueType> AddResult;
......@@ -1199,7 +1202,7 @@ struct HashTableBucketInitializer<false> {
STATIC_ONLY(HashTableBucketInitializer);
template <typename Traits, typename Allocator, typename Value>
static void Initialize(Value& bucket) {
ConstructTraits<Value, Allocator>::ConstructAndNotifyElement(
ConstructTraits<Value, Traits, Allocator>::ConstructAndNotifyElement(
&bucket, Traits::EmptyValue());
}
};
......@@ -1398,7 +1401,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::
++stats_->numReinserts;
#endif
Value* new_entry = LookupForWriting(Extractor::Extract(entry)).first;
Mover<ValueType, Allocator,
Mover<ValueType, Allocator, Traits,
Traits::template NeedsToForbidGCOnMove<>::value>::Move(std::move(entry),
*new_entry);
......@@ -1682,7 +1685,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::
InitializeBucket(temporary_table[i]);
}
} else {
Mover<ValueType, Allocator,
Mover<ValueType, Allocator, Traits,
Traits::template NeedsToForbidGCOnMove<>::value>::
Move(std::move(table_[i]), temporary_table[i]);
table_[i].~ValueType();
......@@ -1917,12 +1920,12 @@ void HashTable<Key,
#endif
if (table_) {
ConstructTraits<ValueType, Allocator>::NotifyNewElements(table_,
table_size_);
ConstructTraits<ValueType, Traits, Allocator>::NotifyNewElements(
table_, table_size_);
}
if (other.table_) {
ConstructTraits<ValueType, Allocator>::NotifyNewElements(other.table_,
other.table_size_);
ConstructTraits<ValueType, Traits, Allocator>::NotifyNewElements(
other.table_, other.table_size_);
}
}
......
......@@ -45,7 +45,8 @@ class TerminatedArrayBuilder {
CHECK_LT(count_, capacity_);
DCHECK(!item.IsLastInArray());
array_->at(count_++) = item;
ConstructTraits<T, typename ArrayType<T>::Allocator::BackendAllocator>::
ConstructTraits<T, VectorTraits<T>,
typename ArrayType<T>::Allocator::BackendAllocator>::
NotifyNewElements(&array_->at(count_ - 1), 1);
if (count_ == capacity_)
array_->at(capacity_ - 1).SetLastInArray(true);
......
......@@ -153,8 +153,8 @@ struct VectorMover<false, T, Allocator> {
STATIC_ONLY(VectorMover);
static void Move(T* src, T* src_end, T* dst) {
while (src != src_end) {
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(dst,
std::move(*src));
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
dst, std::move(*src));
src->~T();
++dst;
++src;
......@@ -168,8 +168,10 @@ struct VectorMover<false, T, Allocator> {
while (src != src_end) {
--src_end;
--dst_end;
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(
dst_end, std::move(*src_end));
ConstructTraits<T, VectorTraits<T>,
Allocator>::ConstructAndNotifyElement(dst_end,
std::move(
*src_end));
src_end->~T();
}
}
......@@ -177,8 +179,8 @@ struct VectorMover<false, T, Allocator> {
static void Swap(T* src, T* src_end, T* dst) {
std::swap_ranges(src, src_end, dst);
const size_t len = src_end - src;
ConstructTraits<T, Allocator>::NotifyNewElements(src, len);
ConstructTraits<T, Allocator>::NotifyNewElements(dst, len);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(src, len);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(dst, len);
}
};
......@@ -190,7 +192,8 @@ struct VectorMover<true, T, Allocator> {
memcpy(dst, src,
reinterpret_cast<const char*>(src_end) -
reinterpret_cast<const char*>(src));
ConstructTraits<T, Allocator>::NotifyNewElements(dst, src_end - src);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(
dst, src_end - src);
}
}
static void MoveOverlapping(const T* src, const T* src_end, T* dst) {
......@@ -198,7 +201,8 @@ struct VectorMover<true, T, Allocator> {
memmove(dst, src,
reinterpret_cast<const char*>(src_end) -
reinterpret_cast<const char*>(src));
ConstructTraits<T, Allocator>::NotifyNewElements(dst, src_end - src);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(
dst, src_end - src);
}
}
static void Swap(T* src, T* src_end, T* dst) {
......@@ -206,8 +210,8 @@ struct VectorMover<true, T, Allocator> {
reinterpret_cast<char*>(src_end),
reinterpret_cast<char*>(dst));
const size_t len = src_end - src;
ConstructTraits<T, Allocator>::NotifyNewElements(src, len);
ConstructTraits<T, Allocator>::NotifyNewElements(dst, len);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(src, len);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(dst, len);
}
};
......@@ -220,7 +224,8 @@ struct VectorCopier<false, T, Allocator> {
template <typename U>
static void UninitializedCopy(const U* src, const U* src_end, T* dst) {
while (src != src_end) {
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(dst, *src);
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
dst, *src);
++dst;
++src;
}
......@@ -235,7 +240,8 @@ struct VectorCopier<true, T, Allocator> {
memcpy(dst, src,
reinterpret_cast<const char*>(src_end) -
reinterpret_cast<const char*>(src));
ConstructTraits<T, Allocator>::NotifyNewElements(dst, src_end - src);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(
dst, src_end - src);
}
}
template <typename U>
......@@ -252,7 +258,8 @@ struct VectorFiller<false, T, Allocator> {
STATIC_ONLY(VectorFiller);
static void UninitializedFill(T* dst, T* dst_end, const T& val) {
while (dst != dst_end) {
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(dst, T(val));
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
dst, T(val));
++dst;
}
}
......@@ -534,11 +541,12 @@ class VectorBuffer<T, 0, Allocator>
std::swap(capacity_, other.capacity_);
std::swap(size_, other.size_);
if (buffer_) {
ConstructTraits<T, Allocator>::NotifyNewElements(buffer_, size_);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(buffer_,
size_);
}
if (other.buffer_) {
ConstructTraits<T, Allocator>::NotifyNewElements(other.buffer_,
other.size_);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(
other.buffer_, other.size_);
}
}
......@@ -686,11 +694,12 @@ class VectorBuffer : protected VectorBufferBase<T, true, Allocator> {
std::swap(capacity_, other.capacity_);
std::swap(size_, other.size_);
if (buffer_) {
ConstructTraits<T, Allocator>::NotifyNewElements(buffer_, size_);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(
buffer_, size_);
}
if (other.buffer_) {
ConstructTraits<T, Allocator>::NotifyNewElements(other.buffer_,
other.size_);
ConstructTraits<T, VectorTraits<T>, Allocator>::NotifyNewElements(
other.buffer_, other.size_);
}
return;
}
......@@ -1721,7 +1730,7 @@ ALWAYS_INLINE void Vector<T, inlineCapacity, Allocator>::push_back(U&& val) {
DCHECK(Allocator::IsAllocationAllowed());
if (LIKELY(size() != capacity())) {
ANNOTATE_CHANGE_SIZE(begin(), capacity(), size_, size_ + 1);
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
end(), std::forward<U>(val));
++size_;
return;
......@@ -1739,8 +1748,9 @@ ALWAYS_INLINE T& Vector<T, inlineCapacity, Allocator>::emplace_back(
ExpandCapacity(size() + 1);
ANNOTATE_CHANGE_SIZE(begin(), capacity(), size_, size_ + 1);
T* t = ConstructTraits<T, Allocator>::ConstructAndNotifyElement(
end(), std::forward<Args>(args)...);
T* t =
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
end(), std::forward<Args>(args)...);
++size_;
return *t;
}
......@@ -1774,7 +1784,7 @@ NEVER_INLINE void Vector<T, inlineCapacity, Allocator>::AppendSlowCase(
DCHECK(begin());
ANNOTATE_CHANGE_SIZE(begin(), capacity(), size_, size_ + 1);
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
end(), std::forward<U>(*ptr));
++size_;
}
......@@ -1805,7 +1815,7 @@ ALWAYS_INLINE void Vector<T, inlineCapacity, Allocator>::UncheckedAppend(
push_back(std::forward<U>(val));
#else
DCHECK_LT(size(), capacity());
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
end(), std::forward<U>(val));
++size_;
#endif
......@@ -1825,7 +1835,7 @@ inline void Vector<T, inlineCapacity, Allocator>::insert(size_t position,
ANNOTATE_CHANGE_SIZE(begin(), capacity(), size_, size_ + 1);
T* spot = begin() + position;
TypeOperations::MoveOverlapping(spot, end(), spot + 1);
ConstructTraits<T, Allocator>::ConstructAndNotifyElement(
ConstructTraits<T, VectorTraits<T>, Allocator>::ConstructAndNotifyElement(
spot, std::forward<U>(*data));
++size_;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment