pstore2
compilation.hpp
1 //===- include/pstore/mcrepo/compilation.hpp --------------*- mode: C++ -*-===//
2 //* _ _ _ _ *
3 //* ___ ___ _ __ ___ _ __ (_) | __ _| |_(_) ___ _ __ *
4 //* / __/ _ \| '_ ` _ \| '_ \| | |/ _` | __| |/ _ \| '_ \ *
5 //* | (_| (_) | | | | | | |_) | | | (_| | |_| | (_) | | | | *
6 //* \___\___/|_| |_| |_| .__/|_|_|\__,_|\__|_|\___/|_| |_| *
7 //* |_| *
8 //===----------------------------------------------------------------------===//
9 //
10 // Part of the pstore project, under the Apache License v2.0 with LLVM Exceptions.
11 // See https://github.com/SNSystems/pstore/blob/master/LICENSE.txt for license
12 // information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //===----------------------------------------------------------------------===//
16 #ifndef PSTORE_MCREPO_COMPILATION_HPP
17 #define PSTORE_MCREPO_COMPILATION_HPP
18 
19 #include <new>
20 
21 #include "pstore/core/index_types.hpp"
23 #include "pstore/mcrepo/repo_error.hpp"
26 
27 namespace pstore {
28  namespace repo {
29 
30 #define PSTORE_REPO_LINKAGES \
31  X (append) \
32  X (common) \
33  X (external) \
34  X (internal_no_symbol) \
35  X (internal) \
36  X (link_once_any) \
37  X (link_once_odr) \
38  X (weak_any) \
39  X (weak_odr)
40 
41 #define X(a) a,
42  enum class linkage : std::uint8_t { PSTORE_REPO_LINKAGES };
43 #undef X
44 
45  std::ostream & operator<< (std::ostream & os, linkage l);
46 
47 #define PSTORE_REPO_VISIBILITIES \
48  X (default_vis) \
49  X (hidden_vis) \
50  X (protected_vis)
51 
52 #define X(a) a,
53  enum class visibility : std::uint8_t { PSTORE_REPO_VISIBILITIES };
54 #undef X
55 
56  //* _ __ _ _ _ _ *
57  //* __| |___ / _(_)_ _ (_) |_(_)___ _ _ *
58  //* / _` / -_) _| | ' \| | _| / _ \ ' \ *
59  //* \__,_\___|_| |_|_||_|_|\__|_\___/_||_| *
60  //* *
65  struct definition {
72  linkage l, visibility v = repo::visibility::default_vis) noexcept;
77  // TODO: it looks tempting to use some of the bits of this address for the
78  // linkage/visibility fields. We know that they're not all used and it would eliminate
79  // all of the padding bits from the structure. Unfortunately, repo-object-writer is
80  // currently stashing host pointers in this field and although the same may be true for
81  // those, it's difficult to be certain.
83  union {
84  std::uint8_t bf = UINT8_C (0);
87  };
88  std::uint8_t padding1 = 0;
89  std::uint16_t padding2 = 0;
90  std::uint32_t padding3 = 0;
91 
92  auto linkage () const noexcept -> enum linkage {
93  return static_cast<enum linkage> (linkage_.value ());
94  }
95  auto visibility () const noexcept -> enum visibility {
96  return static_cast<enum visibility> (visibility_.value ());
97  }
98 
104  static auto load (database const & db, typed_address<definition> addr)
105  -> std::shared_ptr<definition const>;
106 
107  private:
108  friend class compilation;
109  // TODO: using "=default" here causes clang-8 to issue an error:
110  // "default member initializer for 'padding1' needed within definition of enclosing
111  // class 'definition' outside of member functions"
112  definition () noexcept {}
113  };
114  // load
115  // ~~~~
116  inline auto definition::load (database const & db, typed_address<definition> const addr)
117  -> std::shared_ptr<definition const> {
118  return db.getro (addr);
119  }
120 
121  //* _ _ _ _ *
122  //* __ ___ _ __ _ __(_) |__ _| |_(_)___ _ _ *
123  //* / _/ _ \ ' \| '_ \ | / _` | _| / _ \ ' \ *
124  //* \__\___/_|_|_| .__/_|_\__,_|\__|_\___/_||_| *
125  //* |_| *
128  class compilation {
129  public:
130  using iterator = definition *;
131  using const_iterator = definition const *;
132  using size_type = std::uint32_t;
133 
134  void operator delete (void * p);
135 
138 
150  template <typename TransactionType, typename Iterator>
151  static extent<compilation> alloc (TransactionType & transaction,
153  Iterator first_member, Iterator last_member);
154 
160  static std::shared_ptr<compilation const> load (database const & db,
161  extent<compilation> const & location);
163 
166  definition const & operator[] (std::size_t const i) const {
167  PSTORE_ASSERT (i < size_);
168  return members_[i];
169  }
171 
174  iterator begin () { return members_; }
175  const_iterator begin () const { return members_; }
176  const_iterator cbegin () const { return this->begin (); }
177 
178  iterator end () { return members_ + size_; }
179  const_iterator end () const { return members_ + size_; }
180  const_iterator cend () const { return this->end (); }
182 
185 
187  bool empty () const noexcept { return size_ == 0; }
189  size_type size () const noexcept { return size_; }
191 
194 
197  static std::size_t size_bytes (size_type size) noexcept {
198  size = std::max (size, size_type{1}); // Always at least enough for one member.
199  return sizeof (compilation) - sizeof (compilation::members_) +
200  sizeof (compilation::members_[0]) * size;
201  }
202 
204  std::size_t size_bytes () const noexcept {
205  return compilation::size_bytes (this->size ());
206  }
208 
210  typed_address<indirect_string> triple () const noexcept { return triple_; }
211 
217  static constexpr typed_address<definition>
218  index_address (typed_address<compilation> const c, size_type const index) noexcept {
219  return typed_address<definition>::make (c.to_address () +
220  offsetof (compilation, members_) +
221  sizeof (definition) * index);
222  }
223 
224  private:
225  template <typename Iterator>
226  compilation (typed_address<indirect_string> triple, size_type size,
227  Iterator first_member, Iterator last_member) noexcept;
228 
229  struct nmembers {
230  size_type n;
231  };
234  void * operator new (std::size_t s, nmembers size);
236  void * operator new (std::size_t s, void * ptr);
237  void operator delete (void * p, nmembers size);
238  void operator delete (void * p, void * ptr);
239 
240  static constexpr std::array<char, 8> compilation_signature_ = {
241  {'C', 'm', 'p', 'l', '8', 'i', 'o', 'n'}};
242 
243  std::array<char, 8> signature_ = compilation_signature_;
247  size_type size_ = 0;
248  std::uint32_t padding1_ = 0;
249 
250  definition members_[1];
251  };
252  PSTORE_STATIC_ASSERT (std::is_standard_layout<compilation>::value);
253  PSTORE_STATIC_ASSERT (sizeof (compilation) == 32 + sizeof (definition));
254  PSTORE_STATIC_ASSERT (alignof (compilation) == 16);
255 
256  template <typename Iterator>
257  compilation::compilation (typed_address<indirect_string> const triple, size_type const size,
258  Iterator const first_member, Iterator const last_member) noexcept
259  : triple_{triple}
260  , size_{size} {
261  // Assignment to suppress a warning from clang that the field is not used.
262  padding1_ = 0;
263  PSTORE_STATIC_ASSERT (offsetof (compilation, signature_) == 0);
264  PSTORE_STATIC_ASSERT (offsetof (compilation, triple_) == 8);
265  PSTORE_STATIC_ASSERT (offsetof (compilation, size_) == 16);
266  PSTORE_STATIC_ASSERT (offsetof (compilation, padding1_) == 20);
267  PSTORE_STATIC_ASSERT (offsetof (compilation, members_) == 32);
268 
269  // This check can safely be an assertion because the method is private and alloc(),
270  // the sole caller, performs a full run-time check of the size.
271  PSTORE_ASSERT (unsigned_cast (std::distance (first_member, last_member)) == size);
272 
273  std::copy (first_member, last_member, this->begin ());
274  }
275 
276  // alloc
277  // ~~~~~
278  template <typename TransactionType, typename Iterator>
279  auto compilation::alloc (TransactionType & transaction,
280  typed_address<indirect_string> triple, Iterator first_member,
281  Iterator last_member) -> extent<compilation> {
282  // First work out its size.
283  auto const dist = std::distance (first_member, last_member);
284  PSTORE_ASSERT (dist >= 0);
285 
286  if (dist > std::numeric_limits<size_type>::max ()) {
287  raise (error_code::too_many_members_in_compilation);
288  }
289 
290  auto const num_members = static_cast<size_type> (dist);
291  auto const size = size_bytes (num_members);
292 
293  // Allocate the storage.
294  auto const addr = transaction.allocate (size, alignof (compilation));
295  auto ptr = std::static_pointer_cast<compilation> (transaction.getrw (addr, size));
296 
297  // Write the data to the store.
298  new (ptr.get ()) compilation{triple, num_members, first_member, last_member};
299  return extent<compilation> (typed_address<compilation> (addr), size);
300  }
301 
302  } // end namespace repo
303 } // end namespace pstore
304 
305 #endif // PSTORE_MCREPO_COMPILATION_HPP
Definition: uint128.hpp:85
A portable bit-field type.
size_type size() const noexcept
Returns the number of elements.
Definition: compilation.hpp:189
An extent is a contiguous area of storage reserved for a data BLOB, represented as a range...
Definition: address.hpp:441
std::size_t size_bytes() const noexcept
Definition: compilation.hpp:204
extent< fragment > fext
The extent of the fragment referenced by this compilation symbol.
Definition: compilation.hpp:76
static extent< compilation > alloc(TransactionType &transaction, typed_address< indirect_string > triple, Iterator first_member, Iterator last_member)
Allocates a new compilation in-store and copy the ticket file path and the contents of a vector of de...
typed_address< indirect_string > triple() const noexcept
Returns the target triple.
Definition: compilation.hpp:210
unsigned_cast() (and its runtime-checked version) allow for simple integral unsigned casts...
transaction< transaction_lock > begin(database &db, transaction_lock &lock)
Creates a new transaction. Every operation performed on a transaction instance can be potentially und...
Definition: transaction.hpp:311
static std::size_t size_bytes(size_type size) noexcept
Returns the number of bytes of storage required for a compilation with &#39;size&#39; members.
Definition: compilation.hpp:197
The data store transaction class.
Definition: transaction.hpp:191
Definition: address.hpp:231
static auto load(database const &db, typed_address< definition > addr) -> std::shared_ptr< definition const >
Returns a pointer to an in-store definition instance.
Definition: compilation.hpp:116
A compilation is a holder for zero or more definitions.
Definition: compilation.hpp:128
Definition: nonpod2.cpp:40
Definition: database.hpp:40
bool empty() const noexcept
Checks whether the container is empty.
Definition: compilation.hpp:187
static constexpr typed_address< definition > index_address(typed_address< compilation > const c, size_type const index) noexcept
Compute the address of the definition given by index within compilation c.
Definition: compilation.hpp:218
Represents an individual symbol in a compilation.
Definition: compilation.hpp:65
index::digest digest
The digest of the fragment referenced by this compilation symbol.
Definition: compilation.hpp:74