-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
Copy pathgcevent_serializers.h
213 lines (189 loc) · 5.67 KB
/
gcevent_serializers.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#ifndef __GCEVENT_SERIALIZERS_H__
#define __GCEVENT_SERIALIZERS_H__
/*
* gcevent_serializers.h - Serialization traits and plumbing for
* serializing dynamic events.
*
* Dynamic events are events that can be fired by the GC without prior
* knowledge of the EE. In order to accomplish this, the GC sends raw
* bytes to the EE using the `IGCToCLR::FireDynamicEvent` callback, which
* the EE will then fire as its own event.
*
* In order to keep the friction of adding new dynamic events low, this
* file defines a simple ETW-style binary serialization format that
* is efficient and easy to both serialize and deserialize.
*
* ## Serializing Types
*
* This file makes use of `EventSerializationTraits` to serialize
* types. A type can opt-in to serialization using the mechanisms
* in this file by specializing the `EventSerializationTraits` template,
* providing implementations of `Serialize` and `SerializedSize`.
*
* If you attempt to serialize a type that does not implement this trait,
* you will receive an error message like this:
*
* bool gc_event::EventSerializationTraits<Head>::Serialize(const T&,uint8_t **)': attempting to reference a deleted function
* with
* [
* Head=<your type you tried to serialize>,
* T=<your type you tried to serialize>
* ]
*
* If you get this message, you will need to specialize `EventSerializationTraits`
* for the type you want to serialize.
*/
#ifdef _MSC_VER
#define ByteSwap16 _byteswap_ushort
#define ByteSwap32 _byteswap_ulong
#define ByteSwap64 _byteswap_uint64
#else
#define ByteSwap16 __bulitin_bswap16
#define ByteSwap32 __bulitin_bswap32
#define ByteSwap64 __builtin_bswap64
#endif // MSC_VER
namespace gc_event
{
/*
* `EventSerializatonTraits` is a trait implemented by types that
* can be serialized to the payload of a dynamic event.
*/
template<class T>
struct EventSerializationTraits
{
/*
* Serializes the value `value` to the buffer `buffer`, incrementing
* the buffer double-pointer to point to the next byte to be written.
*
* It is the responsibility of the caller to ensure that the buffer is
* large enough to accommodate the serialized form of T.
*/
static void Serialize(const T& value, uint8_t** buffer) = delete;
/*
* Returns the size of the value `value` if it were to be serialized.
*/
static size_t SerializedSize(const T& value) = delete;
};
/*
* EventSerializationTraits implementation for uint16_t. Other integral types
* can follow this pattern.
*
* The convention here is that integral types are always serialized as
* little-endian.
*/
template<>
struct EventSerializationTraits<uint8_t>
{
static void Serialize(const uint8_t& value, uint8_t** buffer)
{
**((uint8_t**)buffer) = value;
*buffer += sizeof(uint8_t);
}
static size_t SerializedSize(const uint8_t& value)
{
return sizeof(uint8_t);
}
};
template<>
struct EventSerializationTraits<uint16_t>
{
static void Serialize(const uint16_t& value, uint8_t** buffer)
{
#if defined(BIGENDIAN)
uint16_t swapped = ByteSwap16(value);
memcpy(*buffer, &swapped, sizeof(uint16_t));
#else
memcpy(*buffer, &value, sizeof(uint16_t));
#endif // BIGENDIAN
*buffer += sizeof(uint16_t);
}
static size_t SerializedSize(const uint16_t& value)
{
return sizeof(uint16_t);
}
};
template<>
struct EventSerializationTraits<uint32_t>
{
static void Serialize(const uint32_t& value, uint8_t** buffer)
{
#if defined(BIGENDIAN)
uint32_t swapped = ByteSwap32(value);
memcpy(*buffer, &swapped, sizeof(uint32_t));
#else
memcpy(*buffer, &value, sizeof(uint32_t));
#endif // BIGENDIAN
*buffer += sizeof(uint32_t);
}
static size_t SerializedSize(const uint32_t& value)
{
return sizeof(uint32_t);
}
};
template<>
struct EventSerializationTraits<uint64_t>
{
static void Serialize(const uint64_t& value, uint8_t** buffer)
{
#if defined(BIGENDIAN)
uint64_t swapped = ByteSwap64(value);
memcpy(*buffer, &swapped, sizeof(uint64_t));
#else
memcpy(*buffer, &value, sizeof(uint64_t));
#endif // BIGENDIAN
*buffer += sizeof(uint64_t);
}
static size_t SerializedSize(const uint64_t& value)
{
return sizeof(uint64_t);
}
};
template<>
struct EventSerializationTraits<float>
{
static void Serialize(const float& value, uint8_t** buffer)
{
memcpy(*buffer, &value, sizeof(float));
*buffer += sizeof(float);
}
static size_t SerializedSize(const float& value)
{
return sizeof(float);
}
};
/*
* Helper routines for serializing lists of arguments.
*/
/*
* Given a list of arguments , returns the total size of
* the buffer required to fully serialize the list of arguments.
*/
template<class Head>
size_t SerializedSize(Head head)
{
return EventSerializationTraits<Head>::SerializedSize(head);
}
template<class Head, class... Tail>
size_t SerializedSize(Head head, Tail... tail)
{
return EventSerializationTraits<Head>::SerializedSize(head) + SerializedSize(tail...);
}
/*
* Given a list of arguments and a list of actual parameters, serialize
* the arguments into the buffer that's given to us.
*/
template<class Head>
void Serialize(uint8_t** buf, Head head)
{
EventSerializationTraits<Head>::Serialize(head, buf);
}
template<class Head, class... Tail>
void Serialize(uint8_t** buf, Head head, Tail... tail)
{
EventSerializationTraits<Head>::Serialize(head, buf);
Serialize(buf, tail...);
}
} // namespace gc_event
#endif // __GCEVENT_SERIALIZERS_H__