1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5#ifndef __GCEVENT_SERIALIZERS_H__
6#define __GCEVENT_SERIALIZERS_H__
7
8/*
9 * gcevent_serializers.h - Serialization traits and plumbing for
10 * serializing dynamic events.
11 *
12 * Dynamic events are events that can be fired by the GC without prior
13 * knowledge of the EE. In order to accomplish this, the GC sends raw
14 * bytes to the EE using the `IGCToCLR::FireDynamicEvent` callback, which
15 * the EE will then fire as its own event.
16 *
17 * In order to keep the friction of adding new dynamic events low, this
18 * file defines a simple ETW-style binary serialization format that
19 * is efficient and easy to both serialize and deserialize.
20 *
21 * ## Serializing Types
22 *
23 * This file makes use of `EventSerializationTraits` to serialize
24 * types. A type can opt-in to serialization using the mechanisms
25 * in this file by specializing the `EventSerializationTraits` template,
26 * providing implementations of `Serialize` and `SerializedSize`.
27 *
28 * If you attempt to serialize a type that does not implement this trait,
29 * you will receive an error message like this:
30 *
31 * bool gc_event::EventSerializationTraits<Head>::Serialize(const T&,uint8_t **)': attempting to reference a deleted function
32 * with
33 * [
34 * Head=<your type you tried to serialize>,
35 * T=<your type you tried to serialize>
36 * ]
37 *
38 * If you get this message, you will need to specialize `EventSerializationTraits`
39 * for the type you want to serialize.
40 */
41
42#ifdef _MSC_VER
43#define ByteSwap32 _byteswap_ulong
44#define ByteSwap64 _byteswap_uint64
45#else
46#define ByteSwap32 __bulitin_bswap32
47#define ByteSwap64 __builtin_bswap64
48#endif // MSC_VER
49
50namespace gc_event
51{
52
53/*
54 * `EventSerializatonTraits` is a trait implemented by types that
55 * can be serialized to the payload of a dynamic event.
56 */
57template<class T>
58struct EventSerializationTraits
59{
60 /*
61 * Serializes the value `value` to the buffer `buffer`, incrementing
62 * the buffer double-pointer to point to the next byte to be written.
63 *
64 * It is the responsibility of the caller to ensure that the buffer is
65 * large enough to accomodate the serialized form of T.
66 */
67 static void Serialize(const T& value, uint8_t** buffer) = delete;
68
69 /*
70 * Returns the size of the value `value` if it were to be serialized.
71 */
72 static size_t SerializedSize(const T& value) = delete;
73};
74
75/*
76 * EventSerializationTraits implementation for uint32_t. Other integral types
77 * can follow this pattern.
78 *
79 * The convention here is that integral types are always serialized as
80 * little-endian.
81 */
82template<>
83struct EventSerializationTraits<uint32_t>
84{
85 static void Serialize(const uint32_t& value, uint8_t** buffer)
86 {
87#if defined(BIGENDIAN)
88 **((uint32_t**)buffer) = ByteSwap32(value);
89#else
90 **((uint32_t**)buffer) = value;
91#endif // BIGENDIAN
92 *buffer += sizeof(uint32_t);
93 }
94
95 static size_t SerializedSize(const uint32_t& value)
96 {
97 return sizeof(uint32_t);
98 }
99};
100
101/*
102 * Helper routines for serializing lists of arguments.
103 */
104
105/*
106 * Given a list of arguments , returns the total size of
107 * the buffer required to fully serialize the list of arguments.
108 */
109template<class Head>
110size_t SerializedSize(Head head)
111{
112 return EventSerializationTraits<Head>::SerializedSize(head);
113}
114
115template<class Head, class... Tail>
116size_t SerializedSize(Head head, Tail... tail)
117{
118 return EventSerializationTraits<Head>::SerializedSize(head) + SerializedSize(tail...);
119}
120
121/*
122 * Given a list of arguments and a list of actual parameters, serialize
123 * the arguments into the buffer that's given to us.
124 */
125template<class Head>
126void Serialize(uint8_t** buf, Head head)
127{
128 EventSerializationTraits<Head>::Serialize(head, buf);
129}
130
131template<class Head, class... Tail>
132void Serialize(uint8_t** buf, Head head, Tail... tail)
133{
134 EventSerializationTraits<Head>::Serialize(head, buf);
135 Serialize(buf, tail...);
136}
137
138} // namespace gc_event
139
140#endif // __GCEVENT_SERIALIZERS_H__
141
142