diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index dafa83627b224a..8c4bc0237702ed 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 6 #define V8_MINOR_VERSION 4 #define V8_BUILD_NUMBER 388 -#define V8_PATCH_LEVEL 41 +#define V8_PATCH_LEVEL 42 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index bd1abda4de8650..23713197f59d66 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -1013,6 +1013,15 @@ JSFunction* JavaScriptFrame::function() const { return JSFunction::cast(function_slot_object()); } +Object* JavaScriptFrame::unchecked_function() const { + // During deoptimization of an optimized function, we may have yet to + // materialize some closures on the stack. The arguments marker object + // marks this case. + DCHECK(function_slot_object()->IsJSFunction() || + isolate()->heap()->arguments_marker() == function_slot_object()); + return function_slot_object(); +} + Object* JavaScriptFrame::receiver() const { return GetParameter(-1); } Object* JavaScriptFrame::context() const { diff --git a/deps/v8/src/frames.h b/deps/v8/src/frames.h index a72832af06dbc0..e21d62764b30c3 100644 --- a/deps/v8/src/frames.h +++ b/deps/v8/src/frames.h @@ -684,6 +684,7 @@ class JavaScriptFrame : public StandardFrame { // Accessors. virtual JSFunction* function() const; + Object* unchecked_function() const; Object* receiver() const override; Object* context() const override; Script* script() const override; diff --git a/deps/v8/src/profiler/sampling-heap-profiler.cc b/deps/v8/src/profiler/sampling-heap-profiler.cc index 0aa0525633ca2c..51fe8866fa1c19 100644 --- a/deps/v8/src/profiler/sampling-heap-profiler.cc +++ b/deps/v8/src/profiler/sampling-heap-profiler.cc @@ -157,12 +157,21 @@ SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::AddStack() { std::vector stack; JavaScriptFrameIterator it(isolate_); int frames_captured = 0; + bool found_arguments_marker_frames = false; while (!it.done() && frames_captured < stack_depth_) { JavaScriptFrame* frame = it.frame(); - SharedFunctionInfo* shared = frame->function()->shared(); - stack.push_back(shared); - - frames_captured++; + // If we are materializing objects during deoptimization, inlined + // closures may not yet be materialized, and this includes the + // closure on the stack. Skip over any such frames (they'll be + // in the top frames of the stack). The allocations made in this + // sensitive moment belong to the formerly optimized frame anyway. + if (frame->unchecked_function()->IsJSFunction()) { + SharedFunctionInfo* shared = frame->function()->shared(); + stack.push_back(shared); + frames_captured++; + } else { + found_arguments_marker_frames = true; + } it.Advance(); } @@ -209,6 +218,12 @@ SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::AddStack() { } node = node->FindOrAddChildNode(name, script_id, shared->start_position()); } + + if (found_arguments_marker_frames) { + node = + node->FindOrAddChildNode("(deopt)", v8::UnboundScript::kNoScriptId, 0); + } + return node; } diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index ce015777e5d6e9..a0796ccd56c158 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -3083,7 +3083,7 @@ TEST(SamplingHeapProfilerPretenuredInlineAllocations) { // Suppress randomness to avoid flakiness in tests. v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true; - // Grow new space unitl maximum capacity reached. + // Grow new space until maximum capacity reached. while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { CcTest::heap()->new_space()->Grow(); } @@ -3138,3 +3138,49 @@ TEST(SamplingHeapProfilerPretenuredInlineAllocations) { CHECK_GE(count, 8000); } + +TEST(SamplingHeapProfilerSampleDuringDeopt) { + i::FLAG_allow_natives_syntax = true; + + v8::HandleScope scope(v8::Isolate::GetCurrent()); + LocalContext env; + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + // Suppress randomness to avoid flakiness in tests. + v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true; + + // Small sample interval to force each object to be sampled. + heap_profiler->StartSamplingHeapProfiler(i::kPointerSize); + + // Lazy deopt from runtime call from inlined callback function. + const char* source = + "var b = " + " [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];" + "(function f() {" + " var result = 0;" + " var lazyDeopt = function(deopt) {" + " var callback = function(v,i,o) {" + " result += i;" + " if (i == 13 && deopt) {" + " %DeoptimizeNow();" + " }" + " return v;" + " };" + " b.map(callback);" + " };" + " lazyDeopt();" + " lazyDeopt();" + " %OptimizeFunctionOnNextCall(lazyDeopt);" + " lazyDeopt();" + " lazyDeopt(true);" + " lazyDeopt();" + "})();"; + + CompileRun(source); + // Should not crash. + + std::unique_ptr profile( + heap_profiler->GetAllocationProfile()); + CHECK(profile); + heap_profiler->StopSamplingHeapProfiler(); +}