diff --git a/src/codegen/external-reference.cc b/src/codegen/external-reference.cc index 90d4b621e4..c077407931 100644 --- a/src/codegen/external-reference.cc +++ b/src/codegen/external-reference.cc @@ -775,6 +775,12 @@ ExternalReference ExternalReference::fast_c_call_caller_pc_address( isolate->isolate_data()->fast_c_call_caller_pc_address()); } +ExternalReference ExternalReference::stack_is_iterable_address( + Isolate* isolate) { + return ExternalReference( + isolate->isolate_data()->stack_is_iterable_address()); +} + FUNCTION_REFERENCE(call_enqueue_microtask_function, MicrotaskQueue::CallEnqueueMicrotask) diff --git a/src/codegen/external-reference.h b/src/codegen/external-reference.h index a889977921..b663ae1621 100644 --- a/src/codegen/external-reference.h +++ b/src/codegen/external-reference.h @@ -72,6 +72,7 @@ class StatsCounter; "IsolateData::fast_c_call_caller_fp_address") \ V(fast_c_call_caller_pc_address, \ "IsolateData::fast_c_call_caller_pc_address") \ + V(stack_is_iterable_address, "IsolateData::stack_is_iterable_address") \ V(address_of_regexp_stack_limit, "RegExpStack::limit_address()") \ V(address_of_regexp_stack_memory_address, "RegExpStack::memory_address()") \ V(address_of_regexp_stack_memory_size, "RegExpStack::memory_size()") \ diff --git a/src/deoptimizer/deoptimizer.cc b/src/deoptimizer/deoptimizer.cc index ee4cf2c2fe..e763fa269c 100644 --- a/src/deoptimizer/deoptimizer.cc +++ b/src/deoptimizer/deoptimizer.cc @@ -633,6 +633,12 @@ bool ShouldPadArguments(int arg_count) { // We rely on this function not causing a GC. It is called from generated code // without having a real stack frame in place. void Deoptimizer::DoComputeOutputFrames() { + // When we call this function, the return address of the previous frame has + // been removed from the stack by GenerateDeoptimizationEntries() so the stack + // is not iterable by the SafeStackFrameIterator. +#if V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK + DCHECK_EQ(0, isolate()->isolate_data()->stack_is_iterable()); +#endif base::ElapsedTimer timer; // Determine basic deoptimization information. The optimized frame is diff --git a/src/deoptimizer/ia32/deoptimizer-ia32.cc b/src/deoptimizer/ia32/deoptimizer-ia32.cc index 6b01449ba7..f40ff562be 100644 --- a/src/deoptimizer/ia32/deoptimizer-ia32.cc +++ b/src/deoptimizer/ia32/deoptimizer-ia32.cc @@ -116,6 +116,12 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, // and check that the generated code never deoptimizes with unbalanced stack. __ fnclex(); + // Mark the stack as not iterable for the CPU profiler which won't be able to + // walk the stack without the return address. + __ mov_b(__ ExternalReferenceAsOperand( + ExternalReference::stack_is_iterable_address(isolate), edx), + Immediate(0)); + // Remove the return address and the double registers. __ add(esp, Immediate(kDoubleRegsSize + 1 * kSystemPointerSize)); @@ -194,6 +200,10 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, __ push(Operand(esi, offset)); } + __ mov_b(__ ExternalReferenceAsOperand( + ExternalReference::stack_is_iterable_address(isolate), edx), + Immediate(1)); + // Restore the registers from the stack. __ popad(); diff --git a/src/deoptimizer/x64/deoptimizer-x64.cc b/src/deoptimizer/x64/deoptimizer-x64.cc index 7654dc965f..cfdd6c9ef1 100644 --- a/src/deoptimizer/x64/deoptimizer-x64.cc +++ b/src/deoptimizer/x64/deoptimizer-x64.cc @@ -129,6 +129,12 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, __ popq(Operand(rbx, dst_offset)); } + // Mark the stack as not iterable for the CPU profiler which won't be able to + // walk the stack without the return address. + __ movb(__ ExternalReferenceAsOperand( + ExternalReference::stack_is_iterable_address(isolate)), + Immediate(0)); + // Remove the return address from the stack. __ addq(rsp, Immediate(kPCOnStackSize)); @@ -218,6 +224,10 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, __ popq(r); } + __ movb(__ ExternalReferenceAsOperand( + ExternalReference::stack_is_iterable_address(isolate)), + Immediate(1)); + // Return to the continuation point. __ ret(0); } diff --git a/src/execution/frames.cc b/src/execution/frames.cc index 2014b739a0..365ffa0bc7 100644 --- a/src/execution/frames.cc +++ b/src/execution/frames.cc @@ -278,6 +278,11 @@ SafeStackFrameIterator::SafeStackFrameIterator(Isolate* isolate, Address pc, bool advance_frame = true; Address fast_c_fp = isolate->isolate_data()->fast_c_call_caller_fp(); + uint8_t stack_is_iterable = isolate->isolate_data()->stack_is_iterable(); + if (!stack_is_iterable) { + frame_ = nullptr; + return; + } // 'Fast C calls' are a special type of C call where we call directly from JS // to C without an exit frame inbetween. The CEntryStub is responsible for // setting Isolate::c_entry_fp, meaning that it won't be set for fast C calls. diff --git a/src/execution/frames.h b/src/execution/frames.h index 21c60408b8..ce4c3bcb97 100644 --- a/src/execution/frames.h +++ b/src/execution/frames.h @@ -147,7 +147,13 @@ class StackFrame { // the type of the value on the stack. static Type MarkerToType(intptr_t marker) { DCHECK(IsTypeMarker(marker)); - return static_cast(marker >> kSmiTagSize); + intptr_t type = marker >> kSmiTagSize; + // TODO(petermarshall): There is a bug in the arm64 simulator that causes + // invalid frame markers. +#if !(defined(USE_SIMULATOR) && V8_TARGET_ARCH_ARM64) + DCHECK_LT(static_cast(type), Type::NUMBER_OF_TYPES); +#endif + return static_cast(type); } // Check if a marker is a stack frame type marker or a tagged pointer. diff --git a/src/execution/isolate-data.h b/src/execution/isolate-data.h index d83ae708ec..adeb7f54d3 100644 --- a/src/execution/isolate-data.h +++ b/src/execution/isolate-data.h @@ -81,8 +81,10 @@ class IsolateData final { // The FP and PC that are saved right before TurboAssembler::CallCFunction. Address* fast_c_call_caller_fp_address() { return &fast_c_call_caller_fp_; } Address* fast_c_call_caller_pc_address() { return &fast_c_call_caller_pc_; } + uint8_t* stack_is_iterable_address() { return &stack_is_iterable_; } Address fast_c_call_caller_fp() { return fast_c_call_caller_fp_; } Address fast_c_call_caller_pc() { return fast_c_call_caller_pc_; } + uint8_t stack_is_iterable() { return stack_is_iterable_; } // Returns true if this address points to data stored in this instance. // If it's the case then the value can be accessed indirectly through the @@ -121,6 +123,7 @@ class IsolateData final { V(kVirtualCallTargetRegisterOffset, kSystemPointerSize) \ V(kFastCCallCallerFPOffset, kSystemPointerSize) \ V(kFastCCallCallerPCOffset, kSystemPointerSize) \ + V(kStackIsIterableOffset, kUInt8Size) \ /* This padding aligns IsolateData size by 8 bytes. */ \ V(kPaddingOffset, \ 8 + RoundUp<8>(static_cast(kPaddingOffset)) - kPaddingOffset) \ @@ -172,6 +175,9 @@ class IsolateData final { // instruction in compiled code. Address fast_c_call_caller_fp_ = kNullAddress; Address fast_c_call_caller_pc_ = kNullAddress; + // Whether the SafeStackFrameIterator can successfully iterate the current + // stack. Only valid values are 0 or 1. + uint8_t stack_is_iterable_ = 1; // Ensure the size is 8-byte aligned in order to make alignment of the field // following the IsolateData field predictable. This solves the issue with @@ -219,6 +225,8 @@ void IsolateData::AssertPredictableLayout() { kFastCCallCallerFPOffset); STATIC_ASSERT(offsetof(IsolateData, fast_c_call_caller_pc_) == kFastCCallCallerPCOffset); + STATIC_ASSERT(offsetof(IsolateData, stack_is_iterable_) == + kStackIsIterableOffset); STATIC_ASSERT(sizeof(IsolateData) == IsolateData::kSize); } diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index feb2fdeba6..17d0096140 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status @@ -81,9 +81,6 @@ 'test-cpu-profiler/SampleWhenFrameIsNotSetup': [SKIP], 'test-sampler/LibSamplerCollectSample': [SKIP], - # BUG(v8:9057). Flaky, maybe only on UBSan - 'test-cpu-profiler/DeoptAtFirstLevelInlinedSource': [SKIP], - # BUG(7202). The test is flaky. 'test-cpu-profiler/NativeFrameStackTrace': [SKIP], diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc index e978aff2ba..4b9ee4629f 100644 --- a/test/cctest/test-cpu-profiler.cc +++ b/test/cctest/test-cpu-profiler.cc @@ -2433,6 +2433,7 @@ TEST(DeoptAtFirstLevelInlinedSource) { "\n" "startProfiling();\n" "\n" + "%EnsureFeedbackVectorForFunction(opt_function);\n" "%PrepareFunctionForOptimization(test);\n" "\n" "test(10, 10);\n"