Skip to content

Commit e031a56

Browse files
authored
[orc-rt] Introduce WrapperFunction APIs. (#157091)
Introduces the following key APIs: `orc_rt_WrapperFunction` defines the signature of an ORC asynchronous wrapper function: ``` typedef void (*orc_rt_WrapperFunctionReturn)( orc_rt_SessionRef Session, void *CallCtx, orc_rt_WrapperFunctionBuffer ResultBytes); typedef void (*orc_rt_WrapperFunction)(orc_rt_SessionRef Session, void *CallCtx, orc_rt_WrapperFunctionReturn Return, orc_rt_WrapperFunctionBuffer ArgBytes); ``` A wrapper function takes a reference to the session object, a context pointer for the call being made, and a pointer to an orc_rt_WrapperFunctionReturn function that can be used to send the result bytes. The `orc_rt::WrapperFunction` utility simplifies the writing of wrapper functions whose arguments and return values are serialized/deserialized using an abstract serialization utility. The `orc_rt::SPSWrapperFunction` utility provides a specialized version of `orc_rt::WrapperFunction` that uses SPS serialization.
1 parent f28f1c2 commit e031a56

File tree

7 files changed

+409
-0
lines changed

7 files changed

+409
-0
lines changed

orc-rt/include/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
set(ORC_RT_HEADERS
2+
orc-rt-c/CoreTyspe.h
23
orc-rt-c/ExternC.h
34
orc-rt-c/WrapperFunction.h
45
orc-rt-c/orc-rt.h
@@ -13,6 +14,7 @@ set(ORC_RT_HEADERS
1314
orc-rt/RTTI.h
1415
orc-rt/WrapperFunction.h
1516
orc-rt/SimplePackedSerialization.h
17+
orc-rt/SPSWrapperFunction.h
1618
orc-rt/bind.h
1719
orc-rt/bit.h
1820
orc-rt/move_only_function.h
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*===-- CoreTypes.h - Essential types for the ORC Runtime C APIs --*- C -*-===*\
2+
|* *|
3+
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
4+
|* Exceptions. *|
5+
|* See https://llvm.org/LICENSE.txt for license information. *|
6+
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
7+
|* *|
8+
|*===----------------------------------------------------------------------===*|
9+
|* *|
10+
|* Defines core types for the ORC runtime. *|
11+
|* *|
12+
\*===----------------------------------------------------------------------===*/
13+
14+
#ifndef ORC_RT_C_CORETYPES_H
15+
#define ORC_RT_C_CORETYPES_H
16+
17+
#include "orc-rt-c/ExternC.h"
18+
19+
ORC_RT_C_EXTERN_C_BEGIN
20+
21+
/**
22+
* A reference to an orc_rt::Session instance.
23+
*/
24+
typedef struct orc_rt_OpaqueSession *orc_rt_SessionRef;
25+
26+
ORC_RT_C_EXTERN_C_END
27+
28+
#endif /* ORC_RT_C_CORETYPES_H */

orc-rt/include/orc-rt-c/WrapperFunction.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef ORC_RT_C_WRAPPERFUNCTION_H
1515
#define ORC_RT_C_WRAPPERFUNCTION_H
1616

17+
#include "orc-rt-c/CoreTypes.h"
1718
#include "orc-rt-c/ExternC.h"
1819

1920
#include <assert.h>
@@ -49,6 +50,25 @@ typedef struct {
4950
size_t Size;
5051
} orc_rt_WrapperFunctionBuffer;
5152

53+
/**
54+
* Asynchronous return function for an orc-rt wrapper function.
55+
*/
56+
typedef void (*orc_rt_WrapperFunctionReturn)(
57+
orc_rt_SessionRef Session, void *CallCtx,
58+
orc_rt_WrapperFunctionBuffer ResultBytes);
59+
60+
/**
61+
* orc-rt wrapper function prototype.
62+
*
63+
* ArgBytes contains the serialized arguments for the wrapper function.
64+
* Session holds a reference to the session object.
65+
* CallCtx holds a pointer to the context object for this particular call.
66+
* Return holds a pointer to the return function.
67+
*/
68+
typedef void (*orc_rt_WrapperFunction)(orc_rt_SessionRef Session, void *CallCtx,
69+
orc_rt_WrapperFunctionReturn Return,
70+
orc_rt_WrapperFunctionBuffer ArgBytes);
71+
5272
/**
5373
* Zero-initialize an orc_rt_WrapperFunctionBuffer.
5474
*/
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//===--- SPSWrapperFunction.h -- SPS-serializing Wrapper utls ---*- 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+
// Utilities for calling / handling wrapper functions that use SPS
10+
// serialization.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef ORC_RT_SPSWRAPPERFUNCTION_H
15+
#define ORC_RT_SPSWRAPPERFUNCTION_H
16+
17+
#include "orc-rt/SimplePackedSerialization.h"
18+
#include "orc-rt/WrapperFunction.h"
19+
20+
namespace orc_rt {
21+
namespace detail {
22+
23+
template <typename... SPSArgTs> struct WFSPSSerializer {
24+
template <typename... ArgTs>
25+
std::optional<WrapperFunctionBuffer> operator()(const ArgTs &...Args) {
26+
auto R =
27+
WrapperFunctionBuffer::allocate(SPSArgList<SPSArgTs...>::size(Args...));
28+
SPSOutputBuffer OB(R.data(), R.size());
29+
if (!SPSArgList<SPSArgTs...>::serialize(OB, Args...))
30+
return std::nullopt;
31+
return std::move(R);
32+
}
33+
};
34+
35+
template <typename... SPSArgTs> struct WFSPSDeserializer {
36+
template <typename... ArgTs>
37+
bool operator()(WrapperFunctionBuffer &ArgBytes, ArgTs &...Args) {
38+
assert(!ArgBytes.getOutOfBandError() &&
39+
"Should not attempt to deserialize out-of-band error");
40+
SPSInputBuffer IB(ArgBytes.data(), ArgBytes.size());
41+
return SPSArgList<SPSArgTs...>::deserialize(IB, Args...);
42+
}
43+
};
44+
45+
} // namespace detail
46+
47+
template <typename SPSSig> struct WrapperFunctionSPSSerializer;
48+
49+
template <typename SPSRetT, typename... SPSArgTs>
50+
struct WrapperFunctionSPSSerializer<SPSRetT(SPSArgTs...)> {
51+
static detail::WFSPSSerializer<SPSArgTs...> argumentSerializer() noexcept {
52+
return {};
53+
}
54+
static detail::WFSPSDeserializer<SPSArgTs...>
55+
argumentDeserializer() noexcept {
56+
return {};
57+
}
58+
static detail::WFSPSSerializer<SPSRetT> resultSerializer() noexcept {
59+
return {};
60+
}
61+
static detail::WFSPSDeserializer<SPSRetT> resultDeserializer() noexcept {
62+
return {};
63+
}
64+
};
65+
66+
/// Provides call and handle utilities to simplify writing and invocation of
67+
/// wrapper functions that use SimplePackedSerialization to serialize and
68+
/// deserialize their arguments and return values.
69+
template <typename SPSSig> struct SPSWrapperFunction {
70+
template <typename Caller, typename ResultHandler, typename... ArgTs>
71+
static void call(Caller &&C, ResultHandler &&RH, ArgTs &&...Args) {
72+
WrapperFunction::call(
73+
std::forward<Caller>(C), WrapperFunctionSPSSerializer<SPSSig>(),
74+
std::forward<ResultHandler>(RH), std::forward<ArgTs>(Args)...);
75+
}
76+
77+
template <typename Handler>
78+
static void handle(orc_rt_SessionRef Session, void *CallCtx,
79+
orc_rt_WrapperFunctionReturn Return,
80+
WrapperFunctionBuffer ArgBytes, Handler &&H) {
81+
WrapperFunction::handle(Session, CallCtx, Return, std::move(ArgBytes),
82+
WrapperFunctionSPSSerializer<SPSSig>(),
83+
std::forward<Handler>(H));
84+
}
85+
};
86+
87+
} // namespace orc_rt
88+
89+
#endif // ORC_RT_SPSWRAPPERFUNCTION_H

orc-rt/include/orc-rt/WrapperFunction.h

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#define ORC_RT_WRAPPERFUNCTION_H
1515

1616
#include "orc-rt-c/WrapperFunction.h"
17+
#include "orc-rt/Error.h"
18+
#include "orc-rt/bind.h"
1719

1820
#include <utility>
1921

@@ -98,6 +100,164 @@ class WrapperFunctionBuffer {
98100
orc_rt_WrapperFunctionBuffer B;
99101
};
100102

103+
namespace detail {
104+
105+
template <typename C>
106+
struct WFCallableTraits
107+
: public WFCallableTraits<
108+
decltype(&std::remove_cv_t<std::remove_reference_t<C>>::operator())> {
109+
};
110+
111+
template <typename RetT> struct WFCallableTraits<RetT()> {
112+
typedef void HeadArgType;
113+
};
114+
115+
template <typename RetT, typename ArgT, typename... ArgTs>
116+
struct WFCallableTraits<RetT(ArgT, ArgTs...)> {
117+
typedef ArgT HeadArgType;
118+
typedef std::tuple<ArgTs...> TailArgTuple;
119+
};
120+
121+
template <typename ClassT, typename RetT, typename... ArgTs>
122+
struct WFCallableTraits<RetT (ClassT::*)(ArgTs...)>
123+
: public WFCallableTraits<RetT(ArgTs...)> {};
124+
125+
template <typename ClassT, typename RetT, typename... ArgTs>
126+
struct WFCallableTraits<RetT (ClassT::*)(ArgTs...) const>
127+
: public WFCallableTraits<RetT(ArgTs...)> {};
128+
129+
template <typename Serializer> class StructuredYieldBase {
130+
public:
131+
StructuredYieldBase(orc_rt_SessionRef Session, void *CallCtx,
132+
orc_rt_WrapperFunctionReturn Return, Serializer &&S)
133+
: Session(Session), CallCtx(CallCtx), Return(Return),
134+
S(std::forward<Serializer>(S)) {}
135+
136+
protected:
137+
orc_rt_SessionRef Session;
138+
void *CallCtx;
139+
orc_rt_WrapperFunctionReturn Return;
140+
std::decay_t<Serializer> S;
141+
};
142+
143+
template <typename RetT, typename Serializer>
144+
class StructuredYield : public StructuredYieldBase<Serializer> {
145+
public:
146+
using StructuredYieldBase<Serializer>::StructuredYieldBase;
147+
void operator()(RetT &&R) {
148+
if (auto ResultBytes = this->S.resultSerializer()(std::forward<RetT>(R)))
149+
this->Return(this->Session, this->CallCtx, ResultBytes->release());
150+
else
151+
this->Return(this->Session, this->CallCtx,
152+
WrapperFunctionBuffer::createOutOfBandError(
153+
"Could not serialize wrapper function result data")
154+
.release());
155+
}
156+
};
157+
158+
template <typename Serializer>
159+
class StructuredYield<void, Serializer>
160+
: public StructuredYieldBase<Serializer> {
161+
public:
162+
using StructuredYieldBase<Serializer>::StructuredYieldBase;
163+
void operator()() {
164+
this->Return(this->Session, this->CallCtx,
165+
WrapperFunctionBuffer().release());
166+
}
167+
};
168+
169+
template <typename T, typename Serializer> struct ResultDeserializer;
170+
171+
template <typename T, typename Serializer>
172+
struct ResultDeserializer<Expected<T>, Serializer> {
173+
static Expected<T> deserialize(WrapperFunctionBuffer ResultBytes,
174+
Serializer &S) {
175+
T Val;
176+
if (S.resultDeserializer()(ResultBytes, Val))
177+
return std::move(Val);
178+
else
179+
return make_error<StringError>("Could not deserialize result");
180+
}
181+
};
182+
183+
template <typename Serializer> struct ResultDeserializer<Error, Serializer> {
184+
static Error deserialize(WrapperFunctionBuffer ResultBytes, Serializer &S) {
185+
assert(ResultBytes.empty());
186+
return Error::success();
187+
}
188+
};
189+
190+
} // namespace detail
191+
192+
/// Provides call and handle utilities to simplify writing and invocation of
193+
/// wrapper functions in C++.
194+
struct WrapperFunction {
195+
196+
/// Make a call to a wrapper function.
197+
///
198+
/// This utility serializes and deserializes arguments and return values
199+
/// (using the given Serializer), and calls the wrapper function via the
200+
/// given Caller object.
201+
template <typename Caller, typename Serializer, typename ResultHandler,
202+
typename... ArgTs>
203+
static void call(Caller &&C, Serializer &&S, ResultHandler &&RH,
204+
ArgTs &&...Args) {
205+
typedef detail::WFCallableTraits<ResultHandler> ResultHandlerTraits;
206+
static_assert(
207+
std::tuple_size_v<typename ResultHandlerTraits::TailArgTuple> == 0,
208+
"Expected one argument to result-handler");
209+
typedef typename ResultHandlerTraits::HeadArgType ResultType;
210+
211+
if (auto ArgBytes = S.argumentSerializer()(std::forward<ArgTs>(Args)...)) {
212+
C(
213+
[RH = std::move(RH),
214+
S = std::move(S)](orc_rt_SessionRef Session,
215+
WrapperFunctionBuffer ResultBytes) mutable {
216+
if (const char *ErrMsg = ResultBytes.getOutOfBandError())
217+
RH(make_error<StringError>(ErrMsg));
218+
else
219+
RH(detail::ResultDeserializer<
220+
ResultType, Serializer>::deserialize(std::move(ResultBytes),
221+
S));
222+
},
223+
std::move(*ArgBytes));
224+
} else
225+
RH(make_error<StringError>(
226+
"Could not serialize wrapper function call arguments"));
227+
}
228+
229+
/// Simplifies implementation of wrapper functions in C++.
230+
///
231+
/// This utility deserializes and serializes arguments and return values
232+
/// (using the given Serializer), and calls the given handler.
233+
template <typename Serializer, typename Handler>
234+
static void handle(orc_rt_SessionRef Session, void *CallCtx,
235+
orc_rt_WrapperFunctionReturn Return,
236+
WrapperFunctionBuffer ArgBytes, Serializer &&S,
237+
Handler &&H) {
238+
typedef detail::WFCallableTraits<Handler> HandlerTraits;
239+
typedef typename HandlerTraits::HeadArgType Yield;
240+
typedef typename HandlerTraits::TailArgTuple ArgTuple;
241+
typedef typename detail::WFCallableTraits<Yield>::HeadArgType RetType;
242+
243+
if (ArgBytes.getOutOfBandError())
244+
return Return(Session, CallCtx, ArgBytes.release());
245+
246+
ArgTuple Args;
247+
if (std::apply(bind_front(S.argumentDeserializer(), std::move(ArgBytes)),
248+
Args))
249+
std::apply(bind_front(std::forward<Handler>(H),
250+
detail::StructuredYield<RetType, Serializer>(
251+
Session, CallCtx, Return, std::move(S))),
252+
std::move(Args));
253+
else
254+
Return(Session, CallCtx,
255+
WrapperFunctionBuffer::createOutOfBandError(
256+
"Could not deserialize wrapper function arg data")
257+
.release());
258+
}
259+
};
260+
101261
} // namespace orc_rt
102262

103263
#endif // ORC_RT_WRAPPERFUNCTION_H

orc-rt/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_orc_rt_unittest(CoreTests
2222
MemoryFlagsTest.cpp
2323
RTTITest.cpp
2424
SimplePackedSerializationTest.cpp
25+
SPSWrapperFunctionTest.cpp
2526
WrapperFunctionBufferTest.cpp
2627
bind-test.cpp
2728
bit-test.cpp

0 commit comments

Comments
 (0)