1 //===-- wrapper_function_utils.h - Utilities for wrapper funcs --*- 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 // This file is a part of the ORC runtime support library.
10 //
11 // The behavior of the utilities in this header must be synchronized with the
12 // behavior of the utilities in
13 // llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h.
14 //
15 // The Simple Packed Serialization (SPS) utilities are used to generate
16 // argument and return buffers for wrapper functions using the following
17 // serialization scheme:
18 //
19 // Primitives:
20 //   bool, char, int8_t, uint8_t -- Two's complement 8-bit (0=false, 1=true)
21 //   int16_t, uint16_t           -- Two's complement 16-bit little endian
22 //   int32_t, uint32_t           -- Two's complement 32-bit little endian
23 //   int64_t, int64_t            -- Two's complement 64-bit little endian
24 //
25 // Sequence<T>:
26 //   Serialized as the sequence length (as a uint64_t) followed by the
27 //   serialization of each of the elements without padding.
28 //
29 // Tuple<T1, ..., TN>:
30 //   Serialized as each of the element types from T1 to TN without padding.
31 //
32 //===----------------------------------------------------------------------===//
33 
34 #ifndef ORC_RT_WRAPPER_FUNCTION_UTILS_H
35 #define ORC_RT_WRAPPER_FUNCTION_UTILS_H
36 
37 #include "adt.h"
38 #include "c_api.h"
39 #include "common.h"
40 #include "endianness.h"
41 #include "error.h"
42 #include "stl_extras.h"
43 
44 #include <string>
45 #include <tuple>
46 #include <type_traits>
47 #include <utility>
48 #include <vector>
49 
50 namespace __orc_rt {
51 
52 /// C++ wrapper function result: Same as CWrapperFunctionResult but
53 /// auto-releases memory.
54 class WrapperFunctionResult {
55 public:
56   /// Create a default WrapperFunctionResult.
57   WrapperFunctionResult() { __orc_rt_CWrapperFunctionResultInit(&R); }
58 
59   /// Create a WrapperFunctionResult from a CWrapperFunctionResult. This
60   /// instance takes ownership of the result object and will automatically
61   /// call dispose on the result upon destruction.
62   WrapperFunctionResult(__orc_rt_CWrapperFunctionResult R) : R(R) {}
63 
64   WrapperFunctionResult(const WrapperFunctionResult &) = delete;
65   WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
66 
67   WrapperFunctionResult(WrapperFunctionResult &&Other) {
68     __orc_rt_CWrapperFunctionResultInit(&R);
69     std::swap(R, Other.R);
70   }
71 
72   WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
73     __orc_rt_CWrapperFunctionResult Tmp;
74     __orc_rt_CWrapperFunctionResultInit(&Tmp);
75     std::swap(Tmp, Other.R);
76     std::swap(R, Tmp);
77     return *this;
78   }
79 
80   ~WrapperFunctionResult() { __orc_rt_DisposeCWrapperFunctionResult(&R); }
81 
82   /// Relinquish ownership of and return the
83   /// __orc_rt_CWrapperFunctionResult.
84   __orc_rt_CWrapperFunctionResult release() {
85     __orc_rt_CWrapperFunctionResult Tmp;
86     __orc_rt_CWrapperFunctionResultInit(&Tmp);
87     std::swap(R, Tmp);
88     return Tmp;
89   }
90 
91   /// Get an ArrayRef covering the data in the result.
92   const char *data() const { return __orc_rt_CWrapperFunctionResultData(&R); }
93 
94   /// Returns the size of the data contained in this instance.
95   size_t size() const { return __orc_rt_CWrapperFunctionResultSize(&R); }
96 
97   /// Returns true if this value is equivalent to a default-constructed
98   /// WrapperFunctionResult.
99   bool empty() const { return __orc_rt_CWrapperFunctionResultEmpty(&R); }
100 
101   /// Create a WrapperFunctionResult with the given size and return a pointer
102   /// to the underlying memory.
103   static char *allocate(WrapperFunctionResult &R, size_t Size) {
104     __orc_rt_DisposeCWrapperFunctionResult(&R.R);
105     __orc_rt_CWrapperFunctionResultInit(&R.R);
106     return __orc_rt_CWrapperFunctionResultAllocate(&R.R, Size);
107   }
108 
109   /// Copy from the given char range.
110   static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
111     return __orc_rt_CreateCWrapperFunctionResultFromRange(Source, Size);
112   }
113 
114   /// Copy from the given null-terminated string (includes the null-terminator).
115   static WrapperFunctionResult copyFrom(const char *Source) {
116     return __orc_rt_CreateCWrapperFunctionResultFromString(Source);
117   }
118 
119   /// Copy from the given std::string (includes the null terminator).
120   static WrapperFunctionResult copyFrom(const std::string &Source) {
121     return copyFrom(Source.c_str());
122   }
123 
124   /// Create an out-of-band error by copying the given string.
125   static WrapperFunctionResult createOutOfBandError(const char *Msg) {
126     return __orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(Msg);
127   }
128 
129   /// If this value is an out-of-band error then this returns the error message,
130   /// otherwise returns nullptr.
131   const char *getOutOfBandError() const {
132     return __orc_rt_CWrapperFunctionResultGetOutOfBandError(&R);
133   }
134 
135 private:
136   __orc_rt_CWrapperFunctionResult R;
137 };
138 
139 /// Output char buffer with overflow check.
140 class SPSOutputBuffer {
141 public:
142   SPSOutputBuffer(char *Buffer, size_t Remaining)
143       : Buffer(Buffer), Remaining(Remaining) {}
144   bool write(const char *Data, size_t Size) {
145     if (Size > Remaining)
146       return false;
147     memcpy(Buffer, Data, Size);
148     Buffer += Size;
149     Remaining -= Size;
150     return true;
151   }
152 
153 private:
154   char *Buffer = nullptr;
155   size_t Remaining = 0;
156 };
157 
158 /// Input char buffer with underflow check.
159 class SPSInputBuffer {
160 public:
161   SPSInputBuffer() = default;
162   SPSInputBuffer(const char *Buffer, size_t Remaining)
163       : Buffer(Buffer), Remaining(Remaining) {}
164   bool read(char *Data, size_t Size) {
165     if (Size > Remaining)
166       return false;
167     memcpy(Data, Buffer, Size);
168     Buffer += Size;
169     Remaining -= Size;
170     return true;
171   }
172 
173   const char *data() const { return Buffer; }
174   bool skip(size_t Size) {
175     if (Size > Remaining)
176       return false;
177     Remaining -= Size;
178     return true;
179   }
180 
181 private:
182   const char *Buffer = nullptr;
183   size_t Remaining = 0;
184 };
185 
186 /// Specialize to describe how to serialize/deserialize to/from the given
187 /// concrete type.
188 template <typename SPSTagT, typename ConcreteT, typename _ = void>
189 class SPSSerializationTraits;
190 
191 /// A utility class for serializing to a blob from a variadic list.
192 template <typename... ArgTs> class SPSArgList;
193 
194 // Empty list specialization for SPSArgList.
195 template <> class SPSArgList<> {
196 public:
197   static size_t size() { return 0; }
198 
199   static bool serialize(SPSOutputBuffer &OB) { return true; }
200   static bool deserialize(SPSInputBuffer &IB) { return true; }
201 
202   static bool toWrapperFunctionResult(WrapperFunctionResult &R) {
203     R = WrapperFunctionResult();
204     return true;
205   }
206 };
207 
208 // Non-empty list specialization for SPSArgList.
209 template <typename SPSTagT, typename... SPSTagTs>
210 class SPSArgList<SPSTagT, SPSTagTs...> {
211 public:
212   template <typename ArgT, typename... ArgTs>
213   static size_t size(const ArgT &Arg, const ArgTs &...Args) {
214     return SPSSerializationTraits<SPSTagT, ArgT>::size(Arg) +
215            SPSArgList<SPSTagTs...>::size(Args...);
216   }
217 
218   template <typename ArgT, typename... ArgTs>
219   static bool serialize(SPSOutputBuffer &OB, const ArgT &Arg,
220                         const ArgTs &...Args) {
221     return SPSSerializationTraits<SPSTagT, ArgT>::serialize(OB, Arg) &&
222            SPSArgList<SPSTagTs...>::serialize(OB, Args...);
223   }
224 
225   template <typename ArgT, typename... ArgTs>
226   static bool deserialize(SPSInputBuffer &IB, ArgT &Arg, ArgTs &...Args) {
227     return SPSSerializationTraits<SPSTagT, ArgT>::deserialize(IB, Arg) &&
228            SPSArgList<SPSTagTs...>::deserialize(IB, Args...);
229   }
230 
231   template <typename... ArgTs>
232   static bool toWrapperFunctionResult(WrapperFunctionResult &R,
233                                       const ArgTs &...Args) {
234     WrapperFunctionResult TR;
235     char *DataPtr = WrapperFunctionResult::allocate(TR, size(Args...));
236 
237     SPSOutputBuffer OB(DataPtr, TR.size());
238     if (!serialize(OB, Args...))
239       return false;
240 
241     R = std::move(TR);
242     return true;
243   }
244 
245   template <typename... ArgTs>
246   static bool fromBuffer(const char *Data, size_t Size, ArgTs &...Args) {
247     SPSInputBuffer IB(Data, Size);
248     return deserialize(IB, Args...);
249   }
250 };
251 
252 /// SPS serialization for integral types, bool, and char.
253 template <typename SPSTagT>
254 class SPSSerializationTraits<
255     SPSTagT, SPSTagT,
256     std::enable_if_t<std::is_same<SPSTagT, bool>::value ||
257                      std::is_same<SPSTagT, char>::value ||
258                      std::is_same<SPSTagT, int8_t>::value ||
259                      std::is_same<SPSTagT, int16_t>::value ||
260                      std::is_same<SPSTagT, int32_t>::value ||
261                      std::is_same<SPSTagT, int64_t>::value ||
262                      std::is_same<SPSTagT, uint8_t>::value ||
263                      std::is_same<SPSTagT, uint16_t>::value ||
264                      std::is_same<SPSTagT, uint32_t>::value ||
265                      std::is_same<SPSTagT, uint64_t>::value>> {
266 public:
267   static size_t size(const SPSTagT &Value) { return sizeof(SPSTagT); }
268 
269   static bool serialize(SPSOutputBuffer &OB, const SPSTagT &Value) {
270     SPSTagT Tmp = Value;
271     if (IsBigEndianHost)
272       swapByteOrder(Tmp);
273     return OB.write(reinterpret_cast<const char *>(&Tmp), sizeof(Tmp));
274   }
275 
276   static bool deserialize(SPSInputBuffer &IB, SPSTagT &Value) {
277     SPSTagT Tmp;
278     if (!IB.read(reinterpret_cast<char *>(&Tmp), sizeof(Tmp)))
279       return false;
280     if (IsBigEndianHost)
281       swapByteOrder(Tmp);
282     Value = Tmp;
283     return true;
284   }
285 };
286 
287 // Any empty placeholder suitable as a substitute for void when deserializing
288 class SPSEmpty {};
289 
290 /// SPS tag type for target addresses.
291 ///
292 /// SPSTagTargetAddresses should be serialized as a uint64_t value.
293 class SPSTagTargetAddress;
294 
295 template <>
296 class SPSSerializationTraits<SPSTagTargetAddress, uint64_t>
297     : public SPSSerializationTraits<uint64_t, uint64_t> {};
298 
299 /// SPS tag type for tuples.
300 ///
301 /// A blob tuple should be serialized by serializing each of the elements in
302 /// sequence.
303 template <typename... SPSTagTs> class SPSTuple {
304 public:
305   /// Convenience typedef of the corresponding arg list.
306   typedef SPSArgList<SPSTagTs...> AsArgList;
307 };
308 
309 /// SPS tag type for sequences.
310 ///
311 /// SPSSequences should be serialized as a uint64_t sequence length,
312 /// followed by the serialization of each of the elements.
313 template <typename SPSElementTagT> class SPSSequence;
314 
315 /// SPS tag type for strings, which are equivalent to sequences of chars.
316 using SPSString = SPSSequence<char>;
317 
318 /// SPS tag type for maps.
319 ///
320 /// SPS maps are just sequences of (Key, Value) tuples.
321 template <typename SPSTagT1, typename SPSTagT2>
322 using SPSMap = SPSSequence<SPSTuple<SPSTagT1, SPSTagT2>>;
323 
324 /// Serialization for SPSEmpty type.
325 template <> class SPSSerializationTraits<SPSEmpty, SPSEmpty> {
326 public:
327   static size_t size(const SPSEmpty &EP) { return 0; }
328   static bool serialize(SPSOutputBuffer &OB, const SPSEmpty &BE) {
329     return true;
330   }
331   static bool deserialize(SPSInputBuffer &IB, SPSEmpty &BE) { return true; }
332 };
333 
334 /// Specialize this to implement 'trivial' sequence serialization for
335 /// a concrete sequence type.
336 ///
337 /// Trivial sequence serialization uses the sequence's 'size' member to get the
338 /// length of the sequence, and uses a range-based for loop to iterate over the
339 /// elements.
340 ///
341 /// Specializing this template class means that you do not need to provide a
342 /// specialization of SPSSerializationTraits for your type.
343 template <typename SPSElementTagT, typename ConcreteSequenceT>
344 class TrivialSPSSequenceSerialization {
345 public:
346   static constexpr bool available = false;
347 };
348 
349 /// Specialize this to implement 'trivial' sequence deserialization for
350 /// a concrete sequence type.
351 ///
352 /// Trivial deserialization calls a static 'reserve(SequenceT&)' method on your
353 /// specialization (you must implement this) to reserve space, and then calls
354 /// a static 'append(SequenceT&, ElementT&) method to append each of the
355 /// deserialized elements.
356 ///
357 /// Specializing this template class means that you do not need to provide a
358 /// specialization of SPSSerializationTraits for your type.
359 template <typename SPSElementTagT, typename ConcreteSequenceT>
360 class TrivialSPSSequenceDeserialization {
361 public:
362   static constexpr bool available = false;
363 };
364 
365 /// Trivial std::string -> SPSSequence<char> serialization.
366 template <> class TrivialSPSSequenceSerialization<char, std::string> {
367 public:
368   static constexpr bool available = true;
369 };
370 
371 /// Trivial SPSSequence<char> -> std::string deserialization.
372 template <> class TrivialSPSSequenceDeserialization<char, std::string> {
373 public:
374   static constexpr bool available = true;
375 
376   using element_type = char;
377 
378   static void reserve(std::string &S, uint64_t Size) { S.reserve(Size); }
379   static bool append(std::string &S, char C) {
380     S.push_back(C);
381     return true;
382   }
383 };
384 
385 /// Trivial std::vector<T> -> SPSSequence<SPSElementTagT> serialization.
386 template <typename SPSElementTagT, typename T>
387 class TrivialSPSSequenceSerialization<SPSElementTagT, std::vector<T>> {
388 public:
389   static constexpr bool available = true;
390 };
391 
392 /// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization.
393 template <typename SPSElementTagT, typename T>
394 class TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>> {
395 public:
396   static constexpr bool available = true;
397 
398   using element_type = typename std::vector<T>::value_type;
399 
400   static void reserve(std::vector<T> &V, uint64_t Size) { V.reserve(Size); }
401   static bool append(std::vector<T> &V, T E) {
402     V.push_back(std::move(E));
403     return true;
404   }
405 };
406 
407 /// 'Trivial' sequence serialization: Sequence is serialized as a uint64_t size
408 /// followed by a for-earch loop over the elements of the sequence to serialize
409 /// each of them.
410 template <typename SPSElementTagT, typename SequenceT>
411 class SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT,
412                              std::enable_if_t<TrivialSPSSequenceSerialization<
413                                  SPSElementTagT, SequenceT>::available>> {
414 public:
415   static size_t size(const SequenceT &S) {
416     size_t Size = SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size()));
417     for (const auto &E : S)
418       Size += SPSArgList<SPSElementTagT>::size(E);
419     return Size;
420   }
421 
422   static bool serialize(SPSOutputBuffer &OB, const SequenceT &S) {
423     if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
424       return false;
425     for (const auto &E : S)
426       if (!SPSArgList<SPSElementTagT>::serialize(OB, E))
427         return false;
428     return true;
429   }
430 
431   static bool deserialize(SPSInputBuffer &IB, SequenceT &S) {
432     using TBSD = TrivialSPSSequenceDeserialization<SPSElementTagT, SequenceT>;
433     uint64_t Size;
434     if (!SPSArgList<uint64_t>::deserialize(IB, Size))
435       return false;
436     TBSD::reserve(S, Size);
437     for (size_t I = 0; I != Size; ++I) {
438       typename TBSD::element_type E;
439       if (!SPSArgList<SPSElementTagT>::deserialize(IB, E))
440         return false;
441       if (!TBSD::append(S, std::move(E)))
442         return false;
443     }
444     return true;
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:
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 
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 
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 string_views.
469 ///
470 /// Serialization is as for regular strings. Deserialization points directly
471 /// into the blob.
472 template <> class SPSSerializationTraits<SPSString, __orc_rt::string_view> {
473 public:
474   static size_t size(const __orc_rt::string_view &S) {
475     return SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size())) +
476            S.size();
477   }
478 
479   static bool serialize(SPSOutputBuffer &OB, const __orc_rt::string_view &S) {
480     if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
481       return false;
482     return OB.write(S.data(), S.size());
483   }
484 
485   static bool deserialize(SPSInputBuffer &IB, __orc_rt::string_view &S) {
486     const char *Data = nullptr;
487     uint64_t Size;
488     if (!SPSArgList<uint64_t>::deserialize(IB, Size))
489       return false;
490     Data = IB.data();
491     if (!IB.skip(Size))
492       return false;
493     S = {Data, Size};
494     return true;
495   }
496 };
497 
498 /// SPS tag type for errors.
499 class SPSError;
500 
501 /// SPS tag type for expecteds, which are either a T or a string representing
502 /// an error.
503 template <typename SPSTagT> class SPSExpected;
504 
505 namespace detail {
506 
507 /// Helper type for serializing Errors.
508 ///
509 /// llvm::Errors are move-only, and not inspectable except by consuming them.
510 /// This makes them unsuitable for direct serialization via
511 /// SPSSerializationTraits, which needs to inspect values twice (once to
512 /// determine the amount of space to reserve, and then again to serialize).
513 ///
514 /// The WrapperFunctionSerializableError type is a helper that can be
515 /// constructed from an llvm::Error, but inspected more than once.
516 struct SPSSerializableError {
517   bool HasError = false;
518   std::string ErrMsg;
519 };
520 
521 /// Helper type for serializing Expected<T>s.
522 ///
523 /// See SPSSerializableError for more details.
524 ///
525 // FIXME: Use std::variant for storage once we have c++17.
526 template <typename T> struct SPSSerializableExpected {
527   bool HasValue = false;
528   T Value{};
529   std::string ErrMsg;
530 };
531 
532 inline SPSSerializableError toSPSSerializable(Error Err) {
533   if (Err)
534     return {true, toString(std::move(Err))};
535   return {false, {}};
536 }
537 
538 inline Error fromSPSSerializable(SPSSerializableError BSE) {
539   if (BSE.HasError)
540     return make_error<StringError>(BSE.ErrMsg);
541   return Error::success();
542 }
543 
544 template <typename T>
545 SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {
546   if (E)
547     return {true, std::move(*E), {}};
548   else
549     return {false, {}, toString(E.takeError())};
550 }
551 
552 template <typename T>
553 Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {
554   if (BSE.HasValue)
555     return std::move(BSE.Value);
556   else
557     return make_error<StringError>(BSE.ErrMsg);
558 }
559 
560 } // end namespace detail
561 
562 /// Serialize to a SPSError from a detail::SPSSerializableError.
563 template <>
564 class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {
565 public:
566   static size_t size(const detail::SPSSerializableError &BSE) {
567     size_t Size = SPSArgList<bool>::size(BSE.HasError);
568     if (BSE.HasError)
569       Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
570     return Size;
571   }
572 
573   static bool serialize(SPSOutputBuffer &OB,
574                         const detail::SPSSerializableError &BSE) {
575     if (!SPSArgList<bool>::serialize(OB, BSE.HasError))
576       return false;
577     if (BSE.HasError)
578       if (!SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg))
579         return false;
580     return true;
581   }
582 
583   static bool deserialize(SPSInputBuffer &IB,
584                           detail::SPSSerializableError &BSE) {
585     if (!SPSArgList<bool>::deserialize(IB, BSE.HasError))
586       return false;
587 
588     if (!BSE.HasError)
589       return true;
590 
591     return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
592   }
593 };
594 
595 /// Serialize to a SPSExpected<SPSTagT> from a
596 /// detail::SPSSerializableExpected<T>.
597 template <typename SPSTagT, typename T>
598 class SPSSerializationTraits<SPSExpected<SPSTagT>,
599                              detail::SPSSerializableExpected<T>> {
600 public:
601   static size_t size(const detail::SPSSerializableExpected<T> &BSE) {
602     size_t Size = SPSArgList<bool>::size(BSE.HasValue);
603     if (BSE.HasValue)
604       Size += SPSArgList<SPSTagT>::size(BSE.Value);
605     else
606       Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
607     return Size;
608   }
609 
610   static bool serialize(SPSOutputBuffer &OB,
611                         const detail::SPSSerializableExpected<T> &BSE) {
612     if (!SPSArgList<bool>::serialize(OB, BSE.HasValue))
613       return false;
614 
615     if (BSE.HasValue)
616       return SPSArgList<SPSTagT>::serialize(OB, BSE.Value);
617 
618     return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
619   }
620 
621   static bool deserialize(SPSInputBuffer &IB,
622                           detail::SPSSerializableExpected<T> &BSE) {
623     if (!SPSArgList<bool>::deserialize(IB, BSE.HasValue))
624       return false;
625 
626     if (BSE.HasValue)
627       return SPSArgList<SPSTagT>::deserialize(IB, BSE.Value);
628 
629     return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
630   }
631 };
632 
633 /// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.
634 template <typename SPSTagT>
635 class SPSSerializationTraits<SPSExpected<SPSTagT>,
636                              detail::SPSSerializableError> {
637 public:
638   static size_t size(const detail::SPSSerializableError &BSE) {
639     assert(BSE.HasError && "Cannot serialize expected from a success value");
640     return SPSArgList<bool>::size(false) +
641            SPSArgList<SPSString>::size(BSE.ErrMsg);
642   }
643 
644   static bool serialize(SPSOutputBuffer &OB,
645                         const detail::SPSSerializableError &BSE) {
646     assert(BSE.HasError && "Cannot serialize expected from a success value");
647     if (!SPSArgList<bool>::serialize(OB, false))
648       return false;
649     return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
650   }
651 };
652 
653 /// Serialize to a SPSExpected<SPSTagT> from a T.
654 template <typename SPSTagT, typename T>
655 class SPSSerializationTraits<SPSExpected<SPSTagT>, T> {
656 public:
657   static size_t size(const T &Value) {
658     return SPSArgList<bool>::size(true) + SPSArgList<SPSTagT>::size(Value);
659   }
660 
661   static bool serialize(SPSOutputBuffer &OB, const T &Value) {
662     if (!SPSArgList<bool>::serialize(OB, true))
663       return false;
664     return SPSArgList<SPSTagT>::serialize(Value);
665   }
666 };
667 
668 namespace detail {
669 
670 template <typename WrapperFunctionImplT,
671           template <typename> class ResultSerializer, typename... SPSTagTs>
672 class WrapperFunctionHandlerHelper
673     : public WrapperFunctionHandlerHelper<
674           decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
675           ResultSerializer, SPSTagTs...> {};
676 
677 template <typename RetT, typename... ArgTs,
678           template <typename> class ResultSerializer, typename... SPSTagTs>
679 class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
680                                    SPSTagTs...> {
681 public:
682   using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
683   using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
684 
685   template <typename HandlerT>
686   static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData,
687                                      size_t ArgSize) {
688     ArgTuple Args;
689     if (!deserialize(ArgData, ArgSize, Args, ArgIndices{}))
690       return WrapperFunctionResult::createOutOfBandError(
691           "Could not deserialize arguments for wrapper function call");
692 
693     return ResultSerializer<RetT>::serialize(
694         call(std::forward<HandlerT>(H), Args, ArgIndices{}));
695   }
696 
697 private:
698   template <std::size_t... I>
699   static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
700                           std::index_sequence<I...>) {
701     SPSInputBuffer IB(ArgData, ArgSize);
702     return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
703   }
704 
705   template <typename HandlerT, std::size_t... I>
706   static decltype(auto) call(HandlerT &&H, ArgTuple &Args,
707                              std::index_sequence<I...>) {
708     return std::forward<HandlerT>(H)(std::get<I>(Args)...);
709   }
710 };
711 
712 // Map function references to function types.
713 template <typename RetT, typename... ArgTs,
714           template <typename> class ResultSerializer, typename... SPSTagTs>
715 class WrapperFunctionHandlerHelper<RetT (&)(ArgTs...), ResultSerializer,
716                                    SPSTagTs...>
717     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
718                                           SPSTagTs...> {};
719 
720 // Map non-const member function types to function types.
721 template <typename ClassT, typename RetT, typename... ArgTs,
722           template <typename> class ResultSerializer, typename... SPSTagTs>
723 class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer,
724                                    SPSTagTs...>
725     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
726                                           SPSTagTs...> {};
727 
728 // Map const member function types to function types.
729 template <typename ClassT, typename RetT, typename... ArgTs,
730           template <typename> class ResultSerializer, typename... SPSTagTs>
731 class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
732                                    ResultSerializer, SPSTagTs...>
733     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
734                                           SPSTagTs...> {};
735 
736 template <typename SPSRetTagT, typename RetT> class ResultSerializer {
737 public:
738   static WrapperFunctionResult serialize(RetT Result) {
739     WrapperFunctionResult R;
740     if (!SPSArgList<SPSRetTagT>::toWrapperFunctionResult(R, Result))
741       return WrapperFunctionResult::createOutOfBandError(
742           "Could not serialize return value from wrapper function");
743     return R;
744   }
745 };
746 
747 template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
748 public:
749   static WrapperFunctionResult serialize(Error Err) {
750     WrapperFunctionResult R;
751     if (!SPSArgList<SPSRetTagT>::toWrapperFunctionResult(
752             R, toSPSSerializable(std::move(Err))))
753       return WrapperFunctionResult::createOutOfBandError(
754           "Could not serialize return value from wrapper function");
755     return R;
756   }
757 };
758 
759 template <typename SPSRetTagT, typename T>
760 class ResultSerializer<SPSRetTagT, Expected<T>> {
761 public:
762   static WrapperFunctionResult serialize(Expected<T> E) {
763     WrapperFunctionResult R;
764     if (!SPSArgList<SPSRetTagT>::toWrapperFunctionResult(
765             R, toSPSSerializable(std::move(E))))
766       return WrapperFunctionResult::createOutOfBandError(
767           "Could not serialize return value from wrapper function");
768     return R;
769   }
770 };
771 
772 template <typename SPSRetTagT, typename RetT> class ResultDeserializer {
773 public:
774   static void makeSafe(RetT &Result) {}
775 
776   static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) {
777     SPSInputBuffer IB(ArgData, ArgSize);
778     if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result))
779       return make_error<StringError>(
780           "Error deserializing return value from blob in call");
781     return Error::success();
782   }
783 };
784 
785 template <> class ResultDeserializer<SPSError, Error> {
786 public:
787   static void makeSafe(Error &Err) { cantFail(std::move(Err)); }
788 
789   static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) {
790     SPSInputBuffer IB(ArgData, ArgSize);
791     SPSSerializableError BSE;
792     if (!SPSArgList<SPSError>::deserialize(IB, BSE))
793       return make_error<StringError>(
794           "Error deserializing return value from blob in call");
795     Err = fromSPSSerializable(std::move(BSE));
796     return Error::success();
797   }
798 };
799 
800 template <typename SPSTagT, typename T>
801 class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> {
802 public:
803   static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); }
804 
805   static Error deserialize(Expected<T> &E, const char *ArgData,
806                            size_t ArgSize) {
807     SPSInputBuffer IB(ArgData, ArgSize);
808     SPSSerializableExpected<T> BSE;
809     if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE))
810       return make_error<StringError>(
811           "Error deserializing return value from blob in call");
812     E = fromSPSSerializable(std::move(BSE));
813     return Error::success();
814   }
815 };
816 
817 } // end namespace detail
818 
819 template <typename SPSSignature> class WrapperFunction;
820 
821 template <typename SPSRetTagT, typename... SPSTagTs>
822 class WrapperFunction<SPSRetTagT(SPSTagTs...)> {
823 private:
824   template <typename RetT>
825   using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>;
826 
827 public:
828   template <typename RetT, typename... ArgTs>
829   static Error call(const void *FnTag, RetT &Result, const ArgTs &...Args) {
830 
831     // RetT might be an Error or Expected value. Set the checked flag now:
832     // we don't want the user to have to check the unused result if this
833     // operation fails.
834     detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result);
835 
836     if (ORC_RT_UNLIKELY(!&__orc_rt_jit_dispatch_ctx))
837       return make_error<StringError>("__orc_jtjit_dispatch_ctx not set");
838     if (ORC_RT_UNLIKELY(!&__orc_rt_jit_dispatch_ctx))
839       return make_error<StringError>("__orc_jtjit_dispatch not set");
840 
841     WrapperFunctionResult ArgBuffer;
842     if (!SPSArgList<SPSTagTs...>::toWrapperFunctionResult(ArgBuffer, Args...))
843       return make_error<StringError>(
844           "Error serializing arguments to blob in call");
845     WrapperFunctionResult ResultBuffer = __orc_rt_jit_dispatch(
846         &__orc_rt_jit_dispatch_ctx, FnTag, ArgBuffer.data(), ArgBuffer.size());
847     if (auto ErrMsg = ResultBuffer.getOutOfBandError())
848       return make_error<StringError>(ErrMsg);
849 
850     return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
851         Result, ResultBuffer.data(), ResultBuffer.size());
852   }
853 
854   template <typename HandlerT>
855   static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize,
856                                       HandlerT &&Handler) {
857     using WFHH =
858         detail::WrapperFunctionHandlerHelper<HandlerT, ResultSerializer,
859                                              SPSTagTs...>;
860     return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
861   }
862 
863 private:
864   template <typename T> static const T &makeSerializable(const T &Value) {
865     return Value;
866   }
867 
868   static detail::SPSSerializableError makeSerializable(Error Err) {
869     return detail::toSPSSerializable(std::move(Err));
870   }
871 
872   template <typename T>
873   static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) {
874     return detail::toSPSSerializable(std::move(E));
875   }
876 };
877 
878 template <typename... SPSTagTs>
879 class WrapperFunction<void(SPSTagTs...)>
880     : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
881 public:
882   template <typename... ArgTs>
883   static Error call(const void *FnTag, const ArgTs &...Args) {
884     SPSEmpty BE;
885     return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(FnTag, BE, Args...);
886   }
887 
888   using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle;
889 };
890 
891 } // end namespace __orc_rt
892 
893 #endif // ORC_RT_WRAPPER_FUNCTION_UTILS_H
894