[compiler] Test transition from Uninitialized to kFullTransitionArray

Since we have an uninitialized TransitionArray that we want to insert
an element (map1), we can't guarantee that said element would exist at
the point of the search. Then, we search for an element guaranteed not
to be (map2) and we check that we did not find it.

If we have a data race, this would also trigger it.

Bug: v8:7790
Change-Id: Ib90044d7c0901d599aed041f608f2c0bce506d67
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2319995
Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69099}
This commit is contained in:
Santiago Aboy Solanes 2020-07-28 13:18:24 +01:00 committed by Commit Bot
parent 367da30543
commit 94cf4347e4
2 changed files with 73 additions and 21 deletions

View File

@ -23,7 +23,7 @@ class ConcurrentSearchThread final : public v8::base::Thread {
ConcurrentSearchThread(Heap* heap, base::Semaphore* sema_started,
std::unique_ptr<PersistentHandles> ph,
Handle<Name> name, Handle<Map> map,
Handle<Map> result_map)
base::Optional<Handle<Map>> result_map)
: v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")),
heap_(heap),
sema_started_(sema_started),
@ -39,7 +39,7 @@ class ConcurrentSearchThread final : public v8::base::Thread {
CHECK_EQ(TransitionsAccessor(CcTest::i_isolate(), map_, true)
.SearchTransition(*name_, kData, NONE),
*result_map_);
result_map_ ? **result_map_ : Map());
CHECK(!ph_);
ph_ = local_heap.DetachPersistentHandles();
@ -50,7 +50,7 @@ class ConcurrentSearchThread final : public v8::base::Thread {
std::unique_ptr<PersistentHandles> ph_;
Handle<Name> name_;
Handle<Map> map_;
Handle<Map> result_map_;
base::Optional<Handle<Map>> result_map_;
};
// Search on the main thread and in the background thread at the same time.
@ -79,15 +79,15 @@ TEST(FullFieldTransitions_OnlySearch) {
std::unique_ptr<PersistentHandles> ph = isolate->NewPersistentHandles();
Handle<Name> persistent_name = ph->NewHandle(name);
Handle<Map> persistent_map = ph->NewHandle(map0);
Handle<Map> persistent_result_map = ph->NewHandle(map1);
Handle<Map> persistent_map0 = ph->NewHandle(map0);
Handle<Map> persistent_result_map1 = ph->NewHandle(map1);
base::Semaphore sema_started(0);
// Pass persistent handles to background thread.
std::unique_ptr<ConcurrentSearchThread> thread(new ConcurrentSearchThread(
isolate->heap(), &sema_started, std::move(ph), persistent_name,
persistent_map, persistent_result_map));
persistent_map0, persistent_result_map1));
CHECK(thread->Start());
sema_started.Wait();
@ -130,16 +130,16 @@ TEST(FullFieldTransitions) {
std::unique_ptr<PersistentHandles> ph = isolate->NewPersistentHandles();
Handle<Name> persistent_name = ph->NewHandle(name1);
Handle<Map> persistent_map = ph->NewHandle(map0);
Handle<Map> persistent_result_map = ph->NewHandle(map1);
Handle<Name> persistent_name1 = ph->NewHandle(name1);
Handle<Map> persistent_map0 = ph->NewHandle(map0);
Handle<Map> persistent_result_map1 = ph->NewHandle(map1);
base::Semaphore sema_started(0);
// Pass persistent handles to background thread.
std::unique_ptr<ConcurrentSearchThread> thread(new ConcurrentSearchThread(
isolate->heap(), &sema_started, std::move(ph), persistent_name,
persistent_map, persistent_result_map));
isolate->heap(), &sema_started, std::move(ph), persistent_name1,
persistent_map0, persistent_result_map1));
CHECK(thread->Start());
sema_started.Wait();
@ -187,16 +187,16 @@ TEST(WeakRefToFullFieldTransitions) {
std::unique_ptr<PersistentHandles> ph = isolate->NewPersistentHandles();
Handle<Name> persistent_name = ph->NewHandle(name1);
Handle<Map> persistent_map = ph->NewHandle(map0);
Handle<Map> persistent_result_map = ph->NewHandle(map1);
Handle<Name> persistent_name1 = ph->NewHandle(name1);
Handle<Map> persistent_map0 = ph->NewHandle(map0);
Handle<Map> persistent_result_map1 = ph->NewHandle(map1);
base::Semaphore sema_started(0);
// Pass persistent handles to background thread.
std::unique_ptr<ConcurrentSearchThread> thread(new ConcurrentSearchThread(
isolate->heap(), &sema_started, std::move(ph), persistent_name,
persistent_map, persistent_result_map));
isolate->heap(), &sema_started, std::move(ph), persistent_name1,
persistent_map0, persistent_result_map1));
CHECK(thread->Start());
sema_started.Wait();
@ -255,16 +255,16 @@ TEST(FullFieldTransitions_withSlack) {
std::unique_ptr<PersistentHandles> ph = isolate->NewPersistentHandles();
Handle<Name> persistent_name = ph->NewHandle(name1);
Handle<Map> persistent_map = ph->NewHandle(map0);
Handle<Map> persistent_result_map = ph->NewHandle(map1);
Handle<Name> persistent_name1 = ph->NewHandle(name1);
Handle<Map> persistent_map0 = ph->NewHandle(map0);
Handle<Map> persistent_result_map1 = ph->NewHandle(map1);
base::Semaphore sema_started(0);
// Pass persistent handles to background thread.
std::unique_ptr<ConcurrentSearchThread> thread(new ConcurrentSearchThread(
isolate->heap(), &sema_started, std::move(ph), persistent_name,
persistent_map, persistent_result_map));
isolate->heap(), &sema_started, std::move(ph), persistent_name1,
persistent_map0, persistent_result_map1));
CHECK(thread->Start());
sema_started.Wait();
@ -286,6 +286,57 @@ TEST(FullFieldTransitions_withSlack) {
thread->Join();
}
// Search and insert on the main thread which changes the encoding from
// kUninitialized to kFullTransitionArray, while the background thread searches
// at the same time.
TEST(UninitializedToFullFieldTransitions) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
Handle<String> name1 = CcTest::MakeString("name1");
Handle<String> name2 = CcTest::MakeString("name2");
const PropertyAttributes attributes = NONE;
const PropertyKind kind = kData;
// Set map0 to be a full transition array with transition 'name1' to map1.
Handle<Map> map0 = Map::Create(isolate, 0);
Handle<Map> map1 =
Map::CopyWithField(isolate, map0, name1, FieldType::Any(isolate),
attributes, PropertyConstness::kMutable,
Representation::Tagged(), OMIT_TRANSITION)
.ToHandleChecked();
{
TestTransitionsAccessor transitions(isolate, map0);
CHECK(transitions.IsUninitializedEncoding());
}
std::unique_ptr<PersistentHandles> ph = isolate->NewPersistentHandles();
Handle<Name> persistent_name2 = ph->NewHandle(name2);
Handle<Map> persistent_map0 = ph->NewHandle(map0);
base::Semaphore background_thread_started(0);
// Pass persistent handles to background thread.
// Background thread will search for name2, guaranteed to *not* be on the map.
std::unique_ptr<ConcurrentSearchThread> thread(new ConcurrentSearchThread(
isolate->heap(), &background_thread_started, std::move(ph),
persistent_name2, persistent_map0, base::nullopt));
CHECK(thread->Start());
background_thread_started.Wait();
TransitionsAccessor(isolate, map0).Insert(name1, map1, PROPERTY_TRANSITION);
CHECK_EQ(*map1, TransitionsAccessor(isolate, map0)
.SearchTransition(*name1, kind, attributes));
{
TestTransitionsAccessor transitions(isolate, map0);
CHECK(transitions.IsFullTransitionArrayEncoding());
}
thread->Join();
}
} // anonymous namespace
} // namespace internal

View File

@ -19,6 +19,7 @@ class TestTransitionsAccessor : public TransitionsAccessor {
: TransitionsAccessor(isolate, map) {}
// Expose internals for tests.
bool IsUninitializedEncoding() { return encoding() == kUninitialized; }
bool IsWeakRefEncoding() { return encoding() == kWeakRef; }
bool IsFullTransitionArrayEncoding() {