diff --git a/common.gypi b/common.gypi index 03220a0200a40d..3e84350395dfe4 100644 --- a/common.gypi +++ b/common.gypi @@ -36,7 +36,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.10', + 'v8_embedder_string': '-node.11', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc index 81255e531cfe7e..ce799eeef33ca7 100644 --- a/deps/v8/src/heap/heap.cc +++ b/deps/v8/src/heap/heap.cc @@ -4283,6 +4283,9 @@ void Heap::AutomaticallyRestoreInitialHeapLimit(double threshold_percent) { bool Heap::InvokeNearHeapLimitCallback() { if (near_heap_limit_callbacks_.size() > 0) { + AllowGarbageCollection allow_gc; + TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_NEAR_HEAP_LIMIT); + VMState callback_state(isolate()); HandleScope scope(isolate()); v8::NearHeapLimitCallback callback = near_heap_limit_callbacks_.back().first; diff --git a/deps/v8/src/init/heap-symbols.h b/deps/v8/src/init/heap-symbols.h index c19f1a11365e7b..8cd69613a678c3 100644 --- a/deps/v8/src/init/heap-symbols.h +++ b/deps/v8/src/init/heap-symbols.h @@ -527,6 +527,7 @@ F(HEAP_EPILOGUE_REDUCE_NEW_SPACE) \ F(HEAP_EPILOGUE_SAFEPOINT) \ F(HEAP_EXTERNAL_EPILOGUE) \ + F(HEAP_EXTERNAL_NEAR_HEAP_LIMIT) \ F(HEAP_EXTERNAL_PROLOGUE) \ F(HEAP_EXTERNAL_WEAK_GLOBAL_HANDLES) \ F(HEAP_PROLOGUE) \ diff --git a/deps/v8/test/cctest/heap/test-heap.cc b/deps/v8/test/cctest/heap/test-heap.cc index 4d679651368c5c..f90922b8a54d83 100644 --- a/deps/v8/test/cctest/heap/test-heap.cc +++ b/deps/v8/test/cctest/heap/test-heap.cc @@ -1271,6 +1271,62 @@ UNINITIALIZED_TEST(Regress10843) { isolate->Dispose(); } +size_t near_heap_limit_invocation_count = 0; +size_t InvokeGCNearHeapLimitCallback(void* data, size_t current_heap_limit, + size_t initial_heap_limit) { + near_heap_limit_invocation_count++; + if (near_heap_limit_invocation_count > 1) { + // We are already in a GC triggered in this callback, raise the limit + // to avoid an OOM. + return current_heap_limit * 5; + } + + DCHECK_EQ(near_heap_limit_invocation_count, 1); + // Operations that may cause GC (e.g. taking heap snapshots) in the + // near heap limit callback should not hit the AllowGarbageCollection + // assertion. + static_cast(data)->GetHeapProfiler()->TakeHeapSnapshot(); + return current_heap_limit * 5; +} + +UNINITIALIZED_TEST(Regress12777) { + v8::Isolate::CreateParams create_params; + create_params.constraints.set_max_old_generation_size_in_bytes(10 * i::MB); + create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + + isolate->AddNearHeapLimitCallback(InvokeGCNearHeapLimitCallback, isolate); + + { + v8::Isolate::Scope isolate_scope(isolate); + + Isolate* i_isolate = reinterpret_cast(isolate); + // Allocate data to trigger the NearHeapLimitCallback. + HandleScope scope(i_isolate); + int length = 2 * i::MB / i::kTaggedSize; + std::vector> arrays; + for (int i = 0; i < 5; i++) { + arrays.push_back(i_isolate->factory()->NewFixedArray(length)); + } + CcTest::CollectAllGarbage(i_isolate); + for (int i = 0; i < 5; i++) { + arrays.push_back(i_isolate->factory()->NewFixedArray(length)); + } + CcTest::CollectAllGarbage(i_isolate); + for (int i = 0; i < 5; i++) { + arrays.push_back(i_isolate->factory()->NewFixedArray(length)); + } + + // The work done above should trigger the heap limit callback at least + // twice to prove that the callback can raise the limit in the second + // or later calls to avoid an OOM. + CHECK_GE(near_heap_limit_invocation_count, 2); + } + + isolate->GetHeapProfiler()->DeleteAllHeapSnapshots(); + isolate->Dispose(); +} + #ifndef V8_LITE_MODE TEST(TestOptimizeAfterBytecodeFlushingCandidate) {