xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1 //===---- SimplePackedSerialization.h - simple serialization ----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // The behavior of the utilities in this header must be synchronized with the
10 // behavior of the utilities in
11 // compiler-rt/lib/orc/simple_packed_serialization.h.
12 //
13 // The Simple Packed Serialization (SPS) utilities are used to generate
14 // argument and return buffers for wrapper functions using the following
15 // serialization scheme:
16 //
17 // Primitives (signed types should be two's complement):
18 //   bool, char, int8_t, uint8_t -- 8-bit (0=false, 1=true)
19 //   int16_t, uint16_t           -- 16-bit little endian
20 //   int32_t, uint32_t           -- 32-bit little endian
21 //   int64_t, int64_t            -- 64-bit little endian
22 //
23 // Sequence<T>:
24 //   Serialized as the sequence length (as a uint64_t) followed by the
25 //   serialization of each of the elements without padding.
26 //
27 // Tuple<T1, ..., TN>:
28 //   Serialized as each of the element types from T1 to TN without padding.
29 //
30 //===----------------------------------------------------------------------===//
31 
32 #ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H
33 #define LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H
34 
35 #include "llvm/ADT/STLExtras.h"
36 #include "llvm/ADT/SmallVector.h"
37 #include "llvm/ADT/StringMap.h"
38 #include "llvm/ADT/StringRef.h"
39 #include "llvm/Support/Error.h"
40 #include "llvm/Support/SwapByteOrder.h"
41 
42 #include <limits>
43 #include <optional>
44 #include <string>
45 #include <tuple>
46 #include <type_traits>
47 #include <utility>
48 #include <vector>
49 
50 namespace llvm {
51 namespace orc {
52 namespace shared {
53 
54 /// Output char buffer with overflow check.
55 class SPSOutputBuffer {
56 public:
SPSOutputBuffer(char * Buffer,size_t Remaining)57   SPSOutputBuffer(char *Buffer, size_t Remaining)
58       : Buffer(Buffer), Remaining(Remaining) {}
write(const char * Data,size_t Size)59   bool write(const char *Data, size_t Size) {
60     assert(Data && "Data must not be null");
61     if (Size > Remaining)
62       return false;
63     memcpy(Buffer, Data, Size);
64     Buffer += Size;
65     Remaining -= Size;
66     return true;
67   }
68 
69 private:
70   char *Buffer = nullptr;
71   size_t Remaining = 0;
72 };
73 
74 /// Input char buffer with underflow check.
75 class SPSInputBuffer {
76 public:
77   SPSInputBuffer() = default;
SPSInputBuffer(const char * Buffer,size_t Remaining)78   SPSInputBuffer(const char *Buffer, size_t Remaining)
79       : Buffer(Buffer), Remaining(Remaining) {}
read(char * Data,size_t Size)80   bool read(char *Data, size_t Size) {
81     if (Size > Remaining)
82       return false;
83     memcpy(Data, Buffer, Size);
84     Buffer += Size;
85     Remaining -= Size;
86     return true;
87   }
88 
data()89   const char *data() const { return Buffer; }
skip(size_t Size)90   bool skip(size_t Size) {
91     if (Size > Remaining)
92       return false;
93     Buffer += Size;
94     Remaining -= Size;
95     return true;
96   }
97 
98 private:
99   const char *Buffer = nullptr;
100   size_t Remaining = 0;
101 };
102 
103 /// Specialize to describe how to serialize/deserialize to/from the given
104 /// concrete type.
105 template <typename SPSTagT, typename ConcreteT, typename _ = void>
106 class SPSSerializationTraits;
107 
108 /// A utility class for serializing to a blob from a variadic list.
109 template <typename... ArgTs> class SPSArgList;
110 
111 // Empty list specialization for SPSArgList.
112 template <> class SPSArgList<> {
113 public:
size()114   static size_t size() { return 0; }
115 
serialize(SPSOutputBuffer & OB)116   static bool serialize(SPSOutputBuffer &OB) { return true; }
deserialize(SPSInputBuffer & IB)117   static bool deserialize(SPSInputBuffer &IB) { return true; }
118 
serializeToSmallVector(SmallVectorImpl<char> & V)119   static bool serializeToSmallVector(SmallVectorImpl<char> &V) { return true; }
120 
deserializeFromSmallVector(const SmallVectorImpl<char> & V)121   static bool deserializeFromSmallVector(const SmallVectorImpl<char> &V) {
122     return true;
123   }
124 };
125 
126 // Non-empty list specialization for SPSArgList.
127 template <typename SPSTagT, typename... SPSTagTs>
128 class SPSArgList<SPSTagT, SPSTagTs...> {
129 public:
130   // FIXME: This typedef is here to enable SPS arg serialization from
131   // JITLink. It can be removed once JITLink can access SPS directly.
132   using OutputBuffer = SPSOutputBuffer;
133 
134   template <typename ArgT, typename... ArgTs>
size(const ArgT & Arg,const ArgTs &...Args)135   static size_t size(const ArgT &Arg, const ArgTs &...Args) {
136     return SPSSerializationTraits<SPSTagT, ArgT>::size(Arg) +
137            SPSArgList<SPSTagTs...>::size(Args...);
138   }
139 
140   template <typename ArgT, typename... ArgTs>
serialize(SPSOutputBuffer & OB,const ArgT & Arg,const ArgTs &...Args)141   static bool serialize(SPSOutputBuffer &OB, const ArgT &Arg,
142                         const ArgTs &...Args) {
143     return SPSSerializationTraits<SPSTagT, ArgT>::serialize(OB, Arg) &&
144            SPSArgList<SPSTagTs...>::serialize(OB, Args...);
145   }
146 
147   template <typename ArgT, typename... ArgTs>
deserialize(SPSInputBuffer & IB,ArgT & Arg,ArgTs &...Args)148   static bool deserialize(SPSInputBuffer &IB, ArgT &Arg, ArgTs &...Args) {
149     return SPSSerializationTraits<SPSTagT, ArgT>::deserialize(IB, Arg) &&
150            SPSArgList<SPSTagTs...>::deserialize(IB, Args...);
151   }
152 };
153 
154 /// SPS serialization for integral types, bool, and char.
155 template <typename SPSTagT>
156 class SPSSerializationTraits<
157     SPSTagT, SPSTagT,
158     std::enable_if_t<std::is_same<SPSTagT, bool>::value ||
159                      std::is_same<SPSTagT, char>::value ||
160                      std::is_same<SPSTagT, int8_t>::value ||
161                      std::is_same<SPSTagT, int16_t>::value ||
162                      std::is_same<SPSTagT, int32_t>::value ||
163                      std::is_same<SPSTagT, int64_t>::value ||
164                      std::is_same<SPSTagT, uint8_t>::value ||
165                      std::is_same<SPSTagT, uint16_t>::value ||
166                      std::is_same<SPSTagT, uint32_t>::value ||
167                      std::is_same<SPSTagT, uint64_t>::value>> {
168 public:
size(const SPSTagT & Value)169   static size_t size(const SPSTagT &Value) { return sizeof(SPSTagT); }
170 
serialize(SPSOutputBuffer & OB,const SPSTagT & Value)171   static bool serialize(SPSOutputBuffer &OB, const SPSTagT &Value) {
172     SPSTagT Tmp = Value;
173     if (sys::IsBigEndianHost)
174       sys::swapByteOrder(Tmp);
175     return OB.write(reinterpret_cast<const char *>(&Tmp), sizeof(Tmp));
176   }
177 
deserialize(SPSInputBuffer & IB,SPSTagT & Value)178   static bool deserialize(SPSInputBuffer &IB, SPSTagT &Value) {
179     SPSTagT Tmp;
180     if (!IB.read(reinterpret_cast<char *>(&Tmp), sizeof(Tmp)))
181       return false;
182     if (sys::IsBigEndianHost)
183       sys::swapByteOrder(Tmp);
184     Value = Tmp;
185     return true;
186   }
187 };
188 
189 // Any empty placeholder suitable as a substitute for void when deserializing
190 class SPSEmpty {};
191 
192 /// SPS tag type for tuples.
193 ///
194 /// A blob tuple should be serialized by serializing each of the elements in
195 /// sequence.
196 template <typename... SPSTagTs> class SPSTuple {
197 public:
198   /// Convenience typedef of the corresponding arg list.
199   typedef SPSArgList<SPSTagTs...> AsArgList;
200 };
201 
202 /// SPS tag type for optionals.
203 ///
204 /// SPSOptionals should be serialized as a bool with true indicating that an
205 /// SPSTagT value is present, and false indicating that there is no value.
206 /// If the boolean is true then the serialized SPSTagT will follow immediately
207 /// after it.
208 template <typename SPSTagT> class SPSOptional {};
209 
210 /// SPS tag type for sequences.
211 ///
212 /// SPSSequences should be serialized as a uint64_t sequence length,
213 /// followed by the serialization of each of the elements.
214 template <typename SPSElementTagT> class SPSSequence;
215 
216 /// SPS tag type for strings, which are equivalent to sequences of chars.
217 using SPSString = SPSSequence<char>;
218 
219 /// SPS tag type for maps.
220 ///
221 /// SPS maps are just sequences of (Key, Value) tuples.
222 template <typename SPSTagT1, typename SPSTagT2>
223 using SPSMap = SPSSequence<SPSTuple<SPSTagT1, SPSTagT2>>;
224 
225 /// Serialization for SPSEmpty type.
226 template <> class SPSSerializationTraits<SPSEmpty, SPSEmpty> {
227 public:
size(const SPSEmpty & EP)228   static size_t size(const SPSEmpty &EP) { return 0; }
serialize(SPSOutputBuffer & OB,const SPSEmpty & BE)229   static bool serialize(SPSOutputBuffer &OB, const SPSEmpty &BE) {
230     return true;
231   }
deserialize(SPSInputBuffer & IB,SPSEmpty & BE)232   static bool deserialize(SPSInputBuffer &IB, SPSEmpty &BE) { return true; }
233 };
234 
235 /// Specialize this to implement 'trivial' sequence serialization for
236 /// a concrete sequence type.
237 ///
238 /// Trivial sequence serialization uses the sequence's 'size' member to get the
239 /// length of the sequence, and uses a range-based for loop to iterate over the
240 /// elements.
241 ///
242 /// Specializing this template class means that you do not need to provide a
243 /// specialization of SPSSerializationTraits for your type.
244 template <typename SPSElementTagT, typename ConcreteSequenceT>
245 class TrivialSPSSequenceSerialization {
246 public:
247   static constexpr bool available = false;
248 };
249 
250 /// Specialize this to implement 'trivial' sequence deserialization for
251 /// a concrete sequence type.
252 ///
253 /// Trivial deserialization calls a static 'reserve(SequenceT&)' method on your
254 /// specialization (you must implement this) to reserve space, and then calls
255 /// a static 'append(SequenceT&, ElementT&) method to append each of the
256 /// deserialized elements.
257 ///
258 /// Specializing this template class means that you do not need to provide a
259 /// specialization of SPSSerializationTraits for your type.
260 template <typename SPSElementTagT, typename ConcreteSequenceT>
261 class TrivialSPSSequenceDeserialization {
262 public:
263   static constexpr bool available = false;
264 };
265 
266 /// Trivial std::string -> SPSSequence<char> serialization.
267 template <> class TrivialSPSSequenceSerialization<char, std::string> {
268 public:
269   static constexpr bool available = true;
270 };
271 
272 /// Trivial SPSSequence<char> -> std::string deserialization.
273 template <> class TrivialSPSSequenceDeserialization<char, std::string> {
274 public:
275   static constexpr bool available = true;
276 
277   using element_type = char;
278 
reserve(std::string & S,uint64_t Size)279   static void reserve(std::string &S, uint64_t Size) { S.reserve(Size); }
append(std::string & S,char C)280   static bool append(std::string &S, char C) {
281     S.push_back(C);
282     return true;
283   }
284 };
285 
286 /// Trivial std::vector<T> -> SPSSequence<SPSElementTagT> serialization.
287 template <typename SPSElementTagT, typename T>
288 class TrivialSPSSequenceSerialization<SPSElementTagT, std::vector<T>> {
289 public:
290   static constexpr bool available = true;
291 };
292 
293 /// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization.
294 template <typename SPSElementTagT, typename T>
295 class TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>> {
296 public:
297   static constexpr bool available = true;
298 
299   using element_type = typename std::vector<T>::value_type;
300 
reserve(std::vector<T> & V,uint64_t Size)301   static void reserve(std::vector<T> &V, uint64_t Size) { V.reserve(Size); }
append(std::vector<T> & V,T E)302   static bool append(std::vector<T> &V, T E) {
303     V.push_back(std::move(E));
304     return true;
305   }
306 };
307 
308 /// Trivial SmallVectorImpl<T> -> SPSSequence<char> serialization.
309 template <typename SPSElementTagT, typename T>
310 class TrivialSPSSequenceSerialization<SPSElementTagT, SmallVectorImpl<T>> {
311 public:
312   static constexpr bool available = true;
313 };
314 
315 /// Trivial SPSSequence<SPSElementTagT> -> SmallVectorImpl<T> deserialization.
316 template <typename SPSElementTagT, typename T>
317 class TrivialSPSSequenceDeserialization<SPSElementTagT, SmallVectorImpl<T>> {
318 public:
319   static constexpr bool available = true;
320 
321   using element_type = typename SmallVectorImpl<T>::value_type;
322 
reserve(SmallVectorImpl<T> & V,uint64_t Size)323   static void reserve(SmallVectorImpl<T> &V, uint64_t Size) { V.reserve(Size); }
append(SmallVectorImpl<T> & V,T E)324   static bool append(SmallVectorImpl<T> &V, T E) {
325     V.push_back(std::move(E));
326     return true;
327   }
328 };
329 
330 /// Trivial SmallVectorImpl<T> -> SPSSequence<char> serialization.
331 template <typename SPSElementTagT, typename T, unsigned N>
332 class TrivialSPSSequenceSerialization<SPSElementTagT, SmallVector<T, N>>
333     : public TrivialSPSSequenceSerialization<SPSElementTagT,
334                                              SmallVectorImpl<T>> {};
335 
336 /// Trivial SPSSequence<SPSElementTagT> -> SmallVectorImpl<T> deserialization.
337 template <typename SPSElementTagT, typename T, unsigned N>
338 class TrivialSPSSequenceDeserialization<SPSElementTagT, SmallVector<T, N>>
339     : public TrivialSPSSequenceDeserialization<SPSElementTagT,
340                                                SmallVectorImpl<T>> {};
341 
342 /// Trivial ArrayRef<T> -> SPSSequence<SPSElementTagT> serialization.
343 template <typename SPSElementTagT, typename T>
344 class TrivialSPSSequenceSerialization<SPSElementTagT, ArrayRef<T>> {
345 public:
346   static constexpr bool available = true;
347 };
348 
349 /// Specialized SPSSequence<char> -> ArrayRef<char> serialization.
350 ///
351 /// On deserialize, points directly into the input buffer.
352 template <> class SPSSerializationTraits<SPSSequence<char>, ArrayRef<char>> {
353 public:
size(const ArrayRef<char> & A)354   static size_t size(const ArrayRef<char> &A) {
355     return SPSArgList<uint64_t>::size(static_cast<uint64_t>(A.size())) +
356            A.size();
357   }
358 
serialize(SPSOutputBuffer & OB,const ArrayRef<char> & A)359   static bool serialize(SPSOutputBuffer &OB, const ArrayRef<char> &A) {
360     if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(A.size())))
361       return false;
362     if (A.empty()) // Empty ArrayRef may have null data, so bail out early.
363       return true;
364     return OB.write(A.data(), A.size());
365   }
366 
deserialize(SPSInputBuffer & IB,ArrayRef<char> & A)367   static bool deserialize(SPSInputBuffer &IB, ArrayRef<char> &A) {
368     uint64_t Size;
369     if (!SPSArgList<uint64_t>::deserialize(IB, Size))
370       return false;
371     if (Size > std::numeric_limits<size_t>::max())
372       return false;
373     A = {Size ? IB.data() : nullptr, static_cast<size_t>(Size)};
374     return IB.skip(Size);
375   }
376 };
377 
378 /// 'Trivial' sequence serialization: Sequence is serialized as a uint64_t size
379 /// followed by a for-earch loop over the elements of the sequence to serialize
380 /// each of them.
381 template <typename SPSElementTagT, typename SequenceT>
382 class SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT,
383                              std::enable_if_t<TrivialSPSSequenceSerialization<
384                                  SPSElementTagT, SequenceT>::available>> {
385 public:
size(const SequenceT & S)386   static size_t size(const SequenceT &S) {
387     size_t Size = SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size()));
388     for (const auto &E : S)
389       Size += SPSArgList<SPSElementTagT>::size(E);
390     return Size;
391   }
392 
serialize(SPSOutputBuffer & OB,const SequenceT & S)393   static bool serialize(SPSOutputBuffer &OB, const SequenceT &S) {
394     if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
395       return false;
396     for (const auto &E : S)
397       if (!SPSArgList<SPSElementTagT>::serialize(OB, E))
398         return false;
399     return true;
400   }
401 
deserialize(SPSInputBuffer & IB,SequenceT & S)402   static bool deserialize(SPSInputBuffer &IB, SequenceT &S) {
403     using TBSD = TrivialSPSSequenceDeserialization<SPSElementTagT, SequenceT>;
404     uint64_t Size;
405     if (!SPSArgList<uint64_t>::deserialize(IB, Size))
406       return false;
407     TBSD::reserve(S, Size);
408     for (size_t I = 0; I != Size; ++I) {
409       typename TBSD::element_type E;
410       if (!SPSArgList<SPSElementTagT>::deserialize(IB, E))
411         return false;
412       if (!TBSD::append(S, std::move(E)))
413         return false;
414     }
415     return true;
416   }
417 };
418 
419 /// SPSTuple serialization for std::tuple.
420 template <typename... SPSTagTs, typename... Ts>
421 class SPSSerializationTraits<SPSTuple<SPSTagTs...>, std::tuple<Ts...>> {
422 private:
423   using TupleArgList = typename SPSTuple<SPSTagTs...>::AsArgList;
424   using ArgIndices = std::make_index_sequence<sizeof...(Ts)>;
425 
426   template <std::size_t... I>
size(const std::tuple<Ts...> & T,std::index_sequence<I...>)427   static size_t size(const std::tuple<Ts...> &T, std::index_sequence<I...>) {
428     return TupleArgList::size(std::get<I>(T)...);
429   }
430 
431   template <std::size_t... I>
serialize(SPSOutputBuffer & OB,const std::tuple<Ts...> & T,std::index_sequence<I...>)432   static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T,
433                         std::index_sequence<I...>) {
434     return TupleArgList::serialize(OB, std::get<I>(T)...);
435   }
436 
437   template <std::size_t... I>
deserialize(SPSInputBuffer & IB,std::tuple<Ts...> & T,std::index_sequence<I...>)438   static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T,
439                           std::index_sequence<I...>) {
440     return TupleArgList::deserialize(IB, std::get<I>(T)...);
441   }
442 
443 public:
size(const std::tuple<Ts...> & T)444   static size_t size(const std::tuple<Ts...> &T) {
445     return size(T, ArgIndices{});
446   }
447 
serialize(SPSOutputBuffer & OB,const std::tuple<Ts...> & T)448   static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T) {
449     return serialize(OB, T, ArgIndices{});
450   }
451 
deserialize(SPSInputBuffer & IB,std::tuple<Ts...> & T)452   static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T) {
453     return deserialize(IB, T, ArgIndices{});
454   }
455 };
456 
457 /// SPSTuple serialization for std::pair.
458 template <typename SPSTagT1, typename SPSTagT2, typename T1, typename T2>
459 class SPSSerializationTraits<SPSTuple<SPSTagT1, SPSTagT2>, std::pair<T1, T2>> {
460 public:
size(const std::pair<T1,T2> & P)461   static size_t size(const std::pair<T1, T2> &P) {
462     return SPSArgList<SPSTagT1>::size(P.first) +
463            SPSArgList<SPSTagT2>::size(P.second);
464   }
465 
serialize(SPSOutputBuffer & OB,const std::pair<T1,T2> & P)466   static bool serialize(SPSOutputBuffer &OB, const std::pair<T1, T2> &P) {
467     return SPSArgList<SPSTagT1>::serialize(OB, P.first) &&
468            SPSArgList<SPSTagT2>::serialize(OB, P.second);
469   }
470 
deserialize(SPSInputBuffer & IB,std::pair<T1,T2> & P)471   static bool deserialize(SPSInputBuffer &IB, std::pair<T1, T2> &P) {
472     return SPSArgList<SPSTagT1>::deserialize(IB, P.first) &&
473            SPSArgList<SPSTagT2>::deserialize(IB, P.second);
474   }
475 };
476 
477 /// SPSOptional serialization for std::optional.
478 template <typename SPSTagT, typename T>
479 class SPSSerializationTraits<SPSOptional<SPSTagT>, std::optional<T>> {
480 public:
size(const std::optional<T> & Value)481   static size_t size(const std::optional<T> &Value) {
482     size_t Size = SPSArgList<bool>::size(!!Value);
483     if (Value)
484       Size += SPSArgList<SPSTagT>::size(*Value);
485     return Size;
486   }
487 
serialize(SPSOutputBuffer & OB,const std::optional<T> & Value)488   static bool serialize(SPSOutputBuffer &OB, const std::optional<T> &Value) {
489     if (!SPSArgList<bool>::serialize(OB, !!Value))
490       return false;
491     if (Value)
492       return SPSArgList<SPSTagT>::serialize(OB, *Value);
493     return true;
494   }
495 
deserialize(SPSInputBuffer & IB,std::optional<T> & Value)496   static bool deserialize(SPSInputBuffer &IB, std::optional<T> &Value) {
497     bool HasValue;
498     if (!SPSArgList<bool>::deserialize(IB, HasValue))
499       return false;
500     if (HasValue) {
501       Value = T();
502       return SPSArgList<SPSTagT>::deserialize(IB, *Value);
503     } else
504       Value = std::optional<T>();
505     return true;
506   }
507 };
508 
509 /// Serialization for StringRefs.
510 ///
511 /// Serialization is as for regular strings. Deserialization points directly
512 /// into the blob.
513 template <> class SPSSerializationTraits<SPSString, StringRef> {
514 public:
size(const StringRef & S)515   static size_t size(const StringRef &S) {
516     return SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size())) +
517            S.size();
518   }
519 
serialize(SPSOutputBuffer & OB,StringRef S)520   static bool serialize(SPSOutputBuffer &OB, StringRef S) {
521     if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
522       return false;
523     if (S.empty()) // Empty StringRef may have null data, so bail out early.
524       return true;
525     return OB.write(S.data(), S.size());
526   }
527 
deserialize(SPSInputBuffer & IB,StringRef & S)528   static bool deserialize(SPSInputBuffer &IB, StringRef &S) {
529     const char *Data = nullptr;
530     uint64_t Size;
531     if (!SPSArgList<uint64_t>::deserialize(IB, Size))
532       return false;
533     Data = IB.data();
534     if (!IB.skip(Size))
535       return false;
536     S = StringRef(Size ? Data : nullptr, Size);
537     return true;
538   }
539 };
540 
541 /// Serialization for StringMap<ValueT>s.
542 template <typename SPSValueT, typename ValueT>
543 class SPSSerializationTraits<SPSSequence<SPSTuple<SPSString, SPSValueT>>,
544                              StringMap<ValueT>> {
545 public:
size(const StringMap<ValueT> & M)546   static size_t size(const StringMap<ValueT> &M) {
547     size_t Sz = SPSArgList<uint64_t>::size(static_cast<uint64_t>(M.size()));
548     for (auto &E : M)
549       Sz += SPSArgList<SPSString, SPSValueT>::size(E.first(), E.second);
550     return Sz;
551   }
552 
serialize(SPSOutputBuffer & OB,const StringMap<ValueT> & M)553   static bool serialize(SPSOutputBuffer &OB, const StringMap<ValueT> &M) {
554     if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(M.size())))
555       return false;
556 
557     for (auto &E : M)
558       if (!SPSArgList<SPSString, SPSValueT>::serialize(OB, E.first(), E.second))
559         return false;
560 
561     return true;
562   }
563 
deserialize(SPSInputBuffer & IB,StringMap<ValueT> & M)564   static bool deserialize(SPSInputBuffer &IB, StringMap<ValueT> &M) {
565     uint64_t Size;
566     assert(M.empty() && "M already contains elements");
567 
568     if (!SPSArgList<uint64_t>::deserialize(IB, Size))
569       return false;
570 
571     while (Size--) {
572       StringRef S;
573       ValueT V;
574       if (!SPSArgList<SPSString, SPSValueT>::deserialize(IB, S, V))
575         return false;
576       if (!M.insert(std::make_pair(S, V)).second)
577         return false;
578     }
579 
580     return true;
581   }
582 };
583 
584 /// SPS tag type for errors.
585 class SPSError;
586 
587 /// SPS tag type for expecteds, which are either a T or a string representing
588 /// an error.
589 template <typename SPSTagT> class SPSExpected;
590 
591 namespace detail {
592 
593 /// Helper type for serializing Errors.
594 ///
595 /// llvm::Errors are move-only, and not inspectable except by consuming them.
596 /// This makes them unsuitable for direct serialization via
597 /// SPSSerializationTraits, which needs to inspect values twice (once to
598 /// determine the amount of space to reserve, and then again to serialize).
599 ///
600 /// The SPSSerializableError type is a helper that can be
601 /// constructed from an llvm::Error, but inspected more than once.
602 struct SPSSerializableError {
603   bool HasError = false;
604   std::string ErrMsg;
605 };
606 
607 /// Helper type for serializing Expected<T>s.
608 ///
609 /// See SPSSerializableError for more details.
610 ///
611 // FIXME: Use std::variant for storage once we have c++17.
612 template <typename T> struct SPSSerializableExpected {
613   bool HasValue = false;
614   T Value{};
615   std::string ErrMsg;
616 };
617 
toSPSSerializable(Error Err)618 inline SPSSerializableError toSPSSerializable(Error Err) {
619   if (Err)
620     return {true, toString(std::move(Err))};
621   return {false, {}};
622 }
623 
fromSPSSerializable(SPSSerializableError BSE)624 inline Error fromSPSSerializable(SPSSerializableError BSE) {
625   if (BSE.HasError)
626     return make_error<StringError>(BSE.ErrMsg, inconvertibleErrorCode());
627   return Error::success();
628 }
629 
630 template <typename T>
toSPSSerializable(Expected<T> E)631 SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {
632   if (E)
633     return {true, std::move(*E), {}};
634   else
635     return {false, T(), toString(E.takeError())};
636 }
637 
638 template <typename T>
fromSPSSerializable(SPSSerializableExpected<T> BSE)639 Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {
640   if (BSE.HasValue)
641     return std::move(BSE.Value);
642   else
643     return make_error<StringError>(BSE.ErrMsg, inconvertibleErrorCode());
644 }
645 
646 } // end namespace detail
647 
648 /// Serialize to a SPSError from a detail::SPSSerializableError.
649 template <>
650 class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {
651 public:
size(const detail::SPSSerializableError & BSE)652   static size_t size(const detail::SPSSerializableError &BSE) {
653     size_t Size = SPSArgList<bool>::size(BSE.HasError);
654     if (BSE.HasError)
655       Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
656     return Size;
657   }
658 
serialize(SPSOutputBuffer & OB,const detail::SPSSerializableError & BSE)659   static bool serialize(SPSOutputBuffer &OB,
660                         const detail::SPSSerializableError &BSE) {
661     if (!SPSArgList<bool>::serialize(OB, BSE.HasError))
662       return false;
663     if (BSE.HasError)
664       if (!SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg))
665         return false;
666     return true;
667   }
668 
deserialize(SPSInputBuffer & IB,detail::SPSSerializableError & BSE)669   static bool deserialize(SPSInputBuffer &IB,
670                           detail::SPSSerializableError &BSE) {
671     if (!SPSArgList<bool>::deserialize(IB, BSE.HasError))
672       return false;
673 
674     if (!BSE.HasError)
675       return true;
676 
677     return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
678   }
679 };
680 
681 /// Serialize to a SPSExpected<SPSTagT> from a
682 /// detail::SPSSerializableExpected<T>.
683 template <typename SPSTagT, typename T>
684 class SPSSerializationTraits<SPSExpected<SPSTagT>,
685                              detail::SPSSerializableExpected<T>> {
686 public:
size(const detail::SPSSerializableExpected<T> & BSE)687   static size_t size(const detail::SPSSerializableExpected<T> &BSE) {
688     size_t Size = SPSArgList<bool>::size(BSE.HasValue);
689     if (BSE.HasValue)
690       Size += SPSArgList<SPSTagT>::size(BSE.Value);
691     else
692       Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
693     return Size;
694   }
695 
serialize(SPSOutputBuffer & OB,const detail::SPSSerializableExpected<T> & BSE)696   static bool serialize(SPSOutputBuffer &OB,
697                         const detail::SPSSerializableExpected<T> &BSE) {
698     if (!SPSArgList<bool>::serialize(OB, BSE.HasValue))
699       return false;
700 
701     if (BSE.HasValue)
702       return SPSArgList<SPSTagT>::serialize(OB, BSE.Value);
703 
704     return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
705   }
706 
deserialize(SPSInputBuffer & IB,detail::SPSSerializableExpected<T> & BSE)707   static bool deserialize(SPSInputBuffer &IB,
708                           detail::SPSSerializableExpected<T> &BSE) {
709     if (!SPSArgList<bool>::deserialize(IB, BSE.HasValue))
710       return false;
711 
712     if (BSE.HasValue)
713       return SPSArgList<SPSTagT>::deserialize(IB, BSE.Value);
714 
715     return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
716   }
717 };
718 
719 /// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.
720 template <typename SPSTagT>
721 class SPSSerializationTraits<SPSExpected<SPSTagT>,
722                              detail::SPSSerializableError> {
723 public:
size(const detail::SPSSerializableError & BSE)724   static size_t size(const detail::SPSSerializableError &BSE) {
725     assert(BSE.HasError && "Cannot serialize expected from a success value");
726     return SPSArgList<bool>::size(false) +
727            SPSArgList<SPSString>::size(BSE.ErrMsg);
728   }
729 
serialize(SPSOutputBuffer & OB,const detail::SPSSerializableError & BSE)730   static bool serialize(SPSOutputBuffer &OB,
731                         const detail::SPSSerializableError &BSE) {
732     assert(BSE.HasError && "Cannot serialize expected from a success value");
733     if (!SPSArgList<bool>::serialize(OB, false))
734       return false;
735     return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
736   }
737 };
738 
739 /// Serialize to a SPSExpected<SPSTagT> from a T.
740 template <typename SPSTagT, typename T>
741 class SPSSerializationTraits<SPSExpected<SPSTagT>, T> {
742 public:
size(const T & Value)743   static size_t size(const T &Value) {
744     return SPSArgList<bool>::size(true) + SPSArgList<SPSTagT>::size(Value);
745   }
746 
serialize(SPSOutputBuffer & OB,const T & Value)747   static bool serialize(SPSOutputBuffer &OB, const T &Value) {
748     if (!SPSArgList<bool>::serialize(OB, true))
749       return false;
750     return SPSArgList<SPSTagT>::serialize(Value);
751   }
752 };
753 
754 } // end namespace shared
755 } // end namespace orc
756 } // end namespace llvm
757 
758 #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H
759