-
Notifications
You must be signed in to change notification settings - Fork 246
/
Copy pathbase_fast_forward.h
139 lines (119 loc) · 4.46 KB
/
base_fast_forward.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <cstddef>
#include <atomic>
#define WINRT_IMPL_STRING_1(expression) #expression
#define WINRT_IMPL_STRING(expression) WINRT_IMPL_STRING_1(expression)
#if defined(_MSC_VER)
#define WINRT_IMPL_FF_NOVTABLE __declspec(novtable)
#else
#define WINRT_IMPL_FF_NOVTABLE
#endif
#if !defined(WINRT_FAST_ABI_SIZE)
#define WINRT_FAST_ABI_SIZE %
#endif
static_assert(WINRT_FAST_ABI_SIZE >= %);
#pragma detect_mismatch("WINRT_FAST_ABI_SIZE", WINRT_IMPL_STRING(WINRT_FAST_ABI_SIZE))
namespace winrt::impl
{
// Thunk definitions are in arch-specific assembly sources
%
struct fast_abi_forwarder
{
struct guid
{
uint32_t Data1;
uint16_t Data2;
uint16_t Data3;
uint8_t Data4[8];
inline bool operator!=(guid const& right) const noexcept
{
return memcmp(this, &right, sizeof(guid));
}
};
struct WINRT_IMPL_FF_NOVTABLE inspectable
{
virtual int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0;
virtual uint32_t __stdcall AddRef() noexcept = 0;
virtual uint32_t __stdcall Release() noexcept = 0;
virtual int32_t __stdcall GetIids(uint32_t* count, guid** ids) noexcept = 0;
virtual int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0;
virtual int32_t __stdcall GetTrustLevel(uint32_t* level) noexcept = 0;
};
void* const* m_vfptr;
inspectable* m_owner;
std::size_t m_offset;
guid m_iid;
std::atomic<uint32_t> m_references{ 1 };
fast_abi_forwarder(void* owner, guid const& iid, std::size_t offset) noexcept :
m_vfptr(s_vtable), m_owner(static_cast<inspectable*>(owner)), m_iid(iid), m_offset(offset)
{
m_owner->AddRef();
}
~fast_abi_forwarder() noexcept
{
m_owner->Release();
}
static int32_t __stdcall QueryInterface(fast_abi_forwarder* self, guid const& iid, void** object) noexcept
{
if (iid != self->m_iid)
{
return self->m_owner->QueryInterface(iid, object);
}
AddRef(self);
*object = self;
return 0;
}
// Note: COM interfaces use stdcall, not thiscall, ('this' gets no special treatment), permitting static implementations
static uint32_t __stdcall AddRef(fast_abi_forwarder* self) noexcept
{
return 1 + self->m_references.fetch_add(1, std::memory_order_relaxed);
}
static uint32_t __stdcall Release(fast_abi_forwarder* self) noexcept
{
uint32_t const remaining = self->m_references.fetch_sub(1, std::memory_order_release) - 1;
if (remaining == 0)
{
std::atomic_thread_fence(std::memory_order_acquire);
delete self;
}
return remaining;
}
static uint32_t __stdcall GetIids(fast_abi_forwarder* self, uint32_t* count, guid** iids) noexcept
{
return self->m_owner->GetIids(count, iids);
}
static uint32_t __stdcall GetRuntimeClassName(fast_abi_forwarder* self, void** name) noexcept
{
return self->m_owner->GetRuntimeClassName(name);
}
static uint32_t __stdcall GetTrustLevel(fast_abi_forwarder* self, uint32_t* level) noexcept
{
return self->m_owner->GetTrustLevel(level);
}
static inline void* const s_vtable[] =
{
QueryInterface,
AddRef,
Release,
GetIids,
GetRuntimeClassName,
GetTrustLevel,
% };
};
// Enforce assumptions made by thunk asm code
static_assert(offsetof(fast_abi_forwarder, m_vfptr) == 0);
static_assert(offsetof(fast_abi_forwarder, m_owner) == sizeof(fast_abi_forwarder::m_vfptr));
static_assert(offsetof(fast_abi_forwarder, m_offset) == sizeof(fast_abi_forwarder::m_vfptr) + sizeof(fast_abi_forwarder::m_owner));
}
namespace winrt
{
template<typename TGuid>
auto make_fast_abi_forwarder(void* owner, TGuid const& guid, size_t offset)
{
using ff_guid = impl::fast_abi_forwarder::guid;
static_assert(sizeof(ff_guid) == sizeof(TGuid));
return new impl::fast_abi_forwarder(owner, *reinterpret_cast<ff_guid const*>(&guid), offset);
}
}
#undef WINRT_IMPL_STRING
#undef WINRT_IMPL_STRING_1
#undef WINRT_IMPL_FF_NOVTABLE