Commit b5bf34bc authored by Dominik Inführ's avatar Dominik Inführ Committed by Commit Bot

[heap] Support collection on main thread

LocalHeap can be used on main thread, however allocation might cause a
GC which works differently on the main thread than on a background
thread. Support collection on main thread by directly performing the GC
instead of requesting the GC as done on background threads.

To allow for differentiation between main and background threads,
LocalHeap/LocalIsolate now require an additional argument.

Change-Id: I08094ea633e303e149913f21dff395da9e046534
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2463238Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Dominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70590}
parent 51f3e021
......@@ -959,7 +959,7 @@ bool GetOptimizedCodeNow(OptimizedCompilationJob* job, Isolate* isolate,
}
{
LocalIsolate local_isolate(isolate);
LocalIsolate local_isolate(isolate, ThreadKind::kMain);
if (job->ExecuteJob(isolate->counters()->runtime_call_stats(),
&local_isolate)) {
CompilerTracer::TraceAbortedJob(isolate, compilation_info);
......@@ -1572,7 +1572,7 @@ void BackgroundCompileTask::Run() {
} else {
DCHECK(info_->flags().is_toplevel());
LocalIsolate isolate(isolate_for_local_isolate_);
LocalIsolate isolate(isolate_for_local_isolate_, ThreadKind::kBackground);
UnparkedScope unparked_scope(isolate.heap());
LocalHandleScope handle_scope(&isolate);
......
......@@ -886,15 +886,7 @@ enum ShouldThrow {
kDontThrow = Internals::kDontThrow
};
// The Store Buffer (GC).
enum StoreBufferEvent {
kStoreBufferFullEvent,
kStoreBufferStartScanningPagesEvent,
kStoreBufferScanningPageEvent
};
using StoreBufferCallback = void (*)(Heap* heap, MemoryChunk* page,
StoreBufferEvent event);
enum class ThreadKind { kMain, kBackground };
// Union used for customized checking of the IEEE double types
// inlined within v8 runtime, rather than going to the underlying
......
......@@ -58,7 +58,7 @@ class OptimizingCompileDispatcher::CompileTask : public CancelableTask {
private:
// v8::Task overrides.
void RunInternal() override {
LocalIsolate local_isolate(isolate_);
LocalIsolate local_isolate(isolate_, ThreadKind::kBackground);
DisallowHeapAllocation no_allocation;
DisallowHandleAllocation no_handles;
DisallowHandleDereference no_deref;
......
......@@ -3026,7 +3026,7 @@ MaybeHandle<Code> Pipeline::GenerateCodeForTesting(
}
{
LocalIsolate local_isolate(isolate);
LocalIsolate local_isolate(isolate, ThreadKind::kMain);
LocalHeapScope local_heap_scope(data.broker(), info, local_isolate.heap());
if (data.broker()->is_concurrent_inlining()) {
if (!pipeline.CreateGraph()) return MaybeHandle<Code>();
......
......@@ -12,9 +12,9 @@
namespace v8 {
namespace internal {
LocalIsolate::LocalIsolate(Isolate* isolate)
LocalIsolate::LocalIsolate(Isolate* isolate, ThreadKind kind)
: HiddenLocalFactory(isolate),
heap_(isolate->heap()),
heap_(isolate->heap(), kind),
isolate_(isolate),
logger_(new LocalLogger(isolate)),
thread_id_(ThreadId::Current()) {}
......
......@@ -36,7 +36,7 @@ class V8_EXPORT_PRIVATE LocalIsolate final : private HiddenLocalFactory {
public:
using HandleScopeType = LocalHandleScope;
explicit LocalIsolate(Isolate* isolate);
explicit LocalIsolate(Isolate* isolate, ThreadKind kind);
~LocalIsolate();
// Kinda sketchy.
......
......@@ -18,7 +18,7 @@ namespace internal {
void StressConcurrentAllocatorTask::RunInternal() {
Heap* heap = isolate_->heap();
LocalHeap local_heap(heap);
LocalHeap local_heap(heap, ThreadKind::kBackground);
UnparkedScope unparked_scope(&local_heap);
const int kNumIterations = 2000;
......
......@@ -1897,8 +1897,14 @@ bool Heap::CollectionRequested() {
return collection_barrier_->CollectionRequested();
}
void Heap::RequestCollectionBackground() {
collection_barrier_->AwaitCollectionBackground();
void Heap::RequestCollectionBackground(LocalHeap* local_heap) {
if (local_heap->is_main_thread()) {
CollectAllGarbage(current_gc_flags_,
GarbageCollectionReason::kBackgroundAllocationFailure,
current_gc_callback_flags_);
} else {
collection_barrier_->AwaitCollectionBackground();
}
}
void Heap::CheckCollectionRequested() {
......
......@@ -669,7 +669,7 @@ class Heap {
inline AllocationMemento FindAllocationMemento(Map map, HeapObject object);
// Requests collection and blocks until GC is finished.
void RequestCollectionBackground();
void RequestCollectionBackground(LocalHeap* local_heap);
//
// Support for the API.
......
......@@ -24,9 +24,10 @@ thread_local LocalHeap* current_local_heap = nullptr;
LocalHeap* LocalHeap::Current() { return current_local_heap; }
LocalHeap::LocalHeap(Heap* heap,
LocalHeap::LocalHeap(Heap* heap, ThreadKind kind,
std::unique_ptr<PersistentHandles> persistent_handles)
: heap_(heap),
is_main_thread_(kind == ThreadKind::kMain),
state_(ThreadState::Parked),
safepoint_requested_(false),
allocation_failed_(false),
......@@ -168,7 +169,7 @@ Address LocalHeap::PerformCollectionAndAllocateAgain(
for (int i = 0; i < kMaxNumberOfRetries; i++) {
{
ParkedScope scope(this);
heap_->RequestCollectionBackground();
heap_->RequestCollectionBackground(this);
}
AllocationResult result = AllocateRaw(object_size, type, origin, alignment);
......
......@@ -34,7 +34,7 @@ class LocalHandles;
class V8_EXPORT_PRIVATE LocalHeap {
public:
explicit LocalHeap(
Heap* heap,
Heap* heap, ThreadKind kind,
std::unique_ptr<PersistentHandles> persistent_handles = nullptr);
~LocalHeap();
......@@ -126,6 +126,8 @@ class V8_EXPORT_PRIVATE LocalHeap {
AllocationOrigin origin = AllocationOrigin::kRuntime,
AllocationAlignment alignment = kWordAligned);
bool is_main_thread() { return is_main_thread_; }
private:
enum class ThreadState {
// Threads in this state need to be stopped in a safepoint.
......@@ -158,6 +160,7 @@ class V8_EXPORT_PRIVATE LocalHeap {
void EnterSafepoint();
Heap* heap_;
bool is_main_thread_;
base::Mutex state_mutex_;
base::ConditionVariable state_change_;
......
......@@ -40,8 +40,10 @@ void GlobalSafepoint::EnterSafepointScope() {
for (LocalHeap* current = local_heaps_head_; current;
current = current->next_) {
if (current == local_heap_of_this_thread_) {
DCHECK(current->is_main_thread());
continue;
}
DCHECK(!current->is_main_thread());
current->state_mutex_.Lock();
while (current->state_ == LocalHeap::ThreadState::Running) {
......
......@@ -262,26 +262,27 @@ void CreateInterpreterDataForDeserializedCode(Isolate* isolate,
namespace {
class StressOffThreadDeserializeThread final : public base::Thread {
public:
explicit StressOffThreadDeserializeThread(LocalIsolate* local_isolate,
explicit StressOffThreadDeserializeThread(Isolate* isolate,
const SerializedCodeData* scd)
: Thread(
base::Thread::Options("StressOffThreadDeserializeThread", 2 * MB)),
local_isolate_(local_isolate),
isolate_(isolate),
scd_(scd) {}
MaybeHandle<SharedFunctionInfo> maybe_result() const { return maybe_result_; }
void Run() final {
LocalIsolate local_isolate(isolate_, ThreadKind::kBackground);
MaybeHandle<SharedFunctionInfo> local_maybe_result =
ObjectDeserializer::DeserializeSharedFunctionInfoOffThread(
local_isolate_, scd_, local_isolate_->factory()->empty_string());
&local_isolate, scd_, local_isolate.factory()->empty_string());
maybe_result_ =
local_isolate_->heap()->NewPersistentMaybeHandle(local_maybe_result);
local_isolate.heap()->NewPersistentMaybeHandle(local_maybe_result);
}
private:
LocalIsolate* local_isolate_;
Isolate* isolate_;
const SerializedCodeData* scd_;
MaybeHandle<SharedFunctionInfo> maybe_result_;
};
......@@ -312,9 +313,7 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
MaybeHandle<SharedFunctionInfo> maybe_result;
// TODO(leszeks): Add LocalHeap support to deserializer
if (false && FLAG_stress_background_compile) {
LocalIsolate local_isolate(isolate);
StressOffThreadDeserializeThread thread(&local_isolate, &scd);
StressOffThreadDeserializeThread thread(isolate, &scd);
CHECK(thread.Start());
thread.Join();
......
......@@ -14,6 +14,7 @@
#include "src/codegen/macro-assembler.h"
#include "src/common/globals.h"
#include "src/handles/handles-inl.h"
#include "src/handles/handles.h"
#include "src/handles/local-handles-inl.h"
#include "src/handles/persistent-handles.h"
#include "src/heap/concurrent-allocator-inl.h"
......@@ -28,6 +29,7 @@
namespace v8 {
namespace internal {
namespace {
void CreateFixedArray(Heap* heap, Address start, int size) {
HeapObject object = HeapObject::FromAddress(start);
object.set_map_after_allocation(ReadOnlyRoots(heap).fixed_array_map(),
......@@ -43,6 +45,23 @@ const int kNumIterations = 2000;
const int kSmallObjectSize = 10 * kTaggedSize;
const int kMediumObjectSize = 8 * KB;
void AllocateSomeObjects(LocalHeap* local_heap) {
for (int i = 0; i < kNumIterations; i++) {
Address address = local_heap->AllocateRawOrFail(
kSmallObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime,
AllocationAlignment::kWordAligned);
CreateFixedArray(local_heap->heap(), address, kSmallObjectSize);
address = local_heap->AllocateRawOrFail(
kMediumObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime,
AllocationAlignment::kWordAligned);
CreateFixedArray(local_heap->heap(), address, kMediumObjectSize);
if (i % 10 == 0) {
local_heap->Safepoint();
}
}
}
} // namespace
class ConcurrentAllocationThread final : public v8::base::Thread {
public:
explicit ConcurrentAllocationThread(Heap* heap, std::atomic<int>* pending)
......@@ -51,23 +70,9 @@ class ConcurrentAllocationThread final : public v8::base::Thread {
pending_(pending) {}
void Run() override {
LocalHeap local_heap(heap_);
LocalHeap local_heap(heap_, ThreadKind::kBackground);
UnparkedScope unparked_scope(&local_heap);
for (int i = 0; i < kNumIterations; i++) {
Address address = local_heap.AllocateRawOrFail(
kSmallObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime,
AllocationAlignment::kWordAligned);
CreateFixedArray(heap_, address, kSmallObjectSize);
address = local_heap.AllocateRawOrFail(
kMediumObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime,
AllocationAlignment::kWordAligned);
CreateFixedArray(heap_, address, kMediumObjectSize);
if (i % 10 == 0) {
local_heap.Safepoint();
}
}
AllocateSomeObjects(&local_heap);
pending_->fetch_sub(1);
}
......@@ -110,6 +115,26 @@ UNINITIALIZED_TEST(ConcurrentAllocationInOldSpace) {
isolate->Dispose();
}
UNINITIALIZED_TEST(ConcurrentAllocationInOldSpaceFromMainThread) {
FLAG_max_old_space_size = 4;
FLAG_concurrent_allocation = true;
FLAG_local_heaps = true;
FLAG_stress_concurrent_allocation = false;
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
{
LocalHeap local_heap(i_isolate->heap(), ThreadKind::kMain);
UnparkedScope unparked_scope(&local_heap);
AllocateSomeObjects(&local_heap);
}
isolate->Dispose();
}
class LargeObjectConcurrentAllocationThread final : public v8::base::Thread {
public:
explicit LargeObjectConcurrentAllocationThread(Heap* heap,
......@@ -119,7 +144,7 @@ class LargeObjectConcurrentAllocationThread final : public v8::base::Thread {
pending_(pending) {}
void Run() override {
LocalHeap local_heap(heap_);
LocalHeap local_heap(heap_, ThreadKind::kBackground);
UnparkedScope unparked_scope(&local_heap);
const size_t kLargeObjectSize = kMaxRegularHeapObjectSize * 2;
......@@ -187,7 +212,7 @@ class ConcurrentBlackAllocationThread final : public v8::base::Thread {
sema_marking_started_(sema_marking_started) {}
void Run() override {
LocalHeap local_heap(heap_);
LocalHeap local_heap(heap_, ThreadKind::kBackground);
UnparkedScope unparked_scope(&local_heap);
for (int i = 0; i < kNumIterations; i++) {
......@@ -267,7 +292,7 @@ class ConcurrentWriteBarrierThread final : public v8::base::Thread {
value_(value) {}
void Run() override {
LocalHeap local_heap(heap_);
LocalHeap local_heap(heap_, ThreadKind::kBackground);
UnparkedScope unparked_scope(&local_heap);
fixed_array_.set(0, value_);
}
......@@ -329,7 +354,7 @@ class ConcurrentRecordRelocSlotThread final : public v8::base::Thread {
value_(value) {}
void Run() override {
LocalHeap local_heap(heap_);
LocalHeap local_heap(heap_, ThreadKind::kBackground);
UnparkedScope unparked_scope(&local_heap);
int mode_mask = RelocInfo::EmbeddedObjectModeMask();
for (RelocIterator it(code_, mode_mask); !it.done(); it.next()) {
......
......@@ -7183,7 +7183,7 @@ TEST(GarbageCollectionWithLocalHeap) {
Heap* heap = CcTest::i_isolate()->heap();
LocalHeap local_heap(heap);
LocalHeap local_heap(heap, ThreadKind::kMain);
UnparkedScope unparked_scope(&local_heap);
CcTest::CollectGarbage(OLD_SPACE);
{ ParkedScope parked_scope(&local_heap); }
......
......@@ -33,7 +33,7 @@ class ConcurrentSearchThread final : public v8::base::Thread {
sema_started_(sema_started) {}
void Run() override {
LocalHeap local_heap(heap_, std::move(ph_));
LocalHeap local_heap(heap_, ThreadKind::kBackground, std::move(ph_));
UnparkedScope unparked_scope(&local_heap);
LocalHandleScope scope(&local_heap);
......
......@@ -32,7 +32,7 @@ class ConcurrentSearchThread final : public v8::base::Thread {
sema_started_(sema_started) {}
void Run() override {
LocalHeap local_heap(heap_, std::move(ph_));
LocalHeap local_heap(heap_, ThreadKind::kBackground, std::move(ph_));
UnparkedScope unparked_scope(&local_heap);
LocalHandleScope scope(&local_heap);
......
......@@ -34,7 +34,7 @@ class ScriptContextTableAccessUsedThread final : public v8::base::Thread {
script_context_table_(script_context_table) {}
void Run() override {
LocalHeap local_heap(heap_, std::move(ph_));
LocalHeap local_heap(heap_, ThreadKind::kBackground, std::move(ph_));
UnparkedScope unparked_scope(&local_heap);
LocalHandleScope scope(&local_heap);
......@@ -67,7 +67,7 @@ class AccessScriptContextTableThread final : public v8::base::Thread {
native_context_(native_context) {}
void Run() override {
LocalHeap local_heap(heap_, std::move(ph_));
LocalHeap local_heap(heap_, ThreadKind::kBackground, std::move(ph_));
UnparkedScope unparked_scope(&local_heap);
LocalHandleScope scope(&local_heap);
......
......@@ -34,7 +34,7 @@ class ConcurrentSearchThread : public v8::base::Thread {
result_map_(result_map) {}
void Run() override {
LocalHeap local_heap(heap_, std::move(ph_));
LocalHeap local_heap(heap_, ThreadKind::kBackground, std::move(ph_));
UnparkedScope scope(&local_heap);
background_thread_started_->Signal();
......@@ -70,7 +70,7 @@ class ConcurrentSearchOnOutdatedAccessorThread final
main_thread_finished_(main_thread_finished) {}
void Run() override {
LocalHeap local_heap(heap_, std::move(ph_));
LocalHeap local_heap(heap_, ThreadKind::kBackground, std::move(ph_));
UnparkedScope scope(&local_heap);
TransitionsAccessor accessor(CcTest::i_isolate(), map_, true);
......
......@@ -35,7 +35,7 @@ class LocalHandlesThread final : public v8::base::Thread {
sema_gc_finished_(sema_gc_finished) {}
void Run() override {
LocalHeap local_heap(heap_);
LocalHeap local_heap(heap_, ThreadKind::kBackground);
UnparkedScope unparked_scope(&local_heap);
LocalHandleScope scope(&local_heap);
......@@ -103,7 +103,7 @@ TEST(CreateLocalHandlesWithoutLocalHandleScope) {
Isolate* isolate = CcTest::i_isolate();
{
LocalHeap local_heap(isolate->heap());
LocalHeap local_heap(isolate->heap(), ThreadKind::kMain);
UnparkedScope scope(&local_heap);
handle(Smi::FromInt(17), &local_heap);
}
......@@ -124,7 +124,7 @@ TEST(DereferenceLocalHandle) {
ph = phs->NewHandle(number);
}
{
LocalHeap local_heap(isolate->heap(), std::move(phs));
LocalHeap local_heap(isolate->heap(), ThreadKind::kMain, std::move(phs));
UnparkedScope unparked_scope(&local_heap);
LocalHandleScope scope(&local_heap);
Handle<HeapNumber> local_number = handle(*ph, &local_heap);
......
......@@ -41,7 +41,7 @@ class PersistentHandlesThread final : public v8::base::Thread {
sema_gc_finished_(sema_gc_finished) {}
void Run() override {
LocalHeap local_heap(heap_, std::move(ph_));
LocalHeap local_heap(heap_, ThreadKind::kBackground, std::move(ph_));
UnparkedScope unparked_scope(&local_heap);
LocalHandleScope scope(&local_heap);
......@@ -129,7 +129,7 @@ TEST(DereferencePersistentHandle) {
ph = phs->NewHandle(number);
}
{
LocalHeap local_heap(isolate->heap(), std::move(phs));
LocalHeap local_heap(isolate->heap(), ThreadKind::kMain, std::move(phs));
UnparkedScope scope(&local_heap);
CHECK_EQ(42, ph->value());
DisallowHandleDereference disallow_scope;
......@@ -141,7 +141,7 @@ TEST(NewPersistentHandleFailsWhenParked) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
LocalHeap local_heap(isolate->heap());
LocalHeap local_heap(isolate->heap(), ThreadKind::kMain);
// Fail here in debug mode: Persistent handles can't be created if local heap
// is parked
local_heap.NewPersistentHandle(Smi::FromInt(1));
......@@ -151,7 +151,8 @@ TEST(NewPersistentHandleFailsWhenParkedExplicit) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
LocalHeap local_heap(isolate->heap(), isolate->NewPersistentHandles());
LocalHeap local_heap(isolate->heap(), ThreadKind::kMain,
isolate->NewPersistentHandles());
// Fail here in debug mode: Persistent handles can't be created if local heap
// is parked
local_heap.NewPersistentHandle(Smi::FromInt(1));
......
......@@ -62,7 +62,7 @@ class LocalFactoryTest : public TestWithIsolateAndZone {
isolate(), true, construct_language_mode(FLAG_use_strict),
REPLMode::kNo),
&state_),
local_isolate_(isolate()),
local_isolate_(isolate(), ThreadKind::kMain),
unparked_scope_(local_isolate_.heap()) {
FLAG_concurrent_allocation = true;
}
......
......@@ -19,7 +19,7 @@ TEST_F(LocalHeapTest, Initialize) {
CHECK(!heap->safepoint()->ContainsAnyLocalHeap());
{
LocalHeap lh(heap);
LocalHeap lh(heap, ThreadKind::kMain);
CHECK(heap->safepoint()->ContainsLocalHeap(&lh));
}
......@@ -32,14 +32,14 @@ TEST_F(LocalHeapTest, Current) {
CHECK_NULL(LocalHeap::Current());
{
LocalHeap lh(heap);
LocalHeap lh(heap, ThreadKind::kMain);
CHECK_EQ(&lh, LocalHeap::Current());
}
CHECK_NULL(LocalHeap::Current());
{
LocalHeap lh(heap);
LocalHeap lh(heap, ThreadKind::kMain);
CHECK_EQ(&lh, LocalHeap::Current());
}
......@@ -56,7 +56,7 @@ class BackgroundThread final : public v8::base::Thread {
void Run() override {
CHECK_NULL(LocalHeap::Current());
{
LocalHeap lh(heap_);
LocalHeap lh(heap_, ThreadKind::kBackground);
CHECK_EQ(&lh, LocalHeap::Current());
}
CHECK_NULL(LocalHeap::Current());
......@@ -70,7 +70,7 @@ TEST_F(LocalHeapTest, CurrentBackground) {
Heap* heap = i_isolate()->heap();
CHECK_NULL(LocalHeap::Current());
{
LocalHeap lh(heap);
LocalHeap lh(heap, ThreadKind::kMain);
auto thread = std::make_unique<BackgroundThread>(heap);
CHECK(thread->Start());
CHECK_EQ(&lh, LocalHeap::Current());
......
......@@ -40,7 +40,7 @@ class ParkedThread final : public v8::base::Thread {
mutex_(mutex) {}
void Run() override {
LocalHeap local_heap(heap_);
LocalHeap local_heap(heap_, ThreadKind::kBackground);
if (mutex_) {
base::MutexGuard guard(mutex_);
......@@ -98,7 +98,7 @@ class RunningThread final : public v8::base::Thread {
counter_(counter) {}
void Run() override {
LocalHeap local_heap(heap_);
LocalHeap local_heap(heap_, ThreadKind::kBackground);
UnparkedScope unparked_scope(&local_heap);
for (int i = 0; i < kRuns; i++) {
......@@ -147,7 +147,7 @@ TEST_F(SafepointTest, StopRunningThreads) {
TEST_F(SafepointTest, SkipLocalHeapOfThisThread) {
EnsureFlagLocalHeapsEnabled();
Heap* heap = i_isolate()->heap();
LocalHeap local_heap(heap);
LocalHeap local_heap(heap, ThreadKind::kMain);
UnparkedScope unparked_scope(&local_heap);
{
SafepointScope scope(heap);
......
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