[vm] Use a non-native definition of the runtime function structure.
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>
This commit is contained in:
@@ -3,30 +3,30 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "platform/unwinding_records.h"
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
#if !(defined(DART_TARGET_OS_WINDOWS) && defined(TARGET_ARCH_IS_64_BIT) || \
|
||||
defined(DART_HOST_OS_WINDOWS) && defined(ARCH_IS_64_BIT))
|
||||
#if !defined(NEED_WINDOWS_UNWINDING_RECORDS)
|
||||
|
||||
intptr_t UnwindingRecordsPlatform::SizeInBytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // !defined(DART_TARGET_OS_WINDOWS) && !defined(DART_HOST_OS_WINDOWS)
|
||||
#endif // !defined(NEED_WINDOWS_UNWINDING_RECORDS)
|
||||
|
||||
// Also use empty definitions when running gen_snapshot on 64-bit Windows, as it
|
||||
// does not use the ELF loader, which is the client of these methods.
|
||||
#if !defined(DART_HOST_OS_WINDOWS) || !defined(ARCH_IS_64_BIT) || \
|
||||
(defined(DART_PRECOMPILER) && !defined(TESTING))
|
||||
#if !defined(UNWINDING_RECORDS_WINDOWS_HOST)
|
||||
|
||||
void UnwindingRecordsPlatform::RegisterExecutableMemory(
|
||||
void* start,
|
||||
intptr_t size,
|
||||
void** pp_dynamic_table) {}
|
||||
|
||||
void UnwindingRecordsPlatform::UnregisterDynamicTable(void* p_dynamic_table) {}
|
||||
|
||||
#endif // !defined(DART_HOST_OS_WINDOWS) || ...
|
||||
#endif // !defined(UNWINDING_RECORDS_WINDOWS_HOST)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
@@ -20,16 +20,20 @@ class UnwindingRecordsPlatform : public AllStatic {
|
||||
static void UnregisterDynamicTable(void* p_dynamic_table);
|
||||
};
|
||||
|
||||
// These definitions are only needed if targeting 64-bit Windows, or if the
|
||||
// ELF loader may be used on 64-bit Windows.
|
||||
//
|
||||
// More specifically, a 64-bit Windows gen_snapshot that does not target
|
||||
// 64-bit Windows does not need these definitions, as the generated snapshot
|
||||
// should not contain Windows-specific unwinding records and gen_snapshot
|
||||
// does not uses the ELF loader.
|
||||
#if (defined(DART_TARGET_OS_WINDOWS) && defined(TARGET_ARCH_IS_64_BIT)) || \
|
||||
(defined(DART_HOST_OS_WINDOWS) && defined(ARCH_IS_64_BIT) && \
|
||||
(!defined(DART_PRECOMPILER) || defined(TESTING)))
|
||||
#if defined(DART_HOST_OS_WINDOWS) && defined(ARCH_IS_64_BIT) && \
|
||||
(!defined(DART_PRECOMPILER) || defined(TESTING))
|
||||
#define NEED_WINDOWS_UNWINDING_RECORDS 1
|
||||
// Guard for code and definitions that are used when the 64-bit Windows runtime
|
||||
// may make calls to the Windows APIs using the unwinding records information.
|
||||
#define UNWINDING_RECORDS_WINDOWS_HOST 1
|
||||
#elif defined(DART_TARGET_OS_WINDOWS) && defined(TARGET_ARCH_IS_64_BIT)
|
||||
#define NEED_WINDOWS_UNWINDING_RECORDS 1
|
||||
// Guard for code and definitions that are used when precompiling for
|
||||
// a 64-bit Windows target without any runtime use (and thus, no API calls).
|
||||
#define UNWINDING_RECORDS_WINDOWS_PRECOMPILER 1
|
||||
#endif
|
||||
|
||||
#if defined(NEED_WINDOWS_UNWINDING_RECORDS)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@@ -63,14 +67,6 @@ typedef struct _UNWIND_INFO {
|
||||
UNWIND_CODE UnwindCode[2];
|
||||
} UNWIND_INFO, *PUNWIND_INFO;
|
||||
|
||||
#if !defined(DART_HOST_OS_WINDOWS)
|
||||
typedef struct _RUNTIME_FUNCTION {
|
||||
ULONG BeginAddress;
|
||||
ULONG EndAddress;
|
||||
ULONG UnwindData;
|
||||
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
|
||||
#endif
|
||||
|
||||
static constexpr int kPushRbpInstructionLength = 1;
|
||||
static const int kMovRbpRspInstructionLength = 3;
|
||||
static constexpr int kRbpPrefixLength =
|
||||
@@ -102,13 +98,20 @@ struct GeneratedCodeUnwindInfo {
|
||||
|
||||
static constexpr uint32_t kUnwindingRecordMagic = 0xAABBCCDD;
|
||||
|
||||
struct TargetRuntimeFunction {
|
||||
ULONG BeginAddress;
|
||||
ULONG EndAddress;
|
||||
ULONG UnwindData;
|
||||
};
|
||||
|
||||
struct CodeRangeUnwindingRecord {
|
||||
void* dynamic_table;
|
||||
uint32_t magic;
|
||||
uint32_t runtime_function_count;
|
||||
GeneratedCodeUnwindInfo unwind_info;
|
||||
intptr_t exception_handler;
|
||||
RUNTIME_FUNCTION runtime_function[1];
|
||||
// Must be cast to a PRUNTIME_FUNCTION when passed to Windows APIs.
|
||||
TargetRuntimeFunction runtime_function[1];
|
||||
};
|
||||
|
||||
#elif defined(TARGET_ARCH_ARM64)
|
||||
@@ -148,13 +151,6 @@ struct UNWIND_INFO {
|
||||
uint32_t CodeWords : 5;
|
||||
};
|
||||
|
||||
#if !defined(DART_HOST_OS_WINDOWS) || !defined(HOST_ARCH_ARM64)
|
||||
typedef struct _RUNTIME_FUNCTION {
|
||||
ULONG BeginAddress;
|
||||
ULONG UnwindData;
|
||||
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Base on below doc, unwind record has 18 bits (unsigned) to encode function
|
||||
* length, besides 2 LSB which are always 0.
|
||||
@@ -218,6 +214,11 @@ struct UnwindData {
|
||||
static const uint32_t kDefaultRuntimeFunctionCount = 1;
|
||||
static constexpr uint32_t kUnwindingRecordMagic = 0xAABBCCEE;
|
||||
|
||||
struct TargetRuntimeFunction {
|
||||
ULONG BeginAddress;
|
||||
ULONG UnwindData;
|
||||
};
|
||||
|
||||
struct CodeRangeUnwindingRecord {
|
||||
void* dynamic_table;
|
||||
uint32_t magic;
|
||||
@@ -231,19 +232,29 @@ struct CodeRangeUnwindingRecord {
|
||||
// than full size.
|
||||
UnwindData<> unwind_info1;
|
||||
|
||||
// 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];
|
||||
// An arbitrary number of runtime function structs follow the initial header
|
||||
// as the number needed to cover the given code range is computed at runtime.
|
||||
// Must be cast to a PRUNTIME_FUNCTION when passed to Windows APIs.
|
||||
TargetRuntimeFunction runtime_function[kDefaultRuntimeFunctionCount];
|
||||
};
|
||||
|
||||
#else
|
||||
#error Unhandled Windows architecture.
|
||||
#endif
|
||||
|
||||
// Since the definition of the RUNTIME_FUNCTION struct differs on X64
|
||||
// and ARM64 Windows and the precompiler may be cross compiling between
|
||||
// the two, TargetRuntimeFunction is defined above, which mimics the
|
||||
// native RUNTIME_FUNCTION struct of the target.
|
||||
//
|
||||
// Make sure that the sizes match, so that TargetRuntimeFunction values
|
||||
// can be used as RUNTIME_FUNCTION values and vice versa in the runtime.
|
||||
#if defined(UNWINDING_RECORDS_WINDOWS_HOST)
|
||||
static_assert(sizeof(TargetRuntimeFunction) == sizeof(RUNTIME_FUNCTION));
|
||||
#endif
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // (defined(DART_TARGET_OS_WINDOWS) || ...
|
||||
#endif // defined(NEED_WINDOWS_UNWINDING_RECORDS)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
#if (defined(DART_TARGET_OS_WINDOWS) && defined(TARGET_ARCH_IS_64_BIT)) || \
|
||||
(defined(DART_HOST_OS_WINDOWS) && defined(ARCH_IS_64_BIT))
|
||||
#if defined(NEED_WINDOWS_UNWINDING_RECORDS)
|
||||
|
||||
#if defined(TARGET_ARCH_X64)
|
||||
const intptr_t kReservedUnwindingRecordsSizeBytes = 64;
|
||||
@@ -24,12 +23,11 @@ intptr_t UnwindingRecordsPlatform::SizeInBytes() {
|
||||
return kReservedUnwindingRecordsSizeBytes;
|
||||
}
|
||||
|
||||
#endif // defined(DART_TARGET_OS_WINDOWS) ...
|
||||
#endif // defined(NEED_WINDOWS_UNWINDING_RECORDS)
|
||||
|
||||
// Only use these definitions when the ELF loader may be used on 64-bit Windows,
|
||||
// as it is the only client of these methods (e.g., _not_ in gen_snapshot).
|
||||
#if defined(DART_HOST_OS_WINDOWS) && defined(ARCH_IS_64_BIT) && \
|
||||
(!defined(DART_PRECOMPILER) || defined(TESTING))
|
||||
#if defined(UNWINDING_RECORDS_WINDOWS_HOST)
|
||||
|
||||
void UnwindingRecordsPlatform::RegisterExecutableMemory(
|
||||
void* start,
|
||||
@@ -44,7 +42,8 @@ void UnwindingRecordsPlatform::RegisterExecutableMemory(
|
||||
uword end_num = start_num + size;
|
||||
DWORD status = RtlAddGrowableFunctionTable(
|
||||
pp_dynamic_table,
|
||||
/*FunctionTable=*/record->runtime_function,
|
||||
/*FunctionTable=*/
|
||||
reinterpret_cast<PRUNTIME_FUNCTION>(record->runtime_function),
|
||||
/*EntryCount=*/record->runtime_function_count,
|
||||
/*MaximumEntryCount=*/record->runtime_function_count,
|
||||
/*RangeBase=*/start_num,
|
||||
@@ -58,6 +57,6 @@ void UnwindingRecordsPlatform::UnregisterDynamicTable(void* p_dynamic_table) {
|
||||
RtlDeleteGrowableFunctionTable(p_dynamic_table);
|
||||
}
|
||||
|
||||
#endif // defined(DART_HOST_OS_WINDOWS) ...
|
||||
#endif // defined(UNWINDING_RECORDS_WINDOWS_HOST)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
Reference in New Issue
Block a user