chromium/chromium-111-v8-std-layout1...

2230 lines
95 KiB
Diff

From 472429e623cf48e864a7a2f10d589817a88289a1 Mon Sep 17 00:00:00 2001
From: Nikolaos Papaspyrou <nikolaos@chromium.org>
Date: Wed, 18 Jan 2023 21:11:59 +0100
Subject: [PATCH] [heap] Fix saving the callee-saved registers on stack
This CL reinstates the trampoline for pushing the values of
callee-saved registers on the stack, which is used for stack scanning.
It reintroduces the set of architecture-specific functions
PushAllRegistersAndIterateStack, removed in crrev.com/c/3989143.
The reason for this change is that the simpler architecture-specific
functions SaveCalleeSavedRegisters failed to correctly save the
values of the registers, in the presence of C++ compiler optimizations.
It also removes the stack context, introduced in crrev.com/c/4017512,
and uses again the trampoline for iterating through the stack.
Bug: v8:13257
Change-Id: I9e656a9b3ba6616168602300f2180b4f340593f3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4171639
Commit-Queue: Nikolaos Papaspyrou <nikolaos@chromium.org>
Reviewed-by: Omer Katz <omerkatz@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85394}
(stripped tests)
---
diff --git a/BUILD.bazel b/BUILD.bazel
index 283eeff..e3269a4 100644
--- a/v8/BUILD.bazel
+++ b/v8/BUILD.bazel
@@ -3201,16 +3201,16 @@
# Note these cannot be v8_target_is_* selects because these contain
# inline assembly that runs inside the executable. Since these are
# linked directly into mksnapshot, they must use the actual target cpu.
- "@v8//bazel/config:is_inline_asm_ia32": ["src/heap/base/asm/ia32/save_registers_asm.cc"],
- "@v8//bazel/config:is_inline_asm_x64": ["src/heap/base/asm/x64/save_registers_asm.cc"],
- "@v8//bazel/config:is_inline_asm_arm": ["src/heap/base/asm/arm/save_registers_asm.cc"],
- "@v8//bazel/config:is_inline_asm_arm64": ["src/heap/base/asm/arm64/save_registers_asm.cc"],
- "@v8//bazel/config:is_inline_asm_s390x": ["src/heap/base/asm/s390/save_registers_asm.cc"],
- "@v8//bazel/config:is_inline_asm_riscv64": ["src/heap/base/asm/riscv64/save_registers_asm.cc"],
- "@v8//bazel/config:is_inline_asm_ppc64le": ["src/heap/base/asm/ppc/save_registers_asm.cc"],
- "@v8//bazel/config:is_msvc_asm_ia32": ["src/heap/base/asm/ia32/save_registers_masm.asm"],
- "@v8//bazel/config:is_msvc_asm_x64": ["src/heap/base/asm/x64/save_registers_masm.asm"],
- "@v8//bazel/config:is_msvc_asm_arm64": ["src/heap/base/asm/arm64/save_registers_masm.S"],
+ "@v8//bazel/config:is_inline_asm_ia32": ["src/heap/base/asm/ia32/push_registers_asm.cc"],
+ "@v8//bazel/config:is_inline_asm_x64": ["src/heap/base/asm/x64/push_registers_asm.cc"],
+ "@v8//bazel/config:is_inline_asm_arm": ["src/heap/base/asm/arm/push_registers_asm.cc"],
+ "@v8//bazel/config:is_inline_asm_arm64": ["src/heap/base/asm/arm64/push_registers_asm.cc"],
+ "@v8//bazel/config:is_inline_asm_s390x": ["src/heap/base/asm/s390/push_registers_asm.cc"],
+ "@v8//bazel/config:is_inline_asm_riscv64": ["src/heap/base/asm/riscv64/push_registers_asm.cc"],
+ "@v8//bazel/config:is_inline_asm_ppc64le": ["src/heap/base/asm/ppc/push_registers_asm.cc"],
+ "@v8//bazel/config:is_msvc_asm_ia32": ["src/heap/base/asm/ia32/push_registers_masm.asm"],
+ "@v8//bazel/config:is_msvc_asm_x64": ["src/heap/base/asm/x64/push_registers_masm.asm"],
+ "@v8//bazel/config:is_msvc_asm_arm64": ["src/heap/base/asm/arm64/push_registers_masm.S"],
}),
)
diff --git a/BUILD.gn b/BUILD.gn
index 80a7eb6..56798db 100644
--- a/v8/BUILD.gn
+++ b/v8/BUILD.gn
@@ -5989,31 +5989,31 @@
if (is_clang || !is_win) {
if (current_cpu == "x64") {
- sources += [ "src/heap/base/asm/x64/save_registers_asm.cc" ]
+ sources += [ "src/heap/base/asm/x64/push_registers_asm.cc" ]
} else if (current_cpu == "x86") {
- sources += [ "src/heap/base/asm/ia32/save_registers_asm.cc" ]
+ sources += [ "src/heap/base/asm/ia32/push_registers_asm.cc" ]
} else if (current_cpu == "arm") {
- sources += [ "src/heap/base/asm/arm/save_registers_asm.cc" ]
+ sources += [ "src/heap/base/asm/arm/push_registers_asm.cc" ]
} else if (current_cpu == "arm64") {
- sources += [ "src/heap/base/asm/arm64/save_registers_asm.cc" ]
+ sources += [ "src/heap/base/asm/arm64/push_registers_asm.cc" ]
} else if (current_cpu == "ppc64") {
- sources += [ "src/heap/base/asm/ppc/save_registers_asm.cc" ]
+ sources += [ "src/heap/base/asm/ppc/push_registers_asm.cc" ]
} else if (current_cpu == "s390x") {
- sources += [ "src/heap/base/asm/s390/save_registers_asm.cc" ]
+ sources += [ "src/heap/base/asm/s390/push_registers_asm.cc" ]
} else if (current_cpu == "mips64el") {
- sources += [ "src/heap/base/asm/mips64/save_registers_asm.cc" ]
+ sources += [ "src/heap/base/asm/mips64/push_registers_asm.cc" ]
} else if (current_cpu == "loong64") {
- sources += [ "src/heap/base/asm/loong64/save_registers_asm.cc" ]
+ sources += [ "src/heap/base/asm/loong64/push_registers_asm.cc" ]
} else if (current_cpu == "riscv64" || current_cpu == "riscv32") {
- sources += [ "src/heap/base/asm/riscv/save_registers_asm.cc" ]
+ sources += [ "src/heap/base/asm/riscv/push_registers_asm.cc" ]
}
} else if (is_win) {
if (current_cpu == "x64") {
- sources += [ "src/heap/base/asm/x64/save_registers_masm.asm" ]
+ sources += [ "src/heap/base/asm/x64/push_registers_masm.asm" ]
} else if (current_cpu == "x86") {
- sources += [ "src/heap/base/asm/ia32/save_registers_masm.asm" ]
+ sources += [ "src/heap/base/asm/ia32/push_registers_masm.asm" ]
} else if (current_cpu == "arm64") {
- sources += [ "src/heap/base/asm/arm64/save_registers_masm.S" ]
+ sources += [ "src/heap/base/asm/arm64/push_registers_masm.S" ]
}
}
diff --git a/src/execution/isolate.cc b/src/execution/isolate.cc
index 8a2ec80..31536a1 100644
--- a/v8/src/execution/isolate.cc
+++ b/v8/src/execution/isolate.cc
@@ -3075,8 +3075,7 @@
.get()
.get();
current = WasmContinuationObject::cast(current).parent();
- thread_local_top()->stack_.SetStackStart(
- reinterpret_cast<void*>(stack->base()));
+ heap()->SetStackStart(reinterpret_cast<void*>(stack->base()));
// We don't need to add all inactive stacks. Only the ones in the active chain
// may contain cpp heap pointers.
while (!current.IsUndefined()) {
@@ -3372,9 +3371,12 @@
Isolate* saved_isolate = isolate->TryGetCurrent();
SetIsolateThreadLocals(isolate, nullptr);
isolate->set_thread_id(ThreadId::Current());
- isolate->thread_local_top()->stack_ =
- saved_isolate ? std::move(saved_isolate->thread_local_top()->stack_)
- : ::heap::base::Stack(base::Stack::GetStackStart());
+ if (saved_isolate) {
+ isolate->thread_local_top()->stack_ =
+ std::move(saved_isolate->thread_local_top()->stack_);
+ } else {
+ isolate->heap()->SetStackStart(base::Stack::GetStackStart());
+ }
bool owns_shared_isolate = isolate->owns_shared_isolate_;
Isolate* maybe_shared_isolate = isolate->shared_isolate_;
diff --git a/src/execution/thread-local-top.cc b/src/execution/thread-local-top.cc
index 0d7071d..c115ae0 100644
--- a/v8/src/execution/thread-local-top.cc
+++ b/v8/src/execution/thread-local-top.cc
@@ -44,10 +44,13 @@
Clear();
isolate_ = isolate;
thread_id_ = ThreadId::Current();
- stack_.SetStackStart(base::Stack::GetStackStart());
#if V8_ENABLE_WEBASSEMBLY
+ stack_.SetStackStart(base::Stack::GetStackStart(),
+ v8_flags.experimental_wasm_stack_switching);
thread_in_wasm_flag_address_ = reinterpret_cast<Address>(
trap_handler::GetThreadInWasmThreadLocalAddress());
+#else
+ stack_.SetStackStart(base::Stack::GetStackStart(), false);
#endif // V8_ENABLE_WEBASSEMBLY
#ifdef USE_SIMULATOR
simulator_ = Simulator::current(isolate);
diff --git a/src/heap/base/asm/arm/push_registers_asm.cc b/src/heap/base/asm/arm/push_registers_asm.cc
new file mode 100644
index 0000000..5246c3f
--- /dev/null
+++ b/v8/src/heap/base/asm/arm/push_registers_asm.cc
@@ -0,0 +1,39 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Push all callee-saved registers to get them on the stack for conservative
+// stack scanning.
+//
+// See asm/x64/push_registers_clang.cc for why the function is not generated
+// using clang.
+//
+// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
+// GN toolchain (e.g. ChromeOS) and not provide them.
+
+// We maintain 8-byte alignment at calls by pushing an additional
+// non-callee-saved register (r3).
+//
+// Calling convention source:
+// https://en.wikipedia.org/wiki/Calling_convention#ARM_(A32)
+// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html
+asm(".globl PushAllRegistersAndIterateStack \n"
+ ".type PushAllRegistersAndIterateStack, %function \n"
+ ".hidden PushAllRegistersAndIterateStack \n"
+ "PushAllRegistersAndIterateStack: \n"
+ // Push all callee-saved registers and save return address.
+ // Only {r4-r11} are callee-saved registers. Push r3 in addition to align
+ // the stack back to 8 bytes.
+ " push {r3-r11, lr} \n"
+ // Pass 1st parameter (r0) unchanged (Stack*).
+ // Pass 2nd parameter (r1) unchanged (StackVisitor*).
+ // Save 3rd parameter (r2; IterateStackCallback).
+ " mov r3, r2 \n"
+ // Pass 3rd parameter as sp (stack pointer).
+ " mov r2, sp \n"
+ // Call the callback.
+ " blx r3 \n"
+ // Discard all the registers.
+ " add sp, sp, #36 \n"
+ // Pop lr into pc which returns and switches mode if needed.
+ " pop {pc} \n");
diff --git a/src/heap/base/asm/arm/save_registers_asm.cc b/src/heap/base/asm/arm/save_registers_asm.cc
deleted file mode 100644
index ace9503..0000000
--- a/v8/src/heap/base/asm/arm/save_registers_asm.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2020 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <src/heap/base/stack.h>
-
-// Save all callee-saved registers in the specified buffer.
-// extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-
-// See asm/x64/save_registers_asm.cc for why the function is not generated
-// using clang.
-//
-// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
-// GN toolchain (e.g. ChromeOS) and not provide them.
-//
-// We maintain 8-byte alignment at calls by pushing an additional
-// non-callee-saved register (r3).
-//
-// Calling convention source:
-// https://en.wikipedia.org/wiki/Calling_convention#ARM_(A32)
-// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html
-
-// 8 32-bit registers = 8 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 8,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 4, "Mismatch in word size");
-
-asm(".globl SaveCalleeSavedRegisters \n"
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
- // r0: [ intptr_t* buffer ]
- // Save the callee-saved registers: {r4-r11}.
- " stm r0, {r4-r11} \n"
- // Return.
- " bx lr \n");
diff --git a/src/heap/base/asm/arm64/push_registers_asm.cc b/src/heap/base/asm/arm64/push_registers_asm.cc
new file mode 100644
index 0000000..1efcc34
--- /dev/null
+++ b/v8/src/heap/base/asm/arm64/push_registers_asm.cc
@@ -0,0 +1,62 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Push all callee-saved registers to get them on the stack for conservative
+// stack scanning.
+//
+// See asm/x64/push_registers_clang.cc for why the function is not generated
+// using clang.
+//
+// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
+// GN toolchain (e.g. ChromeOS) and not provide them.
+
+// We maintain 16-byte alignment.
+//
+// Calling convention source:
+// https://en.wikipedia.org/wiki/Calling_convention#ARM_(A64)
+
+asm(
+#if defined(__APPLE__)
+ ".globl _PushAllRegistersAndIterateStack \n"
+ ".private_extern _PushAllRegistersAndIterateStack \n"
+ ".p2align 2 \n"
+ "_PushAllRegistersAndIterateStack: \n"
+#else // !defined(__APPLE__)
+ ".globl PushAllRegistersAndIterateStack \n"
+#if !defined(_WIN64)
+ ".type PushAllRegistersAndIterateStack, %function \n"
+ ".hidden PushAllRegistersAndIterateStack \n"
+#endif // !defined(_WIN64)
+ ".p2align 2 \n"
+ "PushAllRegistersAndIterateStack: \n"
+#endif // !defined(__APPLE__)
+ // x19-x29 are callee-saved.
+ " stp x19, x20, [sp, #-16]! \n"
+ " stp x21, x22, [sp, #-16]! \n"
+ " stp x23, x24, [sp, #-16]! \n"
+ " stp x25, x26, [sp, #-16]! \n"
+ " stp x27, x28, [sp, #-16]! \n"
+#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY
+ // Sign return address.
+ " paciasp \n"
+#endif
+ " stp fp, lr, [sp, #-16]! \n"
+ // Maintain frame pointer.
+ " mov fp, sp \n"
+ // Pass 1st parameter (x0) unchanged (Stack*).
+ // Pass 2nd parameter (x1) unchanged (StackVisitor*).
+ // Save 3rd parameter (x2; IterateStackCallback)
+ " mov x7, x2 \n"
+ // Pass 3rd parameter as sp (stack pointer).
+ " mov x2, sp \n"
+ " blr x7 \n"
+ // Load return address and frame pointer.
+ " ldp fp, lr, [sp], #16 \n"
+#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY
+ // Authenticate return address.
+ " autiasp \n"
+#endif
+ // Drop all callee-saved registers.
+ " add sp, sp, #80 \n"
+ " ret \n");
diff --git a/src/heap/base/asm/arm64/push_registers_masm.S b/src/heap/base/asm/arm64/push_registers_masm.S
new file mode 100644
index 0000000..888523a
--- /dev/null
+++ b/v8/src/heap/base/asm/arm64/push_registers_masm.S
@@ -0,0 +1,32 @@
+; Copyright 2020 the V8 project authors. All rights reserved.
+; Use of this source code is governed by a BSD-style license that can be
+; found in the LICENSE file.
+
+; This file is exactly the same as push_registers_asm.cc, just formatted for
+; the Microsoft Arm Assembler.
+
+ AREA |.text|, CODE, ALIGN=4, READONLY
+ EXPORT PushAllRegistersAndIterateStack
+PushAllRegistersAndIterateStack
+ ; x19-x29 are callee-saved
+ STP x19, x20, [sp, #-16]!
+ STP x21, x22, [sp, #-16]!
+ STP x23, x24, [sp, #-16]!
+ STP x25, x26, [sp, #-16]!
+ STP x27, x28, [sp, #-16]!
+ STP fp, lr, [sp, #-16]!
+ ; Maintain frame pointer
+ MOV fp, sp
+ ; Pass 1st parameter (x0) unchanged (Stack*).
+ ; Pass 2nd parameter (x1) unchanged (StackVisitor*).
+ ; Save 3rd parameter (x2; IterateStackCallback)
+ MOV x7, x2
+ ; Pass 3rd parameter as sp (stack pointer)
+ MOV x2, sp
+ BLR x7
+ ; Load return address
+ LDR lr, [sp, #8]
+ ; Restore frame pointer and pop all callee-saved registers.
+ LDR fp, [sp], #96
+ RET
+ END
diff --git a/src/heap/base/asm/arm64/save_registers_asm.cc b/src/heap/base/asm/arm64/save_registers_asm.cc
deleted file mode 100644
index 5fe81d8..0000000
--- a/v8/src/heap/base/asm/arm64/save_registers_asm.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2020 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <src/heap/base/stack.h>
-
-// Save all callee-saved registers in the specified buffer.
-// extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-
-// See asm/x64/save_registers_asm.cc for why the function is not generated
-// using clang.
-//
-// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
-// GN toolchain (e.g. ChromeOS) and not provide them.
-//
-// We maintain 16-byte alignment.
-//
-// Calling convention source:
-// https://en.wikipedia.org/wiki/Calling_convention#ARM_(A64)
-
-// 11 64-bit registers = 11 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 11,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 8, "Mismatch in word size");
-
-asm(
-#if defined(__APPLE__)
- ".globl _SaveCalleeSavedRegisters \n"
- ".private_extern _SaveCalleeSavedRegisters \n"
- ".p2align 2 \n"
- "_SaveCalleeSavedRegisters: \n"
-#else // !defined(__APPLE__)
- ".globl SaveCalleeSavedRegisters \n"
-#if !defined(_WIN64)
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
-#endif // !defined(_WIN64)
- ".p2align 2 \n"
- "SaveCalleeSavedRegisters: \n"
-#endif // !defined(__APPLE__)
- // $x0: [ intptr_t* buffer ]
- // Save the callee-saved registers: x19-x29.
- " stp x19, x20, [x0], #16 \n"
- " stp x21, x22, [x0], #16 \n"
- " stp x23, x24, [x0], #16 \n"
- " stp x25, x26, [x0], #16 \n"
- " stp x27, x28, [x0], #16 \n"
- " str x29, [x0] \n"
- // Return.
- " ret \n");
diff --git a/src/heap/base/asm/arm64/save_registers_masm.S b/src/heap/base/asm/arm64/save_registers_masm.S
deleted file mode 100644
index ab79055..0000000
--- a/v8/src/heap/base/asm/arm64/save_registers_masm.S
+++ /dev/null
@@ -1,24 +0,0 @@
-; Copyright 2020 the V8 project authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-; This file is exactly the same as save_registers_asm.cc, just formatted for
-; the Microsoft Arm Assembler.
-
-; Save all callee-saved registers in the specified buffer.
-; extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-
- AREA |.text|, CODE, ALIGN=4, READONLY
- EXPORT SaveCalleeSavedRegisters
-SaveCalleeSavedRegisters
- ; x0: [ intptr_t* buffer ]
- ; x19-x29 are callee-saved
- STP x19, x20, [x0], #16
- STP x21, x22, [x0], #16
- STP x23, x24, [x0], #16
- STP x25, x26, [x0], #16
- STP x27, x28, [x0], #16
- STR x29, [x0]
- ; Return.
- RET
- END
diff --git a/src/heap/base/asm/ia32/push_registers_asm.cc b/src/heap/base/asm/ia32/push_registers_asm.cc
new file mode 100644
index 0000000..ed9c14a
--- /dev/null
+++ b/v8/src/heap/base/asm/ia32/push_registers_asm.cc
@@ -0,0 +1,53 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Push all callee-saved registers to get them on the stack for conservative
+// stack scanning.
+//
+// See asm/x64/push_registers_clang.cc for why the function is not generated
+// using clang.
+//
+// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
+// GN toolchain (e.g. ChromeOS) and not provide them.
+
+// We maintain 16-byte alignment at calls. There is an 4-byte return address
+// on the stack and we push 28 bytes which maintains 16-byte stack alignment
+// at the call.
+//
+// The following assumes cdecl calling convention.
+// Source: https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl
+asm(
+#ifdef _WIN32
+ ".globl _PushAllRegistersAndIterateStack \n"
+ "_PushAllRegistersAndIterateStack: \n"
+#else // !_WIN32
+ ".globl PushAllRegistersAndIterateStack \n"
+ ".type PushAllRegistersAndIterateStack, %function \n"
+ ".hidden PushAllRegistersAndIterateStack \n"
+ "PushAllRegistersAndIterateStack: \n"
+#endif // !_WIN32
+ // [ IterateStackCallback ]
+ // [ StackVisitor* ]
+ // [ Stack* ]
+ // [ ret ]
+ // ebp is callee-saved. Maintain proper frame pointer for debugging.
+ " push %ebp \n"
+ " movl %esp, %ebp \n"
+ " push %ebx \n"
+ " push %esi \n"
+ " push %edi \n"
+ // Save 3rd parameter (IterateStackCallback).
+ " movl 28(%esp), %ecx \n"
+ // Pass 3rd parameter as esp (stack pointer).
+ " push %esp \n"
+ // Pass 2nd parameter (StackVisitor*).
+ " push 28(%esp) \n"
+ // Pass 1st parameter (Stack*).
+ " push 28(%esp) \n"
+ " call *%ecx \n"
+ // Pop the callee-saved registers.
+ " addl $24, %esp \n"
+ // Restore rbp as it was used as frame pointer.
+ " pop %ebp \n"
+ " ret \n");
diff --git a/src/heap/base/asm/ia32/push_registers_masm.asm b/src/heap/base/asm/ia32/push_registers_masm.asm
new file mode 100644
index 0000000..a35fd6e
--- /dev/null
+++ b/v8/src/heap/base/asm/ia32/push_registers_masm.asm
@@ -0,0 +1,48 @@
+;; Copyright 2020 the V8 project authors. All rights reserved.
+;; Use of this source code is governed by a BSD-style license that can be
+;; found in the LICENSE file.
+
+;; MASM syntax
+;; https://docs.microsoft.com/en-us/cpp/assembler/masm/microsoft-macro-assembler-reference?view=vs-2019
+
+.model flat, C
+
+public PushAllRegistersAndIterateStack
+
+.code
+PushAllRegistersAndIterateStack:
+ ;; Push all callee-saved registers to get them on the stack for conservative
+ ;; stack scanning.
+ ;;
+ ;; We maintain 16-byte alignment at calls. There is an 8-byte return address
+ ;; on the stack and we push 72 bytes which maintains 16-byte stack alignment
+ ;; at the call.
+ ;;
+ ;; The following assumes cdecl calling convention.
+ ;; Source: https://docs.microsoft.com/en-us/cpp/cpp/cdecl?view=vs-2019
+ ;;
+ ;; [ IterateStackCallback ]
+ ;; [ StackVisitor* ]
+ ;; [ Stack* ]
+ ;; [ ret ]
+ push ebp
+ mov ebp, esp
+ push ebx
+ push esi
+ push edi
+ ;; Save 3rd parameter (IterateStackCallback).
+ mov ecx, [ esp + 28 ]
+ ;; Pass 3rd parameter as esp (stack pointer).
+ push esp
+ ;; Pass 2nd parameter (StackVisitor*).
+ push [ esp + 28 ]
+ ;; Pass 1st parameter (Stack*).
+ push [ esp + 28 ]
+ call ecx
+ ;; Pop the callee-saved registers.
+ add esp, 24
+ ;; Restore rbp as it was used as frame pointer.
+ pop ebp
+ ret
+
+end
diff --git a/src/heap/base/asm/ia32/save_registers_asm.cc b/src/heap/base/asm/ia32/save_registers_asm.cc
deleted file mode 100644
index 7c05247..0000000
--- a/v8/src/heap/base/asm/ia32/save_registers_asm.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2020 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <src/heap/base/stack.h>
-
-// Save all callee-saved registers in the specified buffer.
-// extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-
-// See asm/x64/save_registers_asm.cc for why the function is not generated
-// using clang.
-//
-// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
-// GN toolchain (e.g. ChromeOS) and not provide them.
-//
-// The following assumes cdecl calling convention.
-// Source: https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl
-
-// 3 32-bit registers = 3 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 3,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 4, "Mismatch in word size");
-
-asm(
-#ifdef _WIN32
- ".globl _SaveCalleeSavedRegisters \n"
- "_SaveCalleeSavedRegisters: \n"
-#else // !_WIN32
- ".globl SaveCalleeSavedRegisters \n"
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
-#endif // !_WIN32
- // 8: [ intptr_t* buffer ]
- // 4: [ ret ]
- // 0: [ saved %ebp ]
- // %ebp is callee-saved. Maintain proper frame pointer for debugging.
- " push %ebp \n"
- " movl %esp, %ebp \n"
- // Load the buffer's address in %ecx.
- " movl 8(%ebp), %ecx \n"
- // Save the callee-saved registers.
- " movl %ebx, 0(%ecx) \n"
- " movl %esi, 4(%ecx) \n"
- " movl %edi, 8(%ecx) \n"
- // Restore %ebp as it was used as frame pointer and return.
- " pop %ebp \n"
- " ret \n");
diff --git a/src/heap/base/asm/ia32/save_registers_masm.asm b/src/heap/base/asm/ia32/save_registers_masm.asm
deleted file mode 100644
index 0892b02..0000000
--- a/v8/src/heap/base/asm/ia32/save_registers_masm.asm
+++ /dev/null
@@ -1,36 +0,0 @@
-;; Copyright 2020 the V8 project authors. All rights reserved.
-;; Use of this source code is governed by a BSD-style license that can be
-;; found in the LICENSE file.
-
-;; MASM syntax
-;; https://docs.microsoft.com/en-us/cpp/assembler/masm/microsoft-macro-assembler-reference?view=vs-2019
-
-.model flat, C
-
-public SaveCalleeSavedRegisters
-
-.code
- ;; Save all callee-saved registers in the specified buffer.
- ;; extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
- ;;
- ;; The following assumes cdecl calling convention.
- ;; Source: https://docs.microsoft.com/en-us/cpp/cpp/cdecl?view=vs-2019
-
-SaveCalleeSavedRegisters:
- ;; 8: [ intptr_t* buffer ]
- ;; 4: [ ret ]
- ;; 0: [ saved %ebp ]
- ;; %ebp is callee-saved. Maintain proper frame pointer for debugging.
- push ebp
- mov ebp, esp
- ;; Load the buffer's address in %ecx.
- mov ecx, [ebp + 8]
- ;; Save the callee-saved registers.
- mov [ecx], ebx
- mov [ecx + 4], esi
- mov [ecx + 8], edi
- ;; Restore %ebp as it was used as frame pointer and return.
- pop ebp
- ret
-
-end
diff --git a/src/heap/base/asm/loong64/push_registers_asm.cc b/src/heap/base/asm/loong64/push_registers_asm.cc
new file mode 100644
index 0000000..aa8dcd3
--- /dev/null
+++ b/v8/src/heap/base/asm/loong64/push_registers_asm.cc
@@ -0,0 +1,48 @@
+// Copyright 2021 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Push all callee-saved registers to get them on the stack for conservative
+// stack scanning.
+//
+// See asm/x64/push_registers_clang.cc for why the function is not generated
+// using clang.
+//
+// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
+// GN toolchain (e.g. ChromeOS) and not provide them.
+asm(".text \n"
+ ".global PushAllRegistersAndIterateStack \n"
+ ".type PushAllRegistersAndIterateStack, %function \n"
+ ".hidden PushAllRegistersAndIterateStack \n"
+ "PushAllRegistersAndIterateStack: \n"
+ // Push all callee-saved registers and save return address.
+ " addi.d $sp, $sp, -96 \n"
+ " st.d $ra, $sp, 88 \n"
+ " st.d $s8, $sp, 80 \n"
+ " st.d $sp, $sp, 72 \n"
+ " st.d $fp, $sp, 64 \n"
+ " st.d $s7, $sp, 56 \n"
+ " st.d $s6, $sp, 48 \n"
+ " st.d $s5, $sp, 40 \n"
+ " st.d $s4, $sp, 32 \n"
+ " st.d $s3, $sp, 24 \n"
+ " st.d $s2, $sp, 16 \n"
+ " st.d $s1, $sp, 8 \n"
+ " st.d $s0, $sp, 0 \n"
+ // Maintain frame pointer.
+ " addi.d $s8, $sp, 0 \n"
+ // Pass 1st parameter (a0) unchanged (Stack*).
+ // Pass 2nd parameter (a1) unchanged (StackVisitor*).
+ // Save 3rd parameter (a2; IterateStackCallback).
+ " addi.d $a3, $a2, 0 \n"
+ // Call the callback.
+ // Pass 3rd parameter as sp (stack pointer).
+ " addi.d $a2, $sp, 0 \n"
+ " jirl $ra, $a3, 0 \n"
+ // Load return address.
+ " ld.d $ra, $sp, 88 \n"
+ // Restore frame pointer.
+ " ld.d $s8, $sp, 80 \n"
+ // Discard all callee-saved registers.
+ " addi.d $sp, $sp, 96 \n"
+ " jirl $zero, $ra, 0 \n");
diff --git a/src/heap/base/asm/loong64/save_registers_asm.cc b/src/heap/base/asm/loong64/save_registers_asm.cc
deleted file mode 100644
index d5b110d..0000000
--- a/v8/src/heap/base/asm/loong64/save_registers_asm.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2021 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <src/heap/base/stack.h>
-
-// Save all callee-saved registers in the specified buffer.
-// extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-
-// See asm/x64/save_registers_asm.cc for why the function is not generated
-// using clang.
-//
-// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
-// GN toolchain (e.g. ChromeOS) and not provide them.
-
-// 11 64-bit registers = 11 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 11,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 8, "Mismatch in word size");
-
-asm(".text \n"
- ".global SaveCalleeSavedRegisters \n"
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
- // $a0: [ intptr_t* buffer ]
- // Save the callee-saved registers.
- " st.d $s8, $a0, 0 \n"
- " st.d $sp, $a0, 8 \n"
- " st.d $fp, $a0, 16 \n"
- " st.d $s7, $a0, 24 \n"
- " st.d $s6, $a0, 32 \n"
- " st.d $s5, $a0, 40 \n"
- " st.d $s4, $a0, 48 \n"
- " st.d $s3, $a0, 56 \n"
- " st.d $s2, $a0, 64 \n"
- " st.d $s1, $a0, 72 \n"
- " st.d $s0, $a0, 80 \n"
- // Return.
- " jirl $zero, $ra, 0 \n");
diff --git a/src/heap/base/asm/mips64/push_registers_asm.cc b/src/heap/base/asm/mips64/push_registers_asm.cc
new file mode 100644
index 0000000..47779e0
--- /dev/null
+++ b/v8/src/heap/base/asm/mips64/push_registers_asm.cc
@@ -0,0 +1,49 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Push all callee-saved registers to get them on the stack for conservative
+// stack scanning.
+//
+// See asm/x64/push_registers_clang.cc for why the function is not generated
+// using clang.
+//
+// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
+// GN toolchain (e.g. ChromeOS) and not provide them.
+asm(".text \n"
+ ".set noreorder \n"
+ ".global PushAllRegistersAndIterateStack \n"
+ ".type PushAllRegistersAndIterateStack, %function \n"
+ ".hidden PushAllRegistersAndIterateStack \n"
+ "PushAllRegistersAndIterateStack: \n"
+ // Push all callee-saved registers and save return address.
+ " daddiu $sp, $sp, -96 \n"
+ " sd $ra, 88($sp) \n"
+ " sd $s8, 80($sp) \n"
+ " sd $sp, 72($sp) \n"
+ " sd $gp, 64($sp) \n"
+ " sd $s7, 56($sp) \n"
+ " sd $s6, 48($sp) \n"
+ " sd $s5, 40($sp) \n"
+ " sd $s4, 32($sp) \n"
+ " sd $s3, 24($sp) \n"
+ " sd $s2, 16($sp) \n"
+ " sd $s1, 8($sp) \n"
+ " sd $s0, 0($sp) \n"
+ // Maintain frame pointer.
+ " move $s8, $sp \n"
+ // Pass 1st parameter (a0) unchanged (Stack*).
+ // Pass 2nd parameter (a1) unchanged (StackVisitor*).
+ // Save 3rd parameter (a2; IterateStackCallback).
+ " move $a3, $a2 \n"
+ // Call the callback.
+ " jalr $a3 \n"
+ // Delay slot: Pass 3rd parameter as sp (stack pointer).
+ " move $a2, $sp \n"
+ // Load return address.
+ " ld $ra, 88($sp) \n"
+ // Restore frame pointer.
+ " ld $s8, 80($sp) \n"
+ " jr $ra \n"
+ // Delay slot: Discard all callee-saved registers.
+ " daddiu $sp, $sp, 96 \n");
diff --git a/src/heap/base/asm/mips64/save_registers_asm.cc b/src/heap/base/asm/mips64/save_registers_asm.cc
deleted file mode 100644
index 95bcc31..0000000
--- a/v8/src/heap/base/asm/mips64/save_registers_asm.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2020 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <src/heap/base/stack.h>
-
-// Save all callee-saved registers in the specified buffer.
-// extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-
-// See asm/x64/save_registers_asm.cc for why the function is not generated
-// using clang.
-//
-// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
-// GN toolchain (e.g. ChromeOS) and not provide them.
-
-// 9 64-bit registers = 9 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 9,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 8, "Mismatch in word size");
-
-asm(".text \n"
- ".set noreorder \n"
- ".global SaveCalleeSavedRegisters \n"
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
- // $a0: [ intptr_t* buffer ]
- // Save the callee-saved registers.
- " sd $gp, 64($a0) \n"
- " sd $s7, 56($a0) \n"
- " sd $s6, 48($a0) \n"
- " sd $s5, 40($a0) \n"
- " sd $s4, 32($a0) \n"
- " sd $s3, 24($a0) \n"
- " sd $s2, 16($a0) \n"
- " sd $s1, 8($a0) \n"
- // ... one more in the delay slot!
- // Return.
- " jr $ra \n"
- // Delay slot:
- " sd $s0, 0($a0) \n");
diff --git a/src/heap/base/asm/ppc/push_registers_asm.cc b/src/heap/base/asm/ppc/push_registers_asm.cc
new file mode 100644
index 0000000..f879980
--- /dev/null
+++ b/v8/src/heap/base/asm/ppc/push_registers_asm.cc
@@ -0,0 +1,97 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Push all callee-saved registers to get them on the stack for conservative
+// stack scanning.
+//
+// See asm/x64/push_registers_clang.cc for why the function is not generated
+// using clang.
+
+// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
+// GN toolchain (e.g. ChromeOS) and not provide them.
+
+// PPC ABI source:
+// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html
+
+// AIX Runtime process stack:
+// https://www.ibm.com/support/knowledgecenter/ssw_aix_71/assembler/idalangref_runtime_process.html
+asm(
+#if defined(_AIX)
+ ".csect .text[PR] \n"
+ ".align 2 \n"
+ ".globl .PushAllRegistersAndIterateStack, hidden \n"
+ ".PushAllRegistersAndIterateStack: \n"
+#else
+ ".text \n"
+ ".align 2 \n"
+ ".globl PushAllRegistersAndIterateStack \n"
+ ".type PushAllRegistersAndIterateStack, %function \n"
+ ".hidden PushAllRegistersAndIterateStack \n"
+ "PushAllRegistersAndIterateStack: \n"
+#endif
+ // Push all callee-saved registers.
+ // lr, TOC pointer, r16 to r31. 160 bytes.
+ // The parameter save area shall be allocated by the caller. 112 bytes.
+ // At anytime, SP (r1) needs to be multiple of 16 (i.e. 16-aligned).
+ " mflr 0 \n"
+ " std 0, 16(1) \n"
+#if defined(_AIX)
+ " std 2, 40(1) \n"
+#else
+ " std 2, 24(1) \n"
+#endif
+ " stdu 1, -256(1) \n"
+ " std 14, 112(1) \n"
+ " std 15, 120(1) \n"
+ " std 16, 128(1) \n"
+ " std 17, 136(1) \n"
+ " std 18, 144(1) \n"
+ " std 19, 152(1) \n"
+ " std 20, 160(1) \n"
+ " std 21, 168(1) \n"
+ " std 22, 176(1) \n"
+ " std 23, 184(1) \n"
+ " std 24, 192(1) \n"
+ " std 25, 200(1) \n"
+ " std 26, 208(1) \n"
+ " std 27, 216(1) \n"
+ " std 28, 224(1) \n"
+ " std 29, 232(1) \n"
+ " std 30, 240(1) \n"
+ " std 31, 248(1) \n"
+ // Pass 1st parameter (r3) unchanged (Stack*).
+ // Pass 2nd parameter (r4) unchanged (StackVisitor*).
+ // Save 3rd parameter (r5; IterateStackCallback).
+ " mr 6, 5 \n"
+#if defined(_AIX)
+ // Set up TOC for callee.
+ " ld 2,8(5) \n"
+ // AIX uses function descriptors, which means that
+ // pointers to functions do not point to code, but
+ // instead point to metadata about them, hence
+ // need to deterrence.
+ " ld 6,0(6) \n"
+#endif
+ // Pass 3rd parameter as sp (stack pointer).
+ " mr 5, 1 \n"
+#if !defined(_AIX)
+ // Set up r12 to be equal to the callee address (in order for TOC
+ // relocation). Only needed on LE Linux.
+ " mr 12, 6 \n"
+#endif
+ // Call the callback.
+ " mtctr 6 \n"
+ " bctrl \n"
+ // Discard all the registers.
+ " addi 1, 1, 256 \n"
+ // Restore lr.
+ " ld 0, 16(1) \n"
+ " mtlr 0 \n"
+#if defined(_AIX)
+ // Restore TOC pointer.
+ " ld 2, 40(1) \n"
+#else
+ " ld 2, 24(1) \n"
+#endif
+ " blr \n");
diff --git a/src/heap/base/asm/ppc/save_registers_asm.cc b/src/heap/base/asm/ppc/save_registers_asm.cc
deleted file mode 100644
index 9e8102a..0000000
--- a/v8/src/heap/base/asm/ppc/save_registers_asm.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2020 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <src/heap/base/stack.h>
-
-// Save all callee-saved registers in the specified buffer.
-// extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-
-// See asm/x64/save_registers_asm.cc for why the function is not generated
-// using clang.
-//
-// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
-// GN toolchain (e.g. ChromeOS) and not provide them.
-//
-// PPC ABI source:
-// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html
-
-// AIX Runtime process stack:
-// https://www.ibm.com/support/knowledgecenter/ssw_aix_71/assembler/idalangref_runtime_process.html
-
-#ifdef __PPC64__
-
-// 20 64-bit registers = 20 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 20,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 8, "Mismatch in word size");
-
-asm(
-#if defined(_AIX)
- ".csect .text[PR] \n"
- ".align 2 \n"
- ".globl .SaveCalleeSavedRegisters, hidden \n"
- ".SaveCalleeSavedRegisters: \n"
-#else
- ".text \n"
- ".align 2 \n"
- ".globl SaveCalleeSavedRegisters \n"
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
-#endif
- // r3: [ intptr_t* buffer ]
- // Save the callee-saved registers: lr, TOC pointer (r2), r14-r31.
- " mflr 0 \n"
- " std 0, 8(3) \n"
- " std 2, 16(3) \n"
- " std 14, 24(3) \n"
- " std 15, 32(3) \n"
- " std 16, 40(3) \n"
- " std 17, 48(3) \n"
- " std 18, 56(3) \n"
- " std 19, 64(3) \n"
- " std 20, 72(3) \n"
- " std 21, 80(3) \n"
- " std 22, 88(3) \n"
- " std 23, 96(3) \n"
- " std 24, 104(3) \n"
- " std 25, 112(3) \n"
- " std 26, 120(3) \n"
- " std 27, 128(3) \n"
- " std 28, 136(3) \n"
- " std 29, 144(3) \n"
- " std 30, 152(3) \n"
- " std 31, 160(3) \n"
- // Return.
- " blr \n");
-
-#else // !__PPC64__
-
-// 20 32-bit registers = 20 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 20,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 4, "Mismatch in word size");
-
-asm(
-#if defined(_AIX)
- ".globl .SaveCalleeSavedRegisters, hidden \n"
- ".csect .text[PR] \n"
- ".SaveCalleeSavedRegisters: \n"
-#else
- ".globl SaveCalleeSavedRegisters \n"
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
-#endif
- // r3: [ intptr_t* buffer ]
- // Save the callee-saved registers: lr, TOC pointer (r2), r14-r31.
- " mflr 0 \n"
- " st 0, 4(3) \n"
- " st 2, 8(3) \n"
- " st 14, 12(3) \n"
- " st 15, 16(3) \n"
- " st 16, 20(3) \n"
- " st 17, 24(3) \n"
- " st 18, 28(3) \n"
- " st 19, 32(3) \n"
- " st 20, 36(3) \n"
- " st 21, 40(3) \n"
- " st 22, 44(3) \n"
- " st 23, 48(3) \n"
- " st 24, 52(3) \n"
- " st 25, 56(3) \n"
- " st 26, 60(3) \n"
- " st 27, 64(3) \n"
- " st 28, 68(3) \n"
- " st 29, 72(3) \n"
- " st 30, 76(3) \n"
- " st 31, 80(3) \n"
- // Return.
- " blr \n");
-
-#endif // __PPC64__
diff --git a/src/heap/base/asm/riscv/push_registers_asm.cc b/src/heap/base/asm/riscv/push_registers_asm.cc
new file mode 100644
index 0000000..7cc13ea
--- /dev/null
+++ b/v8/src/heap/base/asm/riscv/push_registers_asm.cc
@@ -0,0 +1,93 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Push all callee-saved registers to get them on the stack for conservative
+// stack scanning.
+//
+// See asm/x64/push_registers_asm.cc for why the function is not generated
+// using clang.
+//
+// Calling convention source:
+// https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf Table 18.2
+#ifdef V8_TARGET_ARCH_RISCV64
+asm(".global PushAllRegistersAndIterateStack \n"
+ ".type PushAllRegistersAndIterateStack, %function \n"
+ ".hidden PushAllRegistersAndIterateStack \n"
+ "PushAllRegistersAndIterateStack: \n"
+ // Push all callee-saved registers and save return address.
+ " addi sp, sp, -112 \n"
+ // Save return address.
+ " sd ra, 104(sp) \n"
+ // sp is callee-saved.
+ " sd sp, 96(sp) \n"
+ // s0-s11 are callee-saved.
+ " sd s11, 88(sp) \n"
+ " sd s10, 80(sp) \n"
+ " sd s9, 72(sp) \n"
+ " sd s8, 64(sp) \n"
+ " sd s7, 56(sp) \n"
+ " sd s6, 48(sp) \n"
+ " sd s5, 40(sp) \n"
+ " sd s4, 32(sp) \n"
+ " sd s3, 24(sp) \n"
+ " sd s2, 16(sp) \n"
+ " sd s1, 8(sp) \n"
+ " sd s0, 0(sp) \n"
+ // Maintain frame pointer(fp is s0).
+ " mv s0, sp \n"
+ // Pass 1st parameter (a0) unchanged (Stack*).
+ // Pass 2nd parameter (a1) unchanged (StackVisitor*).
+ // Save 3rd parameter (a2; IterateStackCallback) to a3.
+ " mv a3, a2 \n"
+ // Pass 3rd parameter as sp (stack pointer).
+ " mv a2, sp \n"
+ // Call the callback.
+ " jalr a3 \n"
+ // Load return address.
+ " ld ra, 104(sp) \n"
+ // Restore frame pointer.
+ " ld s0, 0(sp) \n"
+ " addi sp, sp, 112 \n"
+ " jr ra \n");
+#elif V8_TARGET_ARCH_RISCV32
+asm(".global PushAllRegistersAndIterateStack \n"
+ ".type PushAllRegistersAndIterateStack, %function \n"
+ ".hidden PushAllRegistersAndIterateStack \n"
+ "PushAllRegistersAndIterateStack: \n"
+ // Push all callee-saved registers and save return address.
+ " addi sp, sp, -56 \n"
+ // Save return address.
+ " sw ra, 52(sp) \n"
+ // sp is callee-saved.
+ " sw sp, 48(sp) \n"
+ // s0-s11 are callee-saved.
+ " sw s11, 44(sp) \n"
+ " sw s10, 40(sp) \n"
+ " sw s9, 36(sp) \n"
+ " sw s8, 32(sp) \n"
+ " sw s7, 28(sp) \n"
+ " sw s6, 24(sp) \n"
+ " sw s5, 20(sp) \n"
+ " sw s4, 16(sp) \n"
+ " sw s3, 12(sp) \n"
+ " sw s2, 8(sp) \n"
+ " sw s1, 4(sp) \n"
+ " sw s0, 0(sp) \n"
+ // Maintain frame pointer(fp is s0).
+ " mv s0, sp \n"
+ // Pass 1st parameter (a0) unchanged (Stack*).
+ // Pass 2nd parameter (a1) unchanged (StackVisitor*).
+ // Save 3rd parameter (a2; IterateStackCallback) to a3.
+ " mv a3, a2 \n"
+ // Pass 3rd parameter as sp (stack pointer).
+ " mv a2, sp \n"
+ // Call the callback.
+ " jalr a3 \n"
+ // Load return address.
+ " lw ra, 52(sp) \n"
+ // Restore frame pointer.
+ " lw s0, 0(sp) \n"
+ " addi sp, sp, 56 \n"
+ " jr ra \n");
+#endif
diff --git a/src/heap/base/asm/riscv/save_registers_asm.cc b/src/heap/base/asm/riscv/save_registers_asm.cc
deleted file mode 100644
index ad0bf98..0000000
--- a/v8/src/heap/base/asm/riscv/save_registers_asm.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2020 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <src/heap/base/stack.h>
-
-// Save all callee-saved registers in the specified buffer.
-// extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-
-// See asm/x64/save_registers_asm.cc for why the function is not generated
-// using clang.
-//
-// Calling convention source:
-// https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf Table 18.2
-
-#if V8_HOST_ARCH_RISCV64
-// 12 64-bit registers = 12 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 12,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 8, "Mismatch in word size");
-
-asm(".global SaveCalleeSavedRegisters \n"
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
- // a0: [ intptr_t* buffer ]
- // Save the callee-saved registers: s0-s11.
- " sd s11, 88(a0) \n"
- " sd s10, 80(a0) \n"
- " sd s9, 72(a0) \n"
- " sd s8, 64(a0) \n"
- " sd s7, 56(a0) \n"
- " sd s6, 48(a0) \n"
- " sd s5, 40(a0) \n"
- " sd s4, 32(a0) \n"
- " sd s3, 24(a0) \n"
- " sd s2, 16(a0) \n"
- " sd s1, 8(a0) \n"
- " sd s0, 0(a0) \n"
- // Return.
- " jr ra \n");
-#elif V8_HOST_ARCH_RISCV32
-// 12 32-bit registers = 12 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 12,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 4, "Mismatch in word size");
-
-asm(".global SaveCalleeSavedRegisters \n"
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
- // a0: [ intptr_t* buffer ]
- // Save the callee-saved registers: s0-s11.
- " sw s11, 44(a0) \n"
- " sw s10, 40(a0) \n"
- " sw s9, 36(a0) \n"
- " sw s8, 32(a0) \n"
- " sw s7, 28(a0) \n"
- " sw s6, 24(a0) \n"
- " sw s5, 20(a0) \n"
- " sw s4, 16(a0) \n"
- " sw s3, 12(a0) \n"
- " sw s2, 8(a0) \n"
- " sw s1, 4(a0) \n"
- " sw s0, 0(a0) \n"
- // Return.
- " jr ra \n");
-#endif
diff --git a/src/heap/base/asm/s390/push_registers_asm.cc b/src/heap/base/asm/s390/push_registers_asm.cc
new file mode 100644
index 0000000..ef954fa
--- /dev/null
+++ b/v8/src/heap/base/asm/s390/push_registers_asm.cc
@@ -0,0 +1,37 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Push all callee-saved registers to get them on the stack for conservative
+// stack scanning.
+
+// See asm/x64/push_registers_clang.cc for why the function is not generated
+// using clang.
+
+// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
+// GN toolchain (e.g. ChromeOS) and not provide them.
+
+// S390 ABI source:
+// http://refspecs.linuxbase.org/ELF/zSeries/lzsabi0_zSeries.html
+asm(".text \n"
+ ".align 8 \n"
+ ".globl PushAllRegistersAndIterateStack \n"
+ ".type PushAllRegistersAndIterateStack, %function \n"
+ ".hidden PushAllRegistersAndIterateStack \n"
+ "PushAllRegistersAndIterateStack: \n"
+ // Push all callee-saved registers.
+ // r6-r13, r14 and sp(r15)
+ " stmg %r6, %sp, 48(%sp) \n"
+ // Allocate frame.
+ " lay %sp, -160(%sp) \n"
+ // Pass 1st parameter (r2) unchanged (Stack*).
+ // Pass 2nd parameter (r3) unchanged (StackVisitor*).
+ // Save 3rd parameter (r4; IterateStackCallback).
+ " lgr %r5, %r4 \n"
+ // Pass sp as 3rd parameter. 160+48 to point
+ // to callee saved region stored above.
+ " lay %r4, 208(%sp) \n"
+ // Call the callback.
+ " basr %r14, %r5 \n"
+ " lmg %r14,%sp, 272(%sp) \n"
+ " br %r14 \n");
diff --git a/src/heap/base/asm/s390/save_registers_asm.cc b/src/heap/base/asm/s390/save_registers_asm.cc
deleted file mode 100644
index be92cc2..0000000
--- a/v8/src/heap/base/asm/s390/save_registers_asm.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2020 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <src/heap/base/stack.h>
-
-// Save all callee-saved registers in the specified buffer.
-// extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-
-// See asm/x64/save_registers_asm.cc for why the function is not generated
-// using clang.
-//
-// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
-// GN toolchain (e.g. ChromeOS) and not provide them.
-
-// S390 ABI source:
-// http://refspecs.linuxbase.org/ELF/zSeries/lzsabi0_zSeries.html
-
-// 10 64-bit registers = 10 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 10,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 8, "Mismatch in word size");
-
-asm(".text \n"
- ".align 8 \n"
- ".globl SaveCalleeSavedRegisters \n"
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
- // r2: [ intptr_t* buffer ]
- // Save the callee-saved registers: r6-r13, r14 and sp(r15).
- " stmg %r6, %sp, 0(%r2) \n"
- // Return.
- " br %r14 \n");
diff --git a/src/heap/base/asm/x64/push_registers_asm.cc b/src/heap/base/asm/x64/push_registers_asm.cc
new file mode 100644
index 0000000..1781a58
--- /dev/null
+++ b/v8/src/heap/base/asm/x64/push_registers_asm.cc
@@ -0,0 +1,106 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Push all callee-saved registers to get them on the stack for conservative
+// stack scanning.
+//
+// We cannot rely on clang generating the function and right symbol mangling
+// as `__attribute__((naked))` does not prevent clang from generating TSAN
+// function entry stubs (`__tsan_func_entry`). Even with
+// `__attribute__((no_sanitize_thread)` annotation clang generates the entry
+// stub.
+// See https://bugs.llvm.org/show_bug.cgi?id=45400.
+
+// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
+// GN toolchain (e.g. ChromeOS) and not provide them.
+// _WIN64 Defined as 1 when the compilation target is 64-bit ARM or x64.
+// Otherwise, undefined.
+#ifdef _WIN64
+
+// We maintain 16-byte alignment at calls. There is an 8-byte return address
+// on the stack and we push 232 bytes which maintains 16-byte stack alignment
+// at the call.
+// Source: https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
+asm(".globl PushAllRegistersAndIterateStack \n"
+ "PushAllRegistersAndIterateStack: \n"
+ // rbp is callee-saved. Maintain proper frame pointer for debugging.
+ " push %rbp \n"
+ " mov %rsp, %rbp \n"
+ // Dummy for alignment.
+ " push $0xCDCDCD \n"
+ " push %rsi \n"
+ " push %rdi \n"
+ " push %rbx \n"
+ " push %r12 \n"
+ " push %r13 \n"
+ " push %r14 \n"
+ " push %r15 \n"
+ " sub $160, %rsp \n"
+ // Use aligned instrs as we are certain that the stack is properly aligned.
+ " movdqa %xmm6, 144(%rsp) \n"
+ " movdqa %xmm7, 128(%rsp) \n"
+ " movdqa %xmm8, 112(%rsp) \n"
+ " movdqa %xmm9, 96(%rsp) \n"
+ " movdqa %xmm10, 80(%rsp) \n"
+ " movdqa %xmm11, 64(%rsp) \n"
+ " movdqa %xmm12, 48(%rsp) \n"
+ " movdqa %xmm13, 32(%rsp) \n"
+ " movdqa %xmm14, 16(%rsp) \n"
+ " movdqa %xmm15, (%rsp) \n"
+ // Pass 1st parameter (rcx) unchanged (Stack*).
+ // Pass 2nd parameter (rdx) unchanged (StackVisitor*).
+ // Save 3rd parameter (r8; IterateStackCallback)
+ " mov %r8, %r9 \n"
+ // Pass 3rd parameter as rsp (stack pointer).
+ " mov %rsp, %r8 \n"
+ // Call the callback.
+ " call *%r9 \n"
+ // Pop the callee-saved registers.
+ " add $224, %rsp \n"
+ // Restore rbp as it was used as frame pointer.
+ " pop %rbp \n"
+ " ret \n");
+
+#else // !_WIN64
+
+// We maintain 16-byte alignment at calls. There is an 8-byte return address
+// on the stack and we push 56 bytes which maintains 16-byte stack alignment
+// at the call.
+// Source: https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf
+asm(
+#ifdef __APPLE__
+ ".globl _PushAllRegistersAndIterateStack \n"
+ ".private_extern _PushAllRegistersAndIterateStack \n"
+ "_PushAllRegistersAndIterateStack: \n"
+#else // !__APPLE__
+ ".globl PushAllRegistersAndIterateStack \n"
+ ".type PushAllRegistersAndIterateStack, %function \n"
+ ".hidden PushAllRegistersAndIterateStack \n"
+ "PushAllRegistersAndIterateStack: \n"
+#endif // !__APPLE__
+ // rbp is callee-saved. Maintain proper frame pointer for debugging.
+ " push %rbp \n"
+ " mov %rsp, %rbp \n"
+ // Dummy for alignment.
+ " push $0xCDCDCD \n"
+ " push %rbx \n"
+ " push %r12 \n"
+ " push %r13 \n"
+ " push %r14 \n"
+ " push %r15 \n"
+ // Pass 1st parameter (rdi) unchanged (Stack*).
+ // Pass 2nd parameter (rsi) unchanged (StackVisitor*).
+ // Save 3rd parameter (rdx; IterateStackCallback)
+ " mov %rdx, %r8 \n"
+ // Pass 3rd parameter as rsp (stack pointer).
+ " mov %rsp, %rdx \n"
+ // Call the callback.
+ " call *%r8 \n"
+ // Pop the callee-saved registers.
+ " add $48, %rsp \n"
+ // Restore rbp as it was used as frame pointer.
+ " pop %rbp \n"
+ " ret \n");
+
+#endif // !_WIN64
diff --git a/src/heap/base/asm/x64/push_registers_masm.asm b/src/heap/base/asm/x64/push_registers_masm.asm
new file mode 100644
index 0000000..a32e193
--- /dev/null
+++ b/v8/src/heap/base/asm/x64/push_registers_masm.asm
@@ -0,0 +1,57 @@
+;; Copyright 2020 the V8 project authors. All rights reserved.
+;; Use of this source code is governed by a BSD-style license that can be
+;; found in the LICENSE file.
+
+;; MASM syntax
+;; https://docs.microsoft.com/en-us/cpp/assembler/masm/microsoft-macro-assembler-reference?view=vs-2019
+
+public PushAllRegistersAndIterateStack
+
+.code
+PushAllRegistersAndIterateStack:
+ ;; Push all callee-saved registers to get them on the stack for conservative
+ ;; stack scanning.
+ ;;
+ ;; We maintain 16-byte alignment at calls. There is an 8-byte return address
+ ;; on the stack and we push 232 bytes which maintains 16-byte stack
+ ;; alignment at the call.
+ ;; Source: https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
+ ;;
+ ;; rbp is callee-saved. Maintain proper frame pointer for debugging.
+ push rbp
+ mov rbp, rsp
+ push 0CDCDCDh ;; Dummy for alignment.
+ push rsi
+ push rdi
+ push rbx
+ push r12
+ push r13
+ push r14
+ push r15
+ sub rsp, 160
+ ;; Use aligned instrs as we are certain that the stack is properly aligned.
+ movdqa xmmword ptr [rsp + 144], xmm6
+ movdqa xmmword ptr [rsp + 128], xmm7
+ movdqa xmmword ptr [rsp + 112], xmm8
+ movdqa xmmword ptr [rsp + 96], xmm9
+ movdqa xmmword ptr [rsp + 80], xmm10
+ movdqa xmmword ptr [rsp + 64], xmm11
+ movdqa xmmword ptr [rsp + 48], xmm12
+ movdqa xmmword ptr [rsp + 32], xmm13
+ movdqa xmmword ptr [rsp + 16], xmm14
+ movdqa xmmword ptr [rsp], xmm15
+ ;; Pass 1st parameter (rcx) unchanged (Stack*).
+ ;; Pass 2nd parameter (rdx) unchanged (StackVisitor*).
+ ;; Save 3rd parameter (r8; IterateStackCallback)
+ mov r9, r8
+ ;; Pass 3rd parameter as rsp (stack pointer).
+ mov r8, rsp
+ ;; Call the callback.
+ call r9
+ ;; Pop the callee-saved registers.
+ add rsp, 224
+ ;; Restore rbp as it was used as frame pointer.
+ pop rbp
+ ret
+
+end
diff --git a/src/heap/base/asm/x64/save_registers_asm.cc b/src/heap/base/asm/x64/save_registers_asm.cc
deleted file mode 100644
index 855a654..0000000
--- a/v8/src/heap/base/asm/x64/save_registers_asm.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2020 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <src/heap/base/stack.h>
-
-// Save all callee-saved registers in the specified buffer.
-// extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-//
-// We cannot rely on clang generating the function and right symbol mangling
-// as `__attribute__((naked))` does not prevent clang from generating TSAN
-// function entry stubs (`__tsan_func_entry`). Even with
-// `__attribute__((no_sanitize_thread)` annotation clang generates the entry
-// stub.
-// See https://bugs.llvm.org/show_bug.cgi?id=45400.
-//
-// Do not depend on V8_TARGET_OS_* defines as some embedders may override the
-// GN toolchain (e.g. ChromeOS) and not provide them.
-// _WIN64 Defined as 1 when the compilation target is 64-bit ARM or x64.
-// Otherwise, undefined.
-
-#ifdef _WIN64
-// Source: https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
-
-// 7 64-bit registers + 1 for alignment purposes = 8 * 1 = 8 intprt_t
-// 10 128-bit registers = 10 * 2 = 20 intptr_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 28,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 8, "Mismatch in word size");
-
-asm(".globl SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
- // %rcx: [ intptr_t* buffer ]
- // %rbp is callee-saved. Maintain proper frame pointer for debugging.
- " push %rbp \n"
- " mov %rsp, %rbp \n"
- // Save the callee-saved registers.
- " mov %rsi, 0(%rcx) \n"
- " mov %rdi, 8(%rcx) \n"
- " mov %rbx, 16(%rcx) \n"
- " mov %r12, 24(%rcx) \n"
- " mov %r13, 32(%rcx) \n"
- " mov %r14, 40(%rcx) \n"
- " mov %r15, 48(%rcx) \n"
- // Skip one slot to achieve proper alignment and use aligned instructions,
- // as we are sure that the buffer is properly aligned.
- " movdqa %xmm6, 64(%rcx) \n"
- " movdqa %xmm7, 80(%rcx) \n"
- " movdqa %xmm8, 96(%rcx) \n"
- " movdqa %xmm9, 112(%rcx) \n"
- " movdqa %xmm10, 128(%rcx) \n"
- " movdqa %xmm11, 144(%rcx) \n"
- " movdqa %xmm12, 160(%rcx) \n"
- " movdqa %xmm13, 176(%rcx) \n"
- " movdqa %xmm14, 192(%rcx) \n"
- " movdqa %xmm15, 208(%rcx) \n"
- // Return.
- " pop %rbp \n"
- " ret \n");
-
-#else // !_WIN64
-// Source: https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf
-
-// 5 64-bit registers = 5 intprt_t
-static_assert(heap::base::Stack::NumberOfCalleeSavedRegisters() == 5,
- "Mismatch in the number of callee-saved registers");
-static_assert(sizeof(intptr_t) == 8, "Mismatch in word size");
-
-asm(
-#ifdef __APPLE__
- ".globl _SaveCalleeSavedRegisters \n"
- ".private_extern _SaveCalleeSavedRegisters \n"
- "_SaveCalleeSavedRegisters: \n"
-#else // !__APPLE__
- ".globl SaveCalleeSavedRegisters \n"
- ".type SaveCalleeSavedRegisters, %function \n"
- ".hidden SaveCalleeSavedRegisters \n"
- "SaveCalleeSavedRegisters: \n"
-#endif // !__APPLE__
- // %rdi: [ intptr_t* buffer ]
- // %rbp is callee-saved. Maintain proper frame pointer for debugging.
- " push %rbp \n"
- " mov %rsp, %rbp \n"
- // Save the callee-saved registers.
- " mov %rbx, 0(%rdi) \n"
- " mov %r12, 8(%rdi) \n"
- " mov %r13, 16(%rdi) \n"
- " mov %r14, 24(%rdi) \n"
- " mov %r15, 32(%rdi) \n"
- // Restore %rbp as it was used as frame pointer and return.
- " pop %rbp \n"
- " ret \n");
-
-#endif // !_WIN64
diff --git a/src/heap/base/asm/x64/save_registers_masm.asm b/src/heap/base/asm/x64/save_registers_masm.asm
deleted file mode 100644
index 29946a4..0000000
--- a/v8/src/heap/base/asm/x64/save_registers_masm.asm
+++ /dev/null
@@ -1,43 +0,0 @@
-;; Copyright 2020 the V8 project authors. All rights reserved.
-;; Use of this source code is governed by a BSD-style license that can be
-;; found in the LICENSE file.
-
-;; MASM syntax
-;; https://docs.microsoft.com/en-us/cpp/assembler/masm/microsoft-macro-assembler-reference?view=vs-2019
-
-public SaveCalleeSavedRegisters
-
-.code
- ;; Save all callee-saved registers in the specified buffer.
- ;; extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
-
-SaveCalleeSavedRegisters:
- ;; %rcx: [ intptr_t* buffer ]
- ;; %rbp is callee-saved. Maintain proper frame pointer for debugging.
- push rbp
- mov rbp, rsp
- ;; Save the callee-saved registers.
- mov qword ptr [rcx], rsi
- mov qword ptr [rcx + 8], rdi
- mov qword ptr [rcx + 16], rbx
- mov qword ptr [rcx + 24], r12
- mov qword ptr [rcx + 32], r13
- mov qword ptr [rcx + 40], r14
- mov qword ptr [rcx + 48], r15
- ;; Skip one slot to achieve proper alignment and use aligned instructions,
- ;; as we are sure that the buffer is properly aligned.
- movdqa xmmword ptr [rcx + 64], xmm6
- movdqa xmmword ptr [rcx + 80], xmm7
- movdqa xmmword ptr [rcx + 96], xmm8
- movdqa xmmword ptr [rcx + 112], xmm9
- movdqa xmmword ptr [rcx + 128], xmm10
- movdqa xmmword ptr [rcx + 144], xmm11
- movdqa xmmword ptr [rcx + 160], xmm12
- movdqa xmmword ptr [rcx + 176], xmm13
- movdqa xmmword ptr [rcx + 192], xmm14
- movdqa xmmword ptr [rcx + 208], xmm15
- ;; Restore %rbp as it was used as frame pointer and return.
- pop rbp
- ret
-
-end
diff --git a/src/heap/base/stack.cc b/src/heap/base/stack.cc
index d8e618d..54a8697 100644
--- a/v8/src/heap/base/stack.cc
+++ b/v8/src/heap/base/stack.cc
@@ -6,18 +6,21 @@
#include <limits>
+#include "src/base/platform/platform.h"
#include "src/base/sanitizer/asan.h"
#include "src/base/sanitizer/msan.h"
#include "src/base/sanitizer/tsan.h"
namespace heap::base {
-Stack::Stack(const void* stack_start) : stack_start_(stack_start) {}
-
-void Stack::SetStackStart(const void* stack_start) {
- DCHECK(!context_);
- 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_);
@@ -141,97 +144,62 @@
} // namespace
-void Stack::IteratePointers(StackVisitor* visitor) const {
- DCHECK_NOT_NULL(stack_start_);
- DCHECK(context_);
- DCHECK_NOT_NULL(context_->stack_marker);
-
+// static
+void Stack::IteratePointersImpl(const Stack* stack, StackVisitor* visitor,
+ const void* stack_end) {
#ifdef V8_USE_ADDRESS_SANITIZER
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 registers.
- for (intptr_t value : context_->registers) {
- const void* address = reinterpret_cast<const void*>(value);
- MSAN_MEMORY_IS_INITIALIZED(&address, sizeof(address));
- if (address == nullptr) continue;
- visitor->VisitPointer(address);
- IterateAsanFakeFrameIfNecessary(visitor, asan_fake_stack, stack_start_,
- context_->stack_marker, address);
- }
-
// Iterate through the stack.
// All supported platforms should have their stack aligned to at least
// sizeof(void*).
constexpr size_t kMinStackAlignment = sizeof(void*);
- CHECK_EQ(0u, reinterpret_cast<uintptr_t>(context_->stack_marker) &
- (kMinStackAlignment - 1));
- IteratePointersInStack(
- visitor, reinterpret_cast<const void* const*>(context_->stack_marker),
- stack_start_, asan_fake_stack);
+ CHECK_EQ(0u,
+ reinterpret_cast<uintptr_t>(stack_end) & (kMinStackAlignment - 1));
+ IteratePointersInStack(visitor,
+ reinterpret_cast<const void* const*>(stack_end),
+ stack->stack_start_, asan_fake_stack);
- for (const auto& stack : inactive_stacks_) {
- IteratePointersInStack(visitor, stack.top, stack.start, asan_fake_stack);
+ for (const auto& segment : stack->inactive_stacks_) {
+ IteratePointersInStack(visitor, segment.top, segment.start,
+ asan_fake_stack);
}
IterateUnsafeStackIfNecessary(visitor);
}
-namespace {
-// Function with architecture-specific implementation:
-// Saves all callee-saved registers in the specified buffer.
-extern "C" void SaveCalleeSavedRegisters(intptr_t* buffer);
+void Stack::IteratePointers(StackVisitor* visitor) const {
+ // 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 {
+ DCHECK_NOT_NULL(stack_start_);
+ DCHECK_NOT_NULL(stack_end);
+ DCHECK_GE(stack_start_, stack_end);
+ IteratePointersImpl(this, visitor, stack_end);
+}
#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;
}
-
#endif // DEBUG
-} // namespace
-
-void Stack::SaveContext(bool check_invariant) {
- // TODO(v8:13493): Remove the method's parameter and the implication as soon
- // as IsOnCurrentStack is compatible with stack switching.
- DCHECK_IMPLIES(check_invariant, IsOnCurrentStack(stack_start_));
- // Contexts can be nested but the marker and the registers are only saved on
- // the first invocation.
- if (context_) {
- ++context_->nesting_counter;
- return;
- }
- // Allocate the context and set the marker.
- const void* stack_top = v8::base::Stack::GetCurrentStackPosition();
- DCHECK_NOT_NULL(stack_top);
- context_ = std::make_unique<Context>(stack_top);
- // TODO(v8:13493): Remove the implication as soon as IsValidMarker is
- // compatible with stack switching.
- DCHECK_IMPLIES(check_invariant, stack_top <= stack_start_);
- context_->stack_marker = stack_top;
- // Save the registers.
- SaveCalleeSavedRegisters(context_->registers.data());
-}
-
-void Stack::ClearContext(bool check_invariant) {
- // TODO(v8:13493): Remove the method's parameter and the implication as soon
- // as IsOnCurrentStack is compatible with stack switching.
- DCHECK_IMPLIES(check_invariant, IsOnCurrentStack(stack_start_));
- DCHECK(context_);
- // Skip clearing the context if that was a nested invocation.
- if (context_->nesting_counter > 0) {
- --context_->nesting_counter;
- return;
- }
- context_.reset();
-}
-
void Stack::AddStackSegment(const void* start, const void* top) {
DCHECK_LE(top, start);
inactive_stacks_.push_back({start, top});
diff --git a/src/heap/base/stack.h b/src/heap/base/stack.h
index 06edf4c..4b0a14e 100644
--- a/v8/src/heap/base/stack.h
+++ b/v8/src/heap/base/stack.h
@@ -5,10 +5,9 @@
#ifndef V8_HEAP_BASE_STACK_H_
#define V8_HEAP_BASE_STACK_H_
-#include <memory>
+#include <vector>
#include "src/base/macros.h"
-#include "src/base/platform/platform.h"
namespace heap::base {
@@ -30,96 +29,54 @@
// of relevant GC stack regions where interesting pointers can be found.
class V8_EXPORT_PRIVATE Stack final {
public:
- // The size of the buffer for storing the callee-saved registers is going to
- // be equal to kNumberOfCalleeSavedRegisters * sizeof(intptr_t).
- // This is architecture-specific.
- static constexpr int NumberOfCalleeSavedRegisters() {
- return Context::kNumberOfCalleeSavedRegisters;
- }
-
- explicit Stack(const void* stack_start = nullptr);
+ explicit Stack(const void* stack_start = nullptr,
+ bool wasm_stack_switching = false)
+ : stack_start_(stack_start),
+ wasm_stack_switching_(wasm_stack_switching) {}
// Sets the start of the stack.
- void SetStackStart(const void* stack_start);
+ void SetStackStart(const void* stack_start, bool wasm_stack_switching) {
+ stack_start_ = stack_start;
+ wasm_stack_switching_ = wasm_stack_switching;
+ }
// Returns true if |slot| is part of the stack and false otherwise.
bool IsOnStack(const void* slot) const;
- // Word-aligned iteration of the stack and the saved registers.
- // Slot values are passed on to `visitor`.
+ // Word-aligned iteration of the stack. Callee-saved registers are pushed to
+ // the stack before iterating pointers. Slot values are passed on to
+ // `visitor`.
void IteratePointers(StackVisitor* visitor) const;
- // Saves and clears the stack context, i.e., it sets the stack marker and
- // saves the registers.
- // TODO(v8:13493): The parameter is for suppressing the invariant check in
- // the case of WASM stack switching. It will be removed as soon as context
- // saving becomes compatible with stack switching.
- void SaveContext(bool check_invariant = true);
- void ClearContext(bool check_invariant = true);
+ // Word-aligned iteration of the stack, starting at `stack_end`. Slot values
+ // are passed on to `visitor`. This is intended to be used with verifiers that
+ // only visit a subset of the stack of IteratePointers().
+ //
+ // **Ignores:**
+ // - Callee-saved registers.
+ // - SafeStack.
+ void IteratePointersUnsafe(StackVisitor* visitor,
+ const void* stack_end) const;
void AddStackSegment(const void* start, const void* top);
void ClearStackSegments();
private:
- struct Context {
- // The following constant is architecture-specific.
-#if V8_HOST_ARCH_IA32
- // Must be consistent with heap/base/asm/ia32/.
- static constexpr int kNumberOfCalleeSavedRegisters = 3;
-#elif V8_HOST_ARCH_X64
-#ifdef _WIN64
- // Must be consistent with heap/base/asm/x64/.
- static constexpr int kNumberOfCalleeSavedRegisters = 28;
-#else // !_WIN64
- // Must be consistent with heap/base/asm/x64/.
- static constexpr int kNumberOfCalleeSavedRegisters = 5;
-#endif // !_WIN64
-#elif V8_HOST_ARCH_ARM64
- // Must be consistent with heap/base/asm/arm64/.
- static constexpr int kNumberOfCalleeSavedRegisters = 11;
-#elif V8_HOST_ARCH_ARM
- // Must be consistent with heap/base/asm/arm/.
- static constexpr int kNumberOfCalleeSavedRegisters = 8;
-#elif V8_HOST_ARCH_PPC64
- // Must be consistent with heap/base/asm/ppc/.
- static constexpr int kNumberOfCalleeSavedRegisters = 20;
-#elif V8_HOST_ARCH_PPC
- // Must be consistent with heap/base/asm/ppc/.
- static constexpr int kNumberOfCalleeSavedRegisters = 20;
-#elif V8_HOST_ARCH_MIPS64
- // Must be consistent with heap/base/asm/mips64el/.
- static constexpr int kNumberOfCalleeSavedRegisters = 9;
-#elif V8_HOST_ARCH_LOONG64
- // Must be consistent with heap/base/asm/loong64/.
- static constexpr int kNumberOfCalleeSavedRegisters = 11;
-#elif V8_HOST_ARCH_S390
- // Must be consistent with heap/base/asm/s390/.
- static constexpr int kNumberOfCalleeSavedRegisters = 10;
-#elif V8_HOST_ARCH_RISCV32
- // Must be consistent with heap/base/asm/riscv/.
- static constexpr int kNumberOfCalleeSavedRegisters = 12;
-#elif V8_HOST_ARCH_RISCV64
- // Must be consistent with heap/base/asm/riscv/.
- static constexpr int kNumberOfCalleeSavedRegisters = 12;
-#else
-#error Unknown architecture.
+#ifdef DEBUG
+ static bool IsOnCurrentStack(const void* ptr);
#endif
- explicit Context(const void* marker) : stack_marker(marker) {}
-
- int nesting_counter = 0;
- const void* stack_marker;
- // We always double-align this buffer, to support for longer registers,
- // e.g., 128-bit registers in WIN64.
- alignas(2 * sizeof(intptr_t))
- std::array<intptr_t, kNumberOfCalleeSavedRegisters> registers;
- };
+ static void IteratePointersImpl(const Stack* stack, StackVisitor* visitor,
+ const void* stack_end);
const void* stack_start_;
- std::unique_ptr<Context> context_;
- // Stack segments that may also contain pointers and should be
- // scanned.
+ // TODO(v8:13493): This is for suppressing the check that we are in the
+ // correct stack, in the case of WASM stack switching. It will be removed as
+ // soon as context saving becomes compatible with stack switching.
+ bool wasm_stack_switching_;
+
+ // Stack segments that may also contain pointers and should be scanned.
struct StackSegments {
const void* start;
const void* top;
diff --git a/src/heap/cppgc-js/cpp-heap.cc b/src/heap/cppgc-js/cpp-heap.cc
index c27c612..63c5212 100644
--- a/v8/src/heap/cppgc-js/cpp-heap.cc
+++ b/v8/src/heap/cppgc-js/cpp-heap.cc
@@ -16,6 +16,7 @@
#include "src/base/logging.h"
#include "src/base/macros.h"
#include "src/base/optional.h"
+#include "src/base/platform/platform.h"
#include "src/base/platform/time.h"
#include "src/execution/isolate-inl.h"
#include "src/flags/flags.h"
@@ -839,7 +840,7 @@
const size_t bytes_allocated_in_prefinalizers = ExecutePreFinalizers();
#if CPPGC_VERIFY_HEAP
UnifiedHeapMarkingVerifier verifier(*this, *collection_type_);
- verifier.Run(stack_state_of_prev_gc(),
+ verifier.Run(stack_state_of_prev_gc(), stack_end_of_current_gc(),
stats_collector()->marked_bytes_on_current_cycle() +
bytes_allocated_in_prefinalizers);
#endif // CPPGC_VERIFY_HEAP
@@ -942,7 +943,7 @@
// Finish sweeping in case it is still running.
sweeper().FinishIfRunning();
- SaveStackContextScope stack_context_scope(stack());
+ SetStackEndOfCurrentGC(v8::base::Stack::GetCurrentStackPosition());
if (isolate_) {
reinterpret_cast<v8::Isolate*>(isolate_)
diff --git a/src/heap/cppgc/heap-base.h b/src/heap/cppgc/heap-base.h
index ac1dd3f..29a88b2 100644
--- a/v8/src/heap/cppgc/heap-base.h
+++ b/v8/src/heap/cppgc/heap-base.h
@@ -183,6 +183,13 @@
stack_state_of_prev_gc_ = stack_state;
}
+ const void* stack_end_of_current_gc() const {
+ return stack_end_of_current_gc_;
+ }
+ void SetStackEndOfCurrentGC(const void* stack_end) {
+ stack_end_of_current_gc_ = stack_end;
+ }
+
void SetInAtomicPauseForTesting(bool value) { in_atomic_pause_ = value; }
virtual void StartIncrementalGarbageCollectionForTesting() = 0;
@@ -288,6 +295,10 @@
EmbedderStackState::kNoHeapPointers;
std::unique_ptr<EmbedderStackState> override_stack_state_;
+ // Marker that signals end of the interesting stack region in which on-heap
+ // pointers can be found.
+ const void* stack_end_of_current_gc_ = nullptr;
+
bool in_atomic_pause_ = false;
int creation_thread_id_ = v8::base::OS::GetCurrentThreadId();
diff --git a/src/heap/cppgc/heap.cc b/src/heap/cppgc/heap.cc
index 7769412..28a11fc 100644
--- a/v8/src/heap/cppgc/heap.cc
+++ b/v8/src/heap/cppgc/heap.cc
@@ -166,10 +166,9 @@
DCHECK(!in_no_gc_scope());
CHECK(!in_disallow_gc_scope());
config_.stack_state = stack_state;
+ SetStackEndOfCurrentGC(v8::base::Stack::GetCurrentStackPosition());
in_atomic_pause_ = true;
- stack()->SaveContext();
-
#if defined(CPPGC_YOUNG_GENERATION)
// Check if the young generation was enabled. We must enable young generation
// before calling the custom weak callbacks to make sure that the callbacks
@@ -188,7 +187,7 @@
const size_t bytes_allocated_in_prefinalizers = ExecutePreFinalizers();
#if CPPGC_VERIFY_HEAP
MarkingVerifier verifier(*this, config_.collection_type);
- verifier.Run(config_.stack_state,
+ verifier.Run(config_.stack_state, stack_end_of_current_gc(),
stats_collector()->marked_bytes_on_current_cycle() +
bytes_allocated_in_prefinalizers);
#endif // CPPGC_VERIFY_HEAP
@@ -197,8 +196,6 @@
#endif
USE(bytes_allocated_in_prefinalizers);
- stack()->ClearContext();
-
#if defined(CPPGC_YOUNG_GENERATION)
ResetRememberedSet();
#endif // defined(CPPGC_YOUNG_GENERATION)
diff --git a/src/heap/cppgc/marking-verifier.cc b/src/heap/cppgc/marking-verifier.cc
index 5508766..b7127c2 100644
--- a/v8/src/heap/cppgc/marking-verifier.cc
+++ b/v8/src/heap/cppgc/marking-verifier.cc
@@ -45,7 +45,8 @@
collection_type_(collection_type) {}
void MarkingVerifierBase::Run(
- StackState stack_state, v8::base::Optional<size_t> expected_marked_bytes) {
+ StackState stack_state, const void* stack_end,
+ v8::base::Optional<size_t> expected_marked_bytes) {
Traverse(heap_.raw_heap());
// Avoid verifying the stack when running with TSAN as the TSAN runtime changes
// stack contents when e.g. working with locks. Specifically, the marker uses
@@ -62,7 +63,7 @@
#if !defined(THREAD_SANITIZER) && !defined(CPPGC_POINTER_COMPRESSION)
if (stack_state == StackState::kMayContainHeapPointers) {
in_construction_objects_ = &in_construction_objects_stack_;
- heap_.stack()->IteratePointers(this);
+ heap_.stack()->IteratePointersUnsafe(this, stack_end);
// The objects found through the unsafe iteration are only a subset of the
// regular iteration as they miss objects held alive only from callee-saved
// registers that are never pushed on the stack and SafeStack.
diff --git a/src/heap/cppgc/marking-verifier.h b/src/heap/cppgc/marking-verifier.h
index 5132b3a..5136f29 100644
--- a/v8/src/heap/cppgc/marking-verifier.h
+++ b/v8/src/heap/cppgc/marking-verifier.h
@@ -41,7 +41,7 @@
MarkingVerifierBase(const MarkingVerifierBase&) = delete;
MarkingVerifierBase& operator=(const MarkingVerifierBase&) = delete;
- void Run(StackState, v8::base::Optional<size_t>);
+ void Run(StackState, const void*, v8::base::Optional<size_t>);
protected:
MarkingVerifierBase(HeapBase&, CollectionType, VerificationState&,
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
index 4994a3a..f4b7da0 100644
--- a/v8/src/heap/heap.cc
+++ b/v8/src/heap/heap.cc
@@ -1685,7 +1685,22 @@
DevToolsTraceEventScope devtools_trace_event_scope(
this, IsYoungGenerationCollector(collector) ? "MinorGC" : "MajorGC",
GarbageCollectionReasonToString(gc_reason));
- SaveStackContextScope stack_context_scope(&stack());
+
+ if (cpp_heap()) {
+ if (collector == GarbageCollector::MARK_COMPACTOR ||
+ (collector == GarbageCollector::MINOR_MARK_COMPACTOR &&
+ CppHeap::From(cpp_heap())->generational_gc_supported())) {
+ // CppHeap needs a stack marker at the top of all entry points to allow
+ // deterministic passes over the stack. E.g., a verifier that should
+ // only find a subset of references of the marker.
+ //
+ // TODO(chromium:1056170): Consider adding a component that keeps track
+ // of relevant GC stack regions where interesting pointers can be found.
+ static_cast<v8::internal::CppHeap*>(cpp_heap())
+ ->SetStackEndOfCurrentGC(
+ v8::base::Stack::GetCurrentStackPosition());
+ }
+ }
GarbageCollectionPrologue(gc_reason, gc_callback_flags);
{
@@ -2396,8 +2411,6 @@
DCHECK(incremental_marking_->IsStopped());
DCHECK_NOT_NULL(isolate()->global_safepoint());
- SaveStackContextScope stack_context_scope(&stack());
-
isolate()->global_safepoint()->IterateClientIsolates([](Isolate* client) {
client->heap()->FreeSharedLinearAllocationAreas();
@@ -5809,7 +5822,12 @@
}
void Heap::SetStackStart(void* stack_start) {
- stack().SetStackStart(stack_start);
+#if V8_ENABLE_WEBASSEMBLY
+ stack().SetStackStart(stack_start,
+ v8_flags.experimental_wasm_stack_switching);
+#else
+ stack().SetStackStart(stack_start, false);
+#endif // V8_ENABLE_WEBASSEMBLY
}
::heap::base::Stack& Heap::stack() {
@@ -6391,8 +6409,7 @@
filtering_(filtering),
filter_(nullptr),
space_iterator_(nullptr),
- object_iterator_(nullptr),
- stack_context_scope_(&heap->stack()) {
+ object_iterator_(nullptr) {
heap_->MakeHeapIterable();
// Start the iteration.
space_iterator_ = new SpaceIterator(heap_);
@@ -7371,28 +7388,5 @@
CppClassNamesAsHeapObjectNameScope::~CppClassNamesAsHeapObjectNameScope() =
default;
-SaveStackContextScope::SaveStackContextScope(::heap::base::Stack* stack)
- : stack_(stack) {
-#if V8_ENABLE_WEBASSEMBLY
- // TODO(v8:13493): Do not check the stack context invariant if WASM stack
- // switching is enabled. This will be removed as soon as context saving
- // becomes compatible with stack switching.
- stack_->SaveContext(!v8_flags.experimental_wasm_stack_switching);
-#else
- stack_->SaveContext();
-#endif // V8_ENABLE_WEBASSEMBLY
-}
-
-SaveStackContextScope::~SaveStackContextScope() {
-#if V8_ENABLE_WEBASSEMBLY
- // TODO(v8:13493): Do not check the stack context invariant if WASM stack
- // switching is enabled. This will be removed as soon as context saving
- // becomes compatible with stack switching.
- stack_->ClearContext(!v8_flags.experimental_wasm_stack_switching);
-#else
- stack_->ClearContext();
-#endif // V8_ENABLE_WEBASSEMBLY
-}
-
} // namespace internal
} // namespace v8
diff --git a/src/heap/heap.h b/src/heap/heap.h
index c93d89c..bc565ca 100644
--- a/v8/src/heap/heap.h
+++ b/v8/src/heap/heap.h
@@ -2633,17 +2633,6 @@
Heap* heap_;
};
-// TODO(v8:13493): This class will move to src/heap/base/stack.h once its
-// implementation no longer needs access to V8 flags.
-class V8_EXPORT_PRIVATE V8_NODISCARD SaveStackContextScope {
- public:
- explicit SaveStackContextScope(::heap::base::Stack* stack);
- ~SaveStackContextScope();
-
- protected:
- ::heap::base::Stack* stack_;
-};
-
class V8_NODISCARD DisableConservativeStackScanningScopeForTesting {
public:
explicit inline DisableConservativeStackScanningScopeForTesting(Heap* heap)
@@ -2695,7 +2684,6 @@
SpaceIterator* space_iterator_;
// Object iterator for the space currently being iterated.
std::unique_ptr<ObjectIterator> object_iterator_;
- SaveStackContextScope stack_context_scope_;
DISALLOW_GARBAGE_COLLECTION(no_heap_allocation_)
};
diff --git a/src/profiler/heap-snapshot-generator.cc b/src/profiler/heap-snapshot-generator.cc
index e076418..f0b3058 100644
--- a/v8/src/profiler/heap-snapshot-generator.cc
+++ b/v8/src/profiler/heap-snapshot-generator.cc
@@ -2055,16 +2055,14 @@
// its custom name to a generic builtin.
RootsReferencesExtractor extractor(this);
ReadOnlyRoots(heap_).Iterate(&extractor);
- {
- SaveStackContextScope scope(&heap_->stack());
- heap_->IterateRoots(&extractor, base::EnumSet<SkipRoot>{SkipRoot::kWeak});
- // TODO(v8:11800): The heap snapshot generator incorrectly considers the
- // weak string tables as strong retainers. Move IterateWeakRoots after
- // SetVisitingWeakRoots.
- heap_->IterateWeakRoots(&extractor, {});
- extractor.SetVisitingWeakRoots();
- heap_->IterateWeakGlobalHandles(&extractor);
- }
+ heap_->IterateRoots(&extractor, base::EnumSet<SkipRoot>{SkipRoot::kWeak});
+ // TODO(v8:11800): The heap snapshot generator incorrectly considers the weak
+ // string tables as strong retainers. Move IterateWeakRoots after
+ // SetVisitingWeakRoots.
+ heap_->IterateWeakRoots(&extractor, {});
+ extractor.SetVisitingWeakRoots();
+ heap_->IterateWeakGlobalHandles(&extractor);
+
bool interrupted = false;
CombinedHeapObjectIterator iterator(heap_,