Mercurial > hg > sv-dependency-builds
comparison win64-msvc/include/capnp/arena.h @ 148:b4bfdf10c4b3
Update Win64 capnp builds to v0.6
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Mon, 22 May 2017 18:56:49 +0100 |
parents | 42a73082be24 |
children |
comparison
equal
deleted
inserted
replaced
147:45360b968bf4 | 148:b4bfdf10c4b3 |
---|---|
32 | 32 |
33 #include <kj/common.h> | 33 #include <kj/common.h> |
34 #include <kj/mutex.h> | 34 #include <kj/mutex.h> |
35 #include <kj/exception.h> | 35 #include <kj/exception.h> |
36 #include <kj/vector.h> | 36 #include <kj/vector.h> |
37 #include <kj/units.h> | |
37 #include "common.h" | 38 #include "common.h" |
38 #include "message.h" | 39 #include "message.h" |
39 #include "layout.h" | 40 #include "layout.h" |
40 #include <unordered_map> | 41 #include <unordered_map> |
41 | 42 |
83 inline explicit ReadLimiter(); // No limit. | 84 inline explicit ReadLimiter(); // No limit. |
84 inline explicit ReadLimiter(WordCount64 limit); // Limit to the given number of words. | 85 inline explicit ReadLimiter(WordCount64 limit); // Limit to the given number of words. |
85 | 86 |
86 inline void reset(WordCount64 limit); | 87 inline void reset(WordCount64 limit); |
87 | 88 |
88 KJ_ALWAYS_INLINE(bool canRead(WordCount amount, Arena* arena)); | 89 KJ_ALWAYS_INLINE(bool canRead(WordCount64 amount, Arena* arena)); |
89 | 90 |
90 void unread(WordCount64 amount); | 91 void unread(WordCount64 amount); |
91 // Adds back some words to the limit. Useful when the caller knows they are double-reading | 92 // Adds back some words to the limit. Useful when the caller knows they are double-reading |
92 // some data. | 93 // some data. |
93 | 94 |
111 }; | 112 }; |
112 #endif // !CAPNP_LITE | 113 #endif // !CAPNP_LITE |
113 | 114 |
114 class SegmentReader { | 115 class SegmentReader { |
115 public: | 116 public: |
116 inline SegmentReader(Arena* arena, SegmentId id, kj::ArrayPtr<const word> ptr, | 117 inline SegmentReader(Arena* arena, SegmentId id, const word* ptr, SegmentWordCount size, |
117 ReadLimiter* readLimiter); | 118 ReadLimiter* readLimiter); |
118 | 119 |
119 KJ_ALWAYS_INLINE(bool containsInterval(const void* from, const void* to)); | 120 KJ_ALWAYS_INLINE(const word* checkOffset(const word* from, ptrdiff_t offset)); |
121 // Adds the given offset to the given pointer, checks that it is still within the bounds of the | |
122 // segment, then returns it. Note that the "end" pointer of the segment (which technically points | |
123 // to the word after the last in the segment) is considered in-bounds for this purpose, so you | |
124 // can't necessarily dereference it. You must call checkObject() next to check that the object | |
125 // you want to read is entirely in-bounds. | |
126 // | |
127 // If `from + offset` is out-of-range, this returns a pointer to the end of the segment. Thus, | |
128 // any non-zero-sized object will fail `checkObject()`. We do this instead of throwing to save | |
129 // some code footprint. | |
130 | |
131 KJ_ALWAYS_INLINE(bool checkObject(const word* start, WordCountN<31> size)); | |
132 // Assuming that `start` is in-bounds for this segment (probably checked using `checkOffset()`), | |
133 // check that `start + size` is also in-bounds, and hence the whole area in-between is valid. | |
120 | 134 |
121 KJ_ALWAYS_INLINE(bool amplifiedRead(WordCount virtualAmount)); | 135 KJ_ALWAYS_INLINE(bool amplifiedRead(WordCount virtualAmount)); |
122 // Indicates that the reader should pretend that `virtualAmount` additional data was read even | 136 // Indicates that the reader should pretend that `virtualAmount` additional data was read even |
123 // though no actual pointer was traversed. This is used e.g. when reading a struct list pointer | 137 // though no actual pointer was traversed. This is used e.g. when reading a struct list pointer |
124 // where the element sizes are zero -- the sender could set the list size arbitrarily high and | 138 // where the element sizes are zero -- the sender could set the list size arbitrarily high and |
127 | 141 |
128 inline Arena* getArena(); | 142 inline Arena* getArena(); |
129 inline SegmentId getSegmentId(); | 143 inline SegmentId getSegmentId(); |
130 | 144 |
131 inline const word* getStartPtr(); | 145 inline const word* getStartPtr(); |
132 inline WordCount getOffsetTo(const word* ptr); | 146 inline SegmentWordCount getOffsetTo(const word* ptr); |
133 inline WordCount getSize(); | 147 inline SegmentWordCount getSize(); |
134 | 148 |
135 inline kj::ArrayPtr<const word> getArray(); | 149 inline kj::ArrayPtr<const word> getArray(); |
136 | 150 |
137 inline void unread(WordCount64 amount); | 151 inline void unread(WordCount64 amount); |
138 // Add back some words to the ReadLimiter. | 152 // Add back some words to the ReadLimiter. |
139 | 153 |
140 private: | 154 private: |
141 Arena* arena; | 155 Arena* arena; |
142 SegmentId id; | 156 SegmentId id; |
143 kj::ArrayPtr<const word> ptr; | 157 kj::ArrayPtr<const word> ptr; // size guaranteed to fit in SEGMENT_WORD_COUNT_BITS bits |
144 ReadLimiter* readLimiter; | 158 ReadLimiter* readLimiter; |
145 | 159 |
146 KJ_DISALLOW_COPY(SegmentReader); | 160 KJ_DISALLOW_COPY(SegmentReader); |
147 | 161 |
148 friend class SegmentBuilder; | 162 friend class SegmentBuilder; |
163 | |
164 static void abortCheckObjectFault(); | |
165 // Called in debug mode in cases that would segfault in opt mode. (Should be impossible!) | |
149 }; | 166 }; |
150 | 167 |
151 class SegmentBuilder: public SegmentReader { | 168 class SegmentBuilder: public SegmentReader { |
152 public: | 169 public: |
153 inline SegmentBuilder(BuilderArena* arena, SegmentId id, kj::ArrayPtr<word> ptr, | 170 inline SegmentBuilder(BuilderArena* arena, SegmentId id, word* ptr, SegmentWordCount size, |
154 ReadLimiter* readLimiter, size_t wordsUsed = 0); | 171 ReadLimiter* readLimiter, SegmentWordCount wordsUsed = ZERO * WORDS); |
155 inline SegmentBuilder(BuilderArena* arena, SegmentId id, kj::ArrayPtr<const word> ptr, | 172 inline SegmentBuilder(BuilderArena* arena, SegmentId id, const word* ptr, SegmentWordCount size, |
156 ReadLimiter* readLimiter); | 173 ReadLimiter* readLimiter); |
157 inline SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr), | 174 inline SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr), |
158 ReadLimiter* readLimiter); | 175 ReadLimiter* readLimiter); |
159 | 176 |
160 KJ_ALWAYS_INLINE(word* allocate(WordCount amount)); | 177 KJ_ALWAYS_INLINE(word* allocate(SegmentWordCount amount)); |
161 | 178 |
162 KJ_ALWAYS_INLINE(void checkWritable()); | 179 KJ_ALWAYS_INLINE(void checkWritable()); |
163 // Throw an exception if the segment is read-only (meaning it is a reference to external data). | 180 // Throw an exception if the segment is read-only (meaning it is a reference to external data). |
164 | 181 |
165 KJ_ALWAYS_INLINE(word* getPtrUnchecked(WordCount offset)); | 182 KJ_ALWAYS_INLINE(word* getPtrUnchecked(SegmentWordCount offset)); |
166 // Get a writable pointer into the segment. Throws an exception if the segment is read-only (i.e. | 183 // Get a writable pointer into the segment. Throws an exception if the segment is read-only (i.e. |
167 // a reference to external immutable data). | 184 // a reference to external immutable data). |
168 | 185 |
169 inline BuilderArena* getArena(); | 186 inline BuilderArena* getArena(); |
170 | 187 |
208 // will need to continue with default values. | 225 // will need to continue with default values. |
209 }; | 226 }; |
210 | 227 |
211 class ReaderArena final: public Arena { | 228 class ReaderArena final: public Arena { |
212 public: | 229 public: |
213 ReaderArena(MessageReader* message); | 230 explicit ReaderArena(MessageReader* message); |
214 ~ReaderArena() noexcept(false); | 231 ~ReaderArena() noexcept(false); |
215 KJ_DISALLOW_COPY(ReaderArena); | 232 KJ_DISALLOW_COPY(ReaderArena); |
216 | 233 |
217 // implements Arena ------------------------------------------------ | 234 // implements Arena ------------------------------------------------ |
218 SegmentReader* tryGetSegment(SegmentId id) override; | 235 SegmentReader* tryGetSegment(SegmentId id) override; |
232 // this only applies to large messages. | 249 // this only applies to large messages. |
233 // | 250 // |
234 // TODO(perf): Thread-local thing instead? Some kind of lockless map? Or do sharing of data | 251 // TODO(perf): Thread-local thing instead? Some kind of lockless map? Or do sharing of data |
235 // in a different way, where you have to construct a new MessageReader in each thread (but | 252 // in a different way, where you have to construct a new MessageReader in each thread (but |
236 // possibly backed by the same data)? | 253 // possibly backed by the same data)? |
254 | |
255 ReaderArena(MessageReader* message, kj::ArrayPtr<const word> firstSegment); | |
256 ReaderArena(MessageReader* message, const word* firstSegment, SegmentWordCount firstSegmentSize); | |
237 }; | 257 }; |
238 | 258 |
239 class BuilderArena final: public Arena { | 259 class BuilderArena final: public Arena { |
240 // A BuilderArena that does not allow the injection of capabilities. | 260 // A BuilderArena that does not allow the injection of capabilities. |
241 | 261 |
275 struct AllocateResult { | 295 struct AllocateResult { |
276 SegmentBuilder* segment; | 296 SegmentBuilder* segment; |
277 word* words; | 297 word* words; |
278 }; | 298 }; |
279 | 299 |
280 AllocateResult allocate(WordCount amount); | 300 AllocateResult allocate(SegmentWordCount amount); |
281 // Find a segment with at least the given amount of space available and allocate the space. | 301 // Find a segment with at least the given amount of space available and allocate the space. |
282 // Note that allocating directly from a particular segment is much faster, but allocating from | 302 // Note that allocating directly from a particular segment is much faster, but allocating from |
283 // the arena is guaranteed to succeed. Therefore callers should try to allocate from a specific | 303 // the arena is guaranteed to succeed. Therefore callers should try to allocate from a specific |
284 // segment first if there is one, then fall back to the arena. | 304 // segment first if there is one, then fall back to the arena. |
285 | 305 |
337 // ======================================================================================= | 357 // ======================================================================================= |
338 | 358 |
339 inline ReadLimiter::ReadLimiter() | 359 inline ReadLimiter::ReadLimiter() |
340 : limit(kj::maxValue) {} | 360 : limit(kj::maxValue) {} |
341 | 361 |
342 inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(limit / WORDS) {} | 362 inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(unbound(limit / WORDS)) {} |
343 | 363 |
344 inline void ReadLimiter::reset(WordCount64 limit) { this->limit = limit / WORDS; } | 364 inline void ReadLimiter::reset(WordCount64 limit) { this->limit = unbound(limit / WORDS); } |
345 | 365 |
346 inline bool ReadLimiter::canRead(WordCount amount, Arena* arena) { | 366 inline bool ReadLimiter::canRead(WordCount64 amount, Arena* arena) { |
347 // Be careful not to store an underflowed value into `limit`, even if multiple threads are | 367 // Be careful not to store an underflowed value into `limit`, even if multiple threads are |
348 // decrementing it. | 368 // decrementing it. |
349 uint64_t current = limit; | 369 uint64_t current = limit; |
350 if (KJ_UNLIKELY(amount / WORDS > current)) { | 370 if (KJ_UNLIKELY(unbound(amount / WORDS) > current)) { |
351 arena->reportReadLimitReached(); | 371 arena->reportReadLimitReached(); |
352 return false; | 372 return false; |
353 } else { | 373 } else { |
354 limit = current - amount / WORDS; | 374 limit = current - unbound(amount / WORDS); |
355 return true; | 375 return true; |
356 } | 376 } |
357 } | 377 } |
358 | 378 |
359 // ------------------------------------------------------------------- | 379 // ------------------------------------------------------------------- |
360 | 380 |
361 inline SegmentReader::SegmentReader(Arena* arena, SegmentId id, kj::ArrayPtr<const word> ptr, | 381 inline SegmentReader::SegmentReader(Arena* arena, SegmentId id, const word* ptr, |
362 ReadLimiter* readLimiter) | 382 SegmentWordCount size, ReadLimiter* readLimiter) |
363 : arena(arena), id(id), ptr(ptr), readLimiter(readLimiter) {} | 383 : arena(arena), id(id), ptr(kj::arrayPtr(ptr, unbound(size / WORDS))), |
364 | 384 readLimiter(readLimiter) {} |
365 inline bool SegmentReader::containsInterval(const void* from, const void* to) { | 385 |
366 return from >= this->ptr.begin() && to <= this->ptr.end() && from <= to && | 386 inline const word* SegmentReader::checkOffset(const word* from, ptrdiff_t offset) { |
367 readLimiter->canRead( | 387 ptrdiff_t min = ptr.begin() - from; |
368 intervalLength(reinterpret_cast<const byte*>(from), | 388 ptrdiff_t max = ptr.end() - from; |
369 reinterpret_cast<const byte*>(to)) / BYTES_PER_WORD, | 389 if (offset >= min && offset <= max) { |
370 arena); | 390 return from + offset; |
391 } else { | |
392 return ptr.end(); | |
393 } | |
394 } | |
395 | |
396 inline bool SegmentReader::checkObject(const word* start, WordCountN<31> size) { | |
397 auto startOffset = intervalLength(ptr.begin(), start, MAX_SEGMENT_WORDS); | |
398 #ifdef KJ_DEBUG | |
399 if (startOffset > bounded(ptr.size()) * WORDS) { | |
400 abortCheckObjectFault(); | |
401 } | |
402 #endif | |
403 return startOffset + size <= bounded(ptr.size()) * WORDS && | |
404 readLimiter->canRead(size, arena); | |
371 } | 405 } |
372 | 406 |
373 inline bool SegmentReader::amplifiedRead(WordCount virtualAmount) { | 407 inline bool SegmentReader::amplifiedRead(WordCount virtualAmount) { |
374 return readLimiter->canRead(virtualAmount, arena); | 408 return readLimiter->canRead(virtualAmount, arena); |
375 } | 409 } |
376 | 410 |
377 inline Arena* SegmentReader::getArena() { return arena; } | 411 inline Arena* SegmentReader::getArena() { return arena; } |
378 inline SegmentId SegmentReader::getSegmentId() { return id; } | 412 inline SegmentId SegmentReader::getSegmentId() { return id; } |
379 inline const word* SegmentReader::getStartPtr() { return ptr.begin(); } | 413 inline const word* SegmentReader::getStartPtr() { return ptr.begin(); } |
380 inline WordCount SegmentReader::getOffsetTo(const word* ptr) { | 414 inline SegmentWordCount SegmentReader::getOffsetTo(const word* ptr) { |
381 return intervalLength(this->ptr.begin(), ptr); | 415 KJ_IREQUIRE(this->ptr.begin() <= ptr && ptr <= this->ptr.end()); |
382 } | 416 return intervalLength(this->ptr.begin(), ptr, MAX_SEGMENT_WORDS); |
383 inline WordCount SegmentReader::getSize() { return ptr.size() * WORDS; } | 417 } |
418 inline SegmentWordCount SegmentReader::getSize() { | |
419 return assumeBits<SEGMENT_WORD_COUNT_BITS>(ptr.size()) * WORDS; | |
420 } | |
384 inline kj::ArrayPtr<const word> SegmentReader::getArray() { return ptr; } | 421 inline kj::ArrayPtr<const word> SegmentReader::getArray() { return ptr; } |
385 inline void SegmentReader::unread(WordCount64 amount) { readLimiter->unread(amount); } | 422 inline void SegmentReader::unread(WordCount64 amount) { readLimiter->unread(amount); } |
386 | 423 |
387 // ------------------------------------------------------------------- | 424 // ------------------------------------------------------------------- |
388 | 425 |
389 inline SegmentBuilder::SegmentBuilder( | 426 inline SegmentBuilder::SegmentBuilder( |
390 BuilderArena* arena, SegmentId id, kj::ArrayPtr<word> ptr, ReadLimiter* readLimiter, | 427 BuilderArena* arena, SegmentId id, word* ptr, SegmentWordCount size, |
391 size_t wordsUsed) | 428 ReadLimiter* readLimiter, SegmentWordCount wordsUsed) |
392 : SegmentReader(arena, id, ptr, readLimiter), pos(ptr.begin() + wordsUsed), readOnly(false) {} | 429 : SegmentReader(arena, id, ptr, size, readLimiter), |
430 pos(ptr + wordsUsed), readOnly(false) {} | |
393 inline SegmentBuilder::SegmentBuilder( | 431 inline SegmentBuilder::SegmentBuilder( |
394 BuilderArena* arena, SegmentId id, kj::ArrayPtr<const word> ptr, ReadLimiter* readLimiter) | 432 BuilderArena* arena, SegmentId id, const word* ptr, SegmentWordCount size, |
395 : SegmentReader(arena, id, ptr, readLimiter), | 433 ReadLimiter* readLimiter) |
434 : SegmentReader(arena, id, ptr, size, readLimiter), | |
396 // const_cast is safe here because the member won't ever be dereferenced because it appears | 435 // const_cast is safe here because the member won't ever be dereferenced because it appears |
397 // to point to the end of the segment anyway. | 436 // to point to the end of the segment anyway. |
398 pos(const_cast<word*>(ptr.end())), | 437 pos(const_cast<word*>(ptr + size)), readOnly(true) {} |
399 readOnly(true) {} | |
400 inline SegmentBuilder::SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr), | 438 inline SegmentBuilder::SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr), |
401 ReadLimiter* readLimiter) | 439 ReadLimiter* readLimiter) |
402 : SegmentReader(arena, id, nullptr, readLimiter), pos(nullptr), readOnly(false) {} | 440 : SegmentReader(arena, id, nullptr, ZERO * WORDS, readLimiter), |
403 | 441 pos(nullptr), readOnly(false) {} |
404 inline word* SegmentBuilder::allocate(WordCount amount) { | 442 |
405 if (intervalLength(pos, ptr.end()) < amount) { | 443 inline word* SegmentBuilder::allocate(SegmentWordCount amount) { |
444 if (intervalLength(pos, ptr.end(), MAX_SEGMENT_WORDS) < amount) { | |
406 // Not enough space in the segment for this allocation. | 445 // Not enough space in the segment for this allocation. |
407 return nullptr; | 446 return nullptr; |
408 } else { | 447 } else { |
409 // Success. | 448 // Success. |
410 word* result = pos; | 449 word* result = pos; |
415 | 454 |
416 inline void SegmentBuilder::checkWritable() { | 455 inline void SegmentBuilder::checkWritable() { |
417 if (KJ_UNLIKELY(readOnly)) throwNotWritable(); | 456 if (KJ_UNLIKELY(readOnly)) throwNotWritable(); |
418 } | 457 } |
419 | 458 |
420 inline word* SegmentBuilder::getPtrUnchecked(WordCount offset) { | 459 inline word* SegmentBuilder::getPtrUnchecked(SegmentWordCount offset) { |
421 return const_cast<word*>(ptr.begin() + offset); | 460 return const_cast<word*>(ptr.begin() + offset); |
422 } | 461 } |
423 | 462 |
424 inline BuilderArena* SegmentBuilder::getArena() { | 463 inline BuilderArena* SegmentBuilder::getArena() { |
425 // Down-cast safe because SegmentBuilder's constructor always initializes its SegmentReader base | 464 // Down-cast safe because SegmentBuilder's constructor always initializes its SegmentReader base |
430 inline kj::ArrayPtr<const word> SegmentBuilder::currentlyAllocated() { | 469 inline kj::ArrayPtr<const word> SegmentBuilder::currentlyAllocated() { |
431 return kj::arrayPtr(ptr.begin(), pos - ptr.begin()); | 470 return kj::arrayPtr(ptr.begin(), pos - ptr.begin()); |
432 } | 471 } |
433 | 472 |
434 inline void SegmentBuilder::reset() { | 473 inline void SegmentBuilder::reset() { |
435 word* start = getPtrUnchecked(0 * WORDS); | 474 word* start = getPtrUnchecked(ZERO * WORDS); |
436 memset(start, 0, (pos - start) * sizeof(word)); | 475 memset(start, 0, (pos - start) * sizeof(word)); |
437 pos = start; | 476 pos = start; |
438 } | 477 } |
439 | 478 |
440 inline void SegmentBuilder::tryTruncate(word* from, word* to) { | 479 inline void SegmentBuilder::tryTruncate(word* from, word* to) { |