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