Thunks/gen: Emit metadata to check if a type has consistent data layout

This commit is contained in:
Tony Wasserka committed 2024-01-12 14:47:10 +01:00
1 parent d488592eda
commit 52419d9911
3 files changed
+39

No files matched your search

+7
View File
@@ -144,6 +144,9 @@ void GenerateThunkLibsAction::EmitLayoutWrappers(
// Opaque types don't need layout definitions
if (type_repack_info.assumed_compatible && type_repack_info.pointers_only) {
if (guest_abi.pointer_size != 4) {
fmt::print(file, "template<> inline constexpr bool has_compatible_data_layout<{}*> = true;\n", struct_name);
}
continue;
} else if (type_repack_info.assumed_compatible) {
// TODO: Handle more cleanly
@@ -280,6 +283,10 @@ void GenerateThunkLibsAction::EmitLayoutWrappers(
}
fmt::print(file, " return ret;\n");
fmt::print(file, "}}\n\n");
if (type_compat.at(type) == TypeCompatibility::Full) {
fmt::print(file, "template<> inline constexpr bool has_compatible_data_layout<{}> = true;\n", struct_name);
}
}
}
+31
View File
@@ -89,6 +89,35 @@ struct ParameterAnnotations {
bool assume_compatible = false;
};
// Generator emits specializations for this for each type that has compatible layout
template<typename T>
inline constexpr bool has_compatible_data_layout =
std::is_integral_v<T> || std::is_enum_v<T> || std::is_floating_point_v<T>
#ifndef IS_32BIT_THUNK
// If none of the previous predicates matched, the thunk generator did *not* emit a specialization for T.
// This should not happen on 64-bit with the currently thunked libraries, since their types
// * either have fully consistent data layout across 64-bit architectures.
// * or use custom repacking, in which case has_compatible_data_layout isn't used
//
// Throwing a fake exception here will trigger a build failure.
|| (throw "Instantiated on a type that was expected to be compatible", true)
#endif
;
#ifndef IS_32BIT_THUNK
// Pointers have the same size, hence data layout compatibility only depends on the pointee type
template<typename T>
inline constexpr bool has_compatible_data_layout<T*> = has_compatible_data_layout<std::remove_cv_t<T>>;
template<typename T>
inline constexpr bool has_compatible_data_layout<T* const> = has_compatible_data_layout<std::remove_cv_t<T>*>;
// void* and void** are assumed to be compatible to simplify handling of libraries that use them ubiquitously
template<> inline constexpr bool has_compatible_data_layout<void*> = true;
template<> inline constexpr bool has_compatible_data_layout<const void*> = true;
template<> inline constexpr bool has_compatible_data_layout<void**> = true;
template<> inline constexpr bool has_compatible_data_layout<const void**> = true;
#endif
// Placeholder type to indicate the given data is in guest-layout
template<typename T>
struct guest_layout {
@@ -97,6 +126,8 @@ struct guest_layout {
static_assert(!std::is_enum_v<T>, "No guest layout defined for this enum type. This is a bug in the thunk generator.");
static_assert(!std::is_void_v<T>, "Attempted to get guest layout of void. Missing annotation for void pointer?");
static_assert(std::is_fundamental_v<T> || has_compatible_data_layout<T>, "Default guest_layout may not be used for non-compatible data");
using type = std::enable_if_t<!std::is_pointer_v<T>, T>;
type data;
+1
View File
@@ -281,6 +281,7 @@ SourceWithAST Fixture::run_thunkgen_host(std::string_view prelude, std::string_v
"};\n"
"struct ExportEntry { uint8_t* sha256; void(*fn)(void *); };\n"
"void *dlsym_default(void* handle, const char* symbol);\n"
"template<typename T> inline constexpr bool has_compatible_data_layout = std::is_integral_v<T> || std::is_enum_v<T>;\n"
"template<typename T>\n"
"struct guest_layout {\n"
" T data;\n"