cannam@147
|
1 // Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
|
cannam@147
|
2 // Licensed under the MIT License:
|
cannam@147
|
3 //
|
cannam@147
|
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
cannam@147
|
5 // of this software and associated documentation files (the "Software"), to deal
|
cannam@147
|
6 // in the Software without restriction, including without limitation the rights
|
cannam@147
|
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
cannam@147
|
8 // copies of the Software, and to permit persons to whom the Software is
|
cannam@147
|
9 // furnished to do so, subject to the following conditions:
|
cannam@147
|
10 //
|
cannam@147
|
11 // The above copyright notice and this permission notice shall be included in
|
cannam@147
|
12 // all copies or substantial portions of the Software.
|
cannam@147
|
13 //
|
cannam@147
|
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
cannam@147
|
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
cannam@147
|
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
cannam@147
|
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
cannam@147
|
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
cannam@147
|
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
cannam@147
|
20 // THE SOFTWARE.
|
cannam@147
|
21
|
cannam@147
|
22 // This file is NOT intended for use by clients, except in generated code.
|
cannam@147
|
23 //
|
cannam@147
|
24 // This file defines low-level, non-type-safe classes for traversing the Cap'n Proto memory layout
|
cannam@147
|
25 // (which is also its wire format). Code generated by the Cap'n Proto compiler uses these classes,
|
cannam@147
|
26 // as does other parts of the Cap'n proto library which provide a higher-level interface for
|
cannam@147
|
27 // dynamic introspection.
|
cannam@147
|
28
|
cannam@147
|
29 #ifndef CAPNP_LAYOUT_H_
|
cannam@147
|
30 #define CAPNP_LAYOUT_H_
|
cannam@147
|
31
|
cannam@147
|
32 #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
|
cannam@147
|
33 #pragma GCC system_header
|
cannam@147
|
34 #endif
|
cannam@147
|
35
|
cannam@147
|
36 #include <kj/common.h>
|
cannam@147
|
37 #include <kj/memory.h>
|
cannam@147
|
38 #include "common.h"
|
cannam@147
|
39 #include "blob.h"
|
cannam@147
|
40 #include "endian.h"
|
cannam@147
|
41
|
cannam@147
|
42 #if (defined(__mips__) || defined(__hppa__)) && !defined(CAPNP_CANONICALIZE_NAN)
|
cannam@147
|
43 #define CAPNP_CANONICALIZE_NAN 1
|
cannam@147
|
44 // Explicitly detect NaNs and canonicalize them to the quiet NaN value as would be returned by
|
cannam@147
|
45 // __builtin_nan("") on systems implementing the IEEE-754 recommended (but not required) NaN
|
cannam@147
|
46 // signalling/quiet differentiation (such as x86). Unfortunately, some architectures -- in
|
cannam@147
|
47 // particular, MIPS -- represent quiet vs. signalling nans differently than the rest of the world.
|
cannam@147
|
48 // Canonicalizing them makes output consistent (which is important!), but hurts performance
|
cannam@147
|
49 // slightly.
|
cannam@147
|
50 //
|
cannam@147
|
51 // Note that trying to convert MIPS NaNs to standard NaNs without losing data doesn't work.
|
cannam@147
|
52 // Signaling vs. quiet is indicated by a bit, with the meaning being the opposite on MIPS vs.
|
cannam@147
|
53 // everyone else. It would be great if we could just flip that bit, but we can't, because if the
|
cannam@147
|
54 // significand is all-zero, then the value is infinity rather than NaN. This means that on most
|
cannam@147
|
55 // machines, where the bit indicates quietness, there is one more quiet NaN value than signalling
|
cannam@147
|
56 // NaN value, whereas on MIPS there is one more sNaN than qNaN, and thus there is no isomorphic
|
cannam@147
|
57 // mapping that properly preserves quietness. Instead of doing something hacky, we just give up
|
cannam@147
|
58 // and blow away NaN payloads, because no one uses them anyway.
|
cannam@147
|
59 #endif
|
cannam@147
|
60
|
cannam@147
|
61 namespace capnp {
|
cannam@147
|
62
|
cannam@147
|
63 #if !CAPNP_LITE
|
cannam@147
|
64 class ClientHook;
|
cannam@147
|
65 #endif // !CAPNP_LITE
|
cannam@147
|
66
|
cannam@147
|
67 namespace _ { // private
|
cannam@147
|
68
|
cannam@147
|
69 class PointerBuilder;
|
cannam@147
|
70 class PointerReader;
|
cannam@147
|
71 class StructBuilder;
|
cannam@147
|
72 class StructReader;
|
cannam@147
|
73 class ListBuilder;
|
cannam@147
|
74 class ListReader;
|
cannam@147
|
75 class OrphanBuilder;
|
cannam@147
|
76 struct WirePointer;
|
cannam@147
|
77 struct WireHelpers;
|
cannam@147
|
78 class SegmentReader;
|
cannam@147
|
79 class SegmentBuilder;
|
cannam@147
|
80 class Arena;
|
cannam@147
|
81 class BuilderArena;
|
cannam@147
|
82
|
cannam@147
|
83 // =============================================================================
|
cannam@147
|
84
|
cannam@147
|
85 #if CAPNP_DEBUG_TYPES
|
cannam@147
|
86 typedef kj::UnitRatio<kj::Bounded<64, uint>, BitLabel, ElementLabel> BitsPerElementTableType;
|
cannam@147
|
87 #else
|
cannam@147
|
88 typedef uint BitsPerElementTableType;
|
cannam@147
|
89 #endif
|
cannam@147
|
90
|
cannam@147
|
91 static constexpr BitsPerElementTableType BITS_PER_ELEMENT_TABLE[8] = {
|
cannam@147
|
92 bounded< 0>() * BITS / ELEMENTS,
|
cannam@147
|
93 bounded< 1>() * BITS / ELEMENTS,
|
cannam@147
|
94 bounded< 8>() * BITS / ELEMENTS,
|
cannam@147
|
95 bounded<16>() * BITS / ELEMENTS,
|
cannam@147
|
96 bounded<32>() * BITS / ELEMENTS,
|
cannam@147
|
97 bounded<64>() * BITS / ELEMENTS,
|
cannam@147
|
98 bounded< 0>() * BITS / ELEMENTS,
|
cannam@147
|
99 bounded< 0>() * BITS / ELEMENTS
|
cannam@147
|
100 };
|
cannam@147
|
101
|
cannam@147
|
102 inline KJ_CONSTEXPR() BitsPerElementTableType dataBitsPerElement(ElementSize size) {
|
cannam@147
|
103 return _::BITS_PER_ELEMENT_TABLE[static_cast<int>(size)];
|
cannam@147
|
104 }
|
cannam@147
|
105
|
cannam@147
|
106 inline constexpr PointersPerElementN<1> pointersPerElement(ElementSize size) {
|
cannam@147
|
107 return size == ElementSize::POINTER
|
cannam@147
|
108 ? PointersPerElementN<1>(ONE * POINTERS / ELEMENTS)
|
cannam@147
|
109 : PointersPerElementN<1>(ZERO * POINTERS / ELEMENTS);
|
cannam@147
|
110 }
|
cannam@147
|
111
|
cannam@147
|
112 static constexpr BitsPerElementTableType BITS_PER_ELEMENT_INCLUDING_PONITERS_TABLE[8] = {
|
cannam@147
|
113 bounded< 0>() * BITS / ELEMENTS,
|
cannam@147
|
114 bounded< 1>() * BITS / ELEMENTS,
|
cannam@147
|
115 bounded< 8>() * BITS / ELEMENTS,
|
cannam@147
|
116 bounded<16>() * BITS / ELEMENTS,
|
cannam@147
|
117 bounded<32>() * BITS / ELEMENTS,
|
cannam@147
|
118 bounded<64>() * BITS / ELEMENTS,
|
cannam@147
|
119 bounded<64>() * BITS / ELEMENTS,
|
cannam@147
|
120 bounded< 0>() * BITS / ELEMENTS
|
cannam@147
|
121 };
|
cannam@147
|
122
|
cannam@147
|
123 inline KJ_CONSTEXPR() BitsPerElementTableType bitsPerElementIncludingPointers(ElementSize size) {
|
cannam@147
|
124 return _::BITS_PER_ELEMENT_INCLUDING_PONITERS_TABLE[static_cast<int>(size)];
|
cannam@147
|
125 }
|
cannam@147
|
126
|
cannam@147
|
127 template <size_t size> struct ElementSizeForByteSize;
|
cannam@147
|
128 template <> struct ElementSizeForByteSize<1> { static constexpr ElementSize value = ElementSize::BYTE; };
|
cannam@147
|
129 template <> struct ElementSizeForByteSize<2> { static constexpr ElementSize value = ElementSize::TWO_BYTES; };
|
cannam@147
|
130 template <> struct ElementSizeForByteSize<4> { static constexpr ElementSize value = ElementSize::FOUR_BYTES; };
|
cannam@147
|
131 template <> struct ElementSizeForByteSize<8> { static constexpr ElementSize value = ElementSize::EIGHT_BYTES; };
|
cannam@147
|
132
|
cannam@147
|
133 template <typename T> struct ElementSizeForType {
|
cannam@147
|
134 static constexpr ElementSize value =
|
cannam@147
|
135 // Primitive types that aren't special-cased below can be determined from sizeof().
|
cannam@147
|
136 CAPNP_KIND(T) == Kind::PRIMITIVE ? ElementSizeForByteSize<sizeof(T)>::value :
|
cannam@147
|
137 CAPNP_KIND(T) == Kind::ENUM ? ElementSize::TWO_BYTES :
|
cannam@147
|
138 CAPNP_KIND(T) == Kind::STRUCT ? ElementSize::INLINE_COMPOSITE :
|
cannam@147
|
139
|
cannam@147
|
140 // Everything else is a pointer.
|
cannam@147
|
141 ElementSize::POINTER;
|
cannam@147
|
142 };
|
cannam@147
|
143
|
cannam@147
|
144 // Void and bool are special.
|
cannam@147
|
145 template <> struct ElementSizeForType<Void> { static constexpr ElementSize value = ElementSize::VOID; };
|
cannam@147
|
146 template <> struct ElementSizeForType<bool> { static constexpr ElementSize value = ElementSize::BIT; };
|
cannam@147
|
147
|
cannam@147
|
148 // Lists and blobs are pointers, not structs.
|
cannam@147
|
149 template <typename T, Kind K> struct ElementSizeForType<List<T, K>> {
|
cannam@147
|
150 static constexpr ElementSize value = ElementSize::POINTER;
|
cannam@147
|
151 };
|
cannam@147
|
152 template <> struct ElementSizeForType<Text> {
|
cannam@147
|
153 static constexpr ElementSize value = ElementSize::POINTER;
|
cannam@147
|
154 };
|
cannam@147
|
155 template <> struct ElementSizeForType<Data> {
|
cannam@147
|
156 static constexpr ElementSize value = ElementSize::POINTER;
|
cannam@147
|
157 };
|
cannam@147
|
158
|
cannam@147
|
159 template <typename T>
|
cannam@147
|
160 inline constexpr ElementSize elementSizeForType() {
|
cannam@147
|
161 return ElementSizeForType<T>::value;
|
cannam@147
|
162 }
|
cannam@147
|
163
|
cannam@147
|
164 struct MessageSizeCounts {
|
cannam@147
|
165 WordCountN<61, uint64_t> wordCount; // 2^64 bytes
|
cannam@147
|
166 uint capCount;
|
cannam@147
|
167
|
cannam@147
|
168 MessageSizeCounts& operator+=(const MessageSizeCounts& other) {
|
cannam@147
|
169 // OK to truncate unchecked because this class is used to count actual stuff in memory, and
|
cannam@147
|
170 // we couldn't possibly have anywhere near 2^61 words.
|
cannam@147
|
171 wordCount = assumeBits<61>(wordCount + other.wordCount);
|
cannam@147
|
172 capCount += other.capCount;
|
cannam@147
|
173 return *this;
|
cannam@147
|
174 }
|
cannam@147
|
175
|
cannam@147
|
176 void addWords(WordCountN<61, uint64_t> other) {
|
cannam@147
|
177 wordCount = assumeBits<61>(wordCount + other);
|
cannam@147
|
178 }
|
cannam@147
|
179
|
cannam@147
|
180 MessageSize asPublic() {
|
cannam@147
|
181 return MessageSize { unbound(wordCount / WORDS), capCount };
|
cannam@147
|
182 }
|
cannam@147
|
183 };
|
cannam@147
|
184
|
cannam@147
|
185 // =============================================================================
|
cannam@147
|
186
|
cannam@147
|
187 template <int wordCount>
|
cannam@147
|
188 union AlignedData {
|
cannam@147
|
189 // Useful for declaring static constant data blobs as an array of bytes, but forcing those
|
cannam@147
|
190 // bytes to be word-aligned.
|
cannam@147
|
191
|
cannam@147
|
192 uint8_t bytes[wordCount * sizeof(word)];
|
cannam@147
|
193 word words[wordCount];
|
cannam@147
|
194 };
|
cannam@147
|
195
|
cannam@147
|
196 struct StructSize {
|
cannam@147
|
197 StructDataWordCount data;
|
cannam@147
|
198 StructPointerCount pointers;
|
cannam@147
|
199
|
cannam@147
|
200 inline constexpr WordCountN<17> total() const { return data + pointers * WORDS_PER_POINTER; }
|
cannam@147
|
201
|
cannam@147
|
202 StructSize() = default;
|
cannam@147
|
203 inline constexpr StructSize(StructDataWordCount data, StructPointerCount pointers)
|
cannam@147
|
204 : data(data), pointers(pointers) {}
|
cannam@147
|
205 };
|
cannam@147
|
206
|
cannam@147
|
207 template <typename T, typename CapnpPrivate = typename T::_capnpPrivate>
|
cannam@147
|
208 inline constexpr StructSize structSize() {
|
cannam@147
|
209 return StructSize(bounded(CapnpPrivate::dataWordSize) * WORDS,
|
cannam@147
|
210 bounded(CapnpPrivate::pointerCount) * POINTERS);
|
cannam@147
|
211 }
|
cannam@147
|
212
|
cannam@147
|
213 template <typename T, typename CapnpPrivate = typename T::_capnpPrivate,
|
cannam@147
|
214 typename = kj::EnableIf<CAPNP_KIND(T) == Kind::STRUCT>>
|
cannam@147
|
215 inline constexpr StructSize minStructSizeForElement() {
|
cannam@147
|
216 // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough
|
cannam@147
|
217 // to hold a T.
|
cannam@147
|
218
|
cannam@147
|
219 return StructSize(bounded(CapnpPrivate::dataWordSize) * WORDS,
|
cannam@147
|
220 bounded(CapnpPrivate::pointerCount) * POINTERS);
|
cannam@147
|
221 }
|
cannam@147
|
222
|
cannam@147
|
223 template <typename T, typename = kj::EnableIf<CAPNP_KIND(T) != Kind::STRUCT>>
|
cannam@147
|
224 inline constexpr StructSize minStructSizeForElement() {
|
cannam@147
|
225 // If T is a struct, return its struct size. Otherwise return the minimum struct size big enough
|
cannam@147
|
226 // to hold a T.
|
cannam@147
|
227
|
cannam@147
|
228 return StructSize(
|
cannam@147
|
229 dataBitsPerElement(elementSizeForType<T>()) * ELEMENTS > ZERO * BITS
|
cannam@147
|
230 ? StructDataWordCount(ONE * WORDS) : StructDataWordCount(ZERO * WORDS),
|
cannam@147
|
231 pointersPerElement(elementSizeForType<T>()) * ELEMENTS);
|
cannam@147
|
232 }
|
cannam@147
|
233
|
cannam@147
|
234 // -------------------------------------------------------------------
|
cannam@147
|
235 // Masking of default values
|
cannam@147
|
236
|
cannam@147
|
237 template <typename T, Kind kind = CAPNP_KIND(T)> struct Mask_;
|
cannam@147
|
238 template <typename T> struct Mask_<T, Kind::PRIMITIVE> { typedef T Type; };
|
cannam@147
|
239 template <typename T> struct Mask_<T, Kind::ENUM> { typedef uint16_t Type; };
|
cannam@147
|
240 template <> struct Mask_<float, Kind::PRIMITIVE> { typedef uint32_t Type; };
|
cannam@147
|
241 template <> struct Mask_<double, Kind::PRIMITIVE> { typedef uint64_t Type; };
|
cannam@147
|
242
|
cannam@147
|
243 template <typename T> struct Mask_<T, Kind::OTHER> {
|
cannam@147
|
244 // Union discriminants end up here.
|
cannam@147
|
245 static_assert(sizeof(T) == 2, "Don't know how to mask this type.");
|
cannam@147
|
246 typedef uint16_t Type;
|
cannam@147
|
247 };
|
cannam@147
|
248
|
cannam@147
|
249 template <typename T>
|
cannam@147
|
250 using Mask = typename Mask_<T>::Type;
|
cannam@147
|
251
|
cannam@147
|
252 template <typename T>
|
cannam@147
|
253 KJ_ALWAYS_INLINE(Mask<T> mask(T value, Mask<T> mask));
|
cannam@147
|
254 template <typename T>
|
cannam@147
|
255 KJ_ALWAYS_INLINE(T unmask(Mask<T> value, Mask<T> mask));
|
cannam@147
|
256
|
cannam@147
|
257 template <typename T>
|
cannam@147
|
258 inline Mask<T> mask(T value, Mask<T> mask) {
|
cannam@147
|
259 return static_cast<Mask<T> >(value) ^ mask;
|
cannam@147
|
260 }
|
cannam@147
|
261
|
cannam@147
|
262 template <>
|
cannam@147
|
263 inline uint32_t mask<float>(float value, uint32_t mask) {
|
cannam@147
|
264 #if CAPNP_CANONICALIZE_NAN
|
cannam@147
|
265 if (value != value) {
|
cannam@147
|
266 return 0x7fc00000u ^ mask;
|
cannam@147
|
267 }
|
cannam@147
|
268 #endif
|
cannam@147
|
269
|
cannam@147
|
270 uint32_t i;
|
cannam@147
|
271 static_assert(sizeof(i) == sizeof(value), "float is not 32 bits?");
|
cannam@147
|
272 memcpy(&i, &value, sizeof(value));
|
cannam@147
|
273 return i ^ mask;
|
cannam@147
|
274 }
|
cannam@147
|
275
|
cannam@147
|
276 template <>
|
cannam@147
|
277 inline uint64_t mask<double>(double value, uint64_t mask) {
|
cannam@147
|
278 #if CAPNP_CANONICALIZE_NAN
|
cannam@147
|
279 if (value != value) {
|
cannam@147
|
280 return 0x7ff8000000000000ull ^ mask;
|
cannam@147
|
281 }
|
cannam@147
|
282 #endif
|
cannam@147
|
283
|
cannam@147
|
284 uint64_t i;
|
cannam@147
|
285 static_assert(sizeof(i) == sizeof(value), "double is not 64 bits?");
|
cannam@147
|
286 memcpy(&i, &value, sizeof(value));
|
cannam@147
|
287 return i ^ mask;
|
cannam@147
|
288 }
|
cannam@147
|
289
|
cannam@147
|
290 template <typename T>
|
cannam@147
|
291 inline T unmask(Mask<T> value, Mask<T> mask) {
|
cannam@147
|
292 return static_cast<T>(value ^ mask);
|
cannam@147
|
293 }
|
cannam@147
|
294
|
cannam@147
|
295 template <>
|
cannam@147
|
296 inline float unmask<float>(uint32_t value, uint32_t mask) {
|
cannam@147
|
297 value ^= mask;
|
cannam@147
|
298 float result;
|
cannam@147
|
299 static_assert(sizeof(result) == sizeof(value), "float is not 32 bits?");
|
cannam@147
|
300 memcpy(&result, &value, sizeof(value));
|
cannam@147
|
301 return result;
|
cannam@147
|
302 }
|
cannam@147
|
303
|
cannam@147
|
304 template <>
|
cannam@147
|
305 inline double unmask<double>(uint64_t value, uint64_t mask) {
|
cannam@147
|
306 value ^= mask;
|
cannam@147
|
307 double result;
|
cannam@147
|
308 static_assert(sizeof(result) == sizeof(value), "double is not 64 bits?");
|
cannam@147
|
309 memcpy(&result, &value, sizeof(value));
|
cannam@147
|
310 return result;
|
cannam@147
|
311 }
|
cannam@147
|
312
|
cannam@147
|
313 // -------------------------------------------------------------------
|
cannam@147
|
314
|
cannam@147
|
315 class CapTableReader {
|
cannam@147
|
316 public:
|
cannam@147
|
317 #if !CAPNP_LITE
|
cannam@147
|
318 virtual kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) = 0;
|
cannam@147
|
319 // Extract the capability at the given index. If the index is invalid, returns null.
|
cannam@147
|
320 #endif // !CAPNP_LITE
|
cannam@147
|
321 };
|
cannam@147
|
322
|
cannam@147
|
323 class CapTableBuilder: public CapTableReader {
|
cannam@147
|
324 public:
|
cannam@147
|
325 #if !CAPNP_LITE
|
cannam@147
|
326 virtual uint injectCap(kj::Own<ClientHook>&& cap) = 0;
|
cannam@147
|
327 // Add the capability to the message and return its index. If the same ClientHook is injected
|
cannam@147
|
328 // twice, this may return the same index both times, but in this case dropCap() needs to be
|
cannam@147
|
329 // called an equal number of times to actually remove the cap.
|
cannam@147
|
330
|
cannam@147
|
331 virtual void dropCap(uint index) = 0;
|
cannam@147
|
332 // Remove a capability injected earlier. Called when the pointer is overwritten or zero'd out.
|
cannam@147
|
333 #endif // !CAPNP_LITE
|
cannam@147
|
334 };
|
cannam@147
|
335
|
cannam@147
|
336 // -------------------------------------------------------------------
|
cannam@147
|
337
|
cannam@147
|
338 class PointerBuilder: public kj::DisallowConstCopy {
|
cannam@147
|
339 // Represents a single pointer, usually embedded in a struct or a list.
|
cannam@147
|
340
|
cannam@147
|
341 public:
|
cannam@147
|
342 inline PointerBuilder(): segment(nullptr), capTable(nullptr), pointer(nullptr) {}
|
cannam@147
|
343
|
cannam@147
|
344 static inline PointerBuilder getRoot(
|
cannam@147
|
345 SegmentBuilder* segment, CapTableBuilder* capTable, word* location);
|
cannam@147
|
346 // Get a PointerBuilder representing a message root located in the given segment at the given
|
cannam@147
|
347 // location.
|
cannam@147
|
348
|
cannam@147
|
349 inline bool isNull() { return getPointerType() == PointerType::NULL_; }
|
cannam@147
|
350 PointerType getPointerType() const;
|
cannam@147
|
351
|
cannam@147
|
352 StructBuilder getStruct(StructSize size, const word* defaultValue);
|
cannam@147
|
353 ListBuilder getList(ElementSize elementSize, const word* defaultValue);
|
cannam@147
|
354 ListBuilder getStructList(StructSize elementSize, const word* defaultValue);
|
cannam@147
|
355 ListBuilder getListAnySize(const word* defaultValue);
|
cannam@147
|
356 template <typename T> typename T::Builder getBlob(
|
cannam@147
|
357 const void* defaultValue, ByteCount defaultSize);
|
cannam@147
|
358 #if !CAPNP_LITE
|
cannam@147
|
359 kj::Own<ClientHook> getCapability();
|
cannam@147
|
360 #endif // !CAPNP_LITE
|
cannam@147
|
361 // Get methods: Get the value. If it is null, initialize it to a copy of the default value.
|
cannam@147
|
362 // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a
|
cannam@147
|
363 // simple byte array for blobs.
|
cannam@147
|
364
|
cannam@147
|
365 StructBuilder initStruct(StructSize size);
|
cannam@147
|
366 ListBuilder initList(ElementSize elementSize, ElementCount elementCount);
|
cannam@147
|
367 ListBuilder initStructList(ElementCount elementCount, StructSize size);
|
cannam@147
|
368 template <typename T> typename T::Builder initBlob(ByteCount size);
|
cannam@147
|
369 // Init methods: Initialize the pointer to a newly-allocated object, discarding the existing
|
cannam@147
|
370 // object.
|
cannam@147
|
371
|
cannam@147
|
372 void setStruct(const StructReader& value, bool canonical = false);
|
cannam@147
|
373 void setList(const ListReader& value, bool canonical = false);
|
cannam@147
|
374 template <typename T> void setBlob(typename T::Reader value);
|
cannam@147
|
375 #if !CAPNP_LITE
|
cannam@147
|
376 void setCapability(kj::Own<ClientHook>&& cap);
|
cannam@147
|
377 #endif // !CAPNP_LITE
|
cannam@147
|
378 // Set methods: Initialize the pointer to a newly-allocated copy of the given value, discarding
|
cannam@147
|
379 // the existing object.
|
cannam@147
|
380
|
cannam@147
|
381 void adopt(OrphanBuilder&& orphan);
|
cannam@147
|
382 // Set the pointer to point at the given orphaned value.
|
cannam@147
|
383
|
cannam@147
|
384 OrphanBuilder disown();
|
cannam@147
|
385 // Set the pointer to null and return its previous value as an orphan.
|
cannam@147
|
386
|
cannam@147
|
387 void clear();
|
cannam@147
|
388 // Clear the pointer to null, discarding its previous value.
|
cannam@147
|
389
|
cannam@147
|
390 void transferFrom(PointerBuilder other);
|
cannam@147
|
391 // Equivalent to `adopt(other.disown())`.
|
cannam@147
|
392
|
cannam@147
|
393 void copyFrom(PointerReader other, bool canonical = false);
|
cannam@147
|
394 // Equivalent to `set(other.get())`.
|
cannam@147
|
395 // If you set the canonical flag, it will attempt to lay the target out
|
cannam@147
|
396 // canonically, provided enough space is available.
|
cannam@147
|
397
|
cannam@147
|
398 PointerReader asReader() const;
|
cannam@147
|
399
|
cannam@147
|
400 BuilderArena* getArena() const;
|
cannam@147
|
401 // Get the arena containing this pointer.
|
cannam@147
|
402
|
cannam@147
|
403 CapTableBuilder* getCapTable();
|
cannam@147
|
404 // Gets the capability context in which this object is operating.
|
cannam@147
|
405
|
cannam@147
|
406 PointerBuilder imbue(CapTableBuilder* capTable);
|
cannam@147
|
407 // Return a copy of this builder except using the given capability context.
|
cannam@147
|
408
|
cannam@147
|
409 private:
|
cannam@147
|
410 SegmentBuilder* segment; // Memory segment in which the pointer resides.
|
cannam@147
|
411 CapTableBuilder* capTable; // Table of capability indexes.
|
cannam@147
|
412 WirePointer* pointer; // Pointer to the pointer.
|
cannam@147
|
413
|
cannam@147
|
414 inline PointerBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, WirePointer* pointer)
|
cannam@147
|
415 : segment(segment), capTable(capTable), pointer(pointer) {}
|
cannam@147
|
416
|
cannam@147
|
417 friend class StructBuilder;
|
cannam@147
|
418 friend class ListBuilder;
|
cannam@147
|
419 friend class OrphanBuilder;
|
cannam@147
|
420 };
|
cannam@147
|
421
|
cannam@147
|
422 class PointerReader {
|
cannam@147
|
423 public:
|
cannam@147
|
424 inline PointerReader()
|
cannam@147
|
425 : segment(nullptr), capTable(nullptr), pointer(nullptr), nestingLimit(0x7fffffff) {}
|
cannam@147
|
426
|
cannam@147
|
427 static PointerReader getRoot(SegmentReader* segment, CapTableReader* capTable,
|
cannam@147
|
428 const word* location, int nestingLimit);
|
cannam@147
|
429 // Get a PointerReader representing a message root located in the given segment at the given
|
cannam@147
|
430 // location.
|
cannam@147
|
431
|
cannam@147
|
432 static inline PointerReader getRootUnchecked(const word* location);
|
cannam@147
|
433 // Get a PointerReader for an unchecked message.
|
cannam@147
|
434
|
cannam@147
|
435 MessageSizeCounts targetSize() const;
|
cannam@147
|
436 // Return the total size of the target object and everything to which it points. Does not count
|
cannam@147
|
437 // far pointer overhead. This is useful for deciding how much space is needed to copy the object
|
cannam@147
|
438 // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead,
|
cannam@147
|
439 // use the result as a hint for allocating the first segment, do the copy, and then throw an
|
cannam@147
|
440 // exception if it overruns.
|
cannam@147
|
441
|
cannam@147
|
442 inline bool isNull() const { return getPointerType() == PointerType::NULL_; }
|
cannam@147
|
443 PointerType getPointerType() const;
|
cannam@147
|
444
|
cannam@147
|
445 StructReader getStruct(const word* defaultValue) const;
|
cannam@147
|
446 ListReader getList(ElementSize expectedElementSize, const word* defaultValue) const;
|
cannam@147
|
447 ListReader getListAnySize(const word* defaultValue) const;
|
cannam@147
|
448 template <typename T>
|
cannam@147
|
449 typename T::Reader getBlob(const void* defaultValue, ByteCount defaultSize) const;
|
cannam@147
|
450 #if !CAPNP_LITE
|
cannam@147
|
451 kj::Own<ClientHook> getCapability() const;
|
cannam@147
|
452 #endif // !CAPNP_LITE
|
cannam@147
|
453 // Get methods: Get the value. If it is null, return the default value instead.
|
cannam@147
|
454 // The default value is encoded as an "unchecked message" for structs, lists, and objects, or a
|
cannam@147
|
455 // simple byte array for blobs.
|
cannam@147
|
456
|
cannam@147
|
457 const word* getUnchecked() const;
|
cannam@147
|
458 // If this is an unchecked message, get a word* pointing at the location of the pointer. This
|
cannam@147
|
459 // word* can actually be passed to readUnchecked() to read the designated sub-object later. If
|
cannam@147
|
460 // this isn't an unchecked message, throws an exception.
|
cannam@147
|
461
|
cannam@147
|
462 kj::Maybe<Arena&> getArena() const;
|
cannam@147
|
463 // Get the arena containing this pointer.
|
cannam@147
|
464
|
cannam@147
|
465 CapTableReader* getCapTable();
|
cannam@147
|
466 // Gets the capability context in which this object is operating.
|
cannam@147
|
467
|
cannam@147
|
468 PointerReader imbue(CapTableReader* capTable) const;
|
cannam@147
|
469 // Return a copy of this reader except using the given capability context.
|
cannam@147
|
470
|
cannam@147
|
471 bool isCanonical(const word **readHead);
|
cannam@147
|
472 // Validate this pointer's canonicity, subject to the conditions:
|
cannam@147
|
473 // * All data to the left of readHead has been read thus far (for pointer
|
cannam@147
|
474 // ordering)
|
cannam@147
|
475 // * All pointers in preorder have already been checked
|
cannam@147
|
476 // * This pointer is in the first and only segment of the message
|
cannam@147
|
477
|
cannam@147
|
478 private:
|
cannam@147
|
479 SegmentReader* segment; // Memory segment in which the pointer resides.
|
cannam@147
|
480 CapTableReader* capTable; // Table of capability indexes.
|
cannam@147
|
481 const WirePointer* pointer; // Pointer to the pointer. null = treat as null pointer.
|
cannam@147
|
482
|
cannam@147
|
483 int nestingLimit;
|
cannam@147
|
484 // Limits the depth of message structures to guard against stack-overflow-based DoS attacks.
|
cannam@147
|
485 // Once this reaches zero, further pointers will be pruned.
|
cannam@147
|
486
|
cannam@147
|
487 inline PointerReader(SegmentReader* segment, CapTableReader* capTable,
|
cannam@147
|
488 const WirePointer* pointer, int nestingLimit)
|
cannam@147
|
489 : segment(segment), capTable(capTable), pointer(pointer), nestingLimit(nestingLimit) {}
|
cannam@147
|
490
|
cannam@147
|
491 friend class StructReader;
|
cannam@147
|
492 friend class ListReader;
|
cannam@147
|
493 friend class PointerBuilder;
|
cannam@147
|
494 friend class OrphanBuilder;
|
cannam@147
|
495 };
|
cannam@147
|
496
|
cannam@147
|
497 // -------------------------------------------------------------------
|
cannam@147
|
498
|
cannam@147
|
499 class StructBuilder: public kj::DisallowConstCopy {
|
cannam@147
|
500 public:
|
cannam@147
|
501 inline StructBuilder(): segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr) {}
|
cannam@147
|
502
|
cannam@147
|
503 inline word* getLocation() { return reinterpret_cast<word*>(data); }
|
cannam@147
|
504 // Get the object's location. Only valid for independently-allocated objects (i.e. not list
|
cannam@147
|
505 // elements).
|
cannam@147
|
506
|
cannam@147
|
507 inline StructDataBitCount getDataSectionSize() const { return dataSize; }
|
cannam@147
|
508 inline StructPointerCount getPointerSectionSize() const { return pointerCount; }
|
cannam@147
|
509 inline kj::ArrayPtr<byte> getDataSectionAsBlob();
|
cannam@147
|
510 inline _::ListBuilder getPointerSectionAsList();
|
cannam@147
|
511
|
cannam@147
|
512 template <typename T>
|
cannam@147
|
513 KJ_ALWAYS_INLINE(bool hasDataField(StructDataOffset offset));
|
cannam@147
|
514 // Return true if the field is set to something other than its default value.
|
cannam@147
|
515
|
cannam@147
|
516 template <typename T>
|
cannam@147
|
517 KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset));
|
cannam@147
|
518 // Gets the data field value of the given type at the given offset. The offset is measured in
|
cannam@147
|
519 // multiples of the field size, determined by the type.
|
cannam@147
|
520
|
cannam@147
|
521 template <typename T>
|
cannam@147
|
522 KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset, Mask<T> mask));
|
cannam@147
|
523 // Like getDataField() but applies the given XOR mask to the data on load. Used for reading
|
cannam@147
|
524 // fields with non-zero default values.
|
cannam@147
|
525
|
cannam@147
|
526 template <typename T>
|
cannam@147
|
527 KJ_ALWAYS_INLINE(void setDataField(StructDataOffset offset, kj::NoInfer<T> value));
|
cannam@147
|
528 // Sets the data field value at the given offset.
|
cannam@147
|
529
|
cannam@147
|
530 template <typename T>
|
cannam@147
|
531 KJ_ALWAYS_INLINE(void setDataField(StructDataOffset offset,
|
cannam@147
|
532 kj::NoInfer<T> value, Mask<T> mask));
|
cannam@147
|
533 // Like setDataField() but applies the given XOR mask before storing. Used for writing fields
|
cannam@147
|
534 // with non-zero default values.
|
cannam@147
|
535
|
cannam@147
|
536 KJ_ALWAYS_INLINE(PointerBuilder getPointerField(StructPointerOffset ptrIndex));
|
cannam@147
|
537 // Get a builder for a pointer field given the index within the pointer section.
|
cannam@147
|
538
|
cannam@147
|
539 void clearAll();
|
cannam@147
|
540 // Clear all pointers and data.
|
cannam@147
|
541
|
cannam@147
|
542 void transferContentFrom(StructBuilder other);
|
cannam@147
|
543 // Adopt all pointers from `other`, and also copy all data. If `other`'s sections are larger
|
cannam@147
|
544 // than this, the extra data is not transferred, meaning there is a risk of data loss when
|
cannam@147
|
545 // transferring from messages built with future versions of the protocol.
|
cannam@147
|
546
|
cannam@147
|
547 void copyContentFrom(StructReader other);
|
cannam@147
|
548 // Copy content from `other`. If `other`'s sections are larger than this, the extra data is not
|
cannam@147
|
549 // copied, meaning there is a risk of data loss when copying from messages built with future
|
cannam@147
|
550 // versions of the protocol.
|
cannam@147
|
551
|
cannam@147
|
552 StructReader asReader() const;
|
cannam@147
|
553 // Gets a StructReader pointing at the same memory.
|
cannam@147
|
554
|
cannam@147
|
555 BuilderArena* getArena();
|
cannam@147
|
556 // Gets the arena in which this object is allocated.
|
cannam@147
|
557
|
cannam@147
|
558 CapTableBuilder* getCapTable();
|
cannam@147
|
559 // Gets the capability context in which this object is operating.
|
cannam@147
|
560
|
cannam@147
|
561 StructBuilder imbue(CapTableBuilder* capTable);
|
cannam@147
|
562 // Return a copy of this builder except using the given capability context.
|
cannam@147
|
563
|
cannam@147
|
564 private:
|
cannam@147
|
565 SegmentBuilder* segment; // Memory segment in which the struct resides.
|
cannam@147
|
566 CapTableBuilder* capTable; // Table of capability indexes.
|
cannam@147
|
567 void* data; // Pointer to the encoded data.
|
cannam@147
|
568 WirePointer* pointers; // Pointer to the encoded pointers.
|
cannam@147
|
569
|
cannam@147
|
570 StructDataBitCount dataSize;
|
cannam@147
|
571 // Size of data section. We use a bit count rather than a word count to more easily handle the
|
cannam@147
|
572 // case of struct lists encoded with less than a word per element.
|
cannam@147
|
573
|
cannam@147
|
574 StructPointerCount pointerCount; // Size of the pointer section.
|
cannam@147
|
575
|
cannam@147
|
576 inline StructBuilder(SegmentBuilder* segment, CapTableBuilder* capTable,
|
cannam@147
|
577 void* data, WirePointer* pointers,
|
cannam@147
|
578 StructDataBitCount dataSize, StructPointerCount pointerCount)
|
cannam@147
|
579 : segment(segment), capTable(capTable), data(data), pointers(pointers),
|
cannam@147
|
580 dataSize(dataSize), pointerCount(pointerCount) {}
|
cannam@147
|
581
|
cannam@147
|
582 friend class ListBuilder;
|
cannam@147
|
583 friend struct WireHelpers;
|
cannam@147
|
584 friend class OrphanBuilder;
|
cannam@147
|
585 };
|
cannam@147
|
586
|
cannam@147
|
587 class StructReader {
|
cannam@147
|
588 public:
|
cannam@147
|
589 inline StructReader()
|
cannam@147
|
590 : segment(nullptr), capTable(nullptr), data(nullptr), pointers(nullptr),
|
cannam@147
|
591 dataSize(ZERO * BITS), pointerCount(ZERO * POINTERS), nestingLimit(0x7fffffff) {}
|
cannam@147
|
592 inline StructReader(kj::ArrayPtr<const word> data)
|
cannam@147
|
593 : segment(nullptr), capTable(nullptr), data(data.begin()), pointers(nullptr),
|
cannam@147
|
594 dataSize(assumeBits<STRUCT_DATA_WORD_COUNT_BITS>(data.size()) * WORDS * BITS_PER_WORD),
|
cannam@147
|
595 pointerCount(ZERO * POINTERS), nestingLimit(0x7fffffff) {}
|
cannam@147
|
596
|
cannam@147
|
597 const void* getLocation() const { return data; }
|
cannam@147
|
598
|
cannam@147
|
599 inline StructDataBitCount getDataSectionSize() const { return dataSize; }
|
cannam@147
|
600 inline StructPointerCount getPointerSectionSize() const { return pointerCount; }
|
cannam@147
|
601 inline kj::ArrayPtr<const byte> getDataSectionAsBlob();
|
cannam@147
|
602 inline _::ListReader getPointerSectionAsList();
|
cannam@147
|
603
|
cannam@147
|
604 kj::Array<word> canonicalize();
|
cannam@147
|
605
|
cannam@147
|
606 template <typename T>
|
cannam@147
|
607 KJ_ALWAYS_INLINE(bool hasDataField(StructDataOffset offset) const);
|
cannam@147
|
608 // Return true if the field is set to something other than its default value.
|
cannam@147
|
609
|
cannam@147
|
610 template <typename T>
|
cannam@147
|
611 KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset) const);
|
cannam@147
|
612 // Get the data field value of the given type at the given offset. The offset is measured in
|
cannam@147
|
613 // multiples of the field size, determined by the type. Returns zero if the offset is past the
|
cannam@147
|
614 // end of the struct's data section.
|
cannam@147
|
615
|
cannam@147
|
616 template <typename T>
|
cannam@147
|
617 KJ_ALWAYS_INLINE(T getDataField(StructDataOffset offset, Mask<T> mask) const);
|
cannam@147
|
618 // Like getDataField(offset), but applies the given XOR mask to the result. Used for reading
|
cannam@147
|
619 // fields with non-zero default values.
|
cannam@147
|
620
|
cannam@147
|
621 KJ_ALWAYS_INLINE(PointerReader getPointerField(StructPointerOffset ptrIndex) const);
|
cannam@147
|
622 // Get a reader for a pointer field given the index within the pointer section. If the index
|
cannam@147
|
623 // is out-of-bounds, returns a null pointer.
|
cannam@147
|
624
|
cannam@147
|
625 MessageSizeCounts totalSize() const;
|
cannam@147
|
626 // Return the total size of the struct and everything to which it points. Does not count far
|
cannam@147
|
627 // pointer overhead. This is useful for deciding how much space is needed to copy the struct
|
cannam@147
|
628 // into a flat array. However, the caller is advised NOT to treat this value as secure. Instead,
|
cannam@147
|
629 // use the result as a hint for allocating the first segment, do the copy, and then throw an
|
cannam@147
|
630 // exception if it overruns.
|
cannam@147
|
631
|
cannam@147
|
632 CapTableReader* getCapTable();
|
cannam@147
|
633 // Gets the capability context in which this object is operating.
|
cannam@147
|
634
|
cannam@147
|
635 StructReader imbue(CapTableReader* capTable) const;
|
cannam@147
|
636 // Return a copy of this reader except using the given capability context.
|
cannam@147
|
637
|
cannam@147
|
638 bool isCanonical(const word **readHead, const word **ptrHead,
|
cannam@147
|
639 bool *dataTrunc, bool *ptrTrunc);
|
cannam@147
|
640 // Validate this pointer's canonicity, subject to the conditions:
|
cannam@147
|
641 // * All data to the left of readHead has been read thus far (for pointer
|
cannam@147
|
642 // ordering)
|
cannam@147
|
643 // * All pointers in preorder have already been checked
|
cannam@147
|
644 // * This pointer is in the first and only segment of the message
|
cannam@147
|
645 //
|
cannam@147
|
646 // If this function returns false, the struct is non-canonical. If it
|
cannam@147
|
647 // returns true, then:
|
cannam@147
|
648 // * If it is a composite in a list, it is canonical if at least one struct
|
cannam@147
|
649 // in the list outputs dataTrunc = 1, and at least one outputs ptrTrunc = 1
|
cannam@147
|
650 // * If it is derived from a struct pointer, it is canonical if
|
cannam@147
|
651 // dataTrunc = 1 AND ptrTrunc = 1
|
cannam@147
|
652
|
cannam@147
|
653 private:
|
cannam@147
|
654 SegmentReader* segment; // Memory segment in which the struct resides.
|
cannam@147
|
655 CapTableReader* capTable; // Table of capability indexes.
|
cannam@147
|
656
|
cannam@147
|
657 const void* data;
|
cannam@147
|
658 const WirePointer* pointers;
|
cannam@147
|
659
|
cannam@147
|
660 StructDataBitCount dataSize;
|
cannam@147
|
661 // Size of data section. We use a bit count rather than a word count to more easily handle the
|
cannam@147
|
662 // case of struct lists encoded with less than a word per element.
|
cannam@147
|
663
|
cannam@147
|
664 StructPointerCount pointerCount; // Size of the pointer section.
|
cannam@147
|
665
|
cannam@147
|
666 int nestingLimit;
|
cannam@147
|
667 // Limits the depth of message structures to guard against stack-overflow-based DoS attacks.
|
cannam@147
|
668 // Once this reaches zero, further pointers will be pruned.
|
cannam@147
|
669 // TODO(perf): Limit to 16 bits for better packing?
|
cannam@147
|
670
|
cannam@147
|
671 inline StructReader(SegmentReader* segment, CapTableReader* capTable,
|
cannam@147
|
672 const void* data, const WirePointer* pointers,
|
cannam@147
|
673 StructDataBitCount dataSize, StructPointerCount pointerCount,
|
cannam@147
|
674 int nestingLimit)
|
cannam@147
|
675 : segment(segment), capTable(capTable), data(data), pointers(pointers),
|
cannam@147
|
676 dataSize(dataSize), pointerCount(pointerCount),
|
cannam@147
|
677 nestingLimit(nestingLimit) {}
|
cannam@147
|
678
|
cannam@147
|
679 friend class ListReader;
|
cannam@147
|
680 friend class StructBuilder;
|
cannam@147
|
681 friend struct WireHelpers;
|
cannam@147
|
682 };
|
cannam@147
|
683
|
cannam@147
|
684 // -------------------------------------------------------------------
|
cannam@147
|
685
|
cannam@147
|
686 class ListBuilder: public kj::DisallowConstCopy {
|
cannam@147
|
687 public:
|
cannam@147
|
688 inline explicit ListBuilder(ElementSize elementSize)
|
cannam@147
|
689 : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(ZERO * ELEMENTS),
|
cannam@147
|
690 step(ZERO * BITS / ELEMENTS), structDataSize(ZERO * BITS),
|
cannam@147
|
691 structPointerCount(ZERO * POINTERS), elementSize(elementSize) {}
|
cannam@147
|
692
|
cannam@147
|
693 inline word* getLocation() {
|
cannam@147
|
694 // Get the object's location.
|
cannam@147
|
695
|
cannam@147
|
696 if (elementSize == ElementSize::INLINE_COMPOSITE && ptr != nullptr) {
|
cannam@147
|
697 return reinterpret_cast<word*>(ptr) - POINTER_SIZE_IN_WORDS;
|
cannam@147
|
698 } else {
|
cannam@147
|
699 return reinterpret_cast<word*>(ptr);
|
cannam@147
|
700 }
|
cannam@147
|
701 }
|
cannam@147
|
702
|
cannam@147
|
703 inline ElementSize getElementSize() const { return elementSize; }
|
cannam@147
|
704
|
cannam@147
|
705 inline ListElementCount size() const;
|
cannam@147
|
706 // The number of elements in the list.
|
cannam@147
|
707
|
cannam@147
|
708 Text::Builder asText();
|
cannam@147
|
709 Data::Builder asData();
|
cannam@147
|
710 // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized.
|
cannam@147
|
711
|
cannam@147
|
712 template <typename T>
|
cannam@147
|
713 KJ_ALWAYS_INLINE(T getDataElement(ElementCount index));
|
cannam@147
|
714 // Get the element of the given type at the given index.
|
cannam@147
|
715
|
cannam@147
|
716 template <typename T>
|
cannam@147
|
717 KJ_ALWAYS_INLINE(void setDataElement(ElementCount index, kj::NoInfer<T> value));
|
cannam@147
|
718 // Set the element at the given index.
|
cannam@147
|
719
|
cannam@147
|
720 KJ_ALWAYS_INLINE(PointerBuilder getPointerElement(ElementCount index));
|
cannam@147
|
721
|
cannam@147
|
722 StructBuilder getStructElement(ElementCount index);
|
cannam@147
|
723
|
cannam@147
|
724 ListReader asReader() const;
|
cannam@147
|
725 // Get a ListReader pointing at the same memory.
|
cannam@147
|
726
|
cannam@147
|
727 BuilderArena* getArena();
|
cannam@147
|
728 // Gets the arena in which this object is allocated.
|
cannam@147
|
729
|
cannam@147
|
730 CapTableBuilder* getCapTable();
|
cannam@147
|
731 // Gets the capability context in which this object is operating.
|
cannam@147
|
732
|
cannam@147
|
733 ListBuilder imbue(CapTableBuilder* capTable);
|
cannam@147
|
734 // Return a copy of this builder except using the given capability context.
|
cannam@147
|
735
|
cannam@147
|
736 private:
|
cannam@147
|
737 SegmentBuilder* segment; // Memory segment in which the list resides.
|
cannam@147
|
738 CapTableBuilder* capTable; // Table of capability indexes.
|
cannam@147
|
739
|
cannam@147
|
740 byte* ptr; // Pointer to list content.
|
cannam@147
|
741
|
cannam@147
|
742 ListElementCount elementCount; // Number of elements in the list.
|
cannam@147
|
743
|
cannam@147
|
744 BitsPerElementN<23> step;
|
cannam@147
|
745 // The distance between elements. The maximum value occurs when a struct contains 2^16-1 data
|
cannam@147
|
746 // words and 2^16-1 pointers, i.e. 2^17 - 2 words, or 2^23 - 128 bits.
|
cannam@147
|
747
|
cannam@147
|
748 StructDataBitCount structDataSize;
|
cannam@147
|
749 StructPointerCount structPointerCount;
|
cannam@147
|
750 // The struct properties to use when interpreting the elements as structs. All lists can be
|
cannam@147
|
751 // interpreted as struct lists, so these are always filled in.
|
cannam@147
|
752
|
cannam@147
|
753 ElementSize elementSize;
|
cannam@147
|
754 // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE
|
cannam@147
|
755 // from other types when the overall size is exactly zero or one words.
|
cannam@147
|
756
|
cannam@147
|
757 inline ListBuilder(SegmentBuilder* segment, CapTableBuilder* capTable, void* ptr,
|
cannam@147
|
758 BitsPerElementN<23> step, ListElementCount size,
|
cannam@147
|
759 StructDataBitCount structDataSize, StructPointerCount structPointerCount,
|
cannam@147
|
760 ElementSize elementSize)
|
cannam@147
|
761 : segment(segment), capTable(capTable), ptr(reinterpret_cast<byte*>(ptr)),
|
cannam@147
|
762 elementCount(size), step(step), structDataSize(structDataSize),
|
cannam@147
|
763 structPointerCount(structPointerCount), elementSize(elementSize) {}
|
cannam@147
|
764
|
cannam@147
|
765 friend class StructBuilder;
|
cannam@147
|
766 friend struct WireHelpers;
|
cannam@147
|
767 friend class OrphanBuilder;
|
cannam@147
|
768 };
|
cannam@147
|
769
|
cannam@147
|
770 class ListReader {
|
cannam@147
|
771 public:
|
cannam@147
|
772 inline explicit ListReader(ElementSize elementSize)
|
cannam@147
|
773 : segment(nullptr), capTable(nullptr), ptr(nullptr), elementCount(ZERO * ELEMENTS),
|
cannam@147
|
774 step(ZERO * BITS / ELEMENTS), structDataSize(ZERO * BITS),
|
cannam@147
|
775 structPointerCount(ZERO * POINTERS), elementSize(elementSize), nestingLimit(0x7fffffff) {}
|
cannam@147
|
776
|
cannam@147
|
777 inline ListElementCount size() const;
|
cannam@147
|
778 // The number of elements in the list.
|
cannam@147
|
779
|
cannam@147
|
780 inline ElementSize getElementSize() const { return elementSize; }
|
cannam@147
|
781
|
cannam@147
|
782 Text::Reader asText();
|
cannam@147
|
783 Data::Reader asData();
|
cannam@147
|
784 // Reinterpret the list as a blob. Throws an exception if the elements are not byte-sized.
|
cannam@147
|
785
|
cannam@147
|
786 kj::ArrayPtr<const byte> asRawBytes();
|
cannam@147
|
787
|
cannam@147
|
788 template <typename T>
|
cannam@147
|
789 KJ_ALWAYS_INLINE(T getDataElement(ElementCount index) const);
|
cannam@147
|
790 // Get the element of the given type at the given index.
|
cannam@147
|
791
|
cannam@147
|
792 KJ_ALWAYS_INLINE(PointerReader getPointerElement(ElementCount index) const);
|
cannam@147
|
793
|
cannam@147
|
794 StructReader getStructElement(ElementCount index) const;
|
cannam@147
|
795
|
cannam@147
|
796 CapTableReader* getCapTable();
|
cannam@147
|
797 // Gets the capability context in which this object is operating.
|
cannam@147
|
798
|
cannam@147
|
799 ListReader imbue(CapTableReader* capTable) const;
|
cannam@147
|
800 // Return a copy of this reader except using the given capability context.
|
cannam@147
|
801
|
cannam@147
|
802 bool isCanonical(const word **readHead, const WirePointer* ref);
|
cannam@147
|
803 // Validate this pointer's canonicity, subject to the conditions:
|
cannam@147
|
804 // * All data to the left of readHead has been read thus far (for pointer
|
cannam@147
|
805 // ordering)
|
cannam@147
|
806 // * All pointers in preorder have already been checked
|
cannam@147
|
807 // * This pointer is in the first and only segment of the message
|
cannam@147
|
808
|
cannam@147
|
809 private:
|
cannam@147
|
810 SegmentReader* segment; // Memory segment in which the list resides.
|
cannam@147
|
811 CapTableReader* capTable; // Table of capability indexes.
|
cannam@147
|
812
|
cannam@147
|
813 const byte* ptr; // Pointer to list content.
|
cannam@147
|
814
|
cannam@147
|
815 ListElementCount elementCount; // Number of elements in the list.
|
cannam@147
|
816
|
cannam@147
|
817 BitsPerElementN<23> step;
|
cannam@147
|
818 // The distance between elements. The maximum value occurs when a struct contains 2^16-1 data
|
cannam@147
|
819 // words and 2^16-1 pointers, i.e. 2^17 - 2 words, or 2^23 - 2 bits.
|
cannam@147
|
820
|
cannam@147
|
821 StructDataBitCount structDataSize;
|
cannam@147
|
822 StructPointerCount structPointerCount;
|
cannam@147
|
823 // The struct properties to use when interpreting the elements as structs. All lists can be
|
cannam@147
|
824 // interpreted as struct lists, so these are always filled in.
|
cannam@147
|
825
|
cannam@147
|
826 ElementSize elementSize;
|
cannam@147
|
827 // The element size as a ElementSize. This is only really needed to disambiguate INLINE_COMPOSITE
|
cannam@147
|
828 // from other types when the overall size is exactly zero or one words.
|
cannam@147
|
829
|
cannam@147
|
830 int nestingLimit;
|
cannam@147
|
831 // Limits the depth of message structures to guard against stack-overflow-based DoS attacks.
|
cannam@147
|
832 // Once this reaches zero, further pointers will be pruned.
|
cannam@147
|
833
|
cannam@147
|
834 inline ListReader(SegmentReader* segment, CapTableReader* capTable, const void* ptr,
|
cannam@147
|
835 ListElementCount elementCount, BitsPerElementN<23> step,
|
cannam@147
|
836 StructDataBitCount structDataSize, StructPointerCount structPointerCount,
|
cannam@147
|
837 ElementSize elementSize, int nestingLimit)
|
cannam@147
|
838 : segment(segment), capTable(capTable), ptr(reinterpret_cast<const byte*>(ptr)),
|
cannam@147
|
839 elementCount(elementCount), step(step), structDataSize(structDataSize),
|
cannam@147
|
840 structPointerCount(structPointerCount), elementSize(elementSize),
|
cannam@147
|
841 nestingLimit(nestingLimit) {}
|
cannam@147
|
842
|
cannam@147
|
843 friend class StructReader;
|
cannam@147
|
844 friend class ListBuilder;
|
cannam@147
|
845 friend struct WireHelpers;
|
cannam@147
|
846 friend class OrphanBuilder;
|
cannam@147
|
847 };
|
cannam@147
|
848
|
cannam@147
|
849 // -------------------------------------------------------------------
|
cannam@147
|
850
|
cannam@147
|
851 class OrphanBuilder {
|
cannam@147
|
852 public:
|
cannam@147
|
853 inline OrphanBuilder(): segment(nullptr), capTable(nullptr), location(nullptr) {
|
cannam@147
|
854 memset(&tag, 0, sizeof(tag));
|
cannam@147
|
855 }
|
cannam@147
|
856 OrphanBuilder(const OrphanBuilder& other) = delete;
|
cannam@147
|
857 inline OrphanBuilder(OrphanBuilder&& other) noexcept;
|
cannam@147
|
858 inline ~OrphanBuilder() noexcept(false);
|
cannam@147
|
859
|
cannam@147
|
860 static OrphanBuilder initStruct(BuilderArena* arena, CapTableBuilder* capTable, StructSize size);
|
cannam@147
|
861 static OrphanBuilder initList(BuilderArena* arena, CapTableBuilder* capTable,
|
cannam@147
|
862 ElementCount elementCount, ElementSize elementSize);
|
cannam@147
|
863 static OrphanBuilder initStructList(BuilderArena* arena, CapTableBuilder* capTable,
|
cannam@147
|
864 ElementCount elementCount, StructSize elementSize);
|
cannam@147
|
865 static OrphanBuilder initText(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size);
|
cannam@147
|
866 static OrphanBuilder initData(BuilderArena* arena, CapTableBuilder* capTable, ByteCount size);
|
cannam@147
|
867
|
cannam@147
|
868 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, StructReader copyFrom);
|
cannam@147
|
869 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, ListReader copyFrom);
|
cannam@147
|
870 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, PointerReader copyFrom);
|
cannam@147
|
871 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Text::Reader copyFrom);
|
cannam@147
|
872 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable, Data::Reader copyFrom);
|
cannam@147
|
873 #if !CAPNP_LITE
|
cannam@147
|
874 static OrphanBuilder copy(BuilderArena* arena, CapTableBuilder* capTable,
|
cannam@147
|
875 kj::Own<ClientHook> copyFrom);
|
cannam@147
|
876 #endif // !CAPNP_LITE
|
cannam@147
|
877
|
cannam@147
|
878 static OrphanBuilder concat(BuilderArena* arena, CapTableBuilder* capTable,
|
cannam@147
|
879 ElementSize expectedElementSize, StructSize expectedStructSize,
|
cannam@147
|
880 kj::ArrayPtr<const ListReader> lists);
|
cannam@147
|
881
|
cannam@147
|
882 static OrphanBuilder referenceExternalData(BuilderArena* arena, Data::Reader data);
|
cannam@147
|
883
|
cannam@147
|
884 OrphanBuilder& operator=(const OrphanBuilder& other) = delete;
|
cannam@147
|
885 inline OrphanBuilder& operator=(OrphanBuilder&& other);
|
cannam@147
|
886
|
cannam@147
|
887 inline bool operator==(decltype(nullptr)) const { return location == nullptr; }
|
cannam@147
|
888 inline bool operator!=(decltype(nullptr)) const { return location != nullptr; }
|
cannam@147
|
889
|
cannam@147
|
890 StructBuilder asStruct(StructSize size);
|
cannam@147
|
891 // Interpret as a struct, or throw an exception if not a struct.
|
cannam@147
|
892
|
cannam@147
|
893 ListBuilder asList(ElementSize elementSize);
|
cannam@147
|
894 // Interpret as a list, or throw an exception if not a list. elementSize cannot be
|
cannam@147
|
895 // INLINE_COMPOSITE -- use asStructList() instead.
|
cannam@147
|
896
|
cannam@147
|
897 ListBuilder asStructList(StructSize elementSize);
|
cannam@147
|
898 // Interpret as a struct list, or throw an exception if not a list.
|
cannam@147
|
899
|
cannam@147
|
900 ListBuilder asListAnySize();
|
cannam@147
|
901 // For AnyList.
|
cannam@147
|
902
|
cannam@147
|
903 Text::Builder asText();
|
cannam@147
|
904 Data::Builder asData();
|
cannam@147
|
905 // Interpret as a blob, or throw an exception if not a blob.
|
cannam@147
|
906
|
cannam@147
|
907 StructReader asStructReader(StructSize size) const;
|
cannam@147
|
908 ListReader asListReader(ElementSize elementSize) const;
|
cannam@147
|
909 ListReader asListReaderAnySize() const;
|
cannam@147
|
910 #if !CAPNP_LITE
|
cannam@147
|
911 kj::Own<ClientHook> asCapability() const;
|
cannam@147
|
912 #endif // !CAPNP_LITE
|
cannam@147
|
913 Text::Reader asTextReader() const;
|
cannam@147
|
914 Data::Reader asDataReader() const;
|
cannam@147
|
915
|
cannam@147
|
916 bool truncate(ElementCount size, bool isText) KJ_WARN_UNUSED_RESULT;
|
cannam@147
|
917 // Resize the orphan list to the given size. Returns false if the list is currently empty but
|
cannam@147
|
918 // the requested size is non-zero, in which case the caller will need to allocate a new list.
|
cannam@147
|
919
|
cannam@147
|
920 void truncate(ElementCount size, ElementSize elementSize);
|
cannam@147
|
921 void truncate(ElementCount size, StructSize elementSize);
|
cannam@147
|
922 void truncateText(ElementCount size);
|
cannam@147
|
923 // Versions of truncate() that know how to allocate a new list if needed.
|
cannam@147
|
924
|
cannam@147
|
925 private:
|
cannam@147
|
926 static_assert(ONE * POINTERS * WORDS_PER_POINTER == ONE * WORDS,
|
cannam@147
|
927 "This struct assumes a pointer is one word.");
|
cannam@147
|
928 word tag;
|
cannam@147
|
929 // Contains an encoded WirePointer representing this object. WirePointer is defined in
|
cannam@147
|
930 // layout.c++, but fits in a word.
|
cannam@147
|
931 //
|
cannam@147
|
932 // This may be a FAR pointer. Even in that case, `location` points to the eventual destination
|
cannam@147
|
933 // of that far pointer. The reason we keep the far pointer around rather than just making `tag`
|
cannam@147
|
934 // represent the final destination is because if the eventual adopter of the pointer is not in
|
cannam@147
|
935 // the target's segment then it may be useful to reuse the far pointer landing pad.
|
cannam@147
|
936 //
|
cannam@147
|
937 // If `tag` is not a far pointer, its offset is garbage; only `location` points to the actual
|
cannam@147
|
938 // target.
|
cannam@147
|
939
|
cannam@147
|
940 SegmentBuilder* segment;
|
cannam@147
|
941 // Segment in which the object resides.
|
cannam@147
|
942
|
cannam@147
|
943 CapTableBuilder* capTable;
|
cannam@147
|
944 // Table of capability indexes.
|
cannam@147
|
945
|
cannam@147
|
946 word* location;
|
cannam@147
|
947 // Pointer to the object, or nullptr if the pointer is null. For capabilities, we make this
|
cannam@147
|
948 // 0x1 just so that it is non-null for operator==, but it is never used.
|
cannam@147
|
949
|
cannam@147
|
950 inline OrphanBuilder(const void* tagPtr, SegmentBuilder* segment,
|
cannam@147
|
951 CapTableBuilder* capTable, word* location)
|
cannam@147
|
952 : segment(segment), capTable(capTable), location(location) {
|
cannam@147
|
953 memcpy(&tag, tagPtr, sizeof(tag));
|
cannam@147
|
954 }
|
cannam@147
|
955
|
cannam@147
|
956 inline WirePointer* tagAsPtr() { return reinterpret_cast<WirePointer*>(&tag); }
|
cannam@147
|
957 inline const WirePointer* tagAsPtr() const { return reinterpret_cast<const WirePointer*>(&tag); }
|
cannam@147
|
958
|
cannam@147
|
959 void euthanize();
|
cannam@147
|
960 // Erase the target object, zeroing it out and possibly reclaiming the memory. Called when
|
cannam@147
|
961 // the OrphanBuilder is being destroyed or overwritten and it is non-null.
|
cannam@147
|
962
|
cannam@147
|
963 friend struct WireHelpers;
|
cannam@147
|
964 };
|
cannam@147
|
965
|
cannam@147
|
966 // =======================================================================================
|
cannam@147
|
967 // Internal implementation details...
|
cannam@147
|
968
|
cannam@147
|
969 // These are defined in the source file.
|
cannam@147
|
970 template <> typename Text::Builder PointerBuilder::initBlob<Text>(ByteCount size);
|
cannam@147
|
971 template <> void PointerBuilder::setBlob<Text>(typename Text::Reader value);
|
cannam@147
|
972 template <> typename Text::Builder PointerBuilder::getBlob<Text>(
|
cannam@147
|
973 const void* defaultValue, ByteCount defaultSize);
|
cannam@147
|
974 template <> typename Text::Reader PointerReader::getBlob<Text>(
|
cannam@147
|
975 const void* defaultValue, ByteCount defaultSize) const;
|
cannam@147
|
976
|
cannam@147
|
977 template <> typename Data::Builder PointerBuilder::initBlob<Data>(ByteCount size);
|
cannam@147
|
978 template <> void PointerBuilder::setBlob<Data>(typename Data::Reader value);
|
cannam@147
|
979 template <> typename Data::Builder PointerBuilder::getBlob<Data>(
|
cannam@147
|
980 const void* defaultValue, ByteCount defaultSize);
|
cannam@147
|
981 template <> typename Data::Reader PointerReader::getBlob<Data>(
|
cannam@147
|
982 const void* defaultValue, ByteCount defaultSize) const;
|
cannam@147
|
983
|
cannam@147
|
984 inline PointerBuilder PointerBuilder::getRoot(
|
cannam@147
|
985 SegmentBuilder* segment, CapTableBuilder* capTable, word* location) {
|
cannam@147
|
986 return PointerBuilder(segment, capTable, reinterpret_cast<WirePointer*>(location));
|
cannam@147
|
987 }
|
cannam@147
|
988
|
cannam@147
|
989 inline PointerReader PointerReader::getRootUnchecked(const word* location) {
|
cannam@147
|
990 return PointerReader(nullptr, nullptr,
|
cannam@147
|
991 reinterpret_cast<const WirePointer*>(location), 0x7fffffff);
|
cannam@147
|
992 }
|
cannam@147
|
993
|
cannam@147
|
994 // -------------------------------------------------------------------
|
cannam@147
|
995
|
cannam@147
|
996 inline kj::ArrayPtr<byte> StructBuilder::getDataSectionAsBlob() {
|
cannam@147
|
997 return kj::ArrayPtr<byte>(reinterpret_cast<byte*>(data),
|
cannam@147
|
998 unbound(dataSize / BITS_PER_BYTE / BYTES));
|
cannam@147
|
999 }
|
cannam@147
|
1000
|
cannam@147
|
1001 inline _::ListBuilder StructBuilder::getPointerSectionAsList() {
|
cannam@147
|
1002 return _::ListBuilder(segment, capTable, pointers, ONE * POINTERS * BITS_PER_POINTER / ELEMENTS,
|
cannam@147
|
1003 pointerCount * (ONE * ELEMENTS / POINTERS),
|
cannam@147
|
1004 ZERO * BITS, ONE * POINTERS, ElementSize::POINTER);
|
cannam@147
|
1005 }
|
cannam@147
|
1006
|
cannam@147
|
1007 template <typename T>
|
cannam@147
|
1008 inline bool StructBuilder::hasDataField(StructDataOffset offset) {
|
cannam@147
|
1009 return getDataField<Mask<T>>(offset) != 0;
|
cannam@147
|
1010 }
|
cannam@147
|
1011
|
cannam@147
|
1012 template <>
|
cannam@147
|
1013 inline bool StructBuilder::hasDataField<Void>(StructDataOffset offset) {
|
cannam@147
|
1014 return false;
|
cannam@147
|
1015 }
|
cannam@147
|
1016
|
cannam@147
|
1017 template <typename T>
|
cannam@147
|
1018 inline T StructBuilder::getDataField(StructDataOffset offset) {
|
cannam@147
|
1019 return reinterpret_cast<WireValue<T>*>(data)[unbound(offset / ELEMENTS)].get();
|
cannam@147
|
1020 }
|
cannam@147
|
1021
|
cannam@147
|
1022 template <>
|
cannam@147
|
1023 inline bool StructBuilder::getDataField<bool>(StructDataOffset offset) {
|
cannam@147
|
1024 BitCount32 boffset = offset * (ONE * BITS / ELEMENTS);
|
cannam@147
|
1025 byte* b = reinterpret_cast<byte*>(data) + boffset / BITS_PER_BYTE;
|
cannam@147
|
1026 return (*reinterpret_cast<uint8_t*>(b) &
|
cannam@147
|
1027 unbound(ONE << (boffset % BITS_PER_BYTE / BITS))) != 0;
|
cannam@147
|
1028 }
|
cannam@147
|
1029
|
cannam@147
|
1030 template <>
|
cannam@147
|
1031 inline Void StructBuilder::getDataField<Void>(StructDataOffset offset) {
|
cannam@147
|
1032 return VOID;
|
cannam@147
|
1033 }
|
cannam@147
|
1034
|
cannam@147
|
1035 template <typename T>
|
cannam@147
|
1036 inline T StructBuilder::getDataField(StructDataOffset offset, Mask<T> mask) {
|
cannam@147
|
1037 return unmask<T>(getDataField<Mask<T> >(offset), mask);
|
cannam@147
|
1038 }
|
cannam@147
|
1039
|
cannam@147
|
1040 template <typename T>
|
cannam@147
|
1041 inline void StructBuilder::setDataField(StructDataOffset offset, kj::NoInfer<T> value) {
|
cannam@147
|
1042 reinterpret_cast<WireValue<T>*>(data)[unbound(offset / ELEMENTS)].set(value);
|
cannam@147
|
1043 }
|
cannam@147
|
1044
|
cannam@147
|
1045 #if CAPNP_CANONICALIZE_NAN
|
cannam@147
|
1046 // Use mask() on floats and doubles to make sure we canonicalize NaNs.
|
cannam@147
|
1047 template <>
|
cannam@147
|
1048 inline void StructBuilder::setDataField<float>(StructDataOffset offset, float value) {
|
cannam@147
|
1049 setDataField<uint32_t>(offset, mask<float>(value, 0));
|
cannam@147
|
1050 }
|
cannam@147
|
1051 template <>
|
cannam@147
|
1052 inline void StructBuilder::setDataField<double>(StructDataOffset offset, double value) {
|
cannam@147
|
1053 setDataField<uint64_t>(offset, mask<double>(value, 0));
|
cannam@147
|
1054 }
|
cannam@147
|
1055 #endif
|
cannam@147
|
1056
|
cannam@147
|
1057 template <>
|
cannam@147
|
1058 inline void StructBuilder::setDataField<bool>(StructDataOffset offset, bool value) {
|
cannam@147
|
1059 auto boffset = offset * (ONE * BITS / ELEMENTS);
|
cannam@147
|
1060 byte* b = reinterpret_cast<byte*>(data) + boffset / BITS_PER_BYTE;
|
cannam@147
|
1061 uint bitnum = unboundMaxBits<3>(boffset % BITS_PER_BYTE / BITS);
|
cannam@147
|
1062 *reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << bitnum))
|
cannam@147
|
1063 | (static_cast<uint8_t>(value) << bitnum);
|
cannam@147
|
1064 }
|
cannam@147
|
1065
|
cannam@147
|
1066 template <>
|
cannam@147
|
1067 inline void StructBuilder::setDataField<Void>(StructDataOffset offset, Void value) {}
|
cannam@147
|
1068
|
cannam@147
|
1069 template <typename T>
|
cannam@147
|
1070 inline void StructBuilder::setDataField(StructDataOffset offset,
|
cannam@147
|
1071 kj::NoInfer<T> value, Mask<T> m) {
|
cannam@147
|
1072 setDataField<Mask<T> >(offset, mask<T>(value, m));
|
cannam@147
|
1073 }
|
cannam@147
|
1074
|
cannam@147
|
1075 inline PointerBuilder StructBuilder::getPointerField(StructPointerOffset ptrIndex) {
|
cannam@147
|
1076 // Hacky because WirePointer is defined in the .c++ file (so is incomplete here).
|
cannam@147
|
1077 return PointerBuilder(segment, capTable, reinterpret_cast<WirePointer*>(
|
cannam@147
|
1078 reinterpret_cast<word*>(pointers) + ptrIndex * WORDS_PER_POINTER));
|
cannam@147
|
1079 }
|
cannam@147
|
1080
|
cannam@147
|
1081 // -------------------------------------------------------------------
|
cannam@147
|
1082
|
cannam@147
|
1083 inline kj::ArrayPtr<const byte> StructReader::getDataSectionAsBlob() {
|
cannam@147
|
1084 return kj::ArrayPtr<const byte>(reinterpret_cast<const byte*>(data),
|
cannam@147
|
1085 unbound(dataSize / BITS_PER_BYTE / BYTES));
|
cannam@147
|
1086 }
|
cannam@147
|
1087
|
cannam@147
|
1088 inline _::ListReader StructReader::getPointerSectionAsList() {
|
cannam@147
|
1089 return _::ListReader(segment, capTable, pointers, pointerCount * (ONE * ELEMENTS / POINTERS),
|
cannam@147
|
1090 ONE * POINTERS * BITS_PER_POINTER / ELEMENTS, ZERO * BITS, ONE * POINTERS,
|
cannam@147
|
1091 ElementSize::POINTER, nestingLimit);
|
cannam@147
|
1092 }
|
cannam@147
|
1093
|
cannam@147
|
1094 template <typename T>
|
cannam@147
|
1095 inline bool StructReader::hasDataField(StructDataOffset offset) const {
|
cannam@147
|
1096 return getDataField<Mask<T>>(offset) != 0;
|
cannam@147
|
1097 }
|
cannam@147
|
1098
|
cannam@147
|
1099 template <>
|
cannam@147
|
1100 inline bool StructReader::hasDataField<Void>(StructDataOffset offset) const {
|
cannam@147
|
1101 return false;
|
cannam@147
|
1102 }
|
cannam@147
|
1103
|
cannam@147
|
1104 template <typename T>
|
cannam@147
|
1105 inline T StructReader::getDataField(StructDataOffset offset) const {
|
cannam@147
|
1106 if ((offset + ONE * ELEMENTS) * capnp::bitsPerElement<T>() <= dataSize) {
|
cannam@147
|
1107 return reinterpret_cast<const WireValue<T>*>(data)[unbound(offset / ELEMENTS)].get();
|
cannam@147
|
1108 } else {
|
cannam@147
|
1109 return static_cast<T>(0);
|
cannam@147
|
1110 }
|
cannam@147
|
1111 }
|
cannam@147
|
1112
|
cannam@147
|
1113 template <>
|
cannam@147
|
1114 inline bool StructReader::getDataField<bool>(StructDataOffset offset) const {
|
cannam@147
|
1115 auto boffset = offset * (ONE * BITS / ELEMENTS);
|
cannam@147
|
1116 if (boffset < dataSize) {
|
cannam@147
|
1117 const byte* b = reinterpret_cast<const byte*>(data) + boffset / BITS_PER_BYTE;
|
cannam@147
|
1118 return (*reinterpret_cast<const uint8_t*>(b) &
|
cannam@147
|
1119 unbound(ONE << (boffset % BITS_PER_BYTE / BITS))) != 0;
|
cannam@147
|
1120 } else {
|
cannam@147
|
1121 return false;
|
cannam@147
|
1122 }
|
cannam@147
|
1123 }
|
cannam@147
|
1124
|
cannam@147
|
1125 template <>
|
cannam@147
|
1126 inline Void StructReader::getDataField<Void>(StructDataOffset offset) const {
|
cannam@147
|
1127 return VOID;
|
cannam@147
|
1128 }
|
cannam@147
|
1129
|
cannam@147
|
1130 template <typename T>
|
cannam@147
|
1131 T StructReader::getDataField(StructDataOffset offset, Mask<T> mask) const {
|
cannam@147
|
1132 return unmask<T>(getDataField<Mask<T> >(offset), mask);
|
cannam@147
|
1133 }
|
cannam@147
|
1134
|
cannam@147
|
1135 inline PointerReader StructReader::getPointerField(StructPointerOffset ptrIndex) const {
|
cannam@147
|
1136 if (ptrIndex < pointerCount) {
|
cannam@147
|
1137 // Hacky because WirePointer is defined in the .c++ file (so is incomplete here).
|
cannam@147
|
1138 return PointerReader(segment, capTable, reinterpret_cast<const WirePointer*>(
|
cannam@147
|
1139 reinterpret_cast<const word*>(pointers) + ptrIndex * WORDS_PER_POINTER), nestingLimit);
|
cannam@147
|
1140 } else{
|
cannam@147
|
1141 return PointerReader();
|
cannam@147
|
1142 }
|
cannam@147
|
1143 }
|
cannam@147
|
1144
|
cannam@147
|
1145 // -------------------------------------------------------------------
|
cannam@147
|
1146
|
cannam@147
|
1147 inline ListElementCount ListBuilder::size() const { return elementCount; }
|
cannam@147
|
1148
|
cannam@147
|
1149 template <typename T>
|
cannam@147
|
1150 inline T ListBuilder::getDataElement(ElementCount index) {
|
cannam@147
|
1151 return reinterpret_cast<WireValue<T>*>(
|
cannam@147
|
1152 ptr + upgradeBound<uint64_t>(index) * step / BITS_PER_BYTE)->get();
|
cannam@147
|
1153
|
cannam@147
|
1154 // TODO(perf): Benchmark this alternate implementation, which I suspect may make better use of
|
cannam@147
|
1155 // the x86 SIB byte. Also use it for all the other getData/setData implementations below, and
|
cannam@147
|
1156 // the various non-inline methods that look up pointers.
|
cannam@147
|
1157 // Also if using this, consider changing ptr back to void* instead of byte*.
|
cannam@147
|
1158 // return reinterpret_cast<WireValue<T>*>(ptr)[
|
cannam@147
|
1159 // index / ELEMENTS * (step / capnp::bitsPerElement<T>())].get();
|
cannam@147
|
1160 }
|
cannam@147
|
1161
|
cannam@147
|
1162 template <>
|
cannam@147
|
1163 inline bool ListBuilder::getDataElement<bool>(ElementCount index) {
|
cannam@147
|
1164 // Ignore step for bit lists because bit lists cannot be upgraded to struct lists.
|
cannam@147
|
1165 auto bindex = index * (ONE * BITS / ELEMENTS);
|
cannam@147
|
1166 byte* b = ptr + bindex / BITS_PER_BYTE;
|
cannam@147
|
1167 return (*reinterpret_cast<uint8_t*>(b) &
|
cannam@147
|
1168 unbound(ONE << (bindex % BITS_PER_BYTE / BITS))) != 0;
|
cannam@147
|
1169 }
|
cannam@147
|
1170
|
cannam@147
|
1171 template <>
|
cannam@147
|
1172 inline Void ListBuilder::getDataElement<Void>(ElementCount index) {
|
cannam@147
|
1173 return VOID;
|
cannam@147
|
1174 }
|
cannam@147
|
1175
|
cannam@147
|
1176 template <typename T>
|
cannam@147
|
1177 inline void ListBuilder::setDataElement(ElementCount index, kj::NoInfer<T> value) {
|
cannam@147
|
1178 reinterpret_cast<WireValue<T>*>(
|
cannam@147
|
1179 ptr + upgradeBound<uint64_t>(index) * step / BITS_PER_BYTE)->set(value);
|
cannam@147
|
1180 }
|
cannam@147
|
1181
|
cannam@147
|
1182 #if CAPNP_CANONICALIZE_NAN
|
cannam@147
|
1183 // Use mask() on floats and doubles to make sure we canonicalize NaNs.
|
cannam@147
|
1184 template <>
|
cannam@147
|
1185 inline void ListBuilder::setDataElement<float>(ElementCount index, float value) {
|
cannam@147
|
1186 setDataElement<uint32_t>(index, mask<float>(value, 0));
|
cannam@147
|
1187 }
|
cannam@147
|
1188 template <>
|
cannam@147
|
1189 inline void ListBuilder::setDataElement<double>(ElementCount index, double value) {
|
cannam@147
|
1190 setDataElement<uint64_t>(index, mask<double>(value, 0));
|
cannam@147
|
1191 }
|
cannam@147
|
1192 #endif
|
cannam@147
|
1193
|
cannam@147
|
1194 template <>
|
cannam@147
|
1195 inline void ListBuilder::setDataElement<bool>(ElementCount index, bool value) {
|
cannam@147
|
1196 // Ignore stepBytes for bit lists because bit lists cannot be upgraded to struct lists.
|
cannam@147
|
1197 auto bindex = index * (ONE * BITS / ELEMENTS);
|
cannam@147
|
1198 byte* b = ptr + bindex / BITS_PER_BYTE;
|
cannam@147
|
1199 auto bitnum = bindex % BITS_PER_BYTE / BITS;
|
cannam@147
|
1200 *reinterpret_cast<uint8_t*>(b) = (*reinterpret_cast<uint8_t*>(b) & ~(1 << unbound(bitnum)))
|
cannam@147
|
1201 | (static_cast<uint8_t>(value) << unbound(bitnum));
|
cannam@147
|
1202 }
|
cannam@147
|
1203
|
cannam@147
|
1204 template <>
|
cannam@147
|
1205 inline void ListBuilder::setDataElement<Void>(ElementCount index, Void value) {}
|
cannam@147
|
1206
|
cannam@147
|
1207 inline PointerBuilder ListBuilder::getPointerElement(ElementCount index) {
|
cannam@147
|
1208 return PointerBuilder(segment, capTable, reinterpret_cast<WirePointer*>(ptr +
|
cannam@147
|
1209 upgradeBound<uint64_t>(index) * step / BITS_PER_BYTE));
|
cannam@147
|
1210 }
|
cannam@147
|
1211
|
cannam@147
|
1212 // -------------------------------------------------------------------
|
cannam@147
|
1213
|
cannam@147
|
1214 inline ListElementCount ListReader::size() const { return elementCount; }
|
cannam@147
|
1215
|
cannam@147
|
1216 template <typename T>
|
cannam@147
|
1217 inline T ListReader::getDataElement(ElementCount index) const {
|
cannam@147
|
1218 return reinterpret_cast<const WireValue<T>*>(
|
cannam@147
|
1219 ptr + upgradeBound<uint64_t>(index) * step / BITS_PER_BYTE)->get();
|
cannam@147
|
1220 }
|
cannam@147
|
1221
|
cannam@147
|
1222 template <>
|
cannam@147
|
1223 inline bool ListReader::getDataElement<bool>(ElementCount index) const {
|
cannam@147
|
1224 // Ignore step for bit lists because bit lists cannot be upgraded to struct lists.
|
cannam@147
|
1225 auto bindex = index * (ONE * BITS / ELEMENTS);
|
cannam@147
|
1226 const byte* b = ptr + bindex / BITS_PER_BYTE;
|
cannam@147
|
1227 return (*reinterpret_cast<const uint8_t*>(b) &
|
cannam@147
|
1228 unbound(ONE << (bindex % BITS_PER_BYTE / BITS))) != 0;
|
cannam@147
|
1229 }
|
cannam@147
|
1230
|
cannam@147
|
1231 template <>
|
cannam@147
|
1232 inline Void ListReader::getDataElement<Void>(ElementCount index) const {
|
cannam@147
|
1233 return VOID;
|
cannam@147
|
1234 }
|
cannam@147
|
1235
|
cannam@147
|
1236 inline PointerReader ListReader::getPointerElement(ElementCount index) const {
|
cannam@147
|
1237 return PointerReader(segment, capTable, reinterpret_cast<const WirePointer*>(
|
cannam@147
|
1238 ptr + upgradeBound<uint64_t>(index) * step / BITS_PER_BYTE), nestingLimit);
|
cannam@147
|
1239 }
|
cannam@147
|
1240
|
cannam@147
|
1241 // -------------------------------------------------------------------
|
cannam@147
|
1242
|
cannam@147
|
1243 inline OrphanBuilder::OrphanBuilder(OrphanBuilder&& other) noexcept
|
cannam@147
|
1244 : segment(other.segment), capTable(other.capTable), location(other.location) {
|
cannam@147
|
1245 memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules.
|
cannam@147
|
1246 other.segment = nullptr;
|
cannam@147
|
1247 other.location = nullptr;
|
cannam@147
|
1248 }
|
cannam@147
|
1249
|
cannam@147
|
1250 inline OrphanBuilder::~OrphanBuilder() noexcept(false) {
|
cannam@147
|
1251 if (segment != nullptr) euthanize();
|
cannam@147
|
1252 }
|
cannam@147
|
1253
|
cannam@147
|
1254 inline OrphanBuilder& OrphanBuilder::operator=(OrphanBuilder&& other) {
|
cannam@147
|
1255 // With normal smart pointers, it's important to handle the case where the incoming pointer
|
cannam@147
|
1256 // is actually transitively owned by this one. In this case, euthanize() would destroy `other`
|
cannam@147
|
1257 // before we copied it. This isn't possible in the case of `OrphanBuilder` because it only
|
cannam@147
|
1258 // owns message objects, and `other` is not itself a message object, therefore cannot possibly
|
cannam@147
|
1259 // be transitively owned by `this`.
|
cannam@147
|
1260
|
cannam@147
|
1261 if (segment != nullptr) euthanize();
|
cannam@147
|
1262 segment = other.segment;
|
cannam@147
|
1263 capTable = other.capTable;
|
cannam@147
|
1264 location = other.location;
|
cannam@147
|
1265 memcpy(&tag, &other.tag, sizeof(tag)); // Needs memcpy to comply with aliasing rules.
|
cannam@147
|
1266 other.segment = nullptr;
|
cannam@147
|
1267 other.location = nullptr;
|
cannam@147
|
1268 return *this;
|
cannam@147
|
1269 }
|
cannam@147
|
1270
|
cannam@147
|
1271 } // namespace _ (private)
|
cannam@147
|
1272 } // namespace capnp
|
cannam@147
|
1273
|
cannam@147
|
1274 #endif // CAPNP_LAYOUT_H_
|