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