From 472429e623cf48e864a7a2f10d589817a88289a1 Mon Sep 17 00:00:00 2001 From: Nikolaos Papaspyrou 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 Reviewed-by: Omer Katz Reviewed-by: Michael Lippautz 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(stack->base())); + heap()->SetStackStart(reinterpret_cast(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
( 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 - -// 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 - -// 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 - -// 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 - -// 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 - -// 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 - -// 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 - -// 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 - -// 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 - -// 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 +#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(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(context_->stack_marker) & - (kMinStackAlignment - 1)); - IteratePointersInStack( - visitor, reinterpret_cast(context_->stack_marker), - stack_start_, asan_fake_stack); + CHECK_EQ(0u, + reinterpret_cast(stack_end) & (kMinStackAlignment - 1)); + IteratePointersInStack(visitor, + reinterpret_cast(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(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 +#include #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 registers; - }; + static void IteratePointersImpl(const Stack* stack, StackVisitor* visitor, + const void* stack_end); const void* stack_start_; - std::unique_ptr 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(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 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 expected_marked_bytes) { + StackState stack_state, const void* stack_end, + v8::base::Optional 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); + void Run(StackState, const void*, v8::base::Optional); 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(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 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::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::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_,