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 return; 509 } 510 511 SDR(Error::success(), std::move(RetVal)); 512 }; 513 514 Caller(std::move(SendSerializedResult), ArgBuffer.data(), ArgBuffer.size()); 515 } 516 517 /// Handle a call to a wrapper function. 518 template <typename HandlerT> 519 static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize, 520 HandlerT &&Handler) { 521 using WFHH = 522 detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>, 523 ResultSerializer, SPSTagTs...>; 524 return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize); 525 } 526 527 /// Handle a call to an async wrapper function. 528 template <typename HandlerT, typename SendResultT> 529 static void handleAsync(const char *ArgData, size_t ArgSize, 530 HandlerT &&Handler, SendResultT &&SendResult) { 531 using WFAHH = detail::WrapperFunctionAsyncHandlerHelper< 532 std::remove_reference_t<HandlerT>, ResultSerializer, SPSTagTs...>; 533 WFAHH::applyAsync(std::forward<HandlerT>(Handler), 534 std::forward<SendResultT>(SendResult), ArgData, ArgSize); 535 } 536 537 private: 538 template <typename T> static const T &makeSerializable(const T &Value) { 539 return Value; 540 } 541 542 static detail::SPSSerializableError makeSerializable(Error Err) { 543 return detail::toSPSSerializable(std::move(Err)); 544 } 545 546 template <typename T> 547 static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) { 548 return detail::toSPSSerializable(std::move(E)); 549 } 550 }; 551 552 template <typename... SPSTagTs> 553 class WrapperFunction<void(SPSTagTs...)> 554 : private WrapperFunction<SPSEmpty(SPSTagTs...)> { 555 556 public: 557 template <typename CallerFn, typename... ArgTs> 558 static Error call(const CallerFn &Caller, const ArgTs &...Args) { 559 SPSEmpty BE; 560 return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(Caller, BE, Args...); 561 } 562 563 template <typename AsyncCallerFn, typename SendDeserializedResultFn, 564 typename... ArgTs> 565 static void callAsync(AsyncCallerFn &&Caller, 566 SendDeserializedResultFn &&SendDeserializedResult, 567 const ArgTs &...Args) { 568 WrapperFunction<SPSEmpty(SPSTagTs...)>::callAsync( 569 std::forward<AsyncCallerFn>(Caller), 570 [SDR = std::move(SendDeserializedResult)](Error SerializeErr, 571 SPSEmpty E) mutable { 572 SDR(std::move(SerializeErr)); 573 }, 574 Args...); 575 } 576 577 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle; 578 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handleAsync; 579 }; 580 581 /// A function object that takes an ExecutorAddr as its first argument, 582 /// casts that address to a ClassT*, then calls the given method on that 583 /// pointer passing in the remaining function arguments. This utility 584 /// removes some of the boilerplate from writing wrappers for method calls. 585 /// 586 /// @code{.cpp} 587 /// class MyClass { 588 /// public: 589 /// void myMethod(uint32_t, bool) { ... } 590 /// }; 591 /// 592 /// // SPS Method signature -- note MyClass object address as first argument. 593 /// using SPSMyMethodWrapperSignature = 594 /// SPSTuple<SPSExecutorAddr, uint32_t, bool>; 595 /// 596 /// WrapperFunctionResult 597 /// myMethodCallWrapper(const char *ArgData, size_t ArgSize) { 598 /// return WrapperFunction<SPSMyMethodWrapperSignature>::handle( 599 /// ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod)); 600 /// } 601 /// @endcode 602 /// 603 template <typename RetT, typename ClassT, typename... ArgTs> 604 class MethodWrapperHandler { 605 public: 606 using MethodT = RetT (ClassT::*)(ArgTs...); 607 MethodWrapperHandler(MethodT M) : M(M) {} 608 RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) { 609 return (ObjAddr.toPtr<ClassT*>()->*M)(std::forward<ArgTs>(Args)...); 610 } 611 612 private: 613 MethodT M; 614 }; 615 616 /// Create a MethodWrapperHandler object from the given method pointer. 617 template <typename RetT, typename ClassT, typename... ArgTs> 618 MethodWrapperHandler<RetT, ClassT, ArgTs...> 619 makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) { 620 return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method); 621 } 622 623 /// Represents a serialized wrapper function call. 624 /// Serializing calls themselves allows us to batch them: We can make one 625 /// "run-wrapper-functions" utility and send it a list of calls to run. 626 /// 627 /// The motivating use-case for this API is JITLink allocation actions, where 628 /// we want to run multiple functions to finalize linked memory without having 629 /// to make separate IPC calls for each one. 630 class WrapperFunctionCall { 631 public: 632 using ArgDataBufferType = SmallVector<char, 24>; 633 634 /// Create a WrapperFunctionCall using the given SPS serializer to serialize 635 /// the arguments. 636 template <typename SPSSerializer, typename... ArgTs> 637 static Expected<WrapperFunctionCall> Create(ExecutorAddr FnAddr, 638 const ArgTs &...Args) { 639 ArgDataBufferType ArgData; 640 ArgData.resize(SPSSerializer::size(Args...)); 641 SPSOutputBuffer OB(ArgData.empty() ? nullptr : ArgData.data(), 642 ArgData.size()); 643 if (SPSSerializer::serialize(OB, Args...)) 644 return WrapperFunctionCall(FnAddr, std::move(ArgData)); 645 return make_error<StringError>("Cannot serialize arguments for " 646 "AllocActionCall", 647 inconvertibleErrorCode()); 648 } 649 650 WrapperFunctionCall() = default; 651 652 /// Create a WrapperFunctionCall from a target function and arg buffer. 653 WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData) 654 : FnAddr(FnAddr), ArgData(std::move(ArgData)) {} 655 656 /// Returns the address to be called. 657 const ExecutorAddr &getCallee() const { return FnAddr; } 658 659 /// Returns the argument data. 660 const ArgDataBufferType &getArgData() const { return ArgData; } 661 662 /// WrapperFunctionCalls convert to true if the callee is non-null. 663 explicit operator bool() const { return !!FnAddr; } 664 665 /// Run call returning raw WrapperFunctionResult. 666 shared::WrapperFunctionResult run() const { 667 using FnTy = 668 shared::CWrapperFunctionResult(const char *ArgData, size_t ArgSize); 669 return shared::WrapperFunctionResult( 670 FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size())); 671 } 672 673 /// Run call and deserialize result using SPS. 674 template <typename SPSRetT, typename RetT> 675 std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error> 676 runWithSPSRet(RetT &RetVal) const { 677 auto WFR = run(); 678 if (const char *ErrMsg = WFR.getOutOfBandError()) 679 return make_error<StringError>(ErrMsg, inconvertibleErrorCode()); 680 shared::SPSInputBuffer IB(WFR.data(), WFR.size()); 681 if (!shared::SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal)) 682 return make_error<StringError>("Could not deserialize result from " 683 "serialized wrapper function call", 684 inconvertibleErrorCode()); 685 return Error::success(); 686 } 687 688 /// Overload for SPS functions returning void. 689 template <typename SPSRetT> 690 std::enable_if_t<std::is_same<SPSRetT, void>::value, Error> 691 runWithSPSRet() const { 692 shared::SPSEmpty E; 693 return runWithSPSRet<shared::SPSEmpty>(E); 694 } 695 696 /// Run call and deserialize an SPSError result. SPSError returns and 697 /// deserialization failures are merged into the returned error. 698 Error runWithSPSRetErrorMerged() const { 699 detail::SPSSerializableError RetErr; 700 if (auto Err = runWithSPSRet<SPSError>(RetErr)) 701 return Err; 702 return detail::fromSPSSerializable(std::move(RetErr)); 703 } 704 705 private: 706 orc::ExecutorAddr FnAddr; 707 ArgDataBufferType ArgData; 708 }; 709 710 using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>; 711 712 template <> 713 class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> { 714 public: 715 static size_t size(const WrapperFunctionCall &WFC) { 716 return SPSWrapperFunctionCall::AsArgList::size(WFC.getCallee(), 717 WFC.getArgData()); 718 } 719 720 static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) { 721 return SPSWrapperFunctionCall::AsArgList::serialize(OB, WFC.getCallee(), 722 WFC.getArgData()); 723 } 724 725 static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) { 726 ExecutorAddr FnAddr; 727 WrapperFunctionCall::ArgDataBufferType ArgData; 728 if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData)) 729 return false; 730 WFC = WrapperFunctionCall(FnAddr, std::move(ArgData)); 731 return true; 732 } 733 }; 734 735 } // end namespace shared 736 } // end namespace orc 737 } // end namespace llvm 738 739 #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H 740