9a2234461a
Attempting to use the native definition when available causes problems when cross-compiling, and the original attempts to avoid this broke in subtle ways. Instead, just make a non-native definition that mimics the native definition and use that with reinterpret_casts when sending uses of the non-native definition to Windows API calls that expect a value of the native definition. TEST=windows ci Fixes: https://github.com/dart-lang/sdk/issues/60771 Change-Id: I347fcaf8cccd809a3d8e6f041cc7e360b0b8226e Cq-Include-Trybots: luci.dart.try:vm-aot-win-release-arm64-try,vm-aot-win-release-x64-try,vm-win-release-arm64-try,vm-win-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64-try,pkg-win-release-try,pkg-win-release-arm64-try,dart-sdk-win-try,dart-sdk-win-arm64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/430400 Reviewed-by: Slava Egorov <vegorov@google.com>
145 lines
6.2 KiB
C++
145 lines
6.2 KiB
C++
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "vm/unwinding_records.h"
|
|
|
|
#include "platform/globals.h"
|
|
|
|
namespace dart {
|
|
|
|
#if defined(NEED_WINDOWS_UNWINDING_RECORDS)
|
|
static void InitUnwindingRecord(intptr_t offset,
|
|
CodeRangeUnwindingRecord* record,
|
|
size_t code_size_in_bytes) {
|
|
#if defined(TARGET_ARCH_X64)
|
|
// All addresses are 32bit relative offsets to start.
|
|
record->runtime_function[0].BeginAddress = 0;
|
|
record->runtime_function[0].EndAddress = code_size_in_bytes;
|
|
record->runtime_function[0].UnwindData =
|
|
offset + offsetof(CodeRangeUnwindingRecord, unwind_info);
|
|
record->runtime_function_count = 1;
|
|
#elif defined(TARGET_ARCH_ARM64)
|
|
|
|
const intptr_t kInstrSize = 4;
|
|
|
|
// 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.
|
|
const uint32_t max_runtime_function_count =
|
|
static_cast<uint32_t>((UnwindingRecordsPlatform::SizeInBytes() -
|
|
sizeof(CodeRangeUnwindingRecord)) /
|
|
sizeof(TargetRuntimeFunction) +
|
|
kDefaultRuntimeFunctionCount);
|
|
|
|
uint32_t runtime_function_index = 0;
|
|
uint32_t current_unwind_start_address = 0;
|
|
int64_t remaining_size_in_bytes = static_cast<int64_t>(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 =
|
|
offset +
|
|
static_cast<DWORD>(offsetof(CodeRangeUnwindingRecord, 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) {
|
|
ASSERT((remaining_size_in_bytes % kInstrSize) == 0);
|
|
|
|
record->unwind_info1.unwind_info.FunctionLength = static_cast<uint32_t>(
|
|
remaining_size_in_bytes >> kFunctionLengthShiftSize);
|
|
record->runtime_function[runtime_function_index].BeginAddress =
|
|
current_unwind_start_address;
|
|
record->runtime_function[runtime_function_index].UnwindData =
|
|
offset +
|
|
static_cast<DWORD>(offsetof(CodeRangeUnwindingRecord, unwind_info1));
|
|
|
|
remaining_size_in_bytes -= kMaxFunctionLength;
|
|
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.
|
|
ASSERT(remaining_size_in_bytes <= 0);
|
|
#else
|
|
#error Unhandled Windows architecture.
|
|
#endif
|
|
record->magic = kUnwindingRecordMagic;
|
|
}
|
|
#endif // defined(NEED_WINDOWS_UNWINDING_RECORDS)
|
|
|
|
#if defined(UNWINDING_RECORDS_WINDOWS_PRECOMPILER)
|
|
const void* UnwindingRecords::GenerateRecordsInto(intptr_t offset,
|
|
uint8_t* target_buffer) {
|
|
CodeRangeUnwindingRecord* record =
|
|
new (target_buffer) CodeRangeUnwindingRecord();
|
|
InitUnwindingRecord(offset, record, offset);
|
|
return target_buffer;
|
|
}
|
|
#endif // defined(UNWINDING_RECORDS_WINDOWS_PRECOMPILER)
|
|
|
|
#if defined(UNWINDING_RECORDS_WINDOWS_HOST)
|
|
// Special exception-unwinding records are put at the end of executable
|
|
// page on Windows for 64-bit applications.
|
|
void UnwindingRecords::RegisterExecutablePage(Page* page) {
|
|
ASSERT(page->is_executable());
|
|
ASSERT(sizeof(CodeRangeUnwindingRecord) <=
|
|
UnwindingRecordsPlatform::SizeInBytes());
|
|
page->top_ -= UnwindingRecordsPlatform::SizeInBytes();
|
|
intptr_t unwinding_record_offset =
|
|
page->memory_->size() - UnwindingRecordsPlatform::SizeInBytes();
|
|
CodeRangeUnwindingRecord* record =
|
|
new (reinterpret_cast<uint8_t*>(page->memory_->start()) +
|
|
unwinding_record_offset) CodeRangeUnwindingRecord();
|
|
InitUnwindingRecord(unwinding_record_offset, record, page->memory_->size());
|
|
RELEASE_ASSERT(record->magic == kUnwindingRecordMagic);
|
|
DWORD status = RtlAddGrowableFunctionTable(
|
|
/*DynamicTable=*/&record->dynamic_table,
|
|
/*FunctionTable=*/
|
|
reinterpret_cast<PRUNTIME_FUNCTION>(record->runtime_function),
|
|
/*EntryCount=*/record->runtime_function_count,
|
|
/*MaximumEntryCount=*/record->runtime_function_count,
|
|
/*RangeBase=*/page->memory_->start(),
|
|
/*RangeEnd=*/page->memory_->end());
|
|
if (status != 0) {
|
|
FATAL("Failed to add growable function table: 0x%x\n", status);
|
|
}
|
|
}
|
|
|
|
void UnwindingRecords::UnregisterExecutablePage(Page* page) {
|
|
ASSERT(page->is_executable() && !page->is_image());
|
|
intptr_t unwinding_record_offset =
|
|
page->memory_->size() - UnwindingRecordsPlatform::SizeInBytes();
|
|
CodeRangeUnwindingRecord* record =
|
|
reinterpret_cast<CodeRangeUnwindingRecord*>(
|
|
reinterpret_cast<uint8_t*>(page->memory_->start()) +
|
|
unwinding_record_offset);
|
|
RELEASE_ASSERT(record->magic == kUnwindingRecordMagic);
|
|
RtlDeleteGrowableFunctionTable(record->dynamic_table);
|
|
}
|
|
#endif // defined(UNWINDING_RECORDS_WINDOWS_HOST)
|
|
|
|
} // namespace dart
|