aboutsummaryrefslogtreecommitdiff
path: root/compiler-rt/lib/orc/simple_packed_serialization.h
diff options
context:
space:
mode:
Diffstat (limited to 'compiler-rt/lib/orc/simple_packed_serialization.h')
-rw-r--r--compiler-rt/lib/orc/simple_packed_serialization.h579
1 files changed, 579 insertions, 0 deletions
diff --git a/compiler-rt/lib/orc/simple_packed_serialization.h b/compiler-rt/lib/orc/simple_packed_serialization.h
new file mode 100644
index 000000000000..b561a19d8f04
--- /dev/null
+++ b/compiler-rt/lib/orc/simple_packed_serialization.h
@@ -0,0 +1,579 @@
+//===--- simple_packed_serialization.h - simple serialization ---*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+// The behavior of the utilities in this header must be synchronized with the
+// behavior of the utilities in
+// llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h.
+//
+// The Simple Packed Serialization (SPS) utilities are used to generate
+// argument and return buffers for wrapper functions using the following
+// serialization scheme:
+//
+// Primitives:
+// bool, char, int8_t, uint8_t -- Two's complement 8-bit (0=false, 1=true)
+// int16_t, uint16_t -- Two's complement 16-bit little endian
+// int32_t, uint32_t -- Two's complement 32-bit little endian
+// int64_t, int64_t -- Two's complement 64-bit little endian
+//
+// Sequence<T>:
+// Serialized as the sequence length (as a uint64_t) followed by the
+// serialization of each of the elements without padding.
+//
+// Tuple<T1, ..., TN>:
+// Serialized as each of the element types from T1 to TN without padding.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_SIMPLE_PACKED_SERIALIZATION_H
+#define ORC_RT_SIMPLE_PACKED_SERIALIZATION_H
+
+#include "adt.h"
+#include "endianness.h"
+#include "error.h"
+#include "stl_extras.h"
+
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+namespace __orc_rt {
+
+/// Output char buffer with overflow check.
+class SPSOutputBuffer {
+public:
+ SPSOutputBuffer(char *Buffer, size_t Remaining)
+ : Buffer(Buffer), Remaining(Remaining) {}
+ bool write(const char *Data, size_t Size) {
+ if (Size > Remaining)
+ return false;
+ memcpy(Buffer, Data, Size);
+ Buffer += Size;
+ Remaining -= Size;
+ return true;
+ }
+
+private:
+ char *Buffer = nullptr;
+ size_t Remaining = 0;
+};
+
+/// Input char buffer with underflow check.
+class SPSInputBuffer {
+public:
+ SPSInputBuffer() = default;
+ SPSInputBuffer(const char *Buffer, size_t Remaining)
+ : Buffer(Buffer), Remaining(Remaining) {}
+ bool read(char *Data, size_t Size) {
+ if (Size > Remaining)
+ return false;
+ memcpy(Data, Buffer, Size);
+ Buffer += Size;
+ Remaining -= Size;
+ return true;
+ }
+
+ const char *data() const { return Buffer; }
+ bool skip(size_t Size) {
+ if (Size > Remaining)
+ return false;
+ Buffer += Size;
+ Remaining -= Size;
+ return true;
+ }
+
+private:
+ const char *Buffer = nullptr;
+ size_t Remaining = 0;
+};
+
+/// Specialize to describe how to serialize/deserialize to/from the given
+/// concrete type.
+template <typename SPSTagT, typename ConcreteT, typename _ = void>
+class SPSSerializationTraits;
+
+/// A utility class for serializing to a blob from a variadic list.
+template <typename... ArgTs> class SPSArgList;
+
+// Empty list specialization for SPSArgList.
+template <> class SPSArgList<> {
+public:
+ static size_t size() { return 0; }
+
+ static bool serialize(SPSOutputBuffer &OB) { return true; }
+ static bool deserialize(SPSInputBuffer &IB) { return true; }
+};
+
+// Non-empty list specialization for SPSArgList.
+template <typename SPSTagT, typename... SPSTagTs>
+class SPSArgList<SPSTagT, SPSTagTs...> {
+public:
+ template <typename ArgT, typename... ArgTs>
+ static size_t size(const ArgT &Arg, const ArgTs &...Args) {
+ return SPSSerializationTraits<SPSTagT, ArgT>::size(Arg) +
+ SPSArgList<SPSTagTs...>::size(Args...);
+ }
+
+ template <typename ArgT, typename... ArgTs>
+ static bool serialize(SPSOutputBuffer &OB, const ArgT &Arg,
+ const ArgTs &...Args) {
+ return SPSSerializationTraits<SPSTagT, ArgT>::serialize(OB, Arg) &&
+ SPSArgList<SPSTagTs...>::serialize(OB, Args...);
+ }
+
+ template <typename ArgT, typename... ArgTs>
+ static bool deserialize(SPSInputBuffer &IB, ArgT &Arg, ArgTs &...Args) {
+ return SPSSerializationTraits<SPSTagT, ArgT>::deserialize(IB, Arg) &&
+ SPSArgList<SPSTagTs...>::deserialize(IB, Args...);
+ }
+};
+
+/// SPS serialization for integral types, bool, and char.
+template <typename SPSTagT>
+class SPSSerializationTraits<
+ SPSTagT, SPSTagT,
+ std::enable_if_t<std::is_same<SPSTagT, bool>::value ||
+ std::is_same<SPSTagT, char>::value ||
+ std::is_same<SPSTagT, int8_t>::value ||
+ std::is_same<SPSTagT, int16_t>::value ||
+ std::is_same<SPSTagT, int32_t>::value ||
+ std::is_same<SPSTagT, int64_t>::value ||
+ std::is_same<SPSTagT, uint8_t>::value ||
+ std::is_same<SPSTagT, uint16_t>::value ||
+ std::is_same<SPSTagT, uint32_t>::value ||
+ std::is_same<SPSTagT, uint64_t>::value>> {
+public:
+ static size_t size(const SPSTagT &Value) { return sizeof(SPSTagT); }
+
+ static bool serialize(SPSOutputBuffer &OB, const SPSTagT &Value) {
+ SPSTagT Tmp = Value;
+ if (IsBigEndianHost)
+ swapByteOrder(Tmp);
+ return OB.write(reinterpret_cast<const char *>(&Tmp), sizeof(Tmp));
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, SPSTagT &Value) {
+ SPSTagT Tmp;
+ if (!IB.read(reinterpret_cast<char *>(&Tmp), sizeof(Tmp)))
+ return false;
+ if (IsBigEndianHost)
+ swapByteOrder(Tmp);
+ Value = Tmp;
+ return true;
+ }
+};
+
+/// Any empty placeholder suitable as a substitute for void when deserializing
+class SPSEmpty {};
+
+/// Represents an address in the executor.
+class SPSExecutorAddress {};
+
+/// SPS tag type for tuples.
+///
+/// A blob tuple should be serialized by serializing each of the elements in
+/// sequence.
+template <typename... SPSTagTs> class SPSTuple {
+public:
+ /// Convenience typedef of the corresponding arg list.
+ typedef SPSArgList<SPSTagTs...> AsArgList;
+};
+
+/// SPS tag type for sequences.
+///
+/// SPSSequences should be serialized as a uint64_t sequence length,
+/// followed by the serialization of each of the elements.
+template <typename SPSElementTagT> class SPSSequence;
+
+/// SPS tag type for strings, which are equivalent to sequences of chars.
+using SPSString = SPSSequence<char>;
+
+/// SPS tag type for maps.
+///
+/// SPS maps are just sequences of (Key, Value) tuples.
+template <typename SPSTagT1, typename SPSTagT2>
+using SPSMap = SPSSequence<SPSTuple<SPSTagT1, SPSTagT2>>;
+
+/// Serialization for SPSEmpty type.
+template <> class SPSSerializationTraits<SPSEmpty, SPSEmpty> {
+public:
+ static size_t size(const SPSEmpty &EP) { return 0; }
+ static bool serialize(SPSOutputBuffer &OB, const SPSEmpty &BE) {
+ return true;
+ }
+ static bool deserialize(SPSInputBuffer &IB, SPSEmpty &BE) { return true; }
+};
+
+/// Specialize this to implement 'trivial' sequence serialization for
+/// a concrete sequence type.
+///
+/// Trivial sequence serialization uses the sequence's 'size' member to get the
+/// length of the sequence, and uses a range-based for loop to iterate over the
+/// elements.
+///
+/// Specializing this template class means that you do not need to provide a
+/// specialization of SPSSerializationTraits for your type.
+template <typename SPSElementTagT, typename ConcreteSequenceT>
+class TrivialSPSSequenceSerialization {
+public:
+ static constexpr bool available = false;
+};
+
+/// Specialize this to implement 'trivial' sequence deserialization for
+/// a concrete sequence type.
+///
+/// Trivial deserialization calls a static 'reserve(SequenceT&)' method on your
+/// specialization (you must implement this) to reserve space, and then calls
+/// a static 'append(SequenceT&, ElementT&) method to append each of the
+/// deserialized elements.
+///
+/// Specializing this template class means that you do not need to provide a
+/// specialization of SPSSerializationTraits for your type.
+template <typename SPSElementTagT, typename ConcreteSequenceT>
+class TrivialSPSSequenceDeserialization {
+public:
+ static constexpr bool available = false;
+};
+
+/// Trivial std::string -> SPSSequence<char> serialization.
+template <> class TrivialSPSSequenceSerialization<char, std::string> {
+public:
+ static constexpr bool available = true;
+};
+
+/// Trivial SPSSequence<char> -> std::string deserialization.
+template <> class TrivialSPSSequenceDeserialization<char, std::string> {
+public:
+ static constexpr bool available = true;
+
+ using element_type = char;
+
+ static void reserve(std::string &S, uint64_t Size) { S.reserve(Size); }
+ static bool append(std::string &S, char C) {
+ S.push_back(C);
+ return true;
+ }
+};
+
+/// Trivial std::vector<T> -> SPSSequence<SPSElementTagT> serialization.
+template <typename SPSElementTagT, typename T>
+class TrivialSPSSequenceSerialization<SPSElementTagT, std::vector<T>> {
+public:
+ static constexpr bool available = true;
+};
+
+/// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization.
+template <typename SPSElementTagT, typename T>
+class TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>> {
+public:
+ static constexpr bool available = true;
+
+ using element_type = typename std::vector<T>::value_type;
+
+ static void reserve(std::vector<T> &V, uint64_t Size) { V.reserve(Size); }
+ static bool append(std::vector<T> &V, T E) {
+ V.push_back(std::move(E));
+ return true;
+ }
+};
+
+/// Trivial std::unordered_map<K, V> -> SPSSequence<SPSTuple<SPSKey, SPSValue>>
+/// serialization.
+template <typename SPSKeyTagT, typename SPSValueTagT, typename K, typename V>
+class TrivialSPSSequenceSerialization<SPSTuple<SPSKeyTagT, SPSValueTagT>,
+ std::unordered_map<K, V>> {
+public:
+ static constexpr bool available = true;
+};
+
+/// Trivial SPSSequence<SPSTuple<SPSKey, SPSValue>> -> std::unordered_map<K, V>
+/// deserialization.
+template <typename SPSKeyTagT, typename SPSValueTagT, typename K, typename V>
+class TrivialSPSSequenceDeserialization<SPSTuple<SPSKeyTagT, SPSValueTagT>,
+ std::unordered_map<K, V>> {
+public:
+ static constexpr bool available = true;
+
+ using element_type = std::pair<K, V>;
+
+ static void reserve(std::unordered_map<K, V> &M, uint64_t Size) {
+ M.reserve(Size);
+ }
+ static bool append(std::unordered_map<K, V> &M, element_type E) {
+ return M.insert(std::move(E)).second;
+ }
+};
+
+/// 'Trivial' sequence serialization: Sequence is serialized as a uint64_t size
+/// followed by a for-earch loop over the elements of the sequence to serialize
+/// each of them.
+template <typename SPSElementTagT, typename SequenceT>
+class SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT,
+ std::enable_if_t<TrivialSPSSequenceSerialization<
+ SPSElementTagT, SequenceT>::available>> {
+public:
+ static size_t size(const SequenceT &S) {
+ size_t Size = SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size()));
+ for (const auto &E : S)
+ Size += SPSArgList<SPSElementTagT>::size(E);
+ return Size;
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const SequenceT &S) {
+ if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
+ return false;
+ for (const auto &E : S)
+ if (!SPSArgList<SPSElementTagT>::serialize(OB, E))
+ return false;
+ return true;
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, SequenceT &S) {
+ using TBSD = TrivialSPSSequenceDeserialization<SPSElementTagT, SequenceT>;
+ uint64_t Size;
+ if (!SPSArgList<uint64_t>::deserialize(IB, Size))
+ return false;
+ TBSD::reserve(S, Size);
+ for (size_t I = 0; I != Size; ++I) {
+ typename TBSD::element_type E;
+ if (!SPSArgList<SPSElementTagT>::deserialize(IB, E))
+ return false;
+ if (!TBSD::append(S, std::move(E)))
+ return false;
+ }
+ return true;
+ }
+};
+
+/// SPSTuple serialization for std::pair.
+template <typename SPSTagT1, typename SPSTagT2, typename T1, typename T2>
+class SPSSerializationTraits<SPSTuple<SPSTagT1, SPSTagT2>, std::pair<T1, T2>> {
+public:
+ static size_t size(const std::pair<T1, T2> &P) {
+ return SPSArgList<SPSTagT1>::size(P.first) +
+ SPSArgList<SPSTagT2>::size(P.second);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const std::pair<T1, T2> &P) {
+ return SPSArgList<SPSTagT1>::serialize(OB, P.first) &&
+ SPSArgList<SPSTagT2>::serialize(OB, P.second);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, std::pair<T1, T2> &P) {
+ return SPSArgList<SPSTagT1>::deserialize(IB, P.first) &&
+ SPSArgList<SPSTagT2>::deserialize(IB, P.second);
+ }
+};
+
+/// Serialization for string_views.
+///
+/// Serialization is as for regular strings. Deserialization points directly
+/// into the blob.
+template <> class SPSSerializationTraits<SPSString, __orc_rt::string_view> {
+public:
+ static size_t size(const __orc_rt::string_view &S) {
+ return SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size())) +
+ S.size();
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const __orc_rt::string_view &S) {
+ if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
+ return false;
+ return OB.write(S.data(), S.size());
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, __orc_rt::string_view &S) {
+ const char *Data = nullptr;
+ uint64_t Size;
+ if (!SPSArgList<uint64_t>::deserialize(IB, Size))
+ return false;
+ Data = IB.data();
+ if (!IB.skip(Size))
+ return false;
+ S = {Data, Size};
+ return true;
+ }
+};
+
+/// SPS tag type for errors.
+class SPSError;
+
+/// SPS tag type for expecteds, which are either a T or a string representing
+/// an error.
+template <typename SPSTagT> class SPSExpected;
+
+namespace detail {
+
+/// Helper type for serializing Errors.
+///
+/// llvm::Errors are move-only, and not inspectable except by consuming them.
+/// This makes them unsuitable for direct serialization via
+/// SPSSerializationTraits, which needs to inspect values twice (once to
+/// determine the amount of space to reserve, and then again to serialize).
+///
+/// The SPSSerializableError type is a helper that can be
+/// constructed from an llvm::Error, but inspected more than once.
+struct SPSSerializableError {
+ bool HasError = false;
+ std::string ErrMsg;
+};
+
+/// Helper type for serializing Expected<T>s.
+///
+/// See SPSSerializableError for more details.
+///
+// FIXME: Use std::variant for storage once we have c++17.
+template <typename T> struct SPSSerializableExpected {
+ bool HasValue = false;
+ T Value{};
+ std::string ErrMsg;
+};
+
+inline SPSSerializableError toSPSSerializable(Error Err) {
+ if (Err)
+ return {true, toString(std::move(Err))};
+ return {false, {}};
+}
+
+inline Error fromSPSSerializable(SPSSerializableError BSE) {
+ if (BSE.HasError)
+ return make_error<StringError>(BSE.ErrMsg);
+ return Error::success();
+}
+
+template <typename T>
+SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {
+ if (E)
+ return {true, std::move(*E), {}};
+ else
+ return {false, {}, toString(E.takeError())};
+}
+
+template <typename T>
+Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {
+ if (BSE.HasValue)
+ return std::move(BSE.Value);
+ else
+ return make_error<StringError>(BSE.ErrMsg);
+}
+
+} // end namespace detail
+
+/// Serialize to a SPSError from a detail::SPSSerializableError.
+template <>
+class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {
+public:
+ static size_t size(const detail::SPSSerializableError &BSE) {
+ size_t Size = SPSArgList<bool>::size(BSE.HasError);
+ if (BSE.HasError)
+ Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
+ return Size;
+ }
+
+ static bool serialize(SPSOutputBuffer &OB,
+ const detail::SPSSerializableError &BSE) {
+ if (!SPSArgList<bool>::serialize(OB, BSE.HasError))
+ return false;
+ if (BSE.HasError)
+ if (!SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg))
+ return false;
+ return true;
+ }
+
+ static bool deserialize(SPSInputBuffer &IB,
+ detail::SPSSerializableError &BSE) {
+ if (!SPSArgList<bool>::deserialize(IB, BSE.HasError))
+ return false;
+
+ if (!BSE.HasError)
+ return true;
+
+ return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
+ }
+};
+
+/// Serialize to a SPSExpected<SPSTagT> from a
+/// detail::SPSSerializableExpected<T>.
+template <typename SPSTagT, typename T>
+class SPSSerializationTraits<SPSExpected<SPSTagT>,
+ detail::SPSSerializableExpected<T>> {
+public:
+ static size_t size(const detail::SPSSerializableExpected<T> &BSE) {
+ size_t Size = SPSArgList<bool>::size(BSE.HasValue);
+ if (BSE.HasValue)
+ Size += SPSArgList<SPSTagT>::size(BSE.Value);
+ else
+ Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
+ return Size;
+ }
+
+ static bool serialize(SPSOutputBuffer &OB,
+ const detail::SPSSerializableExpected<T> &BSE) {
+ if (!SPSArgList<bool>::serialize(OB, BSE.HasValue))
+ return false;
+
+ if (BSE.HasValue)
+ return SPSArgList<SPSTagT>::serialize(OB, BSE.Value);
+
+ return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB,
+ detail::SPSSerializableExpected<T> &BSE) {
+ if (!SPSArgList<bool>::deserialize(IB, BSE.HasValue))
+ return false;
+
+ if (BSE.HasValue)
+ return SPSArgList<SPSTagT>::deserialize(IB, BSE.Value);
+
+ return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
+ }
+};
+
+/// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.
+template <typename SPSTagT>
+class SPSSerializationTraits<SPSExpected<SPSTagT>,
+ detail::SPSSerializableError> {
+public:
+ static size_t size(const detail::SPSSerializableError &BSE) {
+ assert(BSE.HasError && "Cannot serialize expected from a success value");
+ return SPSArgList<bool>::size(false) +
+ SPSArgList<SPSString>::size(BSE.ErrMsg);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB,
+ const detail::SPSSerializableError &BSE) {
+ assert(BSE.HasError && "Cannot serialize expected from a success value");
+ if (!SPSArgList<bool>::serialize(OB, false))
+ return false;
+ return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
+ }
+};
+
+/// Serialize to a SPSExpected<SPSTagT> from a T.
+template <typename SPSTagT, typename T>
+class SPSSerializationTraits<SPSExpected<SPSTagT>, T> {
+public:
+ static size_t size(const T &Value) {
+ return SPSArgList<bool>::size(true) + SPSArgList<SPSTagT>::size(Value);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const T &Value) {
+ if (!SPSArgList<bool>::serialize(OB, true))
+ return false;
+ return SPSArgList<SPSTagT>::serialize(Value);
+ }
+};
+
+} // end namespace __orc_rt
+
+#endif // ORC_RT_SIMPLE_PACKED_SERIALIZATION_H