diff options
Diffstat (limited to 'deps/v8/src/heap/base/stack.cc')
-rw-r--r-- | deps/v8/src/heap/base/stack.cc | 188 |
1 files changed, 79 insertions, 109 deletions
diff --git a/deps/v8/src/heap/base/stack.cc b/deps/v8/src/heap/base/stack.cc index 337206e817..3a0ec5f352 100644 --- a/deps/v8/src/heap/base/stack.cc +++ b/deps/v8/src/heap/base/stack.cc @@ -12,11 +12,14 @@ namespace heap::base { -Stack::Stack(const void* stack_start) : stack_start_(stack_start) {} - -void Stack::SetStackStart(const void* stack_start) { - stack_start_ = stack_start; -} +// Function with architecture-specific implementation: +// Pushes all callee-saved registers to the stack and invokes the callback, +// passing the supplied pointers (stack and argument) and the intended stack +// marker. +using IterateStackCallback = void (*)(const Stack*, StackVisitor*, const void*); +extern "C" void PushAllRegistersAndIterateStack(const Stack* stack, + StackVisitor* visitor, + IterateStackCallback callback); bool Stack::IsOnStack(const void* slot) const { DCHECK_NOT_NULL(stack_start_); @@ -61,29 +64,33 @@ void IterateAsanFakeFrameIfNecessary(StackVisitor* visitor, // native frame. In case |addr| points to a fake frame of the current stack // iterate the fake frame. Frame layout see // https://github.com/google/sanitizers/wiki/AddressSanitizerUseAfterReturn - if (asan_fake_stack) { - void* fake_frame_begin; - void* fake_frame_end; - void* real_stack_frame = __asan_addr_is_in_fake_stack( - const_cast<void*>(asan_fake_stack), const_cast<void*>(address), - &fake_frame_begin, &fake_frame_end); - if (real_stack_frame) { - // |address| points to a fake frame. Check that the fake frame is part - // of this stack. - if (stack_start >= real_stack_frame && real_stack_frame >= stack_end) { - // Iterate the fake frame. - for (const void* const* current = - reinterpret_cast<const void* const*>(fake_frame_begin); - current < fake_frame_end; ++current) { - const void* address = *current; - if (address == nullptr) continue; - visitor->VisitPointer(address); - } + if (!asan_fake_stack) return; + void* fake_frame_begin; + void* fake_frame_end; + void* real_stack_frame = __asan_addr_is_in_fake_stack( + const_cast<void*>(asan_fake_stack), const_cast<void*>(address), + &fake_frame_begin, &fake_frame_end); + if (real_stack_frame) { + // |address| points to a fake frame. Check that the fake frame is part + // of this stack. + if (stack_start >= real_stack_frame && real_stack_frame >= stack_end) { + // Iterate the fake frame. + for (const void* const* current = + reinterpret_cast<const void* const*>(fake_frame_begin); + current < fake_frame_end; ++current) { + const void* address = *current; + if (address == nullptr) continue; + visitor->VisitPointer(address); } } } } - +#else +void IterateAsanFakeFrameIfNecessary(StackVisitor* visitor, + const void* asan_fake_stack, + const void* stack_start, + const void* stack_end, + const void* address) {} #endif // V8_USE_ADDRESS_SANITIZER void IterateUnsafeStackIfNecessary(StackVisitor* visitor) { @@ -110,9 +117,8 @@ void IterateUnsafeStackIfNecessary(StackVisitor* visitor) { #endif // defined(__has_feature) } -// Called by the trampoline that pushes registers on the stack. This method -// should never be inlined to ensure that a possible redzone cannot contain -// any data that needs to be scanned. +// This method should never be inlined to ensure that a possible redzone cannot +// contain any data that needs to be scanned. V8_NOINLINE // No ASAN support as method accesses redzones while walking the stack. DISABLE_ASAN @@ -120,26 +126,31 @@ DISABLE_ASAN // thread, e.g., for interrupt handling. Atomic reads are not enough as the // other thread may use a lock to synchronize the access. DISABLE_TSAN -void IteratePointersImpl(StackVisitor* visitor, const void* stack_start, - const void* stack_end, - const Stack::CalleeSavedRegisters* registers) { -#ifdef V8_USE_ADDRESS_SANITIZER - const void* asan_fake_stack = __asan_get_current_fake_stack(); -#endif // V8_USE_ADDRESS_SANITIZER +void IteratePointersInStack(StackVisitor* visitor, const void* top, + const void* start, const void* asan_fake_stack) { + for (const void* const* current = reinterpret_cast<const void* const*>(top); + current < start; ++current) { + // MSAN: Instead of unpoisoning the whole stack, the slot's value is copied + // into a local which is unpoisoned. + const void* address = *current; + MSAN_MEMORY_IS_INITIALIZED(&address, sizeof(address)); + if (address == nullptr) continue; + visitor->VisitPointer(address); + IterateAsanFakeFrameIfNecessary(visitor, asan_fake_stack, start, top, + address); + } +} + +} // namespace - // Iterate through the registers. - if (registers != nullptr) { - for (intptr_t value : registers->buffer) { - const void* address = reinterpret_cast<const void*>(value); - MSAN_MEMORY_IS_INITIALIZED(&address, sizeof(address)); - if (address == nullptr) continue; - visitor->VisitPointer(address); +// static +void Stack::IteratePointersImpl(const Stack* stack, StackVisitor* visitor, + const void* stack_end) { #ifdef V8_USE_ADDRESS_SANITIZER - IterateAsanFakeFrameIfNecessary(visitor, asan_fake_stack, stack_start, - stack_end, address); + const void* asan_fake_stack = __asan_get_current_fake_stack(); +#else + const void* asan_fake_stack = nullptr; #endif // V8_USE_ADDRESS_SANITIZER - } - } // Iterate through the stack. // All supported platforms should have their stack aligned to at least @@ -147,92 +158,51 @@ void IteratePointersImpl(StackVisitor* visitor, const void* stack_start, constexpr size_t kMinStackAlignment = sizeof(void*); CHECK_EQ(0u, reinterpret_cast<uintptr_t>(stack_end) & (kMinStackAlignment - 1)); - for (const void* const* current = - reinterpret_cast<const void* const*>(stack_end); - current < stack_start; ++current) { - // MSAN: Instead of unpoisoning the whole stack, the slot's value is copied - // into a local which is unpoisoned. - const void* address = *current; - MSAN_MEMORY_IS_INITIALIZED(&address, sizeof(address)); - if (address == nullptr) continue; - visitor->VisitPointer(address); -#ifdef V8_USE_ADDRESS_SANITIZER - IterateAsanFakeFrameIfNecessary(visitor, asan_fake_stack, stack_start, - stack_end, address); -#endif // V8_USE_ADDRESS_SANITIZER + IteratePointersInStack(visitor, + reinterpret_cast<const void* const*>(stack_end), + stack->stack_start_, asan_fake_stack); + + for (const auto& segment : stack->inactive_stacks_) { + IteratePointersInStack(visitor, segment.top, segment.start, + asan_fake_stack); } -} -} // namespace + IterateUnsafeStackIfNecessary(visitor); +} void Stack::IteratePointers(StackVisitor* visitor) const { - DCHECK_NOT_NULL(stack_start_); - PushAllRegistersAndInvokeCallback(visitor, stack_start_, - &IteratePointersImpl); + // TODO(v8:13493): Remove the implication as soon as IsOnCurrentStack is + // compatible with stack switching. + DCHECK_IMPLIES(!wasm_stack_switching_, IsOnCurrentStack(stack_start_)); + PushAllRegistersAndIterateStack(this, visitor, &IteratePointersImpl); // No need to deal with callee-saved registers as they will be kept alive by // the regular conservative stack iteration. // TODO(chromium:1056170): Add support for SIMD and/or filtering. IterateUnsafeStackIfNecessary(visitor); } -void Stack::IteratePointersUnsafe(StackVisitor* visitor, - const void* stack_end) const { - IteratePointersImpl(visitor, stack_start_, stack_end, nullptr); -} - -namespace { -// Function with architecture-specific implementation: -// Saves all callee-saved registers in the specified buffer. -extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer); -} // namespace - -V8_NOINLINE void Stack::PushAllRegistersAndInvokeCallback( - StackVisitor* visitor, const void* stack_start, Callback callback) { - Stack::CalleeSavedRegisters registers; - SaveCalleeSavedRegisters(registers.buffer.data()); - callback(visitor, stack_start, v8::base::Stack::GetCurrentStackPosition(), - ®isters); +void Stack::IteratePointersUntilMarker(StackVisitor* visitor) const { + DCHECK_NOT_NULL(stack_start_); + DCHECK_NOT_NULL(stack_marker_); + DCHECK_GE(stack_start_, stack_marker_); + IteratePointersImpl(this, visitor, stack_marker_); } -namespace { - #ifdef DEBUG - -bool IsOnCurrentStack(const void* ptr) { +// static +bool Stack::IsOnCurrentStack(const void* ptr) { DCHECK_NOT_NULL(ptr); const void* current_stack_start = v8::base::Stack::GetStackStart(); const void* current_stack_top = v8::base::Stack::GetCurrentStackPosition(); return ptr <= current_stack_start && ptr >= current_stack_top; } - -bool IsValidMarker(const void* stack_start, const void* stack_marker) { - const void* current_stack_top = v8::base::Stack::GetCurrentStackPosition(); - return stack_marker <= stack_start && stack_marker >= current_stack_top; -} - #endif // DEBUG -} // namespace - -// In the following three methods, the stored stack start needs not coincide -// with the current (actual) stack start (e.g., in case it was explicitly set to -// a lower address, in tests) but has to be inside the current stack. - -void Stack::set_marker(const void* stack_marker) { - DCHECK(IsOnCurrentStack(stack_start_)); - DCHECK_NOT_NULL(stack_marker); - DCHECK(IsValidMarker(stack_start_, stack_marker)); - stack_marker_ = stack_marker; +void Stack::AddStackSegment(const void* start, const void* top) { + DCHECK_LE(top, start); + inactive_stacks_.push_back({start, top}); } -void Stack::clear_marker() { - DCHECK(IsOnCurrentStack(stack_start_)); - stack_marker_ = nullptr; -} - -const void* Stack::get_marker() const { - DCHECK_NOT_NULL(stack_marker_); - return stack_marker_; -} +void Stack::ClearStackSegments() { inactive_stacks_.clear(); } } // namespace heap::base |