de914c7507
This is a reland of 44708a5b6f
Original change's description:
> [compiler, heap] Create LocalHeap outside of ExecuteJob
>
> Create LocalHeap directly in the Task or in GetOptimizedCodeNow and
> pass its reference as argument to ExecuteJob. This allows us to create
> LocalHeap differently for the main and background thread, e.g. by
> passing an additional argument to the constructor in the future.
> It will be required in the future anyways when the main thread will
> have its own LocalHeap/LocalIsolate.
>
> Extending the scope of LocalHeap, also made
> HandleBase::IsDereferenceAllowed more precise and uncovered two
> potential issues: heap accesses in
> OptimizingCompileDispatcher::CompileNext and PipelineImpl::AssembleCode
> with --code-comments.
>
> LocalHeap can now be created in the parked state. Also fixed a data
> race with LocalHeap's destructor publishing write barrier entries
> without holding the lock.
>
> Bug: v8:10315
> Change-Id: I9226972601a07b87108cd66efbbb6a0d118af58d
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2460818
> Commit-Queue: Georg Neis <neis@chromium.org>
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Santiago Aboy Solanes <solanes@chromium.org>
> Reviewed-by: Georg Neis <neis@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#70521}
Bug: v8:10315
Change-Id: I4c459fd6dfb98d47fc9941c0dc6864bf5a1d2d3e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2474788
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Santiago Aboy Solanes <solanes@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Dominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70560}
169 lines
3.8 KiB
C++
169 lines
3.8 KiB
C++
// Copyright 2020 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/heap/safepoint.h"
|
|
#include "src/base/platform/mutex.h"
|
|
#include "src/base/platform/platform.h"
|
|
#include "src/heap/heap.h"
|
|
#include "src/heap/local-heap.h"
|
|
#include "test/unittests/test-utils.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
void EnsureFlagLocalHeapsEnabled() {
|
|
// Avoid data race in concurrent thread by only setting the flag to true if
|
|
// not already enabled.
|
|
if (!FLAG_local_heaps) FLAG_local_heaps = true;
|
|
}
|
|
|
|
using SafepointTest = TestWithIsolate;
|
|
|
|
TEST_F(SafepointTest, ReachSafepointWithoutLocalHeaps) {
|
|
EnsureFlagLocalHeapsEnabled();
|
|
Heap* heap = i_isolate()->heap();
|
|
bool run = false;
|
|
{
|
|
SafepointScope scope(heap);
|
|
run = true;
|
|
}
|
|
CHECK(run);
|
|
}
|
|
|
|
class ParkedThread final : public v8::base::Thread {
|
|
public:
|
|
ParkedThread(Heap* heap, base::Mutex* mutex)
|
|
: v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")),
|
|
heap_(heap),
|
|
mutex_(mutex) {}
|
|
|
|
void Run() override {
|
|
LocalHeap local_heap(heap_);
|
|
|
|
if (mutex_) {
|
|
base::MutexGuard guard(mutex_);
|
|
}
|
|
}
|
|
|
|
Heap* heap_;
|
|
base::Mutex* mutex_;
|
|
};
|
|
|
|
TEST_F(SafepointTest, StopParkedThreads) {
|
|
EnsureFlagLocalHeapsEnabled();
|
|
Heap* heap = i_isolate()->heap();
|
|
|
|
int safepoints = 0;
|
|
|
|
const int kThreads = 10;
|
|
const int kRuns = 5;
|
|
|
|
for (int run = 0; run < kRuns; run++) {
|
|
base::Mutex mutex;
|
|
std::vector<ParkedThread*> threads;
|
|
|
|
mutex.Lock();
|
|
|
|
for (int i = 0; i < kThreads; i++) {
|
|
ParkedThread* thread =
|
|
new ParkedThread(heap, i % 2 == 0 ? &mutex : nullptr);
|
|
CHECK(thread->Start());
|
|
threads.push_back(thread);
|
|
}
|
|
|
|
{
|
|
SafepointScope scope(heap);
|
|
safepoints++;
|
|
}
|
|
mutex.Unlock();
|
|
|
|
for (ParkedThread* thread : threads) {
|
|
thread->Join();
|
|
delete thread;
|
|
}
|
|
}
|
|
|
|
CHECK_EQ(safepoints, kRuns);
|
|
}
|
|
|
|
static const int kRuns = 10000;
|
|
|
|
class RunningThread final : public v8::base::Thread {
|
|
public:
|
|
RunningThread(Heap* heap, std::atomic<int>* counter)
|
|
: v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")),
|
|
heap_(heap),
|
|
counter_(counter) {}
|
|
|
|
void Run() override {
|
|
LocalHeap local_heap(heap_);
|
|
UnparkedScope unparked_scope(&local_heap);
|
|
|
|
for (int i = 0; i < kRuns; i++) {
|
|
counter_->fetch_add(1);
|
|
if (i % 100 == 0) local_heap.Safepoint();
|
|
}
|
|
}
|
|
|
|
Heap* heap_;
|
|
std::atomic<int>* counter_;
|
|
};
|
|
|
|
TEST_F(SafepointTest, StopRunningThreads) {
|
|
EnsureFlagLocalHeapsEnabled();
|
|
Heap* heap = i_isolate()->heap();
|
|
|
|
const int kThreads = 10;
|
|
const int kRuns = 5;
|
|
const int kSafepoints = 3;
|
|
int safepoint_count = 0;
|
|
|
|
for (int run = 0; run < kRuns; run++) {
|
|
std::atomic<int> counter(0);
|
|
std::vector<RunningThread*> threads;
|
|
|
|
for (int i = 0; i < kThreads; i++) {
|
|
RunningThread* thread = new RunningThread(heap, &counter);
|
|
CHECK(thread->Start());
|
|
threads.push_back(thread);
|
|
}
|
|
|
|
for (int i = 0; i < kSafepoints; i++) {
|
|
SafepointScope scope(heap);
|
|
safepoint_count++;
|
|
}
|
|
|
|
for (RunningThread* thread : threads) {
|
|
thread->Join();
|
|
delete thread;
|
|
}
|
|
}
|
|
|
|
CHECK_EQ(safepoint_count, kRuns * kSafepoints);
|
|
}
|
|
|
|
TEST_F(SafepointTest, SkipLocalHeapOfThisThread) {
|
|
EnsureFlagLocalHeapsEnabled();
|
|
Heap* heap = i_isolate()->heap();
|
|
LocalHeap local_heap(heap);
|
|
UnparkedScope unparked_scope(&local_heap);
|
|
{
|
|
SafepointScope scope(heap);
|
|
local_heap.Safepoint();
|
|
}
|
|
{
|
|
ParkedScope parked_scope(&local_heap);
|
|
SafepointScope scope(heap);
|
|
local_heap.Safepoint();
|
|
}
|
|
{
|
|
SafepointScope scope(heap);
|
|
local_heap.Safepoint();
|
|
}
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|