v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
unwinding-info-win64.cc
Go to the documentation of this file.
1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
9
10#if defined(V8_OS_WIN_X64)
12#elif defined(V8_OS_WIN_ARM64)
15#else
16#error "Unsupported OS"
17#endif // V8_OS_WIN_X64
18
19#include <windows.h>
20
21// This has to come after windows.h.
22#include <versionhelpers.h> // For IsWindows8OrGreater().
23
24namespace v8 {
25namespace internal {
26namespace win64_unwindinfo {
27
28bool CanEmitUnwindInfoForBuiltins() { return v8_flags.win64_unwinding_info; }
29
33
36#if defined(V8_OS_WIN_ARM64)
37 return !v8_flags.win64_unwinding_info;
38#else
39 return !IsWindows8OrGreater() || !v8_flags.win64_unwinding_info;
40#endif
41}
42
43v8::UnhandledExceptionCallback unhandled_exception_callback_g = nullptr;
44
46 v8::UnhandledExceptionCallback unhandled_exception_callback) {
47 unhandled_exception_callback_g = unhandled_exception_callback;
48}
49
50// This function is registered as exception handler for V8-generated code as
51// part of the registration of unwinding info. It is referenced by
52// RegisterNonABICompliantCodeRange(), below, and by the unwinding info for
53// builtins declared in the embedded blob.
54extern "C" __declspec(dllexport) int CRASH_HANDLER_FUNCTION_NAME(
55 PEXCEPTION_RECORD ExceptionRecord, ULONG64 EstablisherFrame,
56 PCONTEXT ContextRecord, PDISPATCHER_CONTEXT DispatcherContext) {
57 if (unhandled_exception_callback_g != nullptr) {
58 EXCEPTION_POINTERS info = {ExceptionRecord, ContextRecord};
60 }
61 return ExceptionContinueSearch;
62}
63
64#if defined(V8_OS_WIN_X64)
65
66#pragma pack(push, 1)
67
68/*
69 * From Windows SDK ehdata.h, which does not compile with Clang.
70 * See https://msdn.microsoft.com/en-us/library/ddssxxy8.aspx.
71 */
72union UNWIND_CODE {
73 struct {
74 unsigned char CodeOffset;
75 unsigned char UnwindOp : 4;
76 unsigned char OpInfo : 4;
77 };
78 uint16_t FrameOffset;
79};
80
81struct UNWIND_INFO {
82 unsigned char Version : 3;
83 unsigned char Flags : 5;
84 unsigned char SizeOfProlog;
85 unsigned char CountOfCodes;
86 unsigned char FrameRegister : 4;
87 unsigned char FrameOffset : 4;
88};
89
90static constexpr int kNumberOfUnwindCodes = 2;
91static constexpr int kMaxExceptionThunkSize = 12;
92
93struct V8UnwindData {
94 UNWIND_INFO unwind_info;
95 UNWIND_CODE unwind_codes[kNumberOfUnwindCodes];
96
97 V8UnwindData() {
98 static constexpr int kOpPushNonvol = 0;
99 static constexpr int kOpSetFPReg = 3;
100
101 unwind_info.Version = 1;
102 unwind_info.Flags = UNW_FLAG_EHANDLER;
103 unwind_info.SizeOfProlog = kRbpPrefixLength;
104 unwind_info.CountOfCodes = kRbpPrefixCodes;
105 unwind_info.FrameRegister = rbp.code();
106 unwind_info.FrameOffset = 0;
107
108 unwind_codes[0].CodeOffset = kRbpPrefixLength; // movq rbp, rsp
109 unwind_codes[0].UnwindOp = kOpSetFPReg;
110 unwind_codes[0].OpInfo = 0;
111
112 unwind_codes[1].CodeOffset = kPushRbpInstructionLength; // push rbp
113 unwind_codes[1].UnwindOp = kOpPushNonvol;
114 unwind_codes[1].OpInfo = rbp.code();
115 }
116};
117
118struct ExceptionHandlerUnwindData {
119 UNWIND_INFO unwind_info;
120
121 ExceptionHandlerUnwindData() {
122 unwind_info.Version = 1;
123 unwind_info.Flags = UNW_FLAG_EHANDLER;
124 unwind_info.SizeOfProlog = 0;
125 unwind_info.CountOfCodes = 0;
126 unwind_info.FrameRegister = 0;
127 unwind_info.FrameOffset = 0;
128 }
129};
130
131struct CodeRangeUnwindingRecord {
132 void* dynamic_table;
133 uint32_t runtime_function_count;
134 V8UnwindData unwind_info;
135 uint32_t exception_handler;
136 uint8_t exception_thunk[kMaxExceptionThunkSize];
137 RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount];
138};
139
140struct ExceptionHandlerRecord {
141 uint32_t runtime_function_count;
142 RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount];
143 ExceptionHandlerUnwindData unwind_info;
144 uint32_t exception_handler;
145 uint8_t exception_thunk[kMaxExceptionThunkSize];
146};
147
148#pragma pack(pop)
149
150std::vector<uint8_t> GetUnwindInfoForBuiltinFunctions() {
151 V8UnwindData xdata;
152 return std::vector<uint8_t>(
153 reinterpret_cast<uint8_t*>(&xdata),
154 reinterpret_cast<uint8_t*>(&xdata) + sizeof(xdata));
155}
156
157template <typename Record>
158void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) {
159 // We assume that the first page of the code range is executable and
160 // committed and reserved to contain PDATA/XDATA.
161
162 // All addresses are 32bit relative offsets to start.
163 record->runtime_function[0].BeginAddress = 0;
164 record->runtime_function[0].EndAddress =
165 static_cast<DWORD>(code_size_in_bytes);
166 record->runtime_function[0].UnwindData = offsetof(Record, unwind_info);
167 record->runtime_function_count = 1;
168 record->exception_handler = offsetof(Record, exception_thunk);
169
170 // Hardcoded thunk.
171 AccountingAllocator allocator;
172 AssemblerOptions options;
173 options.record_reloc_info_for_serialization = false;
174 MacroAssembler masm(&allocator, options, CodeObjectRequired::kNo,
176 masm.movq(rax, reinterpret_cast<uint64_t>(&CRASH_HANDLER_FUNCTION_NAME));
177 masm.jmp(rax);
178 DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk));
179 memcpy(&record->exception_thunk[0], masm.buffer_start(),
180 masm.instruction_size());
181}
182
183#elif defined(V8_OS_WIN_ARM64)
184
185#pragma pack(push, 1)
186
187// ARM64 unwind codes are defined in below doc.
188// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes
189enum UnwindOp8Bit {
190 OpNop = 0xE3,
191 OpAllocS = 0x00,
192 OpSaveFpLr = 0x40,
193 OpSaveFpLrX = 0x80,
194 OpSetFp = 0xE1,
195 OpAddFp = 0xE2,
196 OpEnd = 0xE4,
197};
198
199typedef uint32_t UNWIND_CODE;
200
201constexpr UNWIND_CODE Combine8BitUnwindCodes(uint8_t code0 = OpNop,
202 uint8_t code1 = OpNop,
203 uint8_t code2 = OpNop,
204 uint8_t code3 = OpNop) {
205 return static_cast<uint32_t>(code0) | (static_cast<uint32_t>(code1) << 8) |
206 (static_cast<uint32_t>(code2) << 16) |
207 (static_cast<uint32_t>(code3) << 24);
208}
209
210// UNWIND_INFO defines the static part (first 32-bit) of the .xdata record in
211// below doc.
212// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records
213struct UNWIND_INFO {
214 uint32_t FunctionLength : 18;
215 uint32_t Version : 2;
216 uint32_t X : 1;
217 uint32_t E : 1;
218 uint32_t EpilogCount : 5;
219 uint32_t CodeWords : 5;
220};
221
222static constexpr int kDefaultNumberOfUnwindCodeWords = 1;
223static constexpr int kMaxExceptionThunkSize = 16;
224static constexpr int kFunctionLengthShiftSize = 2;
225static constexpr int kFunctionLengthMask = (1 << kFunctionLengthShiftSize) - 1;
226static constexpr int kAllocStackShiftSize = 4;
227static constexpr int kAllocStackShiftMask = (1 << kAllocStackShiftSize) - 1;
228
229// Generate an unwind code for "stp fp, lr, [sp, #pre_index_offset]!".
230uint8_t MakeOpSaveFpLrX(int pre_index_offset) {
231 // See unwind code save_fplr_x in
232 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes
233 DCHECK_LE(pre_index_offset, -8);
234 DCHECK_GE(pre_index_offset, -512);
235 constexpr int kShiftSize = 3;
236 constexpr int kShiftMask = (1 << kShiftSize) - 1;
237 DCHECK_EQ(pre_index_offset & kShiftMask, 0);
238 USE(kShiftMask);
239 // Solve for Z where -(Z+1)*8 = pre_index_offset.
240 int encoded_value = (-pre_index_offset >> kShiftSize) - 1;
241 return OpSaveFpLrX | encoded_value;
242}
243
244// Generate an unwind code for "sub sp, sp, #stack_space".
245uint8_t MakeOpAllocS(int stack_space) {
246 // See unwind code alloc_s in
247 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes
248 DCHECK_GE(stack_space, 0);
249 DCHECK_LT(stack_space, 512);
250 DCHECK_EQ(stack_space & kAllocStackShiftMask, 0);
251 return OpAllocS | (stack_space >> kAllocStackShiftSize);
252}
253
254// Generate the second byte of the unwind code for "add fp, sp, #offset".
255uint8_t MakeOpAddFpArgument(int offset) {
256 // See unwind code add_fp in
257 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes
258 DCHECK_GE(offset, 0);
259 constexpr int kShiftSize = 3;
260 constexpr int kShiftMask = (1 << kShiftSize) - 1;
261 DCHECK_EQ(offset & kShiftMask, 0);
262 USE(kShiftMask);
263 int encoded_value = offset >> kShiftSize;
264 // Encoded value must fit in 8 bits.
265 DCHECK_LE(encoded_value, 0xff);
266 return encoded_value;
267}
268
269template <int kNumberOfUnwindCodeWords = kDefaultNumberOfUnwindCodeWords>
270struct V8UnwindData {
271 UNWIND_INFO unwind_info;
272 UNWIND_CODE unwind_codes[kNumberOfUnwindCodeWords];
273
274 V8UnwindData() {
275 memset(&unwind_info, 0, sizeof(UNWIND_INFO));
276 unwind_info.X = 1; // has exception handler after unwind-codes.
277 unwind_info.CodeWords = kNumberOfUnwindCodeWords;
278
279 // Generate unwind codes for the following prolog:
280 //
281 // stp fp, lr, [sp, #-kCallerSPOffset]!
282 // mov fp, sp
283 //
284 // This is a very rough approximation of the actual function prologs used in
285 // V8. In particular, we often push other data before the (fp, lr) pair,
286 // meaning the stack pointer computed for the caller frame is wrong. That
287 // error is acceptable when the unwinding info for the caller frame also
288 // depends on fp rather than sp, as is the case for V8 builtins and runtime-
289 // generated code.
290 static_assert(kNumberOfUnwindCodeWords >= 1);
291 unwind_codes[0] = Combine8BitUnwindCodes(
292 OpSetFp, MakeOpSaveFpLrX(-CommonFrameConstants::kCallerSPOffset),
293 OpEnd);
294
295 // Fill the rest with nops.
296 for (int i = 1; i < kNumberOfUnwindCodeWords; ++i) {
297 unwind_codes[i] = Combine8BitUnwindCodes();
298 }
299 }
300};
301
302struct CodeRangeUnwindingRecord {
303 void* dynamic_table;
304 uint32_t runtime_function_count;
305 V8UnwindData<> unwind_info;
306 uint32_t exception_handler;
307
308 // For Windows ARM64 unwinding, register 2 unwind_info for each code range,
309 // unwind_info for all full size ranges (1MB - 4 bytes) and unwind_info1 for
310 // the remaining non full size range. There is at most 1 range which is less
311 // than full size.
312 V8UnwindData<> unwind_info1;
313 uint32_t exception_handler1;
314 uint8_t exception_thunk[kMaxExceptionThunkSize];
315
316 // More RUNTIME_FUNCTION structs could follow below array because the number
317 // of RUNTIME_FUNCTION needed to cover given code range is computed at
318 // runtime.
319 RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount];
320};
321
322#pragma pack(pop)
323
324FrameOffsets::FrameOffsets()
325 : fp_to_saved_caller_fp(CommonFrameConstants::kCallerFPOffset),
326 fp_to_caller_sp(CommonFrameConstants::kCallerSPOffset) {}
327bool FrameOffsets::IsDefault() const {
328 FrameOffsets other;
329 return fp_to_saved_caller_fp == other.fp_to_saved_caller_fp &&
330 fp_to_caller_sp == other.fp_to_caller_sp;
331}
332
333std::vector<uint8_t> GetUnwindInfoForBuiltinFunction(
334 uint32_t func_len, FrameOffsets fp_adjustment) {
335 DCHECK_LE(func_len, kMaxFunctionLength);
336 DCHECK_EQ((func_len & kFunctionLengthMask), 0);
337 USE(kFunctionLengthMask);
338
339 // The largest size of unwind data required for all options below.
340 constexpr int kMaxNumberOfUnwindCodeWords = 2;
341
342 V8UnwindData<kMaxNumberOfUnwindCodeWords> xdata;
343 // FunctionLength is ensured to be aligned at instruction size and Windows
344 // ARM64 doesn't encoding its 2 LSB.
345 xdata.unwind_info.FunctionLength = func_len >> kFunctionLengthShiftSize;
346
347 if (fp_adjustment.IsDefault()) {
348 // One code word is plenty.
349 static_assert(kDefaultNumberOfUnwindCodeWords <
350 kMaxNumberOfUnwindCodeWords);
351 xdata.unwind_info.CodeWords = kDefaultNumberOfUnwindCodeWords;
352 } else {
353 // We want to convey the following facts:
354 // 1. The caller's fp is found at [fp + fp_to_saved_caller_fp].
355 // 2. The caller's pc is found at [fp + fp_to_saved_caller_fp + 8].
356 // 3. The caller's sp is equal to fp + fp_to_caller_sp.
357 //
358 // An imaginary prolog that would establish those relationships might look
359 // like the following, with appropriate values for the various constants:
360 //
361 // stp fp, lr, [sp, #pre_index_amount]!
362 // sub sp, sp, #stack_space
363 // add fp, sp, offset_from_stack_top
364 //
365 // Why do we need offset_from_stack_top? The unwinding encoding for
366 // allocating stack space has 16-byte granularity, and the frame pointer has
367 // only 8-byte alignment.
368 int pre_index_amount =
369 fp_adjustment.fp_to_saved_caller_fp - fp_adjustment.fp_to_caller_sp;
370 int stack_space = fp_adjustment.fp_to_saved_caller_fp;
371 int offset_from_stack_top = stack_space & kAllocStackShiftMask;
372 stack_space += offset_from_stack_top;
373
374 xdata.unwind_codes[0] = Combine8BitUnwindCodes(
375 OpAddFp, MakeOpAddFpArgument(offset_from_stack_top),
376 MakeOpAllocS(stack_space), MakeOpSaveFpLrX(pre_index_amount));
377 xdata.unwind_codes[1] = Combine8BitUnwindCodes(OpEnd);
378 }
379
380 return std::vector<uint8_t>(
381 reinterpret_cast<uint8_t*>(&xdata),
382 reinterpret_cast<uint8_t*>(
383 &xdata.unwind_codes[xdata.unwind_info.CodeWords]));
384}
385
386template <typename Record>
387void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) {
388 // We assume that the first page of the code range is executable and
389 // committed and reserved to contain multiple PDATA/XDATA to cover the whole
390 // range. All addresses are 32bit relative offsets to start.
391
392 // Maximum RUNTIME_FUNCTION count available in reserved memory, this includes
393 // static part in Record as kDefaultRuntimeFunctionCount plus dynamic part in
394 // the remaining reserved memory.
395 constexpr uint32_t max_runtime_function_count = static_cast<uint32_t>(
396 (kOSPageSize - sizeof(Record)) / sizeof(RUNTIME_FUNCTION) +
397 kDefaultRuntimeFunctionCount);
398
399 uint32_t runtime_function_index = 0;
400 uint32_t current_unwind_start_address = 0;
401 int64_t remaining_size_in_bytes = static_cast<int64_t>(code_size_in_bytes);
402
403 // Divide the code range into chunks in size kMaxFunctionLength and create a
404 // RUNTIME_FUNCTION for each of them. All the chunks in the same size can
405 // share 1 unwind_info struct, but a separate unwind_info is needed for the
406 // last chunk if it is smaller than kMaxFunctionLength, because unlike X64,
407 // unwind_info encodes the function/chunk length.
408 while (remaining_size_in_bytes >= kMaxFunctionLength &&
409 runtime_function_index < max_runtime_function_count) {
410 record->runtime_function[runtime_function_index].BeginAddress =
411 current_unwind_start_address;
412 record->runtime_function[runtime_function_index].UnwindData =
413 static_cast<DWORD>(offsetof(Record, unwind_info));
414
415 runtime_function_index++;
416 current_unwind_start_address += kMaxFunctionLength;
417 remaining_size_in_bytes -= kMaxFunctionLength;
418 }
419 // FunctionLength is ensured to be aligned at instruction size and Windows
420 // ARM64 doesn't encoding 2 LSB.
421 record->unwind_info.unwind_info.FunctionLength = kMaxFunctionLength >> 2;
422
423 if (remaining_size_in_bytes > 0 &&
424 runtime_function_index < max_runtime_function_count) {
425 DCHECK_EQ(remaining_size_in_bytes % kInstrSize, 0);
426
427 record->unwind_info1.unwind_info.FunctionLength = static_cast<uint32_t>(
428 remaining_size_in_bytes >> kFunctionLengthShiftSize);
429 record->runtime_function[runtime_function_index].BeginAddress =
430 current_unwind_start_address;
431 record->runtime_function[runtime_function_index].UnwindData =
432 static_cast<DWORD>(offsetof(Record, unwind_info1));
433
434 remaining_size_in_bytes -= kMaxFunctionLength;
435 record->exception_handler1 = offsetof(Record, exception_thunk);
436 record->runtime_function_count = runtime_function_index + 1;
437 } else {
438 record->runtime_function_count = runtime_function_index;
439 }
440
441 // 1 page can cover kMaximalCodeRangeSize for ARM64 (128MB). If
442 // kMaximalCodeRangeSize is changed for ARM64 and makes 1 page insufficient to
443 // cover it, more pages will need to reserved for unwind data.
444 DCHECK_LE(remaining_size_in_bytes, 0);
445
446 record->exception_handler = offsetof(Record, exception_thunk);
447
448 // Hardcoded thunk.
449 AccountingAllocator allocator;
450 AssemblerOptions options;
451 options.record_reloc_info_for_serialization = false;
452 MacroAssembler masm(&allocator, options, CodeObjectRequired::kNo,
454 masm.Mov(x16,
455 Operand(reinterpret_cast<uint64_t>(&CRASH_HANDLER_FUNCTION_NAME)));
456 masm.Br(x16);
457 DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk));
458 memcpy(&record->exception_thunk[0], masm.buffer_start(),
459 masm.instruction_size());
460}
461
462#endif // V8_OS_WIN_X64
463
464namespace {
465
466V8_DECLARE_ONCE(load_ntdll_unwinding_functions_once);
467static decltype(
468 &::RtlAddGrowableFunctionTable) add_growable_function_table_func = nullptr;
469static decltype(
470 &::RtlDeleteGrowableFunctionTable) delete_growable_function_table_func =
471 nullptr;
472
473void LoadNtdllUnwindingFunctionsOnce() {
474 // Load functions from the ntdll.dll module.
475 HMODULE ntdll_module =
476 LoadLibraryEx(L"ntdll.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
477 DCHECK_NOT_NULL(ntdll_module);
478
479 // This fails on Windows 7.
480 add_growable_function_table_func =
481 reinterpret_cast<decltype(&::RtlAddGrowableFunctionTable)>(
482 ::GetProcAddress(ntdll_module, "RtlAddGrowableFunctionTable"));
483 DCHECK_IMPLIES(IsWindows8OrGreater(), add_growable_function_table_func);
484
485 delete_growable_function_table_func =
486 reinterpret_cast<decltype(&::RtlDeleteGrowableFunctionTable)>(
487 ::GetProcAddress(ntdll_module, "RtlDeleteGrowableFunctionTable"));
488 DCHECK_IMPLIES(IsWindows8OrGreater(), delete_growable_function_table_func);
489}
490
491void LoadNtdllUnwindingFunctions() {
492 base::CallOnce(&load_ntdll_unwinding_functions_once,
493 &LoadNtdllUnwindingFunctionsOnce);
494}
495
496bool AddGrowableFunctionTable(PVOID* DynamicTable,
497 PRUNTIME_FUNCTION FunctionTable, DWORD EntryCount,
498 DWORD MaximumEntryCount, ULONG_PTR RangeBase,
499 ULONG_PTR RangeEnd) {
500 DCHECK(::IsWindows8OrGreater());
501
502 LoadNtdllUnwindingFunctions();
503 DCHECK_NOT_NULL(add_growable_function_table_func);
504
505 *DynamicTable = nullptr;
506 DWORD status =
507 add_growable_function_table_func(DynamicTable, FunctionTable, EntryCount,
508 MaximumEntryCount, RangeBase, RangeEnd);
509 DCHECK((status == 0 && *DynamicTable != nullptr) ||
510 status == 0xC000009A); // STATUS_INSUFFICIENT_RESOURCES
511 return (status == 0);
512}
513
514void DeleteGrowableFunctionTable(PVOID dynamic_table) {
515 DCHECK(::IsWindows8OrGreater());
516
517 LoadNtdllUnwindingFunctions();
518 DCHECK_NOT_NULL(delete_growable_function_table_func);
519
520 delete_growable_function_table_func(dynamic_table);
521}
522
523} // namespace
524
525void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
527
528 // When the --win64-unwinding-info flag is set, we call
529 // RtlAddGrowableFunctionTable to register unwinding info for the whole code
530 // range of an isolate or Wasm module. This enables the Windows OS stack
531 // unwinder to work correctly with V8-generated code, enabling stack walking
532 // in Windows debuggers and performance tools. However, the
533 // RtlAddGrowableFunctionTable API is only supported on Windows 8 and above.
534 //
535 // On Windows 7, or when --win64-unwinding-info is not set, we may still need
536 // to call RtlAddFunctionTable to register a custom exception handler passed
537 // by the embedder (like Crashpad).
538
540#if defined(V8_OS_WIN_X64)
541 // Windows ARM64 starts since 1709 Windows build, no need to have exception
542 // handling only unwind info for compatibility.
544 ExceptionHandlerRecord* record = new (start) ExceptionHandlerRecord();
545 InitUnwindingRecord(record, size_in_bytes);
546
547 CHECK(::RtlAddFunctionTable(record->runtime_function,
548 kDefaultRuntimeFunctionCount,
549 reinterpret_cast<DWORD64>(start)));
550
551 // Protect reserved page against modifications.
552 DWORD old_protect;
553 CHECK(VirtualProtect(start, sizeof(ExceptionHandlerRecord),
554 PAGE_EXECUTE_READ, &old_protect));
555 }
556#endif // V8_OS_WIN_X64
557 } else {
558 CodeRangeUnwindingRecord* record = new (start) CodeRangeUnwindingRecord();
559 InitUnwindingRecord(record, size_in_bytes);
560
561 CHECK(AddGrowableFunctionTable(
562 &record->dynamic_table, record->runtime_function,
563 record->runtime_function_count, record->runtime_function_count,
564 reinterpret_cast<DWORD64>(start),
565 reinterpret_cast<DWORD64>(reinterpret_cast<uint8_t*>(start) +
566 size_in_bytes)));
567
568 // Protect reserved page against modifications.
569 DWORD old_protect;
570 CHECK(VirtualProtect(start, sizeof(CodeRangeUnwindingRecord),
571 PAGE_EXECUTE_READ, &old_protect));
572 }
573}
574
577
579#if defined(V8_OS_WIN_X64)
580 // Windows ARM64 starts since 1709 Windows build, no need to have exception
581 // handling only unwind info for compatibility.
583 ExceptionHandlerRecord* record =
584 reinterpret_cast<ExceptionHandlerRecord*>(start);
585 CHECK(::RtlDeleteFunctionTable(record->runtime_function));
586
587 // Unprotect reserved page.
588 DWORD old_protect;
589 CHECK(VirtualProtect(start, sizeof(ExceptionHandlerRecord),
590 PAGE_READWRITE, &old_protect));
591 }
592#endif // V8_OS_WIN_X64
593 } else {
594 CodeRangeUnwindingRecord* record =
595 reinterpret_cast<CodeRangeUnwindingRecord*>(start);
596 if (record->dynamic_table) {
597 DeleteGrowableFunctionTable(record->dynamic_table);
598 }
599
600 // Unprotect reserved page.
601 DWORD old_protect;
602 CHECK(VirtualProtect(start, sizeof(CodeRangeUnwindingRecord),
603 PAGE_READWRITE, &old_protect));
604 }
605}
606
607#if defined(V8_OS_WIN_X64)
608
609void XdataEncoder::onPushRbp() {
610 current_frame_code_offset_ =
611 assembler_.pc_offset() - kPushRbpInstructionLength;
612}
613
614void XdataEncoder::onMovRbpRsp() {
615 if (current_frame_code_offset_ >= 0 &&
616 current_frame_code_offset_ == assembler_.pc_offset() - kRbpPrefixLength) {
617 fp_offsets_.push_back(current_frame_code_offset_);
618 }
619}
620
621#elif defined(V8_OS_WIN_ARM64)
622
623void XdataEncoder::onSaveFpLr() {
624 current_frame_code_offset_ = assembler_.pc_offset() - 4;
625 fp_offsets_.push_back(current_frame_code_offset_);
626 fp_adjustments_.push_back(current_frame_adjustment_);
627 current_frame_adjustment_ = FrameOffsets();
628}
629
630void XdataEncoder::onFramePointerAdjustment(int fp_to_saved_caller_fp,
631 int fp_to_caller_sp) {
632 current_frame_adjustment_.fp_to_saved_caller_fp = fp_to_saved_caller_fp;
633 current_frame_adjustment_.fp_to_caller_sp = fp_to_caller_sp;
634}
635
636#endif // V8_OS_WIN_X64
637
638} // namespace win64_unwindinfo
639} // namespace internal
640} // namespace v8
int start
#define RUNTIME_FUNCTION(Name)
Definition arguments.h:162
BytecodeAssembler & assembler_
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and X(inclusive) percent " "of the regular marking start limit") DEFINE_INT(stress_scavenge
int32_t offset
DirectHandle< JSReceiver > options
DurationRecord record
void CallOnce(OnceType *once, std::function< void()> init_func)
Definition once.h:90
void RegisterNonABICompliantCodeRange(void *start, size_t size_in_bytes)
void UnregisterNonABICompliantCodeRange(void *start)
v8::UnhandledExceptionCallback unhandled_exception_callback_g
__declspec(dllexport) int CRASH_HANDLER_FUNCTION_NAME(PEXCEPTION_RECORD ExceptionRecord
ULONG64 PCONTEXT PDISPATCHER_CONTEXT DispatcherContext
void SetUnhandledExceptionCallback(v8::UnhandledExceptionCallback unhandled_exception_callback)
constexpr int L
std::unique_ptr< AssemblerBuffer > NewAssemblerBuffer(int size)
Definition assembler.cc:167
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr uint8_t kInstrSize
#define V8_DECLARE_ONCE(NAME)
Definition once.h:72
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
void * PVOID
__w64 unsigned long ULONG_PTR
unsigned long DWORD