brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.0 KiB · b4726da Raw
690 lines · c
1//===--- simple_packed_serialization.h - simple serialization ---*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of the ORC runtime support library.10//11// The behavior of the utilities in this header must be synchronized with the12// behavior of the utilities in13// llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h.14//15// The Simple Packed Serialization (SPS) utilities are used to generate16// argument and return buffers for wrapper functions using the following17// serialization scheme:18//19// Primitives:20//   bool, char, int8_t, uint8_t -- Two's complement 8-bit (0=false, 1=true)21//   int16_t, uint16_t           -- Two's complement 16-bit little endian22//   int32_t, uint32_t           -- Two's complement 32-bit little endian23//   int64_t, int64_t            -- Two's complement 64-bit little endian24//25// Sequence<T>:26//   Serialized as the sequence length (as a uint64_t) followed by the27//   serialization of each of the elements without padding.28//29// Tuple<T1, ..., TN>:30//   Serialized as each of the element types from T1 to TN without padding.31//32//===----------------------------------------------------------------------===//33 34#ifndef ORC_RT_SIMPLE_PACKED_SERIALIZATION_H35#define ORC_RT_SIMPLE_PACKED_SERIALIZATION_H36 37#include "adt.h"38#include "endianness.h"39#include "error.h"40#include "stl_extras.h"41 42#include <optional>43#include <string>44#include <string_view>45#include <tuple>46#include <type_traits>47#include <unordered_map>48#include <utility>49#include <vector>50 51namespace orc_rt {52 53/// Output char buffer with overflow check.54class SPSOutputBuffer {55public:56  SPSOutputBuffer(char *Buffer, size_t Remaining)57      : Buffer(Buffer), Remaining(Remaining) {}58  bool write(const char *Data, size_t Size) {59    if (Size > Remaining)60      return false;61    memcpy(Buffer, Data, Size);62    Buffer += Size;63    Remaining -= Size;64    return true;65  }66 67private:68  char *Buffer = nullptr;69  size_t Remaining = 0;70};71 72/// Input char buffer with underflow check.73class SPSInputBuffer {74public:75  SPSInputBuffer() = default;76  SPSInputBuffer(const char *Buffer, size_t Remaining)77      : Buffer(Buffer), Remaining(Remaining) {}78  bool read(char *Data, size_t Size) {79    if (Size > Remaining)80      return false;81    memcpy(Data, Buffer, Size);82    Buffer += Size;83    Remaining -= Size;84    return true;85  }86 87  const char *data() const { return Buffer; }88  bool skip(size_t Size) {89    if (Size > Remaining)90      return false;91    Buffer += Size;92    Remaining -= Size;93    return true;94  }95 96private:97  const char *Buffer = nullptr;98  size_t Remaining = 0;99};100 101/// Specialize to describe how to serialize/deserialize to/from the given102/// concrete type.103template <typename SPSTagT, typename ConcreteT, typename _ = void>104class SPSSerializationTraits;105 106/// A utility class for serializing to a blob from a variadic list.107template <typename... ArgTs> class SPSArgList;108 109// Empty list specialization for SPSArgList.110template <> class SPSArgList<> {111public:112  static size_t size() { return 0; }113 114  static bool serialize(SPSOutputBuffer &OB) { return true; }115  static bool deserialize(SPSInputBuffer &IB) { return true; }116};117 118// Non-empty list specialization for SPSArgList.119template <typename SPSTagT, typename... SPSTagTs>120class SPSArgList<SPSTagT, SPSTagTs...> {121public:122  template <typename ArgT, typename... ArgTs>123  static size_t size(const ArgT &Arg, const ArgTs &...Args) {124    return SPSSerializationTraits<SPSTagT, ArgT>::size(Arg) +125           SPSArgList<SPSTagTs...>::size(Args...);126  }127 128  template <typename ArgT, typename... ArgTs>129  static bool serialize(SPSOutputBuffer &OB, const ArgT &Arg,130                        const ArgTs &...Args) {131    return SPSSerializationTraits<SPSTagT, ArgT>::serialize(OB, Arg) &&132           SPSArgList<SPSTagTs...>::serialize(OB, Args...);133  }134 135  template <typename ArgT, typename... ArgTs>136  static bool deserialize(SPSInputBuffer &IB, ArgT &Arg, ArgTs &...Args) {137    return SPSSerializationTraits<SPSTagT, ArgT>::deserialize(IB, Arg) &&138           SPSArgList<SPSTagTs...>::deserialize(IB, Args...);139  }140};141 142/// SPS serialization for integral types, bool, and char.143template <typename SPSTagT>144class SPSSerializationTraits<145    SPSTagT, SPSTagT,146    std::enable_if_t<std::is_same<SPSTagT, bool>::value ||147                     std::is_same<SPSTagT, char>::value ||148                     std::is_same<SPSTagT, int8_t>::value ||149                     std::is_same<SPSTagT, int16_t>::value ||150                     std::is_same<SPSTagT, int32_t>::value ||151                     std::is_same<SPSTagT, int64_t>::value ||152                     std::is_same<SPSTagT, uint8_t>::value ||153                     std::is_same<SPSTagT, uint16_t>::value ||154                     std::is_same<SPSTagT, uint32_t>::value ||155                     std::is_same<SPSTagT, uint64_t>::value>> {156public:157  static size_t size(const SPSTagT &Value) { return sizeof(SPSTagT); }158 159  static bool serialize(SPSOutputBuffer &OB, const SPSTagT &Value) {160    SPSTagT Tmp = Value;161    if (IsBigEndianHost)162      swapByteOrder(Tmp);163    return OB.write(reinterpret_cast<const char *>(&Tmp), sizeof(Tmp));164  }165 166  static bool deserialize(SPSInputBuffer &IB, SPSTagT &Value) {167    SPSTagT Tmp;168    if (!IB.read(reinterpret_cast<char *>(&Tmp), sizeof(Tmp)))169      return false;170    if (IsBigEndianHost)171      swapByteOrder(Tmp);172    Value = Tmp;173    return true;174  }175};176 177/// Any empty placeholder suitable as a substitute for void when deserializing178class SPSEmpty {};179 180/// Represents an address in the executor.181class SPSExecutorAddr {};182 183/// SPS tag type for tuples.184///185/// A blob tuple should be serialized by serializing each of the elements in186/// sequence.187template <typename... SPSTagTs> class SPSTuple {188public:189  /// Convenience typedef of the corresponding arg list.190  typedef SPSArgList<SPSTagTs...> AsArgList;191};192 193/// SPS tag type for optionals.194///195/// SPSOptionals should be serialized as a bool with true indicating that an196/// SPSTagT value is present, and false indicating that there is no value.197/// If the boolean is true then the serialized SPSTagT will follow immediately198/// after it.199template <typename SPSTagT> class SPSOptional {};200 201/// SPS tag type for sequences.202///203/// SPSSequences should be serialized as a uint64_t sequence length,204/// followed by the serialization of each of the elements.205template <typename SPSElementTagT> class SPSSequence;206 207/// SPS tag type for strings, which are equivalent to sequences of chars.208using SPSString = SPSSequence<char>;209 210/// SPS tag type for maps.211///212/// SPS maps are just sequences of (Key, Value) tuples.213template <typename SPSTagT1, typename SPSTagT2>214using SPSMap = SPSSequence<SPSTuple<SPSTagT1, SPSTagT2>>;215 216/// Serialization for SPSEmpty type.217template <> class SPSSerializationTraits<SPSEmpty, SPSEmpty> {218public:219  static size_t size(const SPSEmpty &EP) { return 0; }220  static bool serialize(SPSOutputBuffer &OB, const SPSEmpty &BE) {221    return true;222  }223  static bool deserialize(SPSInputBuffer &IB, SPSEmpty &BE) { return true; }224};225 226/// Specialize this to implement 'trivial' sequence serialization for227/// a concrete sequence type.228///229/// Trivial sequence serialization uses the sequence's 'size' member to get the230/// length of the sequence, and uses a range-based for loop to iterate over the231/// elements.232///233/// Specializing this template class means that you do not need to provide a234/// specialization of SPSSerializationTraits for your type.235template <typename SPSElementTagT, typename ConcreteSequenceT>236class TrivialSPSSequenceSerialization {237public:238  static constexpr bool available = false;239};240 241/// Specialize this to implement 'trivial' sequence deserialization for242/// a concrete sequence type.243///244/// Trivial deserialization calls a static 'reserve(SequenceT&)' method on your245/// specialization (you must implement this) to reserve space, and then calls246/// a static 'append(SequenceT&, ElementT&) method to append each of the247/// deserialized elements.248///249/// Specializing this template class means that you do not need to provide a250/// specialization of SPSSerializationTraits for your type.251template <typename SPSElementTagT, typename ConcreteSequenceT>252class TrivialSPSSequenceDeserialization {253public:254  static constexpr bool available = false;255};256 257/// Trivial std::string -> SPSSequence<char> serialization.258template <> class TrivialSPSSequenceSerialization<char, std::string> {259public:260  static constexpr bool available = true;261};262 263/// Trivial SPSSequence<char> -> std::string deserialization.264template <> class TrivialSPSSequenceDeserialization<char, std::string> {265public:266  static constexpr bool available = true;267 268  using element_type = char;269 270  static void reserve(std::string &S, uint64_t Size) { S.reserve(Size); }271  static bool append(std::string &S, char C) {272    S.push_back(C);273    return true;274  }275};276 277/// Trivial std::vector<T> -> SPSSequence<SPSElementTagT> serialization.278template <typename SPSElementTagT, typename T>279class TrivialSPSSequenceSerialization<SPSElementTagT, std::vector<T>> {280public:281  static constexpr bool available = true;282};283 284/// Trivial span<T> -> SPSSequence<SPSElementTagT> serialization.285template <typename SPSElementTagT, typename T>286class TrivialSPSSequenceSerialization<SPSElementTagT, span<T>> {287public:288  static constexpr bool available = true;289};290 291/// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization.292template <typename SPSElementTagT, typename T>293class TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>> {294public:295  static constexpr bool available = true;296 297  using element_type = typename std::vector<T>::value_type;298 299  static void reserve(std::vector<T> &V, uint64_t Size) { V.reserve(Size); }300  static bool append(std::vector<T> &V, T E) {301    V.push_back(std::move(E));302    return true;303  }304};305 306/// Trivial std::unordered_map<K, V> -> SPSSequence<SPSTuple<SPSKey, SPSValue>>307/// serialization.308template <typename SPSKeyTagT, typename SPSValueTagT, typename K, typename V>309class TrivialSPSSequenceSerialization<SPSTuple<SPSKeyTagT, SPSValueTagT>,310                                      std::unordered_map<K, V>> {311public:312  static constexpr bool available = true;313};314 315/// Trivial SPSSequence<SPSTuple<SPSKey, SPSValue>> -> std::unordered_map<K, V>316/// deserialization.317template <typename SPSKeyTagT, typename SPSValueTagT, typename K, typename V>318class TrivialSPSSequenceDeserialization<SPSTuple<SPSKeyTagT, SPSValueTagT>,319                                        std::unordered_map<K, V>> {320public:321  static constexpr bool available = true;322 323  using element_type = std::pair<K, V>;324 325  static void reserve(std::unordered_map<K, V> &M, uint64_t Size) {326    M.reserve(Size);327  }328  static bool append(std::unordered_map<K, V> &M, element_type E) {329    return M.insert(std::move(E)).second;330  }331};332 333/// 'Trivial' sequence serialization: Sequence is serialized as a uint64_t size334/// followed by a for-earch loop over the elements of the sequence to serialize335/// each of them.336template <typename SPSElementTagT, typename SequenceT>337class SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT,338                             std::enable_if_t<TrivialSPSSequenceSerialization<339                                 SPSElementTagT, SequenceT>::available>> {340public:341  static size_t size(const SequenceT &S) {342    size_t Size = SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size()));343    for (const auto &E : S)344      Size += SPSArgList<SPSElementTagT>::size(E);345    return Size;346  }347 348  static bool serialize(SPSOutputBuffer &OB, const SequenceT &S) {349    if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))350      return false;351    for (const auto &E : S)352      if (!SPSArgList<SPSElementTagT>::serialize(OB, E))353        return false;354    return true;355  }356 357  static bool deserialize(SPSInputBuffer &IB, SequenceT &S) {358    using TBSD = TrivialSPSSequenceDeserialization<SPSElementTagT, SequenceT>;359    uint64_t Size;360    if (!SPSArgList<uint64_t>::deserialize(IB, Size))361      return false;362    TBSD::reserve(S, Size);363    for (size_t I = 0; I != Size; ++I) {364      typename TBSD::element_type E;365      if (!SPSArgList<SPSElementTagT>::deserialize(IB, E))366        return false;367      if (!TBSD::append(S, std::move(E)))368        return false;369    }370    return true;371  }372};373 374/// Trivial serialization / deserialization for span<char>375template <> class SPSSerializationTraits<SPSSequence<char>, span<const char>> {376public:377  static size_t size(const span<const char> &S) {378    return SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size())) +379           S.size();380  }381  static bool serialize(SPSOutputBuffer &OB, const span<const char> &S) {382    if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))383      return false;384    return OB.write(S.data(), S.size());385  }386  static bool deserialize(SPSInputBuffer &IB, span<const char> &S) {387    uint64_t Size;388    if (!SPSArgList<uint64_t>::deserialize(IB, Size))389      return false;390    S = span<const char>(IB.data(), Size);391    return IB.skip(Size);392  }393};394 395/// SPSTuple serialization for std::tuple.396template <typename... SPSTagTs, typename... Ts>397class SPSSerializationTraits<SPSTuple<SPSTagTs...>, std::tuple<Ts...>> {398private:399  using TupleArgList = typename SPSTuple<SPSTagTs...>::AsArgList;400  using ArgIndices = std::make_index_sequence<sizeof...(Ts)>;401 402  template <std::size_t... I>403  static size_t size(const std::tuple<Ts...> &T, std::index_sequence<I...>) {404    return TupleArgList::size(std::get<I>(T)...);405  }406 407  template <std::size_t... I>408  static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T,409                        std::index_sequence<I...>) {410    return TupleArgList::serialize(OB, std::get<I>(T)...);411  }412 413  template <std::size_t... I>414  static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T,415                          std::index_sequence<I...>) {416    return TupleArgList::deserialize(IB, std::get<I>(T)...);417  }418 419public:420  static size_t size(const std::tuple<Ts...> &T) {421    return size(T, ArgIndices{});422  }423 424  static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T) {425    return serialize(OB, T, ArgIndices{});426  }427 428  static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T) {429    return deserialize(IB, T, ArgIndices{});430  }431};432 433/// SPSTuple serialization for std::pair.434template <typename SPSTagT1, typename SPSTagT2, typename T1, typename T2>435class SPSSerializationTraits<SPSTuple<SPSTagT1, SPSTagT2>, std::pair<T1, T2>> {436public:437  static size_t size(const std::pair<T1, T2> &P) {438    return SPSArgList<SPSTagT1>::size(P.first) +439           SPSArgList<SPSTagT2>::size(P.second);440  }441 442  static bool serialize(SPSOutputBuffer &OB, const std::pair<T1, T2> &P) {443    return SPSArgList<SPSTagT1>::serialize(OB, P.first) &&444           SPSArgList<SPSTagT2>::serialize(OB, P.second);445  }446 447  static bool deserialize(SPSInputBuffer &IB, std::pair<T1, T2> &P) {448    return SPSArgList<SPSTagT1>::deserialize(IB, P.first) &&449           SPSArgList<SPSTagT2>::deserialize(IB, P.second);450  }451};452 453/// SPSOptional serialization for std::optional.454template <typename SPSTagT, typename T>455class SPSSerializationTraits<SPSOptional<SPSTagT>, std::optional<T>> {456public:457  static size_t size(const std::optional<T> &Value) {458    size_t Size = SPSArgList<bool>::size(!!Value);459    if (Value)460      Size += SPSArgList<SPSTagT>::size(*Value);461    return Size;462  }463 464  static bool serialize(SPSOutputBuffer &OB, const std::optional<T> &Value) {465    if (!SPSArgList<bool>::serialize(OB, !!Value))466      return false;467    if (Value)468      return SPSArgList<SPSTagT>::serialize(OB, *Value);469    return true;470  }471 472  static bool deserialize(SPSInputBuffer &IB, std::optional<T> &Value) {473    bool HasValue;474    if (!SPSArgList<bool>::deserialize(IB, HasValue))475      return false;476    if (HasValue) {477      Value = T();478      return SPSArgList<SPSTagT>::deserialize(IB, *Value);479    } else480      Value = std::optional<T>();481    return true;482  }483};484 485/// Serialization for string_views.486///487/// Serialization is as for regular strings. Deserialization points directly488/// into the blob.489template <> class SPSSerializationTraits<SPSString, std::string_view> {490public:491  static size_t size(const std::string_view &S) {492    return SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size())) +493           S.size();494  }495 496  static bool serialize(SPSOutputBuffer &OB, const std::string_view &S) {497    if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))498      return false;499    return OB.write(S.data(), S.size());500  }501 502  static bool deserialize(SPSInputBuffer &IB, std::string_view &S) {503    const char *Data = nullptr;504    uint64_t Size;505    if (!SPSArgList<uint64_t>::deserialize(IB, Size))506      return false;507    if (Size > std::numeric_limits<size_t>::max())508      return false;509    Data = IB.data();510    if (!IB.skip(Size))511      return false;512    S = {Data, static_cast<size_t>(Size)};513    return true;514  }515};516 517/// SPS tag type for errors.518class SPSError;519 520/// SPS tag type for expecteds, which are either a T or a string representing521/// an error.522template <typename SPSTagT> class SPSExpected;523 524namespace detail {525 526/// Helper type for serializing Errors.527///528/// llvm::Errors are move-only, and not inspectable except by consuming them.529/// This makes them unsuitable for direct serialization via530/// SPSSerializationTraits, which needs to inspect values twice (once to531/// determine the amount of space to reserve, and then again to serialize).532///533/// The SPSSerializableError type is a helper that can be534/// constructed from an llvm::Error, but inspected more than once.535struct SPSSerializableError {536  bool HasError = false;537  std::string ErrMsg;538};539 540/// Helper type for serializing Expected<T>s.541///542/// See SPSSerializableError for more details.543///544// FIXME: Use std::variant for storage once we have c++17.545template <typename T> struct SPSSerializableExpected {546  bool HasValue = false;547  T Value{};548  std::string ErrMsg;549};550 551inline SPSSerializableError toSPSSerializable(Error Err) {552  if (Err)553    return {true, toString(std::move(Err))};554  return {false, {}};555}556 557inline Error fromSPSSerializable(SPSSerializableError BSE) {558  if (BSE.HasError)559    return make_error<StringError>(BSE.ErrMsg);560  return Error::success();561}562 563template <typename T>564SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {565  if (E)566    return {true, std::move(*E), {}};567  else568    return {false, {}, toString(E.takeError())};569}570 571template <typename T>572Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {573  if (BSE.HasValue)574    return std::move(BSE.Value);575  else576    return make_error<StringError>(BSE.ErrMsg);577}578 579} // namespace detail580 581/// Serialize to a SPSError from a detail::SPSSerializableError.582template <>583class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {584public:585  static size_t size(const detail::SPSSerializableError &BSE) {586    size_t Size = SPSArgList<bool>::size(BSE.HasError);587    if (BSE.HasError)588      Size += SPSArgList<SPSString>::size(BSE.ErrMsg);589    return Size;590  }591 592  static bool serialize(SPSOutputBuffer &OB,593                        const detail::SPSSerializableError &BSE) {594    if (!SPSArgList<bool>::serialize(OB, BSE.HasError))595      return false;596    if (BSE.HasError)597      if (!SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg))598        return false;599    return true;600  }601 602  static bool deserialize(SPSInputBuffer &IB,603                          detail::SPSSerializableError &BSE) {604    if (!SPSArgList<bool>::deserialize(IB, BSE.HasError))605      return false;606 607    if (!BSE.HasError)608      return true;609 610    return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);611  }612};613 614/// Serialize to a SPSExpected<SPSTagT> from a615/// detail::SPSSerializableExpected<T>.616template <typename SPSTagT, typename T>617class SPSSerializationTraits<SPSExpected<SPSTagT>,618                             detail::SPSSerializableExpected<T>> {619public:620  static size_t size(const detail::SPSSerializableExpected<T> &BSE) {621    size_t Size = SPSArgList<bool>::size(BSE.HasValue);622    if (BSE.HasValue)623      Size += SPSArgList<SPSTagT>::size(BSE.Value);624    else625      Size += SPSArgList<SPSString>::size(BSE.ErrMsg);626    return Size;627  }628 629  static bool serialize(SPSOutputBuffer &OB,630                        const detail::SPSSerializableExpected<T> &BSE) {631    if (!SPSArgList<bool>::serialize(OB, BSE.HasValue))632      return false;633 634    if (BSE.HasValue)635      return SPSArgList<SPSTagT>::serialize(OB, BSE.Value);636 637    return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);638  }639 640  static bool deserialize(SPSInputBuffer &IB,641                          detail::SPSSerializableExpected<T> &BSE) {642    if (!SPSArgList<bool>::deserialize(IB, BSE.HasValue))643      return false;644 645    if (BSE.HasValue)646      return SPSArgList<SPSTagT>::deserialize(IB, BSE.Value);647 648    return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);649  }650};651 652/// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.653template <typename SPSTagT>654class SPSSerializationTraits<SPSExpected<SPSTagT>,655                             detail::SPSSerializableError> {656public:657  static size_t size(const detail::SPSSerializableError &BSE) {658    assert(BSE.HasError && "Cannot serialize expected from a success value");659    return SPSArgList<bool>::size(false) +660           SPSArgList<SPSString>::size(BSE.ErrMsg);661  }662 663  static bool serialize(SPSOutputBuffer &OB,664                        const detail::SPSSerializableError &BSE) {665    assert(BSE.HasError && "Cannot serialize expected from a success value");666    if (!SPSArgList<bool>::serialize(OB, false))667      return false;668    return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);669  }670};671 672/// Serialize to a SPSExpected<SPSTagT> from a T.673template <typename SPSTagT, typename T>674class SPSSerializationTraits<SPSExpected<SPSTagT>, T> {675public:676  static size_t size(const T &Value) {677    return SPSArgList<bool>::size(true) + SPSArgList<SPSTagT>::size(Value);678  }679 680  static bool serialize(SPSOutputBuffer &OB, const T &Value) {681    if (!SPSArgList<bool>::serialize(OB, true))682      return false;683    return SPSArgList<SPSTagT>::serialize(Value);684  }685};686 687} // namespace orc_rt688 689#endif // ORC_RT_SIMPLE_PACKED_SERIALIZATION_H690