summaryrefslogtreecommitdiff
path: root/deps/v8/src/heap/base/stack.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/heap/base/stack.cc')
-rw-r--r--deps/v8/src/heap/base/stack.cc188
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(),
- &registers);
+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