Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions orc-rt/include/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(ORC_RT_HEADERS
orc-rt-c/CoreTyspe.h
orc-rt-c/ExternC.h
orc-rt-c/WrapperFunction.h
orc-rt-c/orc-rt.h
Expand All @@ -13,6 +14,7 @@ set(ORC_RT_HEADERS
orc-rt/RTTI.h
orc-rt/WrapperFunction.h
orc-rt/SimplePackedSerialization.h
orc-rt/SPSWrapperFunction.h
orc-rt/bind.h
orc-rt/bit.h
orc-rt/move_only_function.h
Expand Down
28 changes: 28 additions & 0 deletions orc-rt/include/orc-rt-c/CoreTypes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*===-- CoreTypes.h - Essential types for the ORC Runtime C APIs --*- C -*-===*\
|* *|
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
|* Exceptions. *|
|* See https://llvm.org/LICENSE.txt for license information. *|
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
|* *|
|*===----------------------------------------------------------------------===*|
|* *|
|* Defines core types for the ORC runtime. *|
|* *|
\*===----------------------------------------------------------------------===*/

#ifndef ORC_RT_C_CORETYPES_H
#define ORC_RT_C_CORETYPES_H

#include "orc-rt-c/ExternC.h"

ORC_RT_C_EXTERN_C_BEGIN

/**
* A reference to an orc_rt::Session instance.
*/
typedef struct orc_rt_OpaqueSession *orc_rt_SessionRef;

ORC_RT_C_EXTERN_C_END

#endif /* ORC_RT_C_CORETYPES_H */
20 changes: 20 additions & 0 deletions orc-rt/include/orc-rt-c/WrapperFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#ifndef ORC_RT_C_WRAPPERFUNCTION_H
#define ORC_RT_C_WRAPPERFUNCTION_H

#include "orc-rt-c/CoreTypes.h"
#include "orc-rt-c/ExternC.h"

#include <assert.h>
Expand Down Expand Up @@ -49,6 +50,25 @@ typedef struct {
size_t Size;
} orc_rt_WrapperFunctionBuffer;

/**
* Asynchronous return function for an orc-rt wrapper function.
*/
typedef void (*orc_rt_WrapperFunctionReturn)(
orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionBuffer ResultBytes);

/**
* orc-rt wrapper function prototype.
*
* ArgBytes contains the serialized arguments for the wrapper function.
* Session holds a reference to the session object.
* CallCtx holds a pointer to the context object for this particular call.
* Return holds a pointer to the return function.
*/
typedef void (*orc_rt_WrapperFunction)(orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes);

/**
* Zero-initialize an orc_rt_WrapperFunctionBuffer.
*/
Expand Down
89 changes: 89 additions & 0 deletions orc-rt/include/orc-rt/SPSWrapperFunction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//===--- SPSWrapperFunction.h -- SPS-serializing Wrapper utls ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Utilities for calling / handling wrapper functions that use SPS
// serialization.
//
//===----------------------------------------------------------------------===//

#ifndef ORC_RT_SPSWRAPPERFUNCTION_H
#define ORC_RT_SPSWRAPPERFUNCTION_H

#include "orc-rt/SimplePackedSerialization.h"
#include "orc-rt/WrapperFunction.h"

namespace orc_rt {
namespace detail {

template <typename... SPSArgTs> struct WFSPSSerializer {
template <typename... ArgTs>
std::optional<WrapperFunctionBuffer> operator()(const ArgTs &...Args) {
auto R =
WrapperFunctionBuffer::allocate(SPSArgList<SPSArgTs...>::size(Args...));
SPSOutputBuffer OB(R.data(), R.size());
if (!SPSArgList<SPSArgTs...>::serialize(OB, Args...))
return std::nullopt;
return std::move(R);
}
};

template <typename... SPSArgTs> struct WFSPSDeserializer {
template <typename... ArgTs>
bool operator()(WrapperFunctionBuffer &ArgBytes, ArgTs &...Args) {
assert(!ArgBytes.getOutOfBandError() &&
"Should not attempt to deserialize out-of-band error");
SPSInputBuffer IB(ArgBytes.data(), ArgBytes.size());
return SPSArgList<SPSArgTs...>::deserialize(IB, Args...);
}
};

} // namespace detail

template <typename SPSSig> struct WrapperFunctionSPSSerializer;

template <typename SPSRetT, typename... SPSArgTs>
struct WrapperFunctionSPSSerializer<SPSRetT(SPSArgTs...)> {
static detail::WFSPSSerializer<SPSArgTs...> argumentSerializer() noexcept {
return {};
}
static detail::WFSPSDeserializer<SPSArgTs...>
argumentDeserializer() noexcept {
return {};
}
static detail::WFSPSSerializer<SPSRetT> resultSerializer() noexcept {
return {};
}
static detail::WFSPSDeserializer<SPSRetT> resultDeserializer() noexcept {
return {};
}
};

/// Provides call and handle utilities to simplify writing and invocation of
/// wrapper functions that use SimplePackedSerialization to serialize and
/// deserialize their arguments and return values.
template <typename SPSSig> struct SPSWrapperFunction {
template <typename Caller, typename ResultHandler, typename... ArgTs>
static void call(Caller &&C, ResultHandler &&RH, ArgTs &&...Args) {
WrapperFunction::call(
std::forward<Caller>(C), WrapperFunctionSPSSerializer<SPSSig>(),
std::forward<ResultHandler>(RH), std::forward<ArgTs>(Args)...);
}

template <typename Handler>
static void handle(orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionReturn Return,
WrapperFunctionBuffer ArgBytes, Handler &&H) {
WrapperFunction::handle(Session, CallCtx, Return, std::move(ArgBytes),
WrapperFunctionSPSSerializer<SPSSig>(),
std::forward<Handler>(H));
}
};

} // namespace orc_rt

#endif // ORC_RT_SPSWRAPPERFUNCTION_H
160 changes: 160 additions & 0 deletions orc-rt/include/orc-rt/WrapperFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#define ORC_RT_WRAPPERFUNCTION_H

#include "orc-rt-c/WrapperFunction.h"
#include "orc-rt/Error.h"
#include "orc-rt/bind.h"

#include <utility>

Expand Down Expand Up @@ -98,6 +100,164 @@ class WrapperFunctionBuffer {
orc_rt_WrapperFunctionBuffer B;
};

namespace detail {

template <typename C>
struct WFCallableTraits
: public WFCallableTraits<
decltype(&std::remove_cv_t<std::remove_reference_t<C>>::operator())> {
};

template <typename RetT> struct WFCallableTraits<RetT()> {
typedef void HeadArgType;
};

template <typename RetT, typename ArgT, typename... ArgTs>
struct WFCallableTraits<RetT(ArgT, ArgTs...)> {
typedef ArgT HeadArgType;
typedef std::tuple<ArgTs...> TailArgTuple;
};

template <typename ClassT, typename RetT, typename... ArgTs>
struct WFCallableTraits<RetT (ClassT::*)(ArgTs...)>
: public WFCallableTraits<RetT(ArgTs...)> {};

template <typename ClassT, typename RetT, typename... ArgTs>
struct WFCallableTraits<RetT (ClassT::*)(ArgTs...) const>
: public WFCallableTraits<RetT(ArgTs...)> {};

template <typename Serializer> class StructuredYieldBase {
public:
StructuredYieldBase(orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionReturn Return, Serializer &&S)
: Session(Session), CallCtx(CallCtx), Return(Return),
S(std::forward<Serializer>(S)) {}

protected:
orc_rt_SessionRef Session;
void *CallCtx;
orc_rt_WrapperFunctionReturn Return;
std::decay_t<Serializer> S;
};

template <typename RetT, typename Serializer>
class StructuredYield : public StructuredYieldBase<Serializer> {
public:
using StructuredYieldBase<Serializer>::StructuredYieldBase;
void operator()(RetT &&R) {
if (auto ResultBytes = this->S.resultSerializer()(std::forward<RetT>(R)))
this->Return(this->Session, this->CallCtx, ResultBytes->release());
else
this->Return(this->Session, this->CallCtx,
WrapperFunctionBuffer::createOutOfBandError(
"Could not serialize wrapper function result data")
.release());
}
};

template <typename Serializer>
class StructuredYield<void, Serializer>
: public StructuredYieldBase<Serializer> {
public:
using StructuredYieldBase<Serializer>::StructuredYieldBase;
void operator()() {
this->Return(this->Session, this->CallCtx,
WrapperFunctionBuffer().release());
}
};

template <typename T, typename Serializer> struct ResultDeserializer;

template <typename T, typename Serializer>
struct ResultDeserializer<Expected<T>, Serializer> {
static Expected<T> deserialize(WrapperFunctionBuffer ResultBytes,
Serializer &S) {
T Val;
if (S.resultDeserializer()(ResultBytes, Val))
return std::move(Val);
else
return make_error<StringError>("Could not deserialize result");
}
};

template <typename Serializer> struct ResultDeserializer<Error, Serializer> {
static Error deserialize(WrapperFunctionBuffer ResultBytes, Serializer &S) {
assert(ResultBytes.empty());
return Error::success();
}
};

} // namespace detail

/// Provides call and handle utilities to simplify writing and invocation of
/// wrapper functions in C++.
struct WrapperFunction {

/// Make a call to a wrapper function.
///
/// This utility serializes and deserializes arguments and return values
/// (using the given Serializer), and calls the wrapper function via the
/// given Caller object.
template <typename Caller, typename Serializer, typename ResultHandler,
typename... ArgTs>
static void call(Caller &&C, Serializer &&S, ResultHandler &&RH,
ArgTs &&...Args) {
typedef detail::WFCallableTraits<ResultHandler> ResultHandlerTraits;
static_assert(
std::tuple_size_v<typename ResultHandlerTraits::TailArgTuple> == 0,
"Expected one argument to result-handler");
typedef typename ResultHandlerTraits::HeadArgType ResultType;

if (auto ArgBytes = S.argumentSerializer()(std::forward<ArgTs>(Args)...)) {
C(
[RH = std::move(RH),
S = std::move(S)](orc_rt_SessionRef Session,
WrapperFunctionBuffer ResultBytes) mutable {
if (const char *ErrMsg = ResultBytes.getOutOfBandError())
RH(make_error<StringError>(ErrMsg));
else
RH(detail::ResultDeserializer<
ResultType, Serializer>::deserialize(std::move(ResultBytes),
S));
},
std::move(*ArgBytes));
} else
RH(make_error<StringError>(
"Could not serialize wrapper function call arguments"));
}

/// Simplifies implementation of wrapper functions in C++.
///
/// This utility deserializes and serializes arguments and return values
/// (using the given Serializer), and calls the given handler.
template <typename Serializer, typename Handler>
static void handle(orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionReturn Return,
WrapperFunctionBuffer ArgBytes, Serializer &&S,
Handler &&H) {
typedef detail::WFCallableTraits<Handler> HandlerTraits;
typedef typename HandlerTraits::HeadArgType Yield;
typedef typename HandlerTraits::TailArgTuple ArgTuple;
typedef typename detail::WFCallableTraits<Yield>::HeadArgType RetType;

if (ArgBytes.getOutOfBandError())
return Return(Session, CallCtx, ArgBytes.release());

ArgTuple Args;
if (std::apply(bind_front(S.argumentDeserializer(), std::move(ArgBytes)),
Args))
std::apply(bind_front(std::forward<Handler>(H),
detail::StructuredYield<RetType, Serializer>(
Session, CallCtx, Return, std::move(S))),
std::move(Args));
else
Return(Session, CallCtx,
WrapperFunctionBuffer::createOutOfBandError(
"Could not deserialize wrapper function arg data")
.release());
}
};

} // namespace orc_rt

#endif // ORC_RT_WRAPPERFUNCTION_H
1 change: 1 addition & 0 deletions orc-rt/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ add_orc_rt_unittest(CoreTests
MemoryFlagsTest.cpp
RTTITest.cpp
SimplePackedSerializationTest.cpp
SPSWrapperFunctionTest.cpp
WrapperFunctionBufferTest.cpp
bind-test.cpp
bit-test.cpp
Expand Down
Loading
Loading