diff --git a/DEPS b/DEPS index 67e2593db1217..d9d9a9f27e83a 100644 --- a/DEPS +++ b/DEPS @@ -31,6 +31,9 @@ vars = { # To be able to build clean Chromium from sources. 'apply_patches': True, + # Apply the patches specific to windows on arm64 + 'apply_win_arm64_patches': False, + # Python interface to Amazon Web Services. Is used for releases only. 'checkout_boto': False, @@ -96,6 +99,16 @@ hooks = [ 'src/electron/patches/common/config.json', ], }, + { + 'name': 'patch_chromium', + 'condition': '(checkout_chromium and apply_patches) and apply_win_arm64_patches', + 'pattern': 'src/electron', + 'action': [ + 'python', + 'src/electron/script/apply_all_patches.py', + 'src/electron/patches/win_arm64/config.json', + ], + }, { 'name': 'electron_external_binaries', 'pattern': 'src/electron/script/update-external-binaries.py', diff --git a/patches/win_arm64/chromium/.patches b/patches/win_arm64/chromium/.patches new file mode 100644 index 0000000000000..660ef2a0b5818 --- /dev/null +++ b/patches/win_arm64/chromium/.patches @@ -0,0 +1 @@ +backport_crashpad_cpu_context_capture.patch diff --git a/patches/win_arm64/chromium/backport_crashpad_cpu_context_capture.patch b/patches/win_arm64/chromium/backport_crashpad_cpu_context_capture.patch new file mode 100644 index 0000000000000..794973f25e17b --- /dev/null +++ b/patches/win_arm64/chromium/backport_crashpad_cpu_context_capture.patch @@ -0,0 +1,178 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Richard Townsend +Date: Tue, 23 Jul 2019 15:36:43 +0100 +Subject: feat: backport crashpad CPU context capture + +Backport of [1] for Windows on Arm (originally writen by @kaadam). +This allows you to see register values within the crash report. + +[1] https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1632749 + +diff --git a/third_party/crashpad/crashpad/handler/BUILD.gn b/third_party/crashpad/crashpad/handler/BUILD.gn +index dc32b94e651c906f9ab1868165448805c71fe258..67c77e5fbc131d789b77dcca215f507027fd1fd0 100644 +--- a/third_party/crashpad/crashpad/handler/BUILD.gn ++++ b/third_party/crashpad/crashpad/handler/BUILD.gn +@@ -180,8 +180,6 @@ if (crashpad_is_android) { + if (crashpad_is_in_chromium) { + no_default_deps = true + } +- remove_configs = +- [ "//build/config/android:default_orderfile_instrumentation" ] + } + } + +diff --git a/third_party/crashpad/crashpad/util/BUILD.gn b/third_party/crashpad/crashpad/util/BUILD.gn +index 620ae2550a0ba81fb9ad903d570d5ddbb8915b79..088a7b59a4e34bb5489ab34a0ac928f706efc8d3 100644 +--- a/third_party/crashpad/crashpad/util/BUILD.gn ++++ b/third_party/crashpad/crashpad/util/BUILD.gn +@@ -396,8 +396,17 @@ static_library("util") { + "win/safe_terminate_process.asm", + ] + } else { +- # TODO: Add assembly code of CaptureContext for Windows ARM64. +- sources += [ "misc/capture_context_broken.cc" ] ++ # Most Crashpad builds use Microsoft's armasm64.exe macro assembler for ++ # .asm source files. When building in Chromium, clang-cl is used as the ++ # assembler instead. Since the two assemblers recognize different ++ # assembly dialects, the same .asm file can't be used for each. As a ++ # workaround, use a prebuilt .obj file when the Microsoft-dialect ++ # assembler isn't available. ++ if (crashpad_is_in_chromium) { ++ sources += [ "misc/capture_context_win_arm64.obj" ] ++ } else { ++ sources += [ "misc/capture_context_win_arm64.asm" ] ++ } + } + } else { + sources += [ +diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_fuchsia.S b/third_party/crashpad/crashpad/util/misc/capture_context_fuchsia.S +index 21aefad0b1ed0e05112060e427bbef8fd86dfee2..0ebc7f7fe8ca159268bec6dd34c2e043bc1cfc63 100644 +--- a/third_party/crashpad/crashpad/util/misc/capture_context_fuchsia.S ++++ b/third_party/crashpad/crashpad/util/misc/capture_context_fuchsia.S +@@ -116,7 +116,7 @@ CAPTURECONTEXT_SYMBOL: + movq 0x90(%rdi), %rax + movq 0x28(%rdi), %r8 + +- // TODO(scottmg): save floating-point registers. ++ // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. + + popfq + +@@ -166,7 +166,7 @@ CAPTURECONTEXT_SYMBOL: + // Restore x1 from the saved context. + ldr x1, [x0, #0xc0] + +- // TODO(scottmg): save floating-point registers. ++ // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. + + ret + +diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_linux.S b/third_party/crashpad/crashpad/util/misc/capture_context_linux.S +index 657a979a76ea1cfc02633e8553d41005fd1a2749..de71e7231273ac2a79b3eebfde2357e3eda9f94d 100644 +--- a/third_party/crashpad/crashpad/util/misc/capture_context_linux.S ++++ b/third_party/crashpad/crashpad/util/misc/capture_context_linux.S +@@ -282,7 +282,7 @@ CAPTURECONTEXT_SYMBOL2: + // Restore r1. + ldr r1, [r0, #0x24] + +- // TODO(jperaza): save floating-point registers. ++ // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. + + mov PC, LR + +@@ -326,7 +326,7 @@ CAPTURECONTEXT_SYMBOL2: + // Restore x1 from the saved context. + ldr x1, [x0, #0xc0] + +- // TODO(jperaza): save floating-point registers. ++ // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. + + ret + #elif defined(__mips__) +diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_win_arm64.asm b/third_party/crashpad/crashpad/util/misc/capture_context_win_arm64.asm +new file mode 100644 +index 0000000000000000000000000000000000000000..5630698f8d8ef198eb9f8cf28692eeaf97a961a5 +--- /dev/null ++++ b/third_party/crashpad/crashpad/util/misc/capture_context_win_arm64.asm +@@ -0,0 +1,64 @@ ++; Copyright 2019 The Crashpad Authors. All rights reserved. ++; ++; Licensed under the Apache License, Version 2.0 (the "License"); ++; you may not use this file except in compliance with the License. ++; You may obtain a copy of the License at ++; ++; http://www.apache.org/licenses/LICENSE-2.0 ++; ++; Unless required by applicable law or agreed to in writing, software ++; distributed under the License is distributed on an "AS IS" BASIS, ++; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++; See the License for the specific language governing permissions and ++; limitations under the License. ++ ++ EXPORT |?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z| ++ AREA |.text|, CODE ++|?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z| PROC ++ ; Save general purpose registers in context.regs[i]. ++ ; The original x0 can't be recovered. ++ stp x0, x1, [x0, #0x008] ++ stp x2, x3, [x0, #0x018] ++ stp x4, x5, [x0, #0x028] ++ stp x6, x7, [x0, #0x038] ++ stp x8, x9, [x0, #0x048] ++ stp x10, x11, [x0, #0x058] ++ stp x12, x13, [x0, #0x068] ++ stp x14, x15, [x0, #0x078] ++ stp x16, x17, [x0, #0x088] ++ stp x18, x19, [x0, #0x098] ++ stp x20, x21, [x0, #0x0a8] ++ stp x22, x23, [x0, #0x0b8] ++ stp x24, x25, [x0, #0x0c8] ++ stp x26, x27, [x0, #0x0d8] ++ stp x28, x29, [x0, #0x0e8] ++ ++ ; The original LR can't be recovered. ++ str LR, [x0, #0x0f8] ++ ++ ; Use x1 as a scratch register. ++ mov x1, SP ++ str x1, [x0, #0x100] ; context.sp ++ ++ ; The link register holds the return address for this function. ++ str LR, [x0, #0x108] ; context.pc ++ ++ ; pstate should hold SPSR but NZCV are the only bits we know about. ++ mrs x1, NZCV ++ ++ ; Enable Control flags, such as CONTEXT_ARM64, CONTEXT_CONTROL, ++ ; CONTEXT_INTEGER ++ ldr w1, =0x00400003 ++ ++ ; Set ControlFlags /0x000/ and pstate /0x004/ at the same time. ++ str x1, [x0, #0x000] ++ ++ ; Restore x1 from the saved context. ++ ldr x1, [x0, #0x010] ++ ++ ; TODO(https://crashpad.chromium.org/bug/300): save floating-point registers ++ ++ ret ++ ENDP ++ ++ END +diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_win_arm64.obj b/third_party/crashpad/crashpad/util/misc/capture_context_win_arm64.obj +new file mode 100644 +index 0000000000000000000000000000000000000000..11c76a1aae15f8331d37063a3adc5e6ad37fcc8f +GIT binary patch +literal 614 +zcmYdU#l-MIOFuS-k%57S0Rr?&QY%WJY!H5C@9`=<2M>tjro#9+5a)oQ9 +z*d6Yb5>I$mO1EC^;s%D6u%BATb5OC@sm%iOJ0@2FfKCl#~{w +z#wX|Jfjk{wo|zY)Sd?pKqL-hP#lT?0U?a%P#K7dqF$gfs$Yf;j%}g%JFV0UZ +zQP2p|RB#OPRq#y&iYPc17pLYX<)jt?RXZf-=N9N?rp(A>X8ix3fdS~wwA92BJp%&) +zpe#g0FD)}C6=F2QKcJd)7K&V*Sey$ri~%_ofuY5~%m|7{RDc|VKyL!ofZ`AnfI=4p +sK;|$p7y(IpXGq97LjukL7RU|`k&Y1ou8yJc&i;NOt`Q*)4h~Ta0HmRmk^lez + +literal 0 +HcmV?d00001 + diff --git a/patches/win_arm64/config.json b/patches/win_arm64/config.json new file mode 100644 index 0000000000000..7b12f53fb9f58 --- /dev/null +++ b/patches/win_arm64/config.json @@ -0,0 +1,5 @@ +{ + "src/electron/patches/win_arm64/chromium": "src", + + "src/electron/patches/win_arm64/v8": "src/v8" +} diff --git a/patches/win_arm64/v8/.patches b/patches/win_arm64/v8/.patches new file mode 100644 index 0000000000000..98a5d5620f072 --- /dev/null +++ b/patches/win_arm64/v8/.patches @@ -0,0 +1 @@ +unwind_v8_frames_correctly_on_windows_arm64.patch diff --git a/patches/win_arm64/v8/unwind_v8_frames_correctly_on_windows_arm64.patch b/patches/win_arm64/v8/unwind_v8_frames_correctly_on_windows_arm64.patch new file mode 100644 index 0000000000000..12778a2dc42c8 --- /dev/null +++ b/patches/win_arm64/v8/unwind_v8_frames_correctly_on_windows_arm64.patch @@ -0,0 +1,1533 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tom Tan +Date: Fri, 26 Jul 2019 23:36:52 -0700 +Subject: Unwind V8 frames correctly on Windows ARM64 + +On Windows ARM64, OS stack walking does not work because the V8 ARM64 backend +doesn't emit unwinding info and also because it doesn't emit ABI compliant +stack frames. This was fixed for Windows X64 (https://crrev.com/c/1469329) and +documented below: + +https://docs.google.com/document/d/1-wf50jFlii0c_Pr52lm2ZU-49m220nhYMrHDi3vXnh0 + +This problem can be fixed similarly for Windows ARM64 by observing that V8 +frames usually all have the same prolog which maintains a chain via frame +pointer (fp or x29 register). + +stp fp, lr, [sp, ...] + +One exception is JSEntry which stops fp pointer chain and needs to be handled +specially. + +So it is possible to define XDATA with UNWIND_CODE which specify how Windows +should walk through V8 dynamic frames. The same as X64, since V8 Code objects +are all allocated in the same code-range for an Isolate, it is possible to +register at most 2 XDATA and a group of PDATA entries to cover stack walking +for all the code generated inside that code-range. This is more than 1 +PDATA/XDATA because according to the Windows ARM64 exeption handling document, +1 PDATA can cover less than 1MB code range (see below doc). + +https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling + +This PR implements stackwalk for Windows ARM64 to be on par with X64, including +embedded builtins, jitted code and wasm jitted code, but not including register +handler for handling exception only, because there is no backward compatibility +to maintain for Windows ARM64 which was released since 1709 windows build. + +Bug: chromium:893460 +Change-Id: Ic74cbdad8af5cf342185030a4c53796f12ea5429 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1701133 +Reviewed-by: Michael Starzinger +Reviewed-by: Jakob Gruber +Commit-Queue: Jakob Gruber +Cr-Commit-Position: refs/heads/master@{#63002} + +diff --git a/BUILD.gn b/BUILD.gn +index 071a85c3f57ae92dcf90d47a13299e43f81753ec..d3cc60935541d080234ebc30b231904a48e68862 100644 +--- a/BUILD.gn ++++ b/BUILD.gn +@@ -91,7 +91,7 @@ declare_args() { + # Enable embedded builtins. + v8_enable_embedded_builtins = true + +- # Enable the registration of unwinding info for Windows/x64. ++ # Enable the registration of unwinding info for Windows x64 and ARM64. + v8_win64_unwinding_info = true + + # Enable code comments for builtins in the snapshot (impacts performance). +@@ -3131,6 +3131,12 @@ v8_source_set("v8_base_without_compiler") { + "src/regexp/arm64/regexp-macro-assembler-arm64.h", + "src/wasm/baseline/arm64/liftoff-assembler-arm64.h", + ] ++ if (is_win) { ++ sources += [ ++ "src/diagnostics/unwinding-info-win64.cc", ++ "src/diagnostics/unwinding-info-win64.h", ++ ] ++ } + jumbo_excluded_sources += [ + # TODO(mostynb@vewd.com): fix this code so it doesn't need + # to be excluded, see the comments inside. +diff --git a/src/api/api.cc b/src/api/api.cc +index 6117189ad11a189e03c4db1307d919b818751b18..5b8f980929b21305f6846e8e6a3342926251efbf 100644 +--- a/src/api/api.cc ++++ b/src/api/api.cc +@@ -121,9 +121,9 @@ + #include + #include "include/v8-wasm-trap-handler-win.h" + #include "src/trap-handler/handler-inside-win.h" +-#if V8_TARGET_ARCH_X64 ++#if defined(V8_OS_WIN64) + #include "src/diagnostics/unwinding-info-win64.h" +-#endif // V8_TARGET_ARCH_X64 ++#endif // V8_OS_WIN64 + #endif // V8_OS_WIN + + namespace v8 { +@@ -5609,14 +5609,14 @@ bool V8::EnableWebAssemblyTrapHandler(bool use_v8_signal_handler) { + #if defined(V8_OS_WIN) + void V8::SetUnhandledExceptionCallback( + UnhandledExceptionCallback unhandled_exception_callback) { +-#if defined(V8_TARGET_ARCH_X64) ++#if defined(V8_OS_WIN64) + v8::internal::win64_unwindinfo::SetUnhandledExceptionCallback( + unhandled_exception_callback); + #else +- // Not implemented on ARM64. +-#endif ++ // Not implemented, port needed. ++#endif // V8_OS_WIN64 + } +-#endif ++#endif // V8_OS_WIN + + void v8::V8::SetEntropySource(EntropySource entropy_source) { + base::RandomNumberGenerator::SetEntropySource(entropy_source); +diff --git a/src/builtins/arm64/builtins-arm64.cc b/src/builtins/arm64/builtins-arm64.cc +index f81a1955eeb474c527f25f9e59edb0522e81824b..0619fbfe55e0efad72ae5f2cb9623285025cacb2 100644 +--- a/src/builtins/arm64/builtins-arm64.cc ++++ b/src/builtins/arm64/builtins-arm64.cc +@@ -24,6 +24,10 @@ + #include "src/runtime/runtime.h" + #include "src/wasm/wasm-objects.h" + ++#if defined(V8_OS_WIN) ++#include "src/diagnostics/unwinding-info-win64.h" ++#endif // V8_OS_WIN ++ + namespace v8 { + namespace internal { + +@@ -623,6 +627,23 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type, + // will have no effect on the model or real hardware. + __ EnableInstrumentation(); + ++#if defined(V8_OS_WIN) ++ // Windows ARM64 relies on a frame pointer (fp/x29 which are aliases to each ++ // other) chain to do stack unwinding, but JSEntry breaks that by setting fp ++ // to point to bad_frame_pointer below. To fix unwind information for this ++ // case, JSEntry registers the offset (from current fp to the caller's fp ++ // saved by PushCalleeSavedRegisters on stack) to xdata_encoder which then ++ // emits the offset value as part of result unwind data accordingly. The ++ // current offset is kFramePointerOffset which includes bad_frame_pointer ++ // saved below plus kFramePointerOffsetInPushCalleeSavedRegisters. ++ const int kFramePointerOffset = ++ kFramePointerOffsetInPushCalleeSavedRegisters + kSystemPointerSize; ++ win64_unwindinfo::XdataEncoder* xdata_encoder = masm->GetXdataEncoder(); ++ if (xdata_encoder) { ++ xdata_encoder->onFramePointerAdjustment(kFramePointerOffset); ++ } ++#endif ++ + __ PushCalleeSavedRegisters(); + + // Set up the reserved register for 0.0. +diff --git a/src/builtins/setup-builtins-internal.cc b/src/builtins/setup-builtins-internal.cc +index 7b4a068300e20f56a1491a494ed8978dbb95398a..39cbf15b6504ce380d165b56ca20e52460d65b23 100644 +--- a/src/builtins/setup-builtins-internal.cc ++++ b/src/builtins/setup-builtins-internal.cc +@@ -119,9 +119,9 @@ Code BuildWithMacroAssembler(Isolate* isolate, int32_t builtin_index, + .set_self_reference(masm.CodeObject()) + .set_builtin_index(builtin_index) + .Build(); +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + isolate->SetBuiltinUnwindData(builtin_index, masm.GetUnwindInfo()); +-#endif ++#endif // V8_OS_WIN64 + return *code; + } + +diff --git a/src/codegen/arm64/assembler-arm64.cc b/src/codegen/arm64/assembler-arm64.cc +index 53da75760ba31bed3e3cf19397474b353bc83fdf..d94370f5d7d6456a21f681bd81afa54e06863ce3 100644 +--- a/src/codegen/arm64/assembler-arm64.cc ++++ b/src/codegen/arm64/assembler-arm64.cc +@@ -520,6 +520,12 @@ Assembler::Assembler(const AssemblerOptions& options, + const_pool_blocked_nesting_ = 0; + veneer_pool_blocked_nesting_ = 0; + Reset(); ++ ++#if defined(V8_OS_WIN) ++ if (options.collect_win64_unwind_info) { ++ xdata_encoder_ = std::make_unique(*this); ++ } ++#endif + } + + Assembler::~Assembler() { +@@ -546,6 +552,14 @@ void Assembler::Reset() { + no_const_pool_before_ = 0; + } + ++#if defined(V8_OS_WIN) ++win64_unwindinfo::BuiltinUnwindInfo Assembler::GetUnwindInfo() const { ++ DCHECK(options().collect_win64_unwind_info); ++ DCHECK_NOT_NULL(xdata_encoder_); ++ return xdata_encoder_->unwinding_info(); ++} ++#endif ++ + void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) { + DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty()); + for (auto& request : heap_object_requests_) { +@@ -1395,6 +1409,12 @@ void Assembler::ldp(const CPURegister& rt, const CPURegister& rt2, + void Assembler::stp(const CPURegister& rt, const CPURegister& rt2, + const MemOperand& dst) { + LoadStorePair(rt, rt2, dst, StorePairOpFor(rt, rt2)); ++ ++#if defined(V8_OS_WIN) ++ if (xdata_encoder_ && rt == x29 && rt2 == lr && dst.base().IsSP()) { ++ xdata_encoder_->onSaveFpLr(); ++ } ++#endif + } + + void Assembler::ldpsw(const Register& rt, const Register& rt2, +diff --git a/src/codegen/arm64/assembler-arm64.h b/src/codegen/arm64/assembler-arm64.h +index fb5feb23074ac888e85a3676c1cbbb63126e72d5..7d1f10ad1132a51d5e93a0866ed2f13c4c9d4857 100644 +--- a/src/codegen/arm64/assembler-arm64.h ++++ b/src/codegen/arm64/assembler-arm64.h +@@ -25,6 +25,10 @@ + #undef mvn + #endif + ++#if defined(V8_OS_WIN) ++#include "src/diagnostics/unwinding-info-win64.h" ++#endif // V8_OS_WIN ++ + namespace v8 { + namespace internal { + +@@ -2452,6 +2456,14 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { + DISALLOW_IMPLICIT_CONSTRUCTORS(BlockPoolsScope); + }; + ++#if defined(V8_OS_WIN) ++ win64_unwindinfo::XdataEncoder* GetXdataEncoder() { ++ return xdata_encoder_.get(); ++ } ++ ++ win64_unwindinfo::BuiltinUnwindInfo GetUnwindInfo() const; ++#endif ++ + protected: + inline const Register& AppropriateZeroRegFor(const CPURegister& reg) const; + +@@ -2774,6 +2786,10 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { + // veneer margin (or kMaxInt if there are no unresolved branches). + int next_veneer_pool_check_; + ++#if defined(V8_OS_WIN) ++ std::unique_ptr xdata_encoder_; ++#endif ++ + private: + // Avoid overflows for displacements etc. + static const int kMaximalBufferSize = 512 * MB; +diff --git a/src/codegen/arm64/macro-assembler-arm64.cc b/src/codegen/arm64/macro-assembler-arm64.cc +index aab9fc79a2c2c25e7f97a8bd41b3e25a1f2f0af1..6c559549759b198734154abf36353e6d730c8e46 100644 +--- a/src/codegen/arm64/macro-assembler-arm64.cc ++++ b/src/codegen/arm64/macro-assembler-arm64.cc +@@ -1302,6 +1302,14 @@ void MacroAssembler::PushCalleeSavedRegisters() { + stp(d8, d9, tos); + + stp(x29, x30, tos); ++#if defined(V8_OS_WIN) ++ // kFramePointerOffsetInPushCalleeSavedRegisters is the offset from tos at ++ // the end of this function to the saved caller's fp/x29 pointer. It includes ++ // registers from x19 to x28, which is 10 pointers defined by below stp ++ // instructions. ++ STATIC_ASSERT(kFramePointerOffsetInPushCalleeSavedRegisters == ++ 10 * kSystemPointerSize); ++#endif // defined(V8_OS_WIN) + stp(x27, x28, tos); + stp(x25, x26, tos); + stp(x23, x24, tos); +diff --git a/src/codegen/arm64/macro-assembler-arm64.h b/src/codegen/arm64/macro-assembler-arm64.h +index 6961428f35a0c052c9faf6afb3db42b9afabe0cf..651524795cdf78935220ef24bac637cd013c9aae 100644 +--- a/src/codegen/arm64/macro-assembler-arm64.h ++++ b/src/codegen/arm64/macro-assembler-arm64.h +@@ -83,6 +83,12 @@ inline MemOperand FieldMemOperand(Register object, int offset); + // ---------------------------------------------------------------------------- + // MacroAssembler + ++#if defined(V8_OS_WIN) ++// This offset is originated from PushCalleeSavedRegisters. ++static constexpr int kFramePointerOffsetInPushCalleeSavedRegisters = ++ 10 * kSystemPointerSize; ++#endif // V8_OS_WIN ++ + enum BranchType { + // Copies of architectural conditions. + // The associated conditions can be used in place of those, the code will +diff --git a/src/common/globals.h b/src/common/globals.h +index 5d4b957e84fc01e12854dc8fed23b967cd971dcd..b981670263f9091677591f806affc9def9044366 100644 +--- a/src/common/globals.h ++++ b/src/common/globals.h +@@ -101,6 +101,14 @@ constexpr int kStackSpaceRequiredForCompilation = 40; + #define V8_OS_WIN_X64 true + #endif + ++#if defined(V8_OS_WIN) && defined(V8_TARGET_ARCH_ARM64) ++#define V8_OS_WIN_ARM64 true ++#endif ++ ++#if defined(V8_OS_WIN_X64) || defined(V8_OS_WIN_ARM64) ++#define V8_OS_WIN64 true ++#endif ++ + // Superclass for classes only using static method functions. + // The subclass of AllStatic cannot be instantiated at all. + class AllStatic { +diff --git a/src/compiler/backend/code-generator.cc b/src/compiler/backend/code-generator.cc +index bb83a8497bbe3e7a398eeb65b5050673311cbd6a..5d20d88cd1351184cac02d69eda4b9455fef328d 100644 +--- a/src/compiler/backend/code-generator.cc ++++ b/src/compiler/backend/code-generator.cc +@@ -396,12 +396,12 @@ MaybeHandle CodeGenerator::FinalizeCode() { + CodeDesc desc; + tasm()->GetCode(isolate(), &desc, safepoints(), handler_table_offset_); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + if (Builtins::IsBuiltinId(info_->builtin_index())) { + isolate_->SetBuiltinUnwindData(info_->builtin_index(), + tasm()->GetUnwindInfo()); + } +-#endif ++#endif // V8_OS_WIN64 + + if (unwinding_info_writer_.eh_frame_writer()) { + unwinding_info_writer_.eh_frame_writer()->GetEhFrame(&desc); +diff --git a/src/diagnostics/unwinding-info-win64.cc b/src/diagnostics/unwinding-info-win64.cc +index 8fb01dba9a55c75de677286baa19bb9edae74231..6cc53da51f16a45c3a8ad14ca0b2150bed43d766 100644 +--- a/src/diagnostics/unwinding-info-win64.cc ++++ b/src/diagnostics/unwinding-info-win64.cc +@@ -4,12 +4,18 @@ + + #include "src/diagnostics/unwinding-info-win64.h" + +-#if defined(V8_OS_WIN_X64) +- + #include "src/codegen/macro-assembler.h" +-#include "src/codegen/x64/assembler-x64.h" + #include "src/utils/allocation.h" + ++#if defined(V8_OS_WIN_X64) ++#include "src/codegen/x64/assembler-x64.h" ++#elif defined(V8_OS_WIN_ARM64) ++#include "src/codegen/arm64/assembler-arm64-inl.h" ++#include "src/codegen/arm64/macro-assembler-arm64-inl.h" ++#else ++#error "Unsupported OS" ++#endif // V8_OS_WIN_X64 ++ + namespace v8 { + namespace internal { + namespace win64_unwindinfo { +@@ -22,9 +28,36 @@ bool CanRegisterUnwindInfoForNonABICompliantCodeRange() { + + bool RegisterUnwindInfoForExceptionHandlingOnly() { + DCHECK(CanRegisterUnwindInfoForNonABICompliantCodeRange()); ++#if defined(V8_OS_WIN_ARM64) ++ return !FLAG_win64_unwinding_info; ++#else + return !IsWindows8OrGreater() || !FLAG_win64_unwinding_info; ++#endif ++} ++ ++v8::UnhandledExceptionCallback unhandled_exception_callback_g = nullptr; ++ ++void SetUnhandledExceptionCallback( ++ v8::UnhandledExceptionCallback unhandled_exception_callback) { ++ unhandled_exception_callback_g = unhandled_exception_callback; ++} ++ ++// This function is registered as exception handler for V8-generated code as ++// part of the registration of unwinding info. It is referenced by ++// RegisterNonABICompliantCodeRange(), below, and by the unwinding info for ++// builtins declared in the embedded blob. ++extern "C" __declspec(dllexport) int CRASH_HANDLER_FUNCTION_NAME( ++ PEXCEPTION_RECORD ExceptionRecord, ULONG64 EstablisherFrame, ++ PCONTEXT ContextRecord, PDISPATCHER_CONTEXT DispatcherContext) { ++ if (unhandled_exception_callback_g != nullptr) { ++ EXCEPTION_POINTERS info = {ExceptionRecord, ContextRecord}; ++ return unhandled_exception_callback_g(&info); ++ } ++ return ExceptionContinueSearch; + } + ++#if defined(V8_OS_WIN_X64) ++ + #pragma pack(push, 1) + + /* +@@ -49,9 +82,12 @@ struct UNWIND_INFO { + unsigned char FrameOffset : 4; + }; + ++static constexpr int kNumberOfUnwindCodes = 2; ++static constexpr int kMaxExceptionThunkSize = 12; ++ + struct V8UnwindData { + UNWIND_INFO unwind_info; +- UNWIND_CODE unwind_codes[2]; ++ UNWIND_CODE unwind_codes[kNumberOfUnwindCodes]; + + V8UnwindData() { + static constexpr int kOpPushNonvol = 0; +@@ -87,46 +123,244 @@ struct ExceptionHandlerUnwindData { + } + }; + ++struct CodeRangeUnwindingRecord { ++ void* dynamic_table; ++ uint32_t runtime_function_count; ++ V8UnwindData unwind_info; ++ uint32_t exception_handler; ++ uint8_t exception_thunk[kMaxExceptionThunkSize]; ++ RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount]; ++}; ++ ++struct ExceptionHandlerRecord { ++ uint32_t runtime_function_count; ++ RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount]; ++ ExceptionHandlerUnwindData unwind_info; ++ uint32_t exception_handler; ++ uint8_t exception_thunk[kMaxExceptionThunkSize]; ++}; ++ + #pragma pack(pop) + +-v8::UnhandledExceptionCallback unhandled_exception_callback_g = nullptr; ++std::vector GetUnwindInfoForBuiltinFunctions() { ++ V8UnwindData xdata; ++ return std::vector( ++ reinterpret_cast(&xdata), ++ reinterpret_cast(&xdata) + sizeof(xdata)); ++} + +-void SetUnhandledExceptionCallback( +- v8::UnhandledExceptionCallback unhandled_exception_callback) { +- unhandled_exception_callback_g = unhandled_exception_callback; ++template ++void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) { ++ // We assume that the first page of the code range is executable and ++ // committed and reserved to contain PDATA/XDATA. ++ ++ // All addresses are 32bit relative offsets to start. ++ record->runtime_function[0].BeginAddress = 0; ++ record->runtime_function[0].EndAddress = ++ static_cast(code_size_in_bytes); ++ record->runtime_function[0].UnwindData = offsetof(Record, unwind_info); ++ record->runtime_function_count = 1; ++ record->exception_handler = offsetof(Record, exception_thunk); ++ ++ // Hardcoded thunk. ++ AssemblerOptions options; ++ options.record_reloc_info_for_serialization = false; ++ MacroAssembler masm(nullptr, options, CodeObjectRequired::kNo, ++ NewAssemblerBuffer(64)); ++ masm.movq(rax, reinterpret_cast(&CRASH_HANDLER_FUNCTION_NAME)); ++ masm.jmp(rax); ++ DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk)); ++ memcpy(&record->exception_thunk[0], masm.buffer_start(), ++ masm.instruction_size()); + } + +-// This function is registered as exception handler for V8-generated code as +-// part of the registration of unwinding info. It is referenced by +-// RegisterNonABICompliantCodeRange(), below, and by the unwinding info for +-// builtins declared in the embedded blob. +-extern "C" __declspec(dllexport) int CRASH_HANDLER_FUNCTION_NAME( +- PEXCEPTION_RECORD ExceptionRecord, ULONG64 EstablisherFrame, +- PCONTEXT ContextRecord, PDISPATCHER_CONTEXT DispatcherContext) { +- if (unhandled_exception_callback_g != nullptr) { +- EXCEPTION_POINTERS info = {ExceptionRecord, ContextRecord}; +- return unhandled_exception_callback_g(&info); +- } +- return ExceptionContinueSearch; ++#elif defined(V8_OS_WIN_ARM64) ++ ++#pragma pack(push, 1) ++ ++// ARM64 unwind codes are defined in below doc. ++// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes ++enum UnwindOp8Bit { ++ OpNop = 0xE3, ++ OpSaveFpLr = 0x40, ++ OpSaveFpLrX = 0x80, ++ OpSetFp = 0xE1, ++ OpEnd = 0xE4, ++}; ++ ++typedef uint32_t UNWIND_CODE; ++ ++constexpr UNWIND_CODE Combine8BitUnwindCodes(uint8_t code0, ++ uint8_t code1 = OpNop, ++ uint8_t code2 = OpNop, ++ uint8_t code3 = OpNop) { ++ return static_cast(code0) | (static_cast(code1) << 8) | ++ (static_cast(code2) << 16) | ++ (static_cast(code3) << 24); + } + +-static constexpr int kMaxExceptionThunkSize = 12; ++// UNWIND_INFO defines the static part (first 32-bit) of the .xdata record in ++// below doc. ++// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records ++struct UNWIND_INFO { ++ uint32_t FunctionLength : 18; ++ uint32_t Version : 2; ++ uint32_t X : 1; ++ uint32_t E : 1; ++ uint32_t EpilogCount : 5; ++ uint32_t CodeWords : 5; ++}; ++ ++static constexpr int kNumberOfUnwindCodes = 1; ++static constexpr int kMaxExceptionThunkSize = 16; ++static constexpr int kFunctionLengthShiftSize = 2; ++static constexpr int kFunctionLengthMask = (1 << kFunctionLengthShiftSize) - 1; ++static constexpr int kFramePointerAdjustmentShiftSize = 3; ++static constexpr int kFramePointerAdjustmentShiftMask = ++ (1 << kFramePointerAdjustmentShiftSize) - 1; ++ ++struct V8UnwindData { ++ UNWIND_INFO unwind_info; ++ UNWIND_CODE unwind_codes[kNumberOfUnwindCodes]; ++ ++ V8UnwindData() { ++ memset(&unwind_info, 0, sizeof(UNWIND_INFO)); ++ unwind_info.X = 1; // has exception handler after unwind-codes. ++ unwind_info.CodeWords = 1; ++ ++ // stp fp, lr, [sp, #offset]! ++ unwind_codes[0] = Combine8BitUnwindCodes(OpSetFp, OpSaveFpLrX, OpEnd); ++ } ++}; + + struct CodeRangeUnwindingRecord { +- RUNTIME_FUNCTION runtime_function; ++ void* dynamic_table; ++ uint32_t runtime_function_count; + V8UnwindData unwind_info; + uint32_t exception_handler; +- uint8_t exception_thunk[kMaxExceptionThunkSize]; +- void* dynamic_table; +-}; + +-struct ExceptionHandlerRecord { +- RUNTIME_FUNCTION runtime_function; +- ExceptionHandlerUnwindData unwind_info; +- uint32_t exception_handler; ++ // For Windows ARM64 unwinding, register 2 unwind_info for each code range, ++ // unwind_info for all full size ranges (1MB - 4 bytes) and unwind_info1 for ++ // the remaining non full size range. There is at most 1 range which is less ++ // than full size. ++ V8UnwindData unwind_info1; ++ uint32_t exception_handler1; + uint8_t exception_thunk[kMaxExceptionThunkSize]; ++ ++ // More RUNTIME_FUNCTION structs could follow below array because the number ++ // of RUNTIME_FUNCTION needed to cover given code range is computed at ++ // runtime. ++ RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount]; + }; + ++#pragma pack(pop) ++ ++std::vector GetUnwindInfoForBuiltinFunction(uint32_t func_len, ++ int32_t fp_adjustment) { ++ DCHECK_LE(func_len, kMaxFunctionLength); ++ DCHECK_EQ((func_len & kFunctionLengthMask), 0); ++ USE(kFunctionLengthMask); ++ ++ // Unwind code save_fplr requires the offset to be within range [0, 504]. ++ // This range is defined in below doc for unwind code save_fplr. ++ // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes ++ DCHECK_GE(fp_adjustment, 0); ++ DCHECK_LE(fp_adjustment, 504); ++ DCHECK_EQ((fp_adjustment & kFramePointerAdjustmentShiftMask), 0); ++ USE(kFramePointerAdjustmentShiftMask); ++ ++ V8UnwindData xdata; ++ // FunctionLength is ensured to be aligned at instruction size and Windows ++ // ARM64 doesn't encoding its 2 LSB. ++ xdata.unwind_info.FunctionLength = func_len >> kFunctionLengthShiftSize; ++ xdata.unwind_info.CodeWords = 1; ++ xdata.unwind_codes[0] = Combine8BitUnwindCodes( ++ OpSetFp, ++ (OpSaveFpLr | (fp_adjustment >> kFramePointerAdjustmentShiftSize)), ++ OpEnd); ++ ++ return std::vector( ++ reinterpret_cast(&xdata), ++ reinterpret_cast(&xdata) + sizeof(xdata)); ++} ++ ++template ++void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) { ++ // We assume that the first page of the code range is executable and ++ // committed and reserved to contain multiple PDATA/XDATA to cover the whole ++ // range. All addresses are 32bit relative offsets to start. ++ ++ // Maximum RUNTIME_FUNCTION count available in reserved memory, this includes ++ // static part in Record as kDefaultRuntimeFunctionCount plus dynamic part in ++ // the remaining reserved memory. ++ constexpr uint32_t max_runtime_function_count = static_cast( ++ (kOSPageSize - sizeof(Record)) / sizeof(RUNTIME_FUNCTION) + ++ kDefaultRuntimeFunctionCount); ++ ++ uint32_t runtime_function_index = 0; ++ uint32_t current_unwind_start_address = 0; ++ int64_t remaining_size_in_bytes = static_cast(code_size_in_bytes); ++ ++ // Divide the code range into chunks in size kMaxFunctionLength and create a ++ // RUNTIME_FUNCTION for each of them. All the chunks in the same size can ++ // share 1 unwind_info struct, but a separate unwind_info is needed for the ++ // last chunk if it is smaller than kMaxFunctionLength, because unlike X64, ++ // unwind_info encodes the function/chunk length. ++ while (remaining_size_in_bytes >= kMaxFunctionLength && ++ runtime_function_index < max_runtime_function_count) { ++ record->runtime_function[runtime_function_index].BeginAddress = ++ current_unwind_start_address; ++ record->runtime_function[runtime_function_index].UnwindData = ++ static_cast(offsetof(Record, unwind_info)); ++ ++ runtime_function_index++; ++ current_unwind_start_address += kMaxFunctionLength; ++ remaining_size_in_bytes -= kMaxFunctionLength; ++ } ++ // FunctionLength is ensured to be aligned at instruction size and Windows ++ // ARM64 doesn't encoding 2 LSB. ++ record->unwind_info.unwind_info.FunctionLength = kMaxFunctionLength >> 2; ++ ++ if (remaining_size_in_bytes > 0 && ++ runtime_function_index < max_runtime_function_count) { ++ DCHECK_EQ(remaining_size_in_bytes % kInstrSize, 0); ++ ++ record->unwind_info1.unwind_info.FunctionLength = static_cast( ++ remaining_size_in_bytes >> kFunctionLengthShiftSize); ++ record->runtime_function[runtime_function_index].BeginAddress = ++ current_unwind_start_address; ++ record->runtime_function[runtime_function_index].UnwindData = ++ static_cast(offsetof(Record, unwind_info1)); ++ ++ remaining_size_in_bytes -= kMaxFunctionLength; ++ record->exception_handler1 = offsetof(Record, exception_thunk); ++ record->runtime_function_count = runtime_function_index + 1; ++ } else { ++ record->runtime_function_count = runtime_function_index; ++ } ++ ++ // 1 page can cover kMaximalCodeRangeSize for ARM64 (128MB). If ++ // kMaximalCodeRangeSize is changed for ARM64 and makes 1 page insufficient to ++ // cover it, more pages will need to reserved for unwind data. ++ DCHECK_LE(remaining_size_in_bytes, 0); ++ ++ record->exception_handler = offsetof(Record, exception_thunk); ++ ++ // Hardcoded thunk. ++ AssemblerOptions options; ++ options.record_reloc_info_for_serialization = false; ++ TurboAssembler masm(nullptr, options, CodeObjectRequired::kNo, ++ NewAssemblerBuffer(64)); ++ masm.Mov(x16, ++ Operand(reinterpret_cast(&CRASH_HANDLER_FUNCTION_NAME))); ++ masm.Br(x16); ++ DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk)); ++ memcpy(&record->exception_thunk[0], masm.buffer_start(), ++ masm.instruction_size()); ++} ++ ++#endif // V8_OS_WIN_X64 ++ + namespace { + + V8_DECLARE_ONCE(load_ntdll_unwinding_functions_once); +@@ -185,37 +419,6 @@ void DeleteGrowableFunctionTable(PVOID dynamic_table) { + + } // namespace + +-std::vector GetUnwindInfoForBuiltinFunctions() { +- V8UnwindData xdata; +- return std::vector( +- reinterpret_cast(&xdata), +- reinterpret_cast(&xdata) + sizeof(xdata)); +-} +- +-template +-void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) { +- // We assume that the first page of the code range is executable and +- // committed and reserved to contain PDATA/XDATA. +- +- // All addresses are 32bit relative offsets to start. +- record->runtime_function.BeginAddress = 0; +- record->runtime_function.EndAddress = static_cast(code_size_in_bytes); +- record->runtime_function.UnwindData = offsetof(Record, unwind_info); +- +- record->exception_handler = offsetof(Record, exception_thunk); +- +- // Hardcoded thunk. +- AssemblerOptions options; +- options.record_reloc_info_for_serialization = false; +- MacroAssembler masm(nullptr, options, CodeObjectRequired::kNo, +- NewAssemblerBuffer(64)); +- masm.movq(rax, reinterpret_cast(&CRASH_HANDLER_FUNCTION_NAME)); +- masm.jmp(rax); +- DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk)); +- memcpy(&record->exception_thunk[0], masm.buffer_start(), +- masm.instruction_size()); +-} +- + void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) { + DCHECK(CanRegisterUnwindInfoForNonABICompliantCodeRange()); + +@@ -231,24 +434,30 @@ void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) { + // by the embedder (like Crashpad). + + if (RegisterUnwindInfoForExceptionHandlingOnly()) { ++#if defined(V8_OS_WIN_X64) ++ // Windows ARM64 starts since 1709 Windows build, no need to have exception ++ // handling only unwind info for compatibility. + if (unhandled_exception_callback_g) { + ExceptionHandlerRecord* record = new (start) ExceptionHandlerRecord(); + InitUnwindingRecord(record, size_in_bytes); + +- CHECK(::RtlAddFunctionTable(&record->runtime_function, 1, ++ CHECK(::RtlAddFunctionTable(record->runtime_function, ++ kDefaultRuntimeFunctionCount, + reinterpret_cast(start))); + + // Protect reserved page against modifications. + DWORD old_protect; +- CHECK(VirtualProtect(start, sizeof(CodeRangeUnwindingRecord), ++ CHECK(VirtualProtect(start, sizeof(ExceptionHandlerRecord), + PAGE_EXECUTE_READ, &old_protect)); + } ++#endif // V8_OS_WIN_X64 + } else { + CodeRangeUnwindingRecord* record = new (start) CodeRangeUnwindingRecord(); + InitUnwindingRecord(record, size_in_bytes); + + CHECK(AddGrowableFunctionTable( +- &record->dynamic_table, &record->runtime_function, 1, 1, ++ &record->dynamic_table, record->runtime_function, ++ record->runtime_function_count, record->runtime_function_count, + reinterpret_cast(start), + reinterpret_cast(reinterpret_cast(start) + + size_in_bytes))); +@@ -264,11 +473,15 @@ void UnregisterNonABICompliantCodeRange(void* start) { + DCHECK(CanRegisterUnwindInfoForNonABICompliantCodeRange()); + + if (RegisterUnwindInfoForExceptionHandlingOnly()) { ++#if defined(V8_OS_WIN_X64) ++ // Windows ARM64 starts since 1709 Windows build, no need to have exception ++ // handling only unwind info for compatibility. + if (unhandled_exception_callback_g) { + ExceptionHandlerRecord* record = + reinterpret_cast(start); +- CHECK(::RtlDeleteFunctionTable(&record->runtime_function)); ++ CHECK(::RtlDeleteFunctionTable(record->runtime_function)); + } ++#endif // V8_OS_WIN_X64 + } else { + CodeRangeUnwindingRecord* record = + reinterpret_cast(start); +@@ -278,19 +491,41 @@ void UnregisterNonABICompliantCodeRange(void* start) { + } + } + ++#if defined(V8_OS_WIN_X64) ++ + void XdataEncoder::onPushRbp() { +- current_push_rbp_offset_ = assembler_.pc_offset() - kPushRbpInstructionLength; ++ current_frame_code_offset_ = ++ assembler_.pc_offset() - kPushRbpInstructionLength; + } + + void XdataEncoder::onMovRbpRsp() { +- if (current_push_rbp_offset_ >= 0 && +- current_push_rbp_offset_ == assembler_.pc_offset() - kRbpPrefixLength) { +- fp_offsets_.push_back(current_push_rbp_offset_); ++ if (current_frame_code_offset_ >= 0 && ++ current_frame_code_offset_ == assembler_.pc_offset() - kRbpPrefixLength) { ++ fp_offsets_.push_back(current_frame_code_offset_); ++ } ++} ++ ++#elif defined(V8_OS_WIN_ARM64) ++ ++void XdataEncoder::onSaveFpLr() { ++ current_frame_code_offset_ = assembler_.pc_offset() - 4; ++ fp_offsets_.push_back(current_frame_code_offset_); ++ fp_adjustments_.push_back(current_frame_adjustment_); ++ if (current_frame_adjustment_ != 0) { ++ current_frame_adjustment_ = 0; + } + } + ++void XdataEncoder::onFramePointerAdjustment(int bytes) { ++ // According to below doc, offset for save_fplr is aligned to pointer size. ++ // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes ++ DCHECK_EQ((bytes & kPointerAlignmentMask), 0); ++ ++ current_frame_adjustment_ = bytes; ++} ++ ++#endif // V8_OS_WIN_X64 ++ + } // namespace win64_unwindinfo + } // namespace internal + } // namespace v8 +- +-#endif // defined(V8_OS_WIN_X64) +diff --git a/src/diagnostics/unwinding-info-win64.h b/src/diagnostics/unwinding-info-win64.h +index f6611e7e2ec5a8afc1769886593f112eb4ad0f89..8f8c9469ebf92c1f81af8364486cd45f4778b248 100644 +--- a/src/diagnostics/unwinding-info-win64.h ++++ b/src/diagnostics/unwinding-info-win64.h +@@ -9,7 +9,7 @@ + #include "include/v8config.h" + #include "src/common/globals.h" + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + #include "src/base/win32-headers.h" + + namespace v8 { +@@ -21,11 +21,7 @@ namespace win64_unwindinfo { + #define CRASH_HANDLER_FUNCTION_NAME_STRING \ + "CrashForExceptionInNonABICompliantCodeRange" + +-static const int kPushRbpInstructionLength = 1; +-static const int kMovRbpRspInstructionLength = 3; +-static const int kRbpPrefixCodes = 2; +-static const int kRbpPrefixLength = +- kPushRbpInstructionLength + kMovRbpRspInstructionLength; ++static const int kOSPageSize = 4096; + + /** + * Returns true if V8 is configured to emit unwinding data for embedded in the +@@ -50,15 +46,33 @@ bool CanRegisterUnwindInfoForNonABICompliantCodeRange(); + void SetUnhandledExceptionCallback( + v8::UnhandledExceptionCallback unhandled_exception_callback); + ++void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes); ++void UnregisterNonABICompliantCodeRange(void* start); ++ + /** +- * Returns a vector of bytes that contains the Win64 unwind data used for all ++ * Default count of RUNTIME_FUNCTION needed. For Windows X64, 1 RUNTIME_FUNCTION ++ * covers 4GB range which is sufficient to cover the whole code range of an ++ * isolate or WASM module. For Windows ARM64, 1 RUNTIME_FUNCTION covers ++ * kMaxFunctionLength bytes so multiple RUNTIME_FUNCTION structs could be needed ++ * to cover the whole code range of an isolate or WASM module. The extra ++ * RUNTIME_FUNCTIONs are assumed following the first one in the reserved page. ++ */ ++static const uint32_t kDefaultRuntimeFunctionCount = 1; ++ ++#if defined(V8_OS_WIN_X64) ++ ++static const int kPushRbpInstructionLength = 1; ++static const int kMovRbpRspInstructionLength = 3; ++static const int kRbpPrefixCodes = 2; ++static const int kRbpPrefixLength = ++ kPushRbpInstructionLength + kMovRbpRspInstructionLength; ++ ++/** ++ * Returns a vector of bytes that contains the Win X64 unwind data used for all + * V8 builtin functions. + */ + std::vector GetUnwindInfoForBuiltinFunctions(); + +-void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes); +-void UnregisterNonABICompliantCodeRange(void* start); +- + class BuiltinUnwindInfo { + public: + BuiltinUnwindInfo() : is_leaf_function_(true) {} +@@ -76,7 +90,7 @@ class BuiltinUnwindInfo { + class XdataEncoder { + public: + explicit XdataEncoder(const Assembler& assembler) +- : assembler_(assembler), current_push_rbp_offset_(-1) {} ++ : assembler_(assembler), current_frame_code_offset_(-1) {} + + void onPushRbp(); + void onMovRbpRsp(); +@@ -88,14 +102,77 @@ class XdataEncoder { + private: + const Assembler& assembler_; + std::vector fp_offsets_; +- int current_push_rbp_offset_; ++ int current_frame_code_offset_; + }; + +-} // namespace win64_unwindinfo ++#elif defined(V8_OS_WIN_ARM64) + ++/** ++ * Base on below doc, unwind record has 18 bits (unsigned) to encode function ++ * length, besides 2 LSB which are always 0. ++ * https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records ++ */ ++static const int kMaxFunctionLength = ((1 << 18) - 1) << 2; ++ ++/** ++ * Returns a vector of bytes that contains the Win ARM64 unwind data used for ++ * all V8 builtin functions. ++ * ++ * func_len: length in bytes of current function/region to unwind. ++ * fp_adjustment: offset of the saved caller's fp based on fp in current frame. ++ * this is necessary to encode unwind data for Windows stack ++ * unwinder to find correct caller's fp. ++ */ ++std::vector GetUnwindInfoForBuiltinFunction(uint32_t func_len, ++ int32_t fp_adjustment); ++class BuiltinUnwindInfo { ++ public: ++ BuiltinUnwindInfo() : is_leaf_function_(true) {} ++ explicit BuiltinUnwindInfo(const std::vector& fp_offsets, ++ const std::vector& fp_adjustments) ++ : is_leaf_function_(false), ++ fp_offsets_(fp_offsets), ++ fp_adjustments_(fp_adjustments) {} ++ ++ const std::vector& fp_adjustments() const { return fp_adjustments_; } ++ ++ bool is_leaf_function() const { return is_leaf_function_; } ++ const std::vector& fp_offsets() const { return fp_offsets_; } ++ ++ private: ++ bool is_leaf_function_; ++ std::vector fp_offsets_; ++ std::vector fp_adjustments_; ++}; ++ ++class XdataEncoder { ++ public: ++ explicit XdataEncoder(const Assembler& assembler) ++ : assembler_(assembler), ++ current_frame_code_offset_(-1), ++ current_frame_adjustment_(0) {} ++ ++ void onSaveFpLr(); ++ void onFramePointerAdjustment(int bytes); ++ ++ BuiltinUnwindInfo unwinding_info() const { ++ return BuiltinUnwindInfo(fp_offsets_, fp_adjustments_); ++ } ++ ++ private: ++ const Assembler& assembler_; ++ std::vector fp_offsets_; ++ int current_frame_code_offset_; ++ int current_frame_adjustment_; ++ std::vector fp_adjustments_; ++}; ++ ++#endif ++ ++} // namespace win64_unwindinfo + } // namespace internal + } // namespace v8 + +-#endif // defined(V8_OS_WIN_X64) ++#endif // V8_OS_WIN64 + + #endif // V8_DIAGNOSTICS_UNWINDING_INFO_WIN64_H_ +diff --git a/src/execution/isolate.cc b/src/execution/isolate.cc +index 8a8db12ca3f59577436d148bb2693c836720af2d..380131730c7e87eced53d7a4d68d328cc9b01b8a 100644 +--- a/src/execution/isolate.cc ++++ b/src/execution/isolate.cc +@@ -85,9 +85,9 @@ + #include "unicode/uobject.h" + #endif // V8_INTL_SUPPORT + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + #include "src/diagnostics/unwinding-info-win64.h" +-#endif ++#endif // V8_OS_WIN64 + + extern "C" const uint8_t* v8_Default_embedded_blob_; + extern "C" uint32_t v8_Default_embedded_blob_size_; +@@ -2935,7 +2935,7 @@ void Isolate::Deinit() { + heap_profiler()->StopSamplingHeapProfiler(); + } + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + if (win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange() && + heap()->memory_allocator()) { + const base::AddressRegion& code_range = +@@ -2943,7 +2943,7 @@ void Isolate::Deinit() { + void* start = reinterpret_cast(code_range.begin()); + win64_unwindinfo::UnregisterNonABICompliantCodeRange(start); + } +-#endif ++#endif // V8_OS_WIN64 + + debug()->Unload(); + +@@ -3512,7 +3512,7 @@ bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer, + sampling_flags); + } + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + if (win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange()) { + const base::AddressRegion& code_range = + heap()->memory_allocator()->code_range(); +@@ -3520,7 +3520,7 @@ bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer, + size_t size_in_bytes = code_range.size(); + win64_unwindinfo::RegisterNonABICompliantCodeRange(start, size_in_bytes); + } +-#endif ++#endif // V8_OS_WIN64 + + if (create_heap_objects && FLAG_profile_deserialization) { + double ms = timer.Elapsed().InMillisecondsF(); +@@ -4324,7 +4324,7 @@ void Isolate::PrepareBuiltinSourcePositionMap() { + } + } + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + void Isolate::SetBuiltinUnwindData( + int builtin_index, + const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) { +@@ -4332,7 +4332,7 @@ void Isolate::SetBuiltinUnwindData( + embedded_file_writer_->SetBuiltinUnwindData(builtin_index, unwinding_info); + } + } +-#endif ++#endif // V8_OS_WIN64 + + void Isolate::SetPrepareStackTraceCallback(PrepareStackTraceCallback callback) { + prepare_stack_trace_callback_ = callback; +diff --git a/src/execution/isolate.h b/src/execution/isolate.h +index 4b4bf9cd7c61687b0f36da1eaa672979c59dab67..33e43c81113ea88d611aa134edc82c2e6d06cfde 100644 +--- a/src/execution/isolate.h ++++ b/src/execution/isolate.h +@@ -1484,11 +1484,11 @@ class Isolate final : private HiddenFactory { + // annotate the builtin blob with debugging information. + void PrepareBuiltinSourcePositionMap(); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + void SetBuiltinUnwindData( + int builtin_index, + const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info); +-#endif ++#endif // V8_OS_WIN64 + + void SetPrepareStackTraceCallback(PrepareStackTraceCallback callback); + MaybeHandle RunPrepareStackTraceCallback(Handle, +diff --git a/src/snapshot/embedded/embedded-file-writer.cc b/src/snapshot/embedded/embedded-file-writer.cc +index 4703ef48224f9f155ef2f8f0cd47507968a3fdfe..5f57993fc3255a68ce6ebcc2368b1c02b1953eff 100644 +--- a/src/snapshot/embedded/embedded-file-writer.cc ++++ b/src/snapshot/embedded/embedded-file-writer.cc +@@ -92,7 +92,7 @@ void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w, + w->Newline(); + } + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + { + i::EmbeddedVector unwind_info_symbol; + i::SNPrintF(unwind_info_symbol, "%s_Builtins_UnwindInfo", +@@ -102,7 +102,7 @@ void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w, + EmbeddedBlobDataSymbol().c_str(), blob, + reinterpret_cast(&unwind_infos_[0])); + } +-#endif ++#endif // V8_OS_WIN64 + + w->FileEpilogue(); + } +diff --git a/src/snapshot/embedded/embedded-file-writer.h b/src/snapshot/embedded/embedded-file-writer.h +index c26465ae6a7d26b799ad2582784973638fbd41cd..e487b9be9bcc77e97d2da6109e1218f3fee69ce4 100644 +--- a/src/snapshot/embedded/embedded-file-writer.h ++++ b/src/snapshot/embedded/embedded-file-writer.h +@@ -13,9 +13,9 @@ + #include "src/snapshot/embedded/embedded-data.h" + #include "src/snapshot/embedded/platform-embedded-file-writer-base.h" + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + #include "src/diagnostics/unwinding-info-win64.h" +-#endif ++#endif // V8_OS_WIN64 + + namespace v8 { + namespace internal { +@@ -35,11 +35,11 @@ class EmbeddedFileWriterInterface { + // compiled builtin Code objects with trampolines. + virtual void PrepareBuiltinSourcePositionMap(Builtins* builtins) = 0; + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + virtual void SetBuiltinUnwindData( + int builtin_index, + const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) = 0; +-#endif ++#endif // V8_OS_WIN64 + }; + + // Generates the embedded.S file which is later compiled into the final v8 +@@ -59,14 +59,14 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { + + void PrepareBuiltinSourcePositionMap(Builtins* builtins) override; + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + void SetBuiltinUnwindData( + int builtin_index, + const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) override { + DCHECK_LT(builtin_index, Builtins::builtin_count); + unwind_infos_[builtin_index] = unwinding_info; + } +-#endif ++#endif // V8_OS_WIN64 + + void SetEmbeddedFile(const char* embedded_src_path) { + embedded_src_path_ = embedded_src_path; +@@ -172,9 +172,6 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { + const i::EmbeddedData* blob) const; + + #if defined(V8_OS_WIN_X64) +- std::string BuiltinsUnwindInfoLabel() const; +- void WriteUnwindInfo(PlatformEmbeddedFileWriterBase* w, +- const i::EmbeddedData* blob) const; + void WriteUnwindInfoEntry(PlatformEmbeddedFileWriterBase* w, + uint64_t rva_start, uint64_t rva_end) const; + #endif +@@ -194,9 +191,9 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { + private: + std::vector source_positions_[Builtins::builtin_count]; + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + win64_unwindinfo::BuiltinUnwindInfo unwind_infos_[Builtins::builtin_count]; +-#endif ++#endif // V8_OS_WIN64 + + std::map external_filenames_; + std::vector external_filenames_by_index_; +diff --git a/src/snapshot/embedded/platform-embedded-file-writer-win.cc b/src/snapshot/embedded/platform-embedded-file-writer-win.cc +index 69457e11a5537a6500b20adb43051e25f645403f..9a9a26fbd0abef6f5b1967cdbd5fe3fcbaef4f20 100644 +--- a/src/snapshot/embedded/platform-embedded-file-writer-win.cc ++++ b/src/snapshot/embedded/platform-embedded-file-writer-win.cc +@@ -6,13 +6,14 @@ + + #include + +-#include "src/common/globals.h" // For V8_OS_WIN_X64. ++#include "src/common/globals.h" // For V8_OS_WIN64 + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + #include "src/builtins/builtins.h" + #include "src/diagnostics/unwinding-info-win64.h" + #include "src/snapshot/embedded/embedded-data.h" +-#endif ++#include "src/snapshot/embedded/embedded-file-writer.h" ++#endif // V8_OS_WIN64 + + namespace v8 { + namespace internal { +@@ -213,20 +214,118 @@ void EmitUnwindData(PlatformEmbeddedFileWriterWin* w, + w->EndPdataSection(); + w->Newline(); + } +-#endif // defined(V8_OS_WIN_X64) ++ ++#elif defined(V8_OS_WIN_ARM64) ++ ++void EmitUnwindData(PlatformEmbeddedFileWriterWin* w, ++ const char* unwind_info_symbol, ++ const char* embedded_blob_data_symbol, ++ const EmbeddedData* blob, ++ const win64_unwindinfo::BuiltinUnwindInfo* unwind_infos) { ++ DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins()); ++ ++ // Fairly arbitrary but should fit all symbol names. ++ static constexpr int kTemporaryStringLength = 256; ++ i::EmbeddedVector unwind_info_full_symbol; ++ ++ // Emit a RUNTIME_FUNCTION (PDATA) entry for each builtin function, as ++ // documented here: ++ // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling. ++ w->Comment( ++ "pdata for all the code in the embedded blob (structs of type " ++ "RUNTIME_FUNCTION)."); ++ w->Comment(" BeginAddress"); ++ w->Comment(" UnwindInfoAddress"); ++ w->StartPdataSection(); ++ std::vector code_chunks; ++ std::vector fp_adjustments; ++ ++ for (int i = 0; i < Builtins::builtin_count; i++) { ++ if (!blob->ContainsBuiltin(i)) continue; ++ if (unwind_infos[i].is_leaf_function()) continue; ++ ++ uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(i) - ++ reinterpret_cast
(blob->data()); ++ uint32_t builtin_size = blob->InstructionSizeOfBuiltin(i); ++ ++ const std::vector& xdata_desc = unwind_infos[i].fp_offsets(); ++ const std::vector& xdata_fp_adjustments = ++ unwind_infos[i].fp_adjustments(); ++ DCHECK_EQ(xdata_desc.size(), xdata_fp_adjustments.size()); ++ ++ for (size_t j = 0; j < xdata_desc.size(); j++) { ++ int chunk_start = xdata_desc[j]; ++ int chunk_end = ++ (j < xdata_desc.size() - 1) ? xdata_desc[j + 1] : builtin_size; ++ int chunk_len = ::RoundUp(chunk_end - chunk_start, kInstrSize); ++ ++ while (chunk_len > 0) { ++ int allowed_chunk_len = ++ std::min(chunk_len, win64_unwindinfo::kMaxFunctionLength); ++ chunk_len -= win64_unwindinfo::kMaxFunctionLength; ++ ++ // Record the chunk length and fp_adjustment for emitting UNWIND_INFO ++ // later. ++ code_chunks.push_back(allowed_chunk_len); ++ fp_adjustments.push_back(xdata_fp_adjustments[j]); ++ i::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol, ++ code_chunks.size()); ++ w->DeclareRvaToSymbol(embedded_blob_data_symbol, ++ builtin_start_offset + chunk_start); ++ w->DeclareRvaToSymbol(unwind_info_full_symbol.begin()); ++ } ++ } ++ } ++ w->EndPdataSection(); ++ w->Newline(); ++ ++ // Emit an UNWIND_INFO (XDATA) structs, which contains the unwinding ++ // information. ++ w->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING); ++ w->StartXdataSection(); ++ { ++ for (size_t i = 0; i < code_chunks.size(); i++) { ++ i::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol, i + 1); ++ w->DeclareLabel(unwind_info_full_symbol.begin()); ++ std::vector xdata = ++ win64_unwindinfo::GetUnwindInfoForBuiltinFunction(code_chunks[i], ++ fp_adjustments[i]); ++ ++ w->IndentedDataDirective(kByte); ++ for (size_t j = 0; j < xdata.size(); j++) { ++ if (j > 0) fprintf(w->fp(), ","); ++ w->HexLiteral(xdata[j]); ++ } ++ w->Newline(); ++ w->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING); ++ } ++ } ++ w->EndXdataSection(); ++ w->Newline(); ++} ++ ++#endif // V8_OS_WIN_X64 + + } // namespace + + void PlatformEmbeddedFileWriterWin::MaybeEmitUnwindData( + const char* unwind_info_symbol, const char* embedded_blob_data_symbol, + const EmbeddedData* blob, const void* unwind_infos) { +-#if defined(V8_OS_WIN_X64) ++// Windows ARM64 supports cross build which could require unwind info for ++// host_os. Ignore this case because it is only used in build time. ++#if defined(V8_OS_WIN_ARM64) ++ if (target_arch_ != EmbeddedTargetArch::kArm64) { ++ return; ++ } ++#endif // V8_OS_WIN_ARM64 ++ ++#if defined(V8_OS_WIN64) + if (win64_unwindinfo::CanEmitUnwindInfoForBuiltins()) { + EmitUnwindData(this, unwind_info_symbol, embedded_blob_data_symbol, blob, + reinterpret_cast( + unwind_infos)); + } +-#endif // defined(V8_OS_WIN_X64) ++#endif // V8_OS_WIN64 + } + + // Windows, MSVC, not arm/arm64. +@@ -544,6 +643,7 @@ void PlatformEmbeddedFileWriterWin::DeclareFunctionBegin(const char* name) { + if (target_arch_ == EmbeddedTargetArch::kArm64) { + // Windows ARM64 assembly is in GAS syntax, but ".type" is invalid directive + // in PE/COFF for Windows. ++ DeclareSymbolGlobal(name); + } else { + // The directives for inserting debugging information on Windows come + // from the PE (Portable Executable) and COFF (Common Object File Format) +diff --git a/src/wasm/wasm-code-manager.cc b/src/wasm/wasm-code-manager.cc +index 2eddce3d956ffcfbf5c668d5eb6e778c66959e45..9be2e75c3e9ed7bfbf31dd7cbbe9c4a634b0abc4 100644 +--- a/src/wasm/wasm-code-manager.cc ++++ b/src/wasm/wasm-code-manager.cc +@@ -29,9 +29,9 @@ + #include "src/wasm/wasm-objects-inl.h" + #include "src/wasm/wasm-objects.h" + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + #include "src/diagnostics/unwinding-info-win64.h" +-#endif ++#endif // V8_OS_WIN64 + + #define TRACE_HEAP(...) \ + do { \ +@@ -630,7 +630,7 @@ NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled, + CompilationState::New(*shared_this, std::move(async_counters)); + DCHECK_NOT_NULL(module_); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + // On some platforms, specifically Win64, we need to reserve some pages at + // the beginning of an executable space. + // See src/heap/spaces.cc, MemoryAllocator::InitializeCodePageAllocator() and +@@ -640,7 +640,7 @@ NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled, + ->CanRegisterUnwindInfoForNonABICompliantCodeRange()) { + code_allocator_.AllocateForCode(this, Heap::GetCodeRangeReservedAreaSize()); + } +-#endif ++#endif // V8_OS_WIN64 + + uint32_t num_wasm_functions = module_->num_declared_functions; + if (num_wasm_functions > 0) { +@@ -1159,21 +1159,21 @@ WasmCodeManager::WasmCodeManager(WasmMemoryTracker* memory_tracker, + size_t max_committed) + : memory_tracker_(memory_tracker), + max_committed_code_space_(max_committed), +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + is_win64_unwind_info_disabled_for_testing_(false), +-#endif ++#endif // V8_OS_WIN64 + total_committed_code_space_(0), + critical_committed_code_space_(max_committed / 2) { + DCHECK_LE(max_committed, kMaxWasmCodeMemory); + } + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + bool WasmCodeManager::CanRegisterUnwindInfoForNonABICompliantCodeRange() const { + return win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange() && + FLAG_win64_unwinding_info && + !is_win64_unwind_info_disabled_for_testing_; + } +-#endif ++#endif // V8_OS_WIN64 + + bool WasmCodeManager::Commit(base::AddressRegion region) { + // TODO(v8:8462): Remove eager commit once perf supports remapping. +@@ -1341,12 +1341,12 @@ std::shared_ptr WasmCodeManager::NewNativeModule( + TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", ret.get(), start, + size); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + if (CanRegisterUnwindInfoForNonABICompliantCodeRange()) { + win64_unwindinfo::RegisterNonABICompliantCodeRange( + reinterpret_cast(start), size); + } +-#endif ++#endif // V8_OS_WIN64 + + base::MutexGuard lock(&native_modules_mutex_); + lookup_map_.insert(std::make_pair(start, std::make_pair(end, ret.get()))); +@@ -1460,12 +1460,12 @@ void WasmCodeManager::FreeNativeModule(Vector owned_code_space, + TRACE_HEAP("VMem Release: 0x%" PRIxPTR ":0x%" PRIxPTR " (%zu)\n", + code_space.address(), code_space.end(), code_space.size()); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + if (CanRegisterUnwindInfoForNonABICompliantCodeRange()) { + win64_unwindinfo::UnregisterNonABICompliantCodeRange( + reinterpret_cast(code_space.address())); + } +-#endif ++#endif // V8_OS_WIN64 + + lookup_map_.erase(code_space.address()); + memory_tracker_->ReleaseReservation(code_space.size()); +diff --git a/src/wasm/wasm-code-manager.h b/src/wasm/wasm-code-manager.h +index 49c287df2c8efa718e2599206e069c26fc03b255..1fd00743996acae7b6c84517baa512e15bc32386 100644 +--- a/src/wasm/wasm-code-manager.h ++++ b/src/wasm/wasm-code-manager.h +@@ -605,9 +605,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final { + } + #endif + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + bool CanRegisterUnwindInfoForNonABICompliantCodeRange() const; +-#endif ++#endif // V8_OS_WIN64 + + NativeModule* LookupNativeModule(Address pc) const; + WasmCode* LookupCode(Address pc) const; +@@ -617,11 +617,11 @@ class V8_EXPORT_PRIVATE WasmCodeManager final { + + void SetMaxCommittedMemoryForTesting(size_t limit); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + void DisableWin64UnwindInfoForTesting() { + is_win64_unwind_info_disabled_for_testing_ = true; + } +-#endif ++#endif // V8_OS_WIN64 + + static size_t EstimateNativeModuleCodeSize(const WasmModule* module); + static size_t EstimateNativeModuleNonCodeSize(const WasmModule* module); +@@ -649,9 +649,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final { + + size_t max_committed_code_space_; + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + bool is_win64_unwind_info_disabled_for_testing_; +-#endif ++#endif // V8_OS_WIN64 + + std::atomic total_committed_code_space_; + // If the committed code space exceeds {critical_committed_code_space_}, then +diff --git a/test/cctest/BUILD.gn b/test/cctest/BUILD.gn +index 42396087eedd844b07f8ca842ce1a0c17d8a94f7..f2d5693793da6d45593b3f18712e959fcac8eecf 100644 +--- a/test/cctest/BUILD.gn ++++ b/test/cctest/BUILD.gn +@@ -310,6 +310,9 @@ v8_source_set("cctest_sources") { + "test-utils-arm64.cc", + "test-utils-arm64.h", + ] ++ if (is_win) { ++ sources += [ "test-stack-unwinding-win64.cc" ] ++ } + } else if (v8_current_cpu == "x86") { + sources += [ ### gcmole(arch:ia32) ### + "test-assembler-ia32.cc", +@@ -348,7 +351,7 @@ v8_source_set("cctest_sources") { + "test-macro-assembler-x64.cc", + ] + if (is_win) { +- sources += [ "test-stack-unwinding-x64.cc" ] ++ sources += [ "test-stack-unwinding-win64.cc" ] + } + } else if (v8_current_cpu == "ppc" || v8_current_cpu == "ppc64") { + sources += [ ### gcmole(arch:ppc) ### +diff --git a/test/cctest/test-stack-unwinding-x64.cc b/test/cctest/test-stack-unwinding-win64.cc +similarity index 76% +rename from test/cctest/test-stack-unwinding-x64.cc +rename to test/cctest/test-stack-unwinding-win64.cc +index 583e14111ad676cf7cb9984407ca9cd0bf9f5f7c..84f1318a29525ae5c71275ecaa6096dfaabcc90c 100644 +--- a/test/cctest/test-stack-unwinding-x64.cc ++++ b/test/cctest/test-stack-unwinding-win64.cc +@@ -6,9 +6,15 @@ + #include "src/init/v8.h" + #include "test/cctest/cctest.h" + +-class UnwindingWinX64Callbacks { ++#if defined(V8_OS_WIN_X64) ++#define CONTEXT_PC(context) (context.Rip) ++#elif defined(V8_OS_WIN_ARM64) ++#define CONTEXT_PC(context) (context.Pc) ++#endif ++ ++class UnwindingWin64Callbacks { + public: +- UnwindingWinX64Callbacks() = default; ++ UnwindingWin64Callbacks() = default; + + static void Getter(v8::Local name, + const v8::PropertyCallbackInfo& info) { +@@ -31,25 +37,26 @@ class UnwindingWinX64Callbacks { + int iframe = 0; + while (++iframe < max_frames) { + uint64_t image_base; +- PRUNTIME_FUNCTION function_entry = +- ::RtlLookupFunctionEntry(context_record.Rip, &image_base, nullptr); ++ PRUNTIME_FUNCTION function_entry = ::RtlLookupFunctionEntry( ++ CONTEXT_PC(context_record), &image_base, nullptr); + if (!function_entry) break; + + void* handler_data; + uint64_t establisher_frame; +- ::RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, context_record.Rip, +- function_entry, &context_record, &handler_data, +- &establisher_frame, NULL); ++ ::RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, ++ CONTEXT_PC(context_record), function_entry, ++ &context_record, &handler_data, &establisher_frame, ++ NULL); + } + return iframe; + } + }; + +-// Verifies that stack unwinding data has been correctly registered on Win/x64. +-UNINITIALIZED_TEST(StackUnwindingWinX64) { ++// Verifies that stack unwinding data has been correctly registered on Win64. ++UNINITIALIZED_TEST(StackUnwindingWin64) { + #ifdef V8_WIN64_UNWINDING_INFO + +- static const char* unwinding_win_x64_test_source = ++ static const char* unwinding_win64_test_source = + "function start(count) {\n" + " for (var i = 0; i < count; i++) {\n" + " var o = instance.foo;\n" +@@ -79,18 +86,18 @@ UNINITIALIZED_TEST(StackUnwindingWinX64) { + v8::Local instance_template = + func_template->InstanceTemplate(); + +- UnwindingWinX64Callbacks accessors; ++ UnwindingWin64Callbacks accessors; + v8::Local data = v8::External::New(isolate, &accessors); + instance_template->SetAccessor(v8_str("foo"), +- &UnwindingWinX64Callbacks::Getter, +- &UnwindingWinX64Callbacks::Setter, data); ++ &UnwindingWin64Callbacks::Getter, ++ &UnwindingWin64Callbacks::Setter, data); + v8::Local func = + func_template->GetFunction(env.local()).ToLocalChecked(); + v8::Local instance = + func->NewInstance(env.local()).ToLocalChecked(); + env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust(); + +- CompileRun(unwinding_win_x64_test_source); ++ CompileRun(unwinding_win64_test_source); + v8::Local function = v8::Local::Cast( + env->Global()->Get(env.local(), v8_str("start")).ToLocalChecked()); + +@@ -106,3 +113,5 @@ UNINITIALIZED_TEST(StackUnwindingWinX64) { + + #endif // V8_WIN64_UNWINDING_INFO + } ++ ++#undef CONTEXT_PC