1 //===- WrapperFunctionUtils.h - Utilities for wrapper functions -*- 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 // A buffer for serialized results. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H 14 #define LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H 15 16 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" 17 #include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h" 18 #include "llvm/Support/Error.h" 19 20 #include <type_traits> 21 22 namespace llvm { 23 namespace orc { 24 namespace shared { 25 26 // Must be kept in-sync with compiler-rt/lib/orc/c-api.h. 27 union CWrapperFunctionResultDataUnion { 28 char *ValuePtr; 29 char Value[sizeof(ValuePtr)]; 30 }; 31 32 // Must be kept in-sync with compiler-rt/lib/orc/c-api.h. 33 typedef struct { 34 CWrapperFunctionResultDataUnion Data; 35 size_t Size; 36 } CWrapperFunctionResult; 37 38 /// C++ wrapper function result: Same as CWrapperFunctionResult but 39 /// auto-releases memory. 40 class WrapperFunctionResult { 41 public: 42 /// Create a default WrapperFunctionResult. 43 WrapperFunctionResult() { init(R); } 44 45 /// Create a WrapperFunctionResult by taking ownership of a 46 /// CWrapperFunctionResult. 47 /// 48 /// Warning: This should only be used by clients writing wrapper-function 49 /// caller utilities (like TargetProcessControl). 50 WrapperFunctionResult(CWrapperFunctionResult R) : R(R) { 51 // Reset R. 52 init(R); 53 } 54 55 WrapperFunctionResult(const WrapperFunctionResult &) = delete; 56 WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete; 57 58 WrapperFunctionResult(WrapperFunctionResult &&Other) { 59 init(R); 60 std::swap(R, Other.R); 61 } 62 63 WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) { 64 WrapperFunctionResult Tmp(std::move(Other)); 65 std::swap(R, Tmp.R); 66 return *this; 67 } 68 69 ~WrapperFunctionResult() { 70 if ((R.Size > sizeof(R.Data.Value)) || 71 (R.Size == 0 && R.Data.ValuePtr != nullptr)) 72 free(R.Data.ValuePtr); 73 } 74 75 /// Release ownership of the contained CWrapperFunctionResult. 76 /// Warning: Do not use -- this method will be removed in the future. It only 77 /// exists to temporarily support some code that will eventually be moved to 78 /// the ORC runtime. 79 CWrapperFunctionResult release() { 80 CWrapperFunctionResult Tmp; 81 init(Tmp); 82 std::swap(R, Tmp); 83 return Tmp; 84 } 85 86 /// Get a pointer to the data contained in this instance. 87 char *data() { 88 assert((R.Size != 0 || R.Data.ValuePtr == nullptr) && 89 "Cannot get data for out-of-band error value"); 90 return R.Size > sizeof(R.Data.Value) ? R.Data.ValuePtr : R.Data.Value; 91 } 92 93 /// Get a const pointer to the data contained in this instance. 94 const char *data() const { 95 assert((R.Size != 0 || R.Data.ValuePtr == nullptr) && 96 "Cannot get data for out-of-band error value"); 97 return R.Size > sizeof(R.Data.Value) ? R.Data.ValuePtr : R.Data.Value; 98 } 99 100 /// Returns the size of the data contained in this instance. 101 size_t size() const { 102 assert((R.Size != 0 || R.Data.ValuePtr == nullptr) && 103 "Cannot get data for out-of-band error value"); 104 return R.Size; 105 } 106 107 /// Returns true if this value is equivalent to a default-constructed 108 /// WrapperFunctionResult. 109 bool empty() const { return R.Size == 0 && R.Data.ValuePtr == nullptr; } 110 111 /// Create a WrapperFunctionResult with the given size and return a pointer 112 /// to the underlying memory. 113 static WrapperFunctionResult allocate(size_t Size) { 114 // Reset. 115 WrapperFunctionResult WFR; 116 WFR.R.Size = Size; 117 if (WFR.R.Size > sizeof(WFR.R.Data.Value)) 118 WFR.R.Data.ValuePtr = (char *)malloc(WFR.R.Size); 119 return WFR; 120 } 121 122 /// Copy from the given char range. 123 static WrapperFunctionResult copyFrom(const char *Source, size_t Size) { 124 auto WFR = allocate(Size); 125 memcpy(WFR.data(), Source, Size); 126 return WFR; 127 } 128 129 /// Copy from the given null-terminated string (includes the null-terminator). 130 static WrapperFunctionResult copyFrom(const char *Source) { 131 return copyFrom(Source, strlen(Source) + 1); 132 } 133 134 /// Copy from the given std::string (includes the null terminator). 135 static WrapperFunctionResult copyFrom(const std::string &Source) { 136 return copyFrom(Source.c_str()); 137 } 138 139 /// Create an out-of-band error by copying the given string. 140 static WrapperFunctionResult createOutOfBandError(const char *Msg) { 141 // Reset. 142 WrapperFunctionResult WFR; 143 char *Tmp = (char *)malloc(strlen(Msg) + 1); 144 strcpy(Tmp, Msg); 145 WFR.R.Data.ValuePtr = Tmp; 146 return WFR; 147 } 148 149 /// Create an out-of-band error by copying the given string. 150 static WrapperFunctionResult createOutOfBandError(const std::string &Msg) { 151 return createOutOfBandError(Msg.c_str()); 152 } 153 154 /// If this value is an out-of-band error then this returns the error message, 155 /// otherwise returns nullptr. 156 const char *getOutOfBandError() const { 157 return R.Size == 0 ? R.Data.ValuePtr : nullptr; 158 } 159 160 private: 161 static void init(CWrapperFunctionResult &R) { 162 R.Data.ValuePtr = nullptr; 163 R.Size = 0; 164 } 165 166 CWrapperFunctionResult R; 167 }; 168 169 namespace detail { 170 171 template <typename SPSArgListT, typename... ArgTs> 172 WrapperFunctionResult 173 serializeViaSPSToWrapperFunctionResult(const ArgTs &...Args) { 174 auto Result = WrapperFunctionResult::allocate(SPSArgListT::size(Args...)); 175 SPSOutputBuffer OB(Result.data(), Result.size()); 176 if (!SPSArgListT::serialize(OB, Args...)) 177 return WrapperFunctionResult::createOutOfBandError( 178 "Error serializing arguments to blob in call"); 179 return Result; 180 } 181 182 template <typename RetT> class WrapperFunctionHandlerCaller { 183 public: 184 template <typename HandlerT, typename ArgTupleT, std::size_t... I> 185 static decltype(auto) call(HandlerT &&H, ArgTupleT &Args, 186 std::index_sequence<I...>) { 187 return std::forward<HandlerT>(H)(std::get<I>(Args)...); 188 } 189 }; 190 191 template <> class WrapperFunctionHandlerCaller<void> { 192 public: 193 template <typename HandlerT, typename ArgTupleT, std::size_t... I> 194 static SPSEmpty call(HandlerT &&H, ArgTupleT &Args, 195 std::index_sequence<I...>) { 196 std::forward<HandlerT>(H)(std::get<I>(Args)...); 197 return SPSEmpty(); 198 } 199 }; 200 201 template <typename WrapperFunctionImplT, 202 template <typename> class ResultSerializer, typename... SPSTagTs> 203 class WrapperFunctionHandlerHelper 204 : public WrapperFunctionHandlerHelper< 205 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()), 206 ResultSerializer, SPSTagTs...> {}; 207 208 template <typename RetT, typename... ArgTs, 209 template <typename> class ResultSerializer, typename... SPSTagTs> 210 class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer, 211 SPSTagTs...> { 212 public: 213 using ArgTuple = std::tuple<std::decay_t<ArgTs>...>; 214 using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>; 215 216 template <typename HandlerT> 217 static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData, 218 size_t ArgSize) { 219 ArgTuple Args; 220 if (!deserialize(ArgData, ArgSize, Args, ArgIndices{})) 221 return WrapperFunctionResult::createOutOfBandError( 222 "Could not deserialize arguments for wrapper function call"); 223 224 auto HandlerResult = WrapperFunctionHandlerCaller<RetT>::call( 225 std::forward<HandlerT>(H), Args, ArgIndices{}); 226 227 return ResultSerializer<decltype(HandlerResult)>::serialize( 228 std::move(HandlerResult)); 229 } 230 231 private: 232 template <std::size_t... I> 233 static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args, 234 std::index_sequence<I...>) { 235 SPSInputBuffer IB(ArgData, ArgSize); 236 return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...); 237 } 238 }; 239 240 // Map function pointers to function types. 241 template <typename RetT, typename... ArgTs, 242 template <typename> class ResultSerializer, typename... SPSTagTs> 243 class WrapperFunctionHandlerHelper<RetT (*)(ArgTs...), ResultSerializer, 244 SPSTagTs...> 245 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer, 246 SPSTagTs...> {}; 247 248 // Map non-const member function types to function types. 249 template <typename ClassT, typename RetT, typename... ArgTs, 250 template <typename> class ResultSerializer, typename... SPSTagTs> 251 class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer, 252 SPSTagTs...> 253 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer, 254 SPSTagTs...> {}; 255 256 // Map const member function types to function types. 257 template <typename ClassT, typename RetT, typename... ArgTs, 258 template <typename> class ResultSerializer, typename... SPSTagTs> 259 class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const, 260 ResultSerializer, SPSTagTs...> 261 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer, 262 SPSTagTs...> {}; 263 264 template <typename WrapperFunctionImplT, 265 template <typename> class ResultSerializer, typename... SPSTagTs> 266 class WrapperFunctionAsyncHandlerHelper 267 : public WrapperFunctionAsyncHandlerHelper< 268 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()), 269 ResultSerializer, SPSTagTs...> {}; 270 271 template <typename RetT, typename SendResultT, typename... ArgTs, 272 template <typename> class ResultSerializer, typename... SPSTagTs> 273 class WrapperFunctionAsyncHandlerHelper<RetT(SendResultT, ArgTs...), 274 ResultSerializer, SPSTagTs...> { 275 public: 276 using ArgTuple = std::tuple<std::decay_t<ArgTs>...>; 277 using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>; 278 279 template <typename HandlerT, typename SendWrapperFunctionResultT> 280 static void applyAsync(HandlerT &&H, 281 SendWrapperFunctionResultT &&SendWrapperFunctionResult, 282 const char *ArgData, size_t ArgSize) { 283 ArgTuple Args; 284 if (!deserialize(ArgData, ArgSize, Args, ArgIndices{})) { 285 SendWrapperFunctionResult(WrapperFunctionResult::createOutOfBandError( 286 "Could not deserialize arguments for wrapper function call")); 287 return; 288 } 289 290 auto SendResult = 291 [SendWFR = std::move(SendWrapperFunctionResult)](auto Result) mutable { 292 using ResultT = decltype(Result); 293 SendWFR(ResultSerializer<ResultT>::serialize(std::move(Result))); 294 }; 295 296 callAsync(std::forward<HandlerT>(H), std::move(SendResult), std::move(Args), 297 ArgIndices{}); 298 } 299 300 private: 301 template <std::size_t... I> 302 static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args, 303 std::index_sequence<I...>) { 304 SPSInputBuffer IB(ArgData, ArgSize); 305 return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...); 306 } 307 308 template <typename HandlerT, typename SerializeAndSendResultT, 309 typename ArgTupleT, std::size_t... I> 310 static void callAsync(HandlerT &&H, 311 SerializeAndSendResultT &&SerializeAndSendResult, 312 ArgTupleT Args, std::index_sequence<I...>) { 313 (void)Args; // Silence a buggy GCC warning. 314 return std::forward<HandlerT>(H)(std::move(SerializeAndSendResult), 315 std::move(std::get<I>(Args))...); 316 } 317 }; 318 319 // Map function pointers to function types. 320 template <typename RetT, typename... ArgTs, 321 template <typename> class ResultSerializer, typename... SPSTagTs> 322 class WrapperFunctionAsyncHandlerHelper<RetT (*)(ArgTs...), ResultSerializer, 323 SPSTagTs...> 324 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer, 325 SPSTagTs...> {}; 326 327 // Map non-const member function types to function types. 328 template <typename ClassT, typename RetT, typename... ArgTs, 329 template <typename> class ResultSerializer, typename... SPSTagTs> 330 class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...), 331 ResultSerializer, SPSTagTs...> 332 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer, 333 SPSTagTs...> {}; 334 335 // Map const member function types to function types. 336 template <typename ClassT, typename RetT, typename... ArgTs, 337 template <typename> class ResultSerializer, typename... SPSTagTs> 338 class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...) const, 339 ResultSerializer, SPSTagTs...> 340 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer, 341 SPSTagTs...> {}; 342 343 template <typename SPSRetTagT, typename RetT> class ResultSerializer { 344 public: 345 static WrapperFunctionResult serialize(RetT Result) { 346 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>( 347 Result); 348 } 349 }; 350 351 template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> { 352 public: 353 static WrapperFunctionResult serialize(Error Err) { 354 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>( 355 toSPSSerializable(std::move(Err))); 356 } 357 }; 358 359 template <typename SPSRetTagT> 360 class ResultSerializer<SPSRetTagT, ErrorSuccess> { 361 public: 362 static WrapperFunctionResult serialize(ErrorSuccess Err) { 363 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>( 364 toSPSSerializable(std::move(Err))); 365 } 366 }; 367 368 template <typename SPSRetTagT, typename T> 369 class ResultSerializer<SPSRetTagT, Expected<T>> { 370 public: 371 static WrapperFunctionResult serialize(Expected<T> E) { 372 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>( 373 toSPSSerializable(std::move(E))); 374 } 375 }; 376 377 template <typename SPSRetTagT, typename RetT> class ResultDeserializer { 378 public: 379 static RetT makeValue() { return RetT(); } 380 static void makeSafe(RetT &Result) {} 381 382 static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) { 383 SPSInputBuffer IB(ArgData, ArgSize); 384 if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result)) 385 return make_error<StringError>( 386 "Error deserializing return value from blob in call", 387 inconvertibleErrorCode()); 388 return Error::success(); 389 } 390 }; 391 392 template <> class ResultDeserializer<SPSError, Error> { 393 public: 394 static Error makeValue() { return Error::success(); } 395 static void makeSafe(Error &Err) { cantFail(std::move(Err)); } 396 397 static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) { 398 SPSInputBuffer IB(ArgData, ArgSize); 399 SPSSerializableError BSE; 400 if (!SPSArgList<SPSError>::deserialize(IB, BSE)) 401 return make_error<StringError>( 402 "Error deserializing return value from blob in call", 403 inconvertibleErrorCode()); 404 Err = fromSPSSerializable(std::move(BSE)); 405 return Error::success(); 406 } 407 }; 408 409 template <typename SPSTagT, typename T> 410 class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> { 411 public: 412 static Expected<T> makeValue() { return T(); } 413 static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); } 414 415 static Error deserialize(Expected<T> &E, const char *ArgData, 416 size_t ArgSize) { 417 SPSInputBuffer IB(ArgData, ArgSize); 418 SPSSerializableExpected<T> BSE; 419 if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE)) 420 return make_error<StringError>( 421 "Error deserializing return value from blob in call", 422 inconvertibleErrorCode()); 423 E = fromSPSSerializable(std::move(BSE)); 424 return Error::success(); 425 } 426 }; 427 428 template <typename SPSRetTagT, typename RetT> class AsyncCallResultHelper { 429 // Did you forget to use Error / Expected in your handler? 430 }; 431 432 } // end namespace detail 433 434 template <typename SPSSignature> class WrapperFunction; 435 436 template <typename SPSRetTagT, typename... SPSTagTs> 437 class WrapperFunction<SPSRetTagT(SPSTagTs...)> { 438 private: 439 template <typename RetT> 440 using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>; 441 442 public: 443 /// Call a wrapper function. Caller should be callable as 444 /// WrapperFunctionResult Fn(const char *ArgData, size_t ArgSize); 445 template <typename CallerFn, typename RetT, typename... ArgTs> 446 static Error call(const CallerFn &Caller, RetT &Result, 447 const ArgTs &...Args) { 448 449 // RetT might be an Error or Expected value. Set the checked flag now: 450 // we don't want the user to have to check the unused result if this 451 // operation fails. 452 detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result); 453 454 auto ArgBuffer = 455 detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>( 456 Args...); 457 if (const char *ErrMsg = ArgBuffer.getOutOfBandError()) 458 return make_error<StringError>(ErrMsg, inconvertibleErrorCode()); 459 460 WrapperFunctionResult ResultBuffer = 461 Caller(ArgBuffer.data(), ArgBuffer.size()); 462 if (auto ErrMsg = ResultBuffer.getOutOfBandError()) 463 return make_error<StringError>(ErrMsg, inconvertibleErrorCode()); 464 465 return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize( 466 Result, ResultBuffer.data(), ResultBuffer.size()); 467 } 468 469 /// Call an async wrapper function. 470 /// Caller should be callable as 471 /// void Fn(unique_function<void(WrapperFunctionResult)> SendResult, 472 /// WrapperFunctionResult ArgBuffer); 473 template <typename AsyncCallerFn, typename SendDeserializedResultFn, 474 typename... ArgTs> 475 static void callAsync(AsyncCallerFn &&Caller, 476 SendDeserializedResultFn &&SendDeserializedResult, 477 const ArgTs &...Args) { 478 using RetT = typename std::tuple_element< 479 1, typename detail::WrapperFunctionHandlerHelper< 480 std::remove_reference_t<SendDeserializedResultFn>, 481 ResultSerializer, SPSRetTagT>::ArgTuple>::type; 482 483 auto ArgBuffer = 484 detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>( 485 Args...); 486 if (auto *ErrMsg = ArgBuffer.getOutOfBandError()) { 487 SendDeserializedResult( 488 make_error<StringError>(ErrMsg, inconvertibleErrorCode()), 489 detail::ResultDeserializer<SPSRetTagT, RetT>::makeValue()); 490 return; 491 } 492 493 auto SendSerializedResult = [SDR = std::move(SendDeserializedResult)]( 494 WrapperFunctionResult R) mutable { 495 RetT RetVal = detail::ResultDeserializer<SPSRetTagT, RetT>::makeValue(); 496 detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(RetVal); 497 498 if (auto *ErrMsg = R.getOutOfBandError()) { 499 SDR(make_error<StringError>(ErrMsg, inconvertibleErrorCode()), 500 std::move(RetVal)); 501 return; 502 } 503 504 SPSInputBuffer IB(R.data(), R.size()); 505 if (auto Err = detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize( 506 RetVal, R.data(), R.size())) 507 SDR(std::move(Err), std::move(RetVal)); 508 509 SDR(Error::success(), std::move(RetVal)); 510 }; 511 512 Caller(std::move(SendSerializedResult), ArgBuffer.data(), ArgBuffer.size()); 513 } 514 515 /// Handle a call to a wrapper function. 516 template <typename HandlerT> 517 static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize, 518 HandlerT &&Handler) { 519 using WFHH = 520 detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>, 521 ResultSerializer, SPSTagTs...>; 522 return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize); 523 } 524 525 /// Handle a call to an async wrapper function. 526 template <typename HandlerT, typename SendResultT> 527 static void handleAsync(const char *ArgData, size_t ArgSize, 528 HandlerT &&Handler, SendResultT &&SendResult) { 529 using WFAHH = detail::WrapperFunctionAsyncHandlerHelper< 530 std::remove_reference_t<HandlerT>, ResultSerializer, SPSTagTs...>; 531 WFAHH::applyAsync(std::forward<HandlerT>(Handler), 532 std::forward<SendResultT>(SendResult), ArgData, ArgSize); 533 } 534 535 private: 536 template <typename T> static const T &makeSerializable(const T &Value) { 537 return Value; 538 } 539 540 static detail::SPSSerializableError makeSerializable(Error Err) { 541 return detail::toSPSSerializable(std::move(Err)); 542 } 543 544 template <typename T> 545 static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) { 546 return detail::toSPSSerializable(std::move(E)); 547 } 548 }; 549 550 template <typename... SPSTagTs> 551 class WrapperFunction<void(SPSTagTs...)> 552 : private WrapperFunction<SPSEmpty(SPSTagTs...)> { 553 554 public: 555 template <typename CallerFn, typename... ArgTs> 556 static Error call(const CallerFn &Caller, const ArgTs &...Args) { 557 SPSEmpty BE; 558 return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(Caller, BE, Args...); 559 } 560 561 template <typename AsyncCallerFn, typename SendDeserializedResultFn, 562 typename... ArgTs> 563 static void callAsync(AsyncCallerFn &&Caller, 564 SendDeserializedResultFn &&SendDeserializedResult, 565 const ArgTs &...Args) { 566 WrapperFunction<SPSEmpty(SPSTagTs...)>::callAsync( 567 std::forward<AsyncCallerFn>(Caller), 568 [SDR = std::move(SendDeserializedResult)](Error SerializeErr, 569 SPSEmpty E) mutable { 570 SDR(std::move(SerializeErr)); 571 }, 572 Args...); 573 } 574 575 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle; 576 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handleAsync; 577 }; 578 579 /// A function object that takes an ExecutorAddr as its first argument, 580 /// casts that address to a ClassT*, then calls the given method on that 581 /// pointer passing in the remaining function arguments. This utility 582 /// removes some of the boilerplate from writing wrappers for method calls. 583 /// 584 /// @code{.cpp} 585 /// class MyClass { 586 /// public: 587 /// void myMethod(uint32_t, bool) { ... } 588 /// }; 589 /// 590 /// // SPS Method signature -- note MyClass object address as first argument. 591 /// using SPSMyMethodWrapperSignature = 592 /// SPSTuple<SPSExecutorAddr, uint32_t, bool>; 593 /// 594 /// WrapperFunctionResult 595 /// myMethodCallWrapper(const char *ArgData, size_t ArgSize) { 596 /// return WrapperFunction<SPSMyMethodWrapperSignature>::handle( 597 /// ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod)); 598 /// } 599 /// @endcode 600 /// 601 template <typename RetT, typename ClassT, typename... ArgTs> 602 class MethodWrapperHandler { 603 public: 604 using MethodT = RetT (ClassT::*)(ArgTs...); 605 MethodWrapperHandler(MethodT M) : M(M) {} 606 RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) { 607 return (ObjAddr.toPtr<ClassT*>()->*M)(std::forward<ArgTs>(Args)...); 608 } 609 610 private: 611 MethodT M; 612 }; 613 614 /// Create a MethodWrapperHandler object from the given method pointer. 615 template <typename RetT, typename ClassT, typename... ArgTs> 616 MethodWrapperHandler<RetT, ClassT, ArgTs...> 617 makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) { 618 return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method); 619 } 620 621 /// Represents a serialized wrapper function call. 622 /// Serializing calls themselves allows us to batch them: We can make one 623 /// "run-wrapper-functions" utility and send it a list of calls to run. 624 /// 625 /// The motivating use-case for this API is JITLink allocation actions, where 626 /// we want to run multiple functions to finalize linked memory without having 627 /// to make separate IPC calls for each one. 628 class WrapperFunctionCall { 629 public: 630 using ArgDataBufferType = SmallVector<char, 24>; 631 632 /// Create a WrapperFunctionCall using the given SPS serializer to serialize 633 /// the arguments. 634 template <typename SPSSerializer, typename... ArgTs> 635 static Expected<WrapperFunctionCall> Create(ExecutorAddr FnAddr, 636 const ArgTs &...Args) { 637 ArgDataBufferType ArgData; 638 ArgData.resize(SPSSerializer::size(Args...)); 639 SPSOutputBuffer OB(&ArgData[0], ArgData.size()); 640 if (SPSSerializer::serialize(OB, Args...)) 641 return WrapperFunctionCall(FnAddr, std::move(ArgData)); 642 return make_error<StringError>("Cannot serialize arguments for " 643 "AllocActionCall", 644 inconvertibleErrorCode()); 645 } 646 647 WrapperFunctionCall() = default; 648 649 /// Create a WrapperFunctionCall from a target function and arg buffer. 650 WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData) 651 : FnAddr(FnAddr), ArgData(std::move(ArgData)) {} 652 653 /// Returns the address to be called. 654 const ExecutorAddr &getCallee() const { return FnAddr; } 655 656 /// Returns the argument data. 657 const ArgDataBufferType &getArgData() const { return ArgData; } 658 659 /// WrapperFunctionCalls convert to true if the callee is non-null. 660 explicit operator bool() const { return !!FnAddr; } 661 662 /// Run call returning raw WrapperFunctionResult. 663 shared::WrapperFunctionResult run() const { 664 using FnTy = 665 shared::CWrapperFunctionResult(const char *ArgData, size_t ArgSize); 666 return shared::WrapperFunctionResult( 667 FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size())); 668 } 669 670 /// Run call and deserialize result using SPS. 671 template <typename SPSRetT, typename RetT> 672 std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error> 673 runWithSPSRet(RetT &RetVal) const { 674 auto WFR = run(); 675 if (const char *ErrMsg = WFR.getOutOfBandError()) 676 return make_error<StringError>(ErrMsg, inconvertibleErrorCode()); 677 shared::SPSInputBuffer IB(WFR.data(), WFR.size()); 678 if (!shared::SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal)) 679 return make_error<StringError>("Could not deserialize result from " 680 "serialized wrapper function call", 681 inconvertibleErrorCode()); 682 return Error::success(); 683 } 684 685 /// Overload for SPS functions returning void. 686 template <typename SPSRetT> 687 std::enable_if_t<std::is_same<SPSRetT, void>::value, Error> 688 runWithSPSRet() const { 689 shared::SPSEmpty E; 690 return runWithSPSRet<shared::SPSEmpty>(E); 691 } 692 693 /// Run call and deserialize an SPSError result. SPSError returns and 694 /// deserialization failures are merged into the returned error. 695 Error runWithSPSRetErrorMerged() const { 696 detail::SPSSerializableError RetErr; 697 if (auto Err = runWithSPSRet<SPSError>(RetErr)) 698 return Err; 699 return detail::fromSPSSerializable(std::move(RetErr)); 700 } 701 702 private: 703 orc::ExecutorAddr FnAddr; 704 ArgDataBufferType ArgData; 705 }; 706 707 using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>; 708 709 template <> 710 class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> { 711 public: 712 static size_t size(const WrapperFunctionCall &WFC) { 713 return SPSWrapperFunctionCall::AsArgList::size(WFC.getCallee(), 714 WFC.getArgData()); 715 } 716 717 static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) { 718 return SPSWrapperFunctionCall::AsArgList::serialize(OB, WFC.getCallee(), 719 WFC.getArgData()); 720 } 721 722 static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) { 723 ExecutorAddr FnAddr; 724 WrapperFunctionCall::ArgDataBufferType ArgData; 725 if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData)) 726 return false; 727 WFC = WrapperFunctionCall(FnAddr, std::move(ArgData)); 728 return true; 729 } 730 }; 731 732 } // end namespace shared 733 } // end namespace orc 734 } // end namespace llvm 735 736 #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H 737