layout.c++ 112 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
21

Kenton Varda's avatar
Kenton Varda committed
22
#define CAPNP_PRIVATE
23
#include "layout.h"
Kenton Varda's avatar
Kenton Varda committed
24
#include <kj/debug.h>
25
#include "arena.h"
26
#include <string.h>
27
#include <stdlib.h>
28

29 30 31 32
#if !CAPNP_LITE
#include "capability.h"
#endif  // !CAPNP_LITE

33
namespace capnp {
34
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
35

36
#if !CAPNP_LITE
37 38 39 40 41
static BrokenCapFactory* brokenCapFactory = nullptr;
// Horrible hack:  We need to be able to construct broken caps without any capability context,
// but we can't have a link-time dependency on libcapnp-rpc.

void setGlobalBrokenCapFactoryForLayoutCpp(BrokenCapFactory& factory) {
42 43
  // Called from capability.c++ when the capability API is used, to make sure that layout.c++
  // is ready for it.  May be called multiple times but always with the same value.
44 45
  __atomic_store_n(&brokenCapFactory, &factory, __ATOMIC_RELAXED);
}
46
#endif  // !CAPNP_LITE
47

48 49
// =======================================================================================

50 51
struct WirePointer {
  // A pointer, in exactly the format in which it appears on the wire.
52 53

  // Copying and moving is not allowed because the offset would become wrong.
54 55 56 57
  WirePointer(const WirePointer& other) = delete;
  WirePointer(WirePointer&& other) = delete;
  WirePointer& operator=(const WirePointer& other) = delete;
  WirePointer& operator=(WirePointer&& other) = delete;
58

59
  // -----------------------------------------------------------------
60
  // Common part of all pointers:  kind + offset
61 62 63
  //
  // Actually this is not terribly common.  The "offset" could actually be different things
  // depending on the context:
64 65
  // - For a regular (e.g. struct/list) pointer, a signed word offset from the word immediately
  //   following the pointer pointer.  (The off-by-one means the offset is more often zero, saving
66
  //   bytes on the wire when packed.)
67
  // - For an inline composite list tag (not really a pointer, but structured similarly), an
68
  //   element count.
69
  // - For a FAR pointer, an unsigned offset into the target segment.
70
  // - For a FAR landing pad, zero indicates that the target value immediately follows the pad while
71
  //   1 indicates that the pad is followed by another FAR pointer that actually points at the
72 73 74
  //   value.

  enum Kind {
75
    STRUCT = 0,
76 77
    // Reference points at / describes a struct.

78
    LIST = 1,
79 80 81 82 83 84
    // Reference points at / describes a list.

    FAR = 2,
    // Reference is a "far pointer", which points at data located in a different segment.  The
    // eventual target is one of the other kinds.

85 86 87
    OTHER = 3
    // Reference has type "other".  If the next 30 bits are all zero (i.e. the lower 32 bits contain
    // only the kind OTHER) then the pointer is a capability.  All other values are reserved.
88 89
  };

90 91
  WireValue<uint32_t> offsetAndKind;

92
  KJ_ALWAYS_INLINE(Kind kind() const) {
93 94
    return static_cast<Kind>(offsetAndKind.get() & 3);
  }
95 96 97 98 99 100
  KJ_ALWAYS_INLINE(bool isPositional() const) {
    return (offsetAndKind.get() & 2) == 0;  // match STRUCT and LIST but not FAR or OTHER
  }
  KJ_ALWAYS_INLINE(bool isCapability() const) {
    return offsetAndKind.get() == OTHER;
  }
101

102
  KJ_ALWAYS_INLINE(word* target()) {
103
    return reinterpret_cast<word*>(this) + 1 + (static_cast<int32_t>(offsetAndKind.get()) >> 2);
104
  }
105
  KJ_ALWAYS_INLINE(const word* target() const) {
106 107
    return reinterpret_cast<const word*>(this) + 1 +
        (static_cast<int32_t>(offsetAndKind.get()) >> 2);
108
  }
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
  KJ_ALWAYS_INLINE(void setKindAndTarget(Kind kind, word* target, SegmentBuilder* segment)) {
    // Check that the target is really in the same segment, otherwise subtracting pointers is
    // undefined behavior.  As it turns out, it's undefined behavior that actually produces
    // unexpected results in a real-world situation that actually happened:  At one time,
    // OrphanBuilder's "tag" (a WirePointer) was allowed to be initialized as if it lived in
    // a particular segment when in fact it does not.  On 32-bit systems, where words might
    // only be 32-bit aligned, it's possible that the difference between `this` and `target` is
    // not a whole number of words.  But clang optimizes:
    //     (target - (word*)this - 1) << 2
    // to:
    //     (((ptrdiff_t)target - (ptrdiff_t)this - 8) >> 1)
    // So now when the pointers are not aligned the same, we can end up corrupting the bottom
    // two bits, where `kind` is stored.  For example, this turns a struct into a far pointer.
    // Ouch!
    KJ_DREQUIRE(segment->containsInterval(
        reinterpret_cast<word*>(this), reinterpret_cast<word*>(this + 1)));
    KJ_DREQUIRE(segment->containsInterval(target, target));
126
    offsetAndKind.set(((target - reinterpret_cast<word*>(this) - 1) << 2) | kind);
127
  }
128
  KJ_ALWAYS_INLINE(void setKindWithZeroOffset(Kind kind)) {
129 130
    offsetAndKind.set(kind);
  }
131 132 133 134 135 136 137 138 139 140
  KJ_ALWAYS_INLINE(void setKindAndTargetForEmptyStruct()) {
    // This pointer points at an empty struct.  Assuming the WirePointer itself is in-bounds, we
    // can set the target to point either at the WirePointer itself or immediately after it.  The
    // latter would cause the WirePointer to be "null" (since for an empty struct the upper 32
    // bits are going to be zero).  So we set an offset of -1, as if the struct were allocated
    // immediately before this pointer, to distinguish it from null.
    offsetAndKind.set(0xfffffffc);
  }
  KJ_ALWAYS_INLINE(void setKindForOrphan(Kind kind)) {
    // OrphanBuilder contains a WirePointer, but since it isn't located in a segment, it should
141 142 143 144
    // not have a valid offset (unless it is a FAR or OTHER pointer).  We set its offset to -1
    // because setting it to zero would mean a pointer to an empty struct would appear to be a null
    // pointer.
    KJ_DREQUIRE(isPositional());
145 146
    offsetAndKind.set(kind | 0xfffffffc);
  }
147

148
  KJ_ALWAYS_INLINE(ElementCount inlineCompositeListElementCount() const) {
149 150
    return (offsetAndKind.get() >> 2) * ELEMENTS;
  }
151
  KJ_ALWAYS_INLINE(void setKindAndInlineCompositeListElementCount(
152 153 154 155
      Kind kind, ElementCount elementCount)) {
    offsetAndKind.set(((elementCount / ELEMENTS) << 2) | kind);
  }

156
  KJ_ALWAYS_INLINE(WordCount farPositionInSegment() const) {
157
    KJ_DREQUIRE(kind() == FAR,
158
        "positionInSegment() should only be called on FAR pointers.");
159
    return (offsetAndKind.get() >> 3) * WORDS;
160
  }
161
  KJ_ALWAYS_INLINE(bool isDoubleFar() const) {
162
    KJ_DREQUIRE(kind() == FAR,
163
        "isDoubleFar() should only be called on FAR pointers.");
164
    return (offsetAndKind.get() >> 2) & 1;
165
  }
166
  KJ_ALWAYS_INLINE(void setFar(bool isDoubleFar, WordCount pos)) {
167 168
    offsetAndKind.set(((pos / WORDS) << 3) | (static_cast<uint32_t>(isDoubleFar) << 2) |
                      static_cast<uint32_t>(Kind::FAR));
169
  }
170 171 172 173
  KJ_ALWAYS_INLINE(void setCap(uint index)) {
    offsetAndKind.set(static_cast<uint32_t>(Kind::OTHER));
    capRef.index.set(index);
  }
174 175

  // -----------------------------------------------------------------
176
  // Part of pointer that depends on the kind.
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
  // Note:  Originally StructRef, ListRef, and FarRef were unnamed types, but this somehow
  //   tickled a bug in GCC:
  //     http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58192
  struct StructRef {
    WireValue<WordCount16> dataSize;
    WireValue<WirePointerCount16> ptrCount;

    inline WordCount wordSize() const {
      return dataSize.get() + ptrCount.get() * WORDS_PER_POINTER;
    }

    KJ_ALWAYS_INLINE(void set(WordCount ds, WirePointerCount rc)) {
      dataSize.set(ds);
      ptrCount.set(rc);
    }
    KJ_ALWAYS_INLINE(void set(StructSize size)) {
      dataSize.set(size.data);
      ptrCount.set(size.pointers);
    }
  };

  struct ListRef {
    WireValue<uint32_t> elementSizeAndCount;

202 203
    KJ_ALWAYS_INLINE(ElementSize elementSize() const) {
      return static_cast<ElementSize>(elementSizeAndCount.get() & 7);
204 205 206 207 208 209 210 211
    }
    KJ_ALWAYS_INLINE(ElementCount elementCount() const) {
      return (elementSizeAndCount.get() >> 3) * ELEMENTS;
    }
    KJ_ALWAYS_INLINE(WordCount inlineCompositeWordCount() const) {
      return elementCount() * (1 * WORDS / ELEMENTS);
    }

212
    KJ_ALWAYS_INLINE(void set(ElementSize es, ElementCount ec)) {
213 214 215 216 217 218 219
      KJ_DREQUIRE(ec < (1 << 29) * ELEMENTS, "Lists are limited to 2**29 elements.");
      elementSizeAndCount.set(((ec / ELEMENTS) << 3) | static_cast<int>(es));
    }

    KJ_ALWAYS_INLINE(void setInlineComposite(WordCount wc)) {
      KJ_DREQUIRE(wc < (1 << 29) * WORDS, "Inline composite lists are limited to 2**29 words.");
      elementSizeAndCount.set(((wc / WORDS) << 3) |
220
                              static_cast<int>(ElementSize::INLINE_COMPOSITE));
221 222 223 224 225 226 227 228 229 230 231
    }
  };

  struct FarRef {
    WireValue<SegmentId> segmentId;

    KJ_ALWAYS_INLINE(void set(SegmentId si)) {
      segmentId.set(si);
    }
  };

232 233 234 235 236
  struct CapRef {
    WireValue<uint32_t> index;
    // Index into the message's capability table.
  };

237
  union {
238 239
    uint32_t upper32Bits;

240
    StructRef structRef;
241

242 243 244
    ListRef listRef;

    FarRef farRef;
245 246

    CapRef capRef;
247
  };
248

249
  KJ_ALWAYS_INLINE(bool isNull() const) {
250 251 252 253
    // If the upper 32 bits are zero, this is a pointer to an empty struct.  We consider that to be
    // our "null" value.
    return (offsetAndKind.get() == 0) & (upper32Bits == 0);
  }
254

255
};
256
static_assert(sizeof(WirePointer) == sizeof(word),
257
    "capnp::WirePointer is not exactly one word.  This will probably break everything.");
258 259 260 261 262 263
static_assert(POINTERS * WORDS_PER_POINTER * BYTES_PER_WORD / BYTES == sizeof(WirePointer),
    "WORDS_PER_POINTER is wrong.");
static_assert(POINTERS * BYTES_PER_POINTER / BYTES == sizeof(WirePointer),
    "BYTES_PER_POINTER is wrong.");
static_assert(POINTERS * BITS_PER_POINTER / BITS_PER_BYTE / BYTES == sizeof(WirePointer),
    "BITS_PER_POINTER is wrong.");
264

265 266 267 268 269 270 271 272 273
namespace {

static const union {
  AlignedData<POINTER_SIZE_IN_WORDS / WORDS> word;
  WirePointer pointer;
} zero = {{{0}}};

}  // namespace

274 275
// =======================================================================================

276 277 278 279 280 281 282 283 284 285
namespace {

template <typename T>
struct SegmentAnd {
  SegmentBuilder* segment;
  T value;
};

}  // namespace

286
struct WireHelpers {
287
  static KJ_ALWAYS_INLINE(WordCount roundBytesUpToWords(ByteCount bytes)) {
Kenton Varda's avatar
Kenton Varda committed
288
    static_assert(sizeof(word) == 8, "This code assumes 64-bit words.");
289 290 291
    return (bytes + 7 * BYTES) / BYTES_PER_WORD;
  }

292
  static KJ_ALWAYS_INLINE(ByteCount roundBitsUpToBytes(BitCount bits)) {
293
    return (bits + 7 * BITS) / BITS_PER_BYTE;
Kenton Varda's avatar
Kenton Varda committed
294 295
  }

296
  static KJ_ALWAYS_INLINE(WordCount64 roundBitsUpToWords(BitCount64 bits)) {
297 298 299 300
    static_assert(sizeof(word) == 8, "This code assumes 64-bit words.");
    return (bits + 63 * BITS) / BITS_PER_WORD;
  }

301
  static KJ_ALWAYS_INLINE(ByteCount64 roundBitsUpToBytes(BitCount64 bits)) {
302 303 304
    return (bits + 7 * BITS) / BITS_PER_BYTE;
  }

305
  static KJ_ALWAYS_INLINE(bool boundsCheck(
306
      SegmentReader* segment, const word* start, const word* end)) {
307
    // If segment is null, this is an unchecked message, so we don't do bounds checks.
308 309 310
    return segment == nullptr || segment->containsInterval(start, end);
  }

311 312 313 314 315
  static KJ_ALWAYS_INLINE(bool amplifiedRead(SegmentReader* segment, WordCount virtualAmount)) {
    // If segment is null, this is an unchecked message, so we don't do read limiter checks.
    return segment == nullptr || segment->amplifiedRead(virtualAmount);
  }

316
  static KJ_ALWAYS_INLINE(word* allocate(
317
      WirePointer*& ref, SegmentBuilder*& segment, WordCount amount,
318
      WirePointer::Kind kind, BuilderArena* orphanArena)) {
David Renshaw's avatar
David Renshaw committed
319
    // Allocate space in the message for a new object, creating far pointers if necessary.
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
    //
    // * `ref` starts out being a reference to the pointer which shall be assigned to point at the
    //   new object.  On return, `ref` points to a pointer which needs to be initialized with
    //   the object's type information.  Normally this is the same pointer, but it can change if
    //   a far pointer was allocated -- in this case, `ref` will end up pointing to the far
    //   pointer's tag.  Either way, `allocate()` takes care of making sure that the original
    //   pointer ends up leading to the new object.  On return, only the upper 32 bit of `*ref`
    //   need to be filled in by the caller.
    // * `segment` starts out pointing to the segment containing `ref`.  On return, it points to
    //   the segment containing the allocated object, which is usually the same segment but could
    //   be a different one if the original segment was out of space.
    // * `amount` is the number of words to allocate.
    // * `kind` is the kind of object to allocate.  It is used to initialize the pointer.  It
    //   cannot be `FAR` -- far pointers are allocated automatically as needed.
    // * `orphanArena` is usually null.  If it is non-null, then we're allocating an orphan object.
    //   In this case, `segment` starts out null; the allocation takes place in an arbitrary
    //   segment belonging to the arena.  `ref` will be initialized as a non-far pointer, but its
    //   target offset will be set to zero.

    if (orphanArena == nullptr) {
      if (!ref->isNull()) zeroObject(segment, ref);

342 343 344 345 346 347 348
      if (amount == 0 * WORDS && kind == WirePointer::STRUCT) {
        // Note that the check for kind == WirePointer::STRUCT will hopefully cause this whole
        // branch to be optimized away from all the call sites that are allocating non-structs.
        ref->setKindAndTargetForEmptyStruct();
        return reinterpret_cast<word*>(ref);
      }

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
      word* ptr = segment->allocate(amount);

      if (ptr == nullptr) {
        // Need to allocate in a new segment.  We'll need to allocate an extra pointer worth of
        // space to act as the landing pad for a far pointer.

        WordCount amountPlusRef = amount + POINTER_SIZE_IN_WORDS;
        auto allocation = segment->getArena()->allocate(amountPlusRef);
        segment = allocation.segment;
        ptr = allocation.words;

        // Set up the original pointer to be a far pointer to the new segment.
        ref->setFar(false, segment->getOffsetTo(ptr));
        ref->farRef.set(segment->getSegmentId());

        // Initialize the landing pad to indicate that the data immediately follows the pad.
        ref = reinterpret_cast<WirePointer*>(ptr);
366
        ref->setKindAndTarget(kind, ptr + POINTER_SIZE_IN_WORDS, segment);
367 368 369 370

        // Allocated space follows new pointer.
        return ptr + POINTER_SIZE_IN_WORDS;
      } else {
371
        ref->setKindAndTarget(kind, ptr, segment);
372 373
        return ptr;
      }
374
    } else {
375
      // orphanArena is non-null.  Allocate an orphan.
376
      KJ_DASSERT(ref->isNull());
377 378
      auto allocation = orphanArena->allocate(amount);
      segment = allocation.segment;
379
      ref->setKindForOrphan(kind);
380
      return allocation.words;
381 382 383
    }
  }

384
  static KJ_ALWAYS_INLINE(word* followFarsNoWritableCheck(
385 386 387 388 389 390 391 392 393 394
      WirePointer*& ref, word* refTarget, SegmentBuilder*& segment)) {
    // If `ref` is a far pointer, follow it.  On return, `ref` will have been updated to point at
    // a WirePointer that contains the type information about the target object, and a pointer to
    // the object contents is returned.  The caller must NOT use `ref->target()` as this may or may
    // not actually return a valid pointer.  `segment` is also updated to point at the segment which
    // actually contains the object.
    //
    // If `ref` is not a far pointer, this simply returns `refTarget`.  Usually, `refTarget` should
    // be the same as `ref->target()`, but may not be in cases where `ref` is only a tag.

395
    if (ref->kind() == WirePointer::FAR) {
396
      segment = segment->getArena()->getSegment(ref->farRef.segmentId.get());
397 398
      WirePointer* pad =
          reinterpret_cast<WirePointer*>(segment->getPtrUnchecked(ref->farPositionInSegment()));
399 400 401
      if (!ref->isDoubleFar()) {
        ref = pad;
        return pad->target();
402
      }
403 404 405 406 407 408 409

      // Landing pad is another far pointer.  It is followed by a tag describing the pointed-to
      // object.
      ref = pad + 1;

      segment = segment->getArena()->getSegment(pad->farRef.segmentId.get());
      return segment->getPtrUnchecked(pad->farPositionInSegment());
410
    } else {
411
      return refTarget;
412 413 414
    }
  }

415 416 417 418 419 420 421
  static KJ_ALWAYS_INLINE(word* followFars(
      WirePointer*& ref, word* refTarget, SegmentBuilder*& segment)) {
    auto result = followFarsNoWritableCheck(ref, refTarget, segment);
    segment->checkWritable();
    return result;
  }

422 423 424
  static KJ_ALWAYS_INLINE(const word* followFars(
      const WirePointer*& ref, const word* refTarget, SegmentReader*& segment)) {
    // Like the other followFars() but operates on readers.
425

426
    // If the segment is null, this is an unchecked message, so there are no FAR pointers.
427
    if (segment != nullptr && ref->kind() == WirePointer::FAR) {
428
      // Look up the segment containing the landing pad.
429
      segment = segment->getArena()->tryGetSegment(ref->farRef.segmentId.get());
430
      KJ_REQUIRE(segment != nullptr, "Message contains far pointer to unknown segment.") {
431
        return nullptr;
Kenton Varda's avatar
Kenton Varda committed
432
      }
433

434 435
      // Find the landing pad and check that it is within bounds.
      const word* ptr = segment->getStartPtr() + ref->farPositionInSegment();
436
      WordCount padWords = (1 + ref->isDoubleFar()) * POINTER_SIZE_IN_WORDS;
437 438
      KJ_REQUIRE(boundsCheck(segment, ptr, ptr + padWords),
                 "Message contains out-of-bounds far pointer.") {
439
        return nullptr;
440 441
      }

442
      const WirePointer* pad = reinterpret_cast<const WirePointer*>(ptr);
443 444 445 446 447 448 449 450 451 452 453 454

      // If this is not a double-far then the landing pad is our final pointer.
      if (!ref->isDoubleFar()) {
        ref = pad;
        return pad->target();
      }

      // Landing pad is another far pointer.  It is followed by a tag describing the pointed-to
      // object.
      ref = pad + 1;

      segment = segment->getArena()->tryGetSegment(pad->farRef.segmentId.get());
455
      KJ_REQUIRE(segment != nullptr, "Message contains double-far pointer to unknown segment.") {
456
        return nullptr;
457
      }
458 459

      return segment->getStartPtr() + pad->farPositionInSegment();
460
    } else {
461
      return refTarget;
462 463 464
    }
  }

465 466
  // -----------------------------------------------------------------

467 468 469 470
  static void zeroObject(SegmentBuilder* segment, WirePointer* ref) {
    // Zero out the pointed-to object.  Use when the pointer is about to be overwritten making the
    // target object no longer reachable.

471 472 473
    // We shouldn't zero out external data linked into the message.
    if (!segment->isWritable()) return;

474 475 476 477 478 479 480
    switch (ref->kind()) {
      case WirePointer::STRUCT:
      case WirePointer::LIST:
        zeroObject(segment, ref, ref->target());
        break;
      case WirePointer::FAR: {
        segment = segment->getArena()->getSegment(ref->farRef.segmentId.get());
481 482 483 484 485 486 487 488 489 490 491 492 493 494
        if (segment->isWritable()) {  // Don't zero external data.
          WirePointer* pad =
              reinterpret_cast<WirePointer*>(segment->getPtrUnchecked(ref->farPositionInSegment()));

          if (ref->isDoubleFar()) {
            segment = segment->getArena()->getSegment(pad->farRef.segmentId.get());
            if (segment->isWritable()) {
              zeroObject(segment, pad + 1, segment->getPtrUnchecked(pad->farPositionInSegment()));
            }
            memset(pad, 0, sizeof(WirePointer) * 2);
          } else {
            zeroObject(segment, pad);
            memset(pad, 0, sizeof(WirePointer));
          }
495 496 497
        }
        break;
      }
498 499
      case WirePointer::OTHER:
        if (ref->isCapability()) {
500 501 502
#if CAPNP_LITE
          KJ_FAIL_ASSERT("Capability encountered in builder in lite mode?") { break; }
#else  // CAPNP_LINE
503
          segment->getArena()->dropCap(ref->capRef.index.get());
504
#endif  // CAPNP_LITE, else
505 506 507 508
        } else {
          KJ_FAIL_REQUIRE("Unknown pointer type.") { break; }
        }
        break;
509 510 511 512
    }
  }

  static void zeroObject(SegmentBuilder* segment, WirePointer* tag, word* ptr) {
513 514 515
    // We shouldn't zero out external data linked into the message.
    if (!segment->isWritable()) return;

516 517 518 519 520 521 522 523 524 525 526 527 528
    switch (tag->kind()) {
      case WirePointer::STRUCT: {
        WirePointer* pointerSection =
            reinterpret_cast<WirePointer*>(ptr + tag->structRef.dataSize.get());
        uint count = tag->structRef.ptrCount.get() / POINTERS;
        for (uint i = 0; i < count; i++) {
          zeroObject(segment, pointerSection + i);
        }
        memset(ptr, 0, tag->structRef.wordSize() * BYTES_PER_WORD / BYTES);
        break;
      }
      case WirePointer::LIST: {
        switch (tag->listRef.elementSize()) {
529
          case ElementSize::VOID:
530 531
            // Nothing.
            break;
532 533 534 535 536
          case ElementSize::BIT:
          case ElementSize::BYTE:
          case ElementSize::TWO_BYTES:
          case ElementSize::FOUR_BYTES:
          case ElementSize::EIGHT_BYTES:
537
            memset(ptr, 0,
538 539
                roundBitsUpToWords(ElementCount64(tag->listRef.elementCount()) *
                                   dataBitsPerElement(tag->listRef.elementSize()))
540 541
                    * BYTES_PER_WORD / BYTES);
            break;
542
          case ElementSize::POINTER: {
543 544 545 546
            uint count = tag->listRef.elementCount() / ELEMENTS;
            for (uint i = 0; i < count; i++) {
              zeroObject(segment, reinterpret_cast<WirePointer*>(ptr) + i);
            }
547
            memset(ptr, 0, POINTER_SIZE_IN_WORDS * count * BYTES_PER_WORD / BYTES);
548 549
            break;
          }
550
          case ElementSize::INLINE_COMPOSITE: {
551 552
            WirePointer* elementTag = reinterpret_cast<WirePointer*>(ptr);

553
            KJ_ASSERT(elementTag->kind() == WirePointer::STRUCT,
554 555 556 557 558
                  "Don't know how to handle non-STRUCT inline composite.");
            WordCount dataSize = elementTag->structRef.dataSize.get();
            WirePointerCount pointerCount = elementTag->structRef.ptrCount.get();

            uint count = elementTag->inlineCompositeListElementCount() / ELEMENTS;
559 560 561 562 563 564 565 566 567
            if (pointerCount > 0 * POINTERS) {
              word* pos = ptr + POINTER_SIZE_IN_WORDS;
              for (uint i = 0; i < count; i++) {
                pos += dataSize;

                for (uint j = 0; j < pointerCount / POINTERS; j++) {
                  zeroObject(segment, reinterpret_cast<WirePointer*>(pos));
                  pos += POINTER_SIZE_IN_WORDS;
                }
568 569 570
              }
            }

571
            memset(ptr, 0, (elementTag->structRef.wordSize() * count + POINTER_SIZE_IN_WORDS)
572 573 574 575 576 577 578
                           * BYTES_PER_WORD / BYTES);
            break;
          }
        }
        break;
      }
      case WirePointer::FAR:
579 580 581
        KJ_FAIL_ASSERT("Unexpected FAR pointer.") {
          break;
        }
582
        break;
583 584 585 586 587
      case WirePointer::OTHER:
        KJ_FAIL_ASSERT("Unexpected OTHER pointer.") {
          break;
        }
        break;
588 589 590
    }
  }

591
  static KJ_ALWAYS_INLINE(
592 593 594 595 596
      void zeroPointerAndFars(SegmentBuilder* segment, WirePointer* ref)) {
    // Zero out the pointer itself and, if it is a far pointer, zero the landing pad as well, but
    // do not zero the object body.  Used when upgrading.

    if (ref->kind() == WirePointer::FAR) {
597 598 599 600 601
      SegmentBuilder* padSegment = segment->getArena()->getSegment(ref->farRef.segmentId.get());
      if (padSegment->isWritable()) {  // Don't zero external data.
        word* pad = padSegment->getPtrUnchecked(ref->farPositionInSegment());
        memset(pad, 0, sizeof(WirePointer) * (1 + ref->isDoubleFar()));
      }
602 603 604 605
    }
    memset(ref, 0, sizeof(*ref));
  }

606 607 608

  // -----------------------------------------------------------------

609 610
  static MessageSizeCounts totalSize(
      SegmentReader* segment, const WirePointer* ref, int nestingLimit) {
611 612
    // Compute the total size of the object pointed to, not counting far pointer overhead.

613 614
    MessageSizeCounts result = { 0 * WORDS, 0 };

615
    if (ref->isNull()) {
616
      return result;
617 618
    }

619
    KJ_REQUIRE(nestingLimit > 0, "Message is too deeply-nested.") {
620
      return result;
621 622 623
    }
    --nestingLimit;

624
    const word* ptr = followFars(ref, ref->target(), segment);
625 626

    switch (ref->kind()) {
627
      case WirePointer::STRUCT: {
628 629 630
        KJ_REQUIRE(boundsCheck(segment, ptr, ptr + ref->structRef.wordSize()),
                   "Message contained out-of-bounds struct pointer.") {
          return result;
631
        }
632
        result.wordCount += ref->structRef.wordSize();
633 634 635 636 637 638 639 640 641 642 643

        const WirePointer* pointerSection =
            reinterpret_cast<const WirePointer*>(ptr + ref->structRef.dataSize.get());
        uint count = ref->structRef.ptrCount.get() / POINTERS;
        for (uint i = 0; i < count; i++) {
          result += totalSize(segment, pointerSection + i, nestingLimit);
        }
        break;
      }
      case WirePointer::LIST: {
        switch (ref->listRef.elementSize()) {
644
          case ElementSize::VOID:
645 646
            // Nothing.
            break;
647 648 649 650 651
          case ElementSize::BIT:
          case ElementSize::BYTE:
          case ElementSize::TWO_BYTES:
          case ElementSize::FOUR_BYTES:
          case ElementSize::EIGHT_BYTES: {
652
            WordCount64 totalWords = roundBitsUpToWords(
653 654
                ElementCount64(ref->listRef.elementCount()) *
                dataBitsPerElement(ref->listRef.elementSize()));
655 656 657
            KJ_REQUIRE(boundsCheck(segment, ptr, ptr + totalWords),
                       "Message contained out-of-bounds list pointer.") {
              return result;
658
            }
659
            result.wordCount += totalWords;
660 661
            break;
          }
662
          case ElementSize::POINTER: {
663 664
            WirePointerCount count = ref->listRef.elementCount() * (POINTERS / ELEMENTS);

665 666 667
            KJ_REQUIRE(boundsCheck(segment, ptr, ptr + count * WORDS_PER_POINTER),
                       "Message contained out-of-bounds list pointer.") {
              return result;
668 669
            }

670
            result.wordCount += count * WORDS_PER_POINTER;
671 672 673 674 675 676 677

            for (uint i = 0; i < count / POINTERS; i++) {
              result += totalSize(segment, reinterpret_cast<const WirePointer*>(ptr) + i,
                                  nestingLimit);
            }
            break;
          }
678
          case ElementSize::INLINE_COMPOSITE: {
679
            WordCount wordCount = ref->listRef.inlineCompositeWordCount();
680 681 682
            KJ_REQUIRE(boundsCheck(segment, ptr, ptr + wordCount + POINTER_SIZE_IN_WORDS),
                       "Message contained out-of-bounds list pointer.") {
              return result;
683 684 685 686 687
            }

            const WirePointer* elementTag = reinterpret_cast<const WirePointer*>(ptr);
            ElementCount count = elementTag->inlineCompositeListElementCount();

688 689 690
            KJ_REQUIRE(elementTag->kind() == WirePointer::STRUCT,
                       "Don't know how to handle non-STRUCT inline composite.") {
              return result;
691
            }
692

693 694
            auto actualSize = elementTag->structRef.wordSize() / ELEMENTS * ElementCount64(count);
            KJ_REQUIRE(actualSize <= wordCount,
695 696
                       "Struct list pointer's elements overran size.") {
              return result;
697 698
            }

699 700 701 702
            // We count the actual size rather than the claimed word count because that's what
            // we'll end up with if we make a copy.
            result.wordCount += actualSize + POINTER_SIZE_IN_WORDS;

703 704 705
            WordCount dataSize = elementTag->structRef.dataSize.get();
            WirePointerCount pointerCount = elementTag->structRef.ptrCount.get();

706 707 708 709
            if (pointerCount > 0 * POINTERS) {
              const word* pos = ptr + POINTER_SIZE_IN_WORDS;
              for (uint i = 0; i < count / ELEMENTS; i++) {
                pos += dataSize;
710

711 712 713 714 715
                for (uint j = 0; j < pointerCount / POINTERS; j++) {
                  result += totalSize(segment, reinterpret_cast<const WirePointer*>(pos),
                                      nestingLimit);
                  pos += POINTER_SIZE_IN_WORDS;
                }
716 717 718 719 720 721 722 723
              }
            }
            break;
          }
        }
        break;
      }
      case WirePointer::FAR:
724
        KJ_FAIL_ASSERT("Unexpected FAR pointer.") {
725 726 727
          break;
        }
        break;
728
      case WirePointer::OTHER:
729 730 731 732 733
        if (ref->isCapability()) {
          result.capCount++;
        } else {
          KJ_FAIL_REQUIRE("Unknown pointer type.") { break; }
        }
734
        break;
735 736 737 738 739
    }

    return result;
  }

740
  // -----------------------------------------------------------------
741
  // Copy from an unchecked message.
742

743
  static KJ_ALWAYS_INLINE(
744
      void copyStruct(SegmentBuilder* segment, word* dst, const word* src,
745
                      WordCount dataSize, WirePointerCount pointerCount)) {
746 747
    memcpy(dst, src, dataSize * BYTES_PER_WORD / BYTES);

748 749
    const WirePointer* srcRefs = reinterpret_cast<const WirePointer*>(src + dataSize);
    WirePointer* dstRefs = reinterpret_cast<WirePointer*>(dst + dataSize);
750

751
    for (uint i = 0; i < pointerCount / POINTERS; i++) {
752
      SegmentBuilder* subSegment = segment;
753
      WirePointer* dstRef = dstRefs + i;
754
      copyMessage(subSegment, dstRef, srcRefs + i);
755 756 757
    }
  }

758
  static word* copyMessage(
759
      SegmentBuilder*& segment, WirePointer*& dst, const WirePointer* src) {
760 761
    // Not always-inline because it's recursive.

762
    switch (src->kind()) {
763
      case WirePointer::STRUCT: {
764
        if (src->isNull()) {
765
          memset(dst, 0, sizeof(WirePointer));
766
          return nullptr;
767 768
        } else {
          const word* srcPtr = src->target();
769 770
          word* dstPtr = allocate(
              dst, segment, src->structRef.wordSize(), WirePointer::STRUCT, nullptr);
771

772
          copyStruct(segment, dstPtr, srcPtr, src->structRef.dataSize.get(),
773
                     src->structRef.ptrCount.get());
774

775
          dst->structRef.set(src->structRef.dataSize.get(), src->structRef.ptrCount.get());
776
          return dstPtr;
777 778
        }
      }
779
      case WirePointer::LIST: {
780
        switch (src->listRef.elementSize()) {
781 782 783 784 785 786
          case ElementSize::VOID:
          case ElementSize::BIT:
          case ElementSize::BYTE:
          case ElementSize::TWO_BYTES:
          case ElementSize::FOUR_BYTES:
          case ElementSize::EIGHT_BYTES: {
787
            WordCount wordCount = roundBitsUpToWords(
788
                ElementCount64(src->listRef.elementCount()) *
789
                dataBitsPerElement(src->listRef.elementSize()));
790
            const word* srcPtr = src->target();
791
            word* dstPtr = allocate(dst, segment, wordCount, WirePointer::LIST, nullptr);
792 793
            memcpy(dstPtr, srcPtr, wordCount * BYTES_PER_WORD / BYTES);

794 795
            dst->listRef.set(src->listRef.elementSize(), src->listRef.elementCount());
            return dstPtr;
796 797
          }

798
          case ElementSize::POINTER: {
799 800
            const WirePointer* srcRefs = reinterpret_cast<const WirePointer*>(src->target());
            WirePointer* dstRefs = reinterpret_cast<WirePointer*>(
801
                allocate(dst, segment, src->listRef.elementCount() *
802
                    (1 * POINTERS / ELEMENTS) * WORDS_PER_POINTER,
803
                    WirePointer::LIST, nullptr));
804 805 806

            uint n = src->listRef.elementCount() / ELEMENTS;
            for (uint i = 0; i < n; i++) {
807
              SegmentBuilder* subSegment = segment;
808
              WirePointer* dstRef = dstRefs + i;
809
              copyMessage(subSegment, dstRef, srcRefs + i);
810 811
            }

812
            dst->listRef.set(ElementSize::POINTER, src->listRef.elementCount());
813
            return reinterpret_cast<word*>(dstRefs);
814 815
          }

816
          case ElementSize::INLINE_COMPOSITE: {
817 818
            const word* srcPtr = src->target();
            word* dstPtr = allocate(dst, segment,
819
                src->listRef.inlineCompositeWordCount() + POINTER_SIZE_IN_WORDS,
820
                WirePointer::LIST, nullptr);
821

822
            dst->listRef.setInlineComposite(src->listRef.inlineCompositeWordCount());
823

824 825
            const WirePointer* srcTag = reinterpret_cast<const WirePointer*>(srcPtr);
            memcpy(dstPtr, srcTag, sizeof(WirePointer));
826

827 828
            const word* srcElement = srcPtr + POINTER_SIZE_IN_WORDS;
            word* dstElement = dstPtr + POINTER_SIZE_IN_WORDS;
829

830
            KJ_ASSERT(srcTag->kind() == WirePointer::STRUCT,
831 832
                "INLINE_COMPOSITE of lists is not yet supported.");

833
            uint n = srcTag->inlineCompositeListElementCount() / ELEMENTS;
834
            for (uint i = 0; i < n; i++) {
835
              copyStruct(segment, dstElement, srcElement,
836
                  srcTag->structRef.dataSize.get(), srcTag->structRef.ptrCount.get());
837 838
              srcElement += srcTag->structRef.wordSize();
              dstElement += srcTag->structRef.wordSize();
839
            }
840
            return dstPtr;
841 842 843 844
          }
        }
        break;
      }
845 846
      case WirePointer::OTHER:
        KJ_FAIL_REQUIRE("Unchecked messages cannot contain OTHER pointers (e.g. capabilities).");
847 848 849
        break;
      case WirePointer::FAR:
        KJ_FAIL_REQUIRE("Unchecked messages cannot contain far pointers.");
850 851 852
        break;
    }

853
    return nullptr;
854 855
  }

856 857
  static void transferPointer(SegmentBuilder* dstSegment, WirePointer* dst,
                              SegmentBuilder* srcSegment, WirePointer* src) {
858 859
    // Make *dst point to the same object as *src.  Both must reside in the same message, but can
    // be in different segments.  Not always-inline because this is rarely used.
860 861 862 863 864
    //
    // Caller MUST zero out the source pointer after calling this, to make sure no later code
    // mistakenly thinks the source location still owns the object.  transferPointer() doesn't do
    // this zeroing itself because many callers transfer several pointers in a loop then zero out
    // the whole section.
865 866 867 868

    KJ_DASSERT(dst->isNull());
    // We expect the caller to ensure the target is already null so won't leak.

869
    if (src->isNull()) {
870 871
      memset(dst, 0, sizeof(WirePointer));
    } else if (src->kind() == WirePointer::FAR) {
872
      // Far pointers are position-independent, so we can just copy.
873
      memcpy(dst, src, sizeof(WirePointer));
874 875 876 877 878 879 880 881 882 883 884 885
    } else {
      transferPointer(dstSegment, dst, srcSegment, src, src->target());
    }
  }

  static void transferPointer(SegmentBuilder* dstSegment, WirePointer* dst,
                              SegmentBuilder* srcSegment, const WirePointer* srcTag,
                              word* srcPtr) {
    // Like the other overload, but splits src into a tag and a target.  Particularly useful for
    // OrphanBuilder.

    if (dstSegment == srcSegment) {
886
      // Same segment, so create a direct pointer.
887
      dst->setKindAndTarget(srcTag->kind(), srcPtr, dstSegment);
888 889

      // We can just copy the upper 32 bits.  (Use memcpy() to comply with aliasing rules.)
890
      memcpy(&dst->upper32Bits, &srcTag->upper32Bits, sizeof(srcTag->upper32Bits));
891 892 893 894
    } else {
      // Need to create a far pointer.  Try to allocate it in the same segment as the source, so
      // that it doesn't need to be a double-far.

895 896
      WirePointer* landingPad =
          reinterpret_cast<WirePointer*>(srcSegment->allocate(1 * WORDS));
897 898
      if (landingPad == nullptr) {
        // Darn, need a double-far.
899 900 901
        auto allocation = srcSegment->getArena()->allocate(2 * WORDS);
        SegmentBuilder* farSegment = allocation.segment;
        landingPad = reinterpret_cast<WirePointer*>(allocation.words);
902

903
        landingPad[0].setFar(false, srcSegment->getOffsetTo(srcPtr));
904 905
        landingPad[0].farRef.segmentId.set(srcSegment->getSegmentId());

906 907
        landingPad[1].setKindWithZeroOffset(srcTag->kind());
        memcpy(&landingPad[1].upper32Bits, &srcTag->upper32Bits, sizeof(srcTag->upper32Bits));
908 909 910 911 912

        dst->setFar(true, farSegment->getOffsetTo(reinterpret_cast<word*>(landingPad)));
        dst->farRef.set(farSegment->getSegmentId());
      } else {
        // Simple landing pad is just a pointer.
913
        landingPad->setKindAndTarget(srcTag->kind(), srcPtr, srcSegment);
914
        memcpy(&landingPad->upper32Bits, &srcTag->upper32Bits, sizeof(srcTag->upper32Bits));
915 916 917 918 919 920 921

        dst->setFar(false, srcSegment->getOffsetTo(reinterpret_cast<word*>(landingPad)));
        dst->farRef.set(srcSegment->getSegmentId());
      }
    }
  }

922 923
  // -----------------------------------------------------------------

924
  static KJ_ALWAYS_INLINE(StructBuilder initStructPointer(
925 926
      WirePointer* ref, SegmentBuilder* segment, StructSize size,
      BuilderArena* orphanArena = nullptr)) {
927
    // Allocate space for the new struct.  Newly-allocated space is automatically zeroed.
928
    word* ptr = allocate(ref, segment, size.total(), WirePointer::STRUCT, orphanArena);
929

930
    // Initialize the pointer.
931
    ref->structRef.set(size);
932 933

    // Build the StructBuilder.
934
    return StructBuilder(segment, ptr, reinterpret_cast<WirePointer*>(ptr + size.data),
935
                         size.data * BITS_PER_WORD, size.pointers);
936
  }
937

938
  static KJ_ALWAYS_INLINE(StructBuilder getWritableStructPointer(
939
      WirePointer* ref, SegmentBuilder* segment, StructSize size, const word* defaultValue)) {
940 941 942 943 944
    return getWritableStructPointer(ref, ref->target(), segment, size, defaultValue);
  }

  static KJ_ALWAYS_INLINE(StructBuilder getWritableStructPointer(
      WirePointer* ref, word* refTarget, SegmentBuilder* segment, StructSize size,
945
      const word* defaultValue, BuilderArena* orphanArena = nullptr)) {
946
    if (ref->isNull()) {
947
    useDefault:
Kenton Varda's avatar
Kenton Varda committed
948
      if (defaultValue == nullptr ||
949
          reinterpret_cast<const WirePointer*>(defaultValue)->isNull()) {
950
        return initStructPointer(ref, segment, size, orphanArena);
951
      }
952
      refTarget = copyMessage(segment, ref, reinterpret_cast<const WirePointer*>(defaultValue));
953 954
      defaultValue = nullptr;  // If the default value is itself invalid, don't use it again.
    }
955

956 957
    WirePointer* oldRef = ref;
    SegmentBuilder* oldSegment = segment;
958
    word* oldPtr = followFars(oldRef, refTarget, oldSegment);
959

960
    KJ_REQUIRE(oldRef->kind() == WirePointer::STRUCT,
961 962 963
        "Message contains non-struct pointer where struct pointer was expected.") {
      goto useDefault;
    }
964

965 966 967 968
    WordCount oldDataSize = oldRef->structRef.dataSize.get();
    WirePointerCount oldPointerCount = oldRef->structRef.ptrCount.get();
    WirePointer* oldPointerSection =
        reinterpret_cast<WirePointer*>(oldPtr + oldDataSize);
969

970 971 972 973
    if (oldDataSize < size.data || oldPointerCount < size.pointers) {
      // The space allocated for this struct is too small.  Unlike with readers, we can't just
      // run with it and do bounds checks at access time, because how would we handle writes?
      // Instead, we have to copy the struct to a new space now.
974

975 976
      WordCount newDataSize = kj::max(oldDataSize, size.data);
      WirePointerCount newPointerCount = kj::max(oldPointerCount, size.pointers);
977
      WordCount totalSize = newDataSize + newPointerCount * WORDS_PER_POINTER;
978

979 980
      // Don't let allocate() zero out the object just yet.
      zeroPointerAndFars(segment, ref);
981

982
      word* ptr = allocate(ref, segment, totalSize, WirePointer::STRUCT, orphanArena);
983
      ref->structRef.set(newDataSize, newPointerCount);
984

985 986
      // Copy data section.
      memcpy(ptr, oldPtr, oldDataSize * BYTES_PER_WORD / BYTES);
987

988 989 990 991
      // Copy pointer section.
      WirePointer* newPointerSection = reinterpret_cast<WirePointer*>(ptr + newDataSize);
      for (uint i = 0; i < oldPointerCount / POINTERS; i++) {
        transferPointer(segment, newPointerSection + i, oldSegment, oldPointerSection + i);
992
      }
993 994 995 996 997 998 999 1000 1001 1002

      // Zero out old location.  This has two purposes:
      // 1) We don't want to leak the original contents of the struct when the message is written
      //    out as it may contain secrets that the caller intends to remove from the new copy.
      // 2) Zeros will be deflated by packing, making this dead memory almost-free if it ever
      //    hits the wire.
      memset(oldPtr, 0,
             (oldDataSize + oldPointerCount * WORDS_PER_POINTER) * BYTES_PER_WORD / BYTES);

      return StructBuilder(segment, ptr, newPointerSection, newDataSize * BITS_PER_WORD,
1003
                           newPointerCount);
1004 1005
    } else {
      return StructBuilder(oldSegment, oldPtr, oldPointerSection, oldDataSize * BITS_PER_WORD,
1006
                           oldPointerCount);
1007
    }
1008 1009
  }

1010
  static KJ_ALWAYS_INLINE(ListBuilder initListPointer(
1011
      WirePointer* ref, SegmentBuilder* segment, ElementCount elementCount,
1012 1013
      ElementSize elementSize, BuilderArena* orphanArena = nullptr)) {
    KJ_DREQUIRE(elementSize != ElementSize::INLINE_COMPOSITE,
1014
        "Should have called initStructListPointer() instead.");
1015

1016
    BitCount dataSize = dataBitsPerElement(elementSize) * ELEMENTS;
1017 1018
    WirePointerCount pointerCount = pointersPerElement(elementSize) * ELEMENTS;
    auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS;
1019

1020
    // Calculate size of the list.
1021
    WordCount wordCount = roundBitsUpToWords(ElementCount64(elementCount) * step);
1022

1023
    // Allocate the list.
1024
    word* ptr = allocate(ref, segment, wordCount, WirePointer::LIST, orphanArena);
1025

1026
    // Initialize the pointer.
1027
    ref->listRef.set(elementSize, elementCount);
1028

1029
    // Build the ListBuilder.
1030
    return ListBuilder(segment, ptr, step, elementCount, dataSize, pointerCount, elementSize);
1031
  }
1032

1033
  static KJ_ALWAYS_INLINE(ListBuilder initStructListPointer(
1034
      WirePointer* ref, SegmentBuilder* segment, ElementCount elementCount,
1035
      StructSize elementSize, BuilderArena* orphanArena = nullptr)) {
1036
    auto wordsPerElement = elementSize.total() / ELEMENTS;
1037

1038
    // Allocate the list, prefixed by a single WirePointer.
1039
    WordCount wordCount = elementCount * wordsPerElement;
1040 1041
    word* ptr = allocate(ref, segment, POINTER_SIZE_IN_WORDS + wordCount, WirePointer::LIST,
                         orphanArena);
1042

1043
    // Initialize the pointer.
1044
    // INLINE_COMPOSITE lists replace the element count with the word count.
1045
    ref->listRef.setInlineComposite(wordCount);
1046

1047
    // Initialize the list tag.
1048 1049 1050 1051
    reinterpret_cast<WirePointer*>(ptr)->setKindAndInlineCompositeListElementCount(
        WirePointer::STRUCT, elementCount);
    reinterpret_cast<WirePointer*>(ptr)->structRef.set(elementSize);
    ptr += POINTER_SIZE_IN_WORDS;
1052

1053
    // Build the ListBuilder.
1054
    return ListBuilder(segment, ptr, wordsPerElement * BITS_PER_WORD, elementCount,
1055
                       elementSize.data * BITS_PER_WORD, elementSize.pointers,
1056
                       ElementSize::INLINE_COMPOSITE);
1057 1058
  }

1059
  static KJ_ALWAYS_INLINE(ListBuilder getWritableListPointer(
1060
      WirePointer* origRef, SegmentBuilder* origSegment, ElementSize elementSize,
1061
      const word* defaultValue)) {
1062 1063 1064 1065 1066
    return getWritableListPointer(origRef, origRef->target(), origSegment, elementSize,
                                  defaultValue);
  }

  static KJ_ALWAYS_INLINE(ListBuilder getWritableListPointer(
1067
      WirePointer* origRef, word* origRefTarget, SegmentBuilder* origSegment, ElementSize elementSize,
1068
      const word* defaultValue, BuilderArena* orphanArena = nullptr)) {
1069
    KJ_DREQUIRE(elementSize != ElementSize::INLINE_COMPOSITE,
1070
             "Use getStructList{Element,Field}() for structs.");
1071

1072 1073
    if (origRef->isNull()) {
    useDefault:
Kenton Varda's avatar
Kenton Varda committed
1074
      if (defaultValue == nullptr ||
1075
          reinterpret_cast<const WirePointer*>(defaultValue)->isNull()) {
1076
        return ListBuilder();
1077
      }
1078 1079
      origRefTarget = copyMessage(
          origSegment, origRef, reinterpret_cast<const WirePointer*>(defaultValue));
1080 1081
      defaultValue = nullptr;  // If the default value is itself invalid, don't use it again.
    }
1082

1083
    // We must verify that the pointer has the right size.  Unlike in
David Renshaw's avatar
David Renshaw committed
1084
    // getWritableStructListPointer(), we never need to "upgrade" the data, because this
1085 1086
    // method is called only for non-struct lists, and there is no allowed upgrade path *to*
    // a non-struct list, only *from* them.
1087

1088 1089
    WirePointer* ref = origRef;
    SegmentBuilder* segment = origSegment;
1090
    word* ptr = followFars(ref, origRefTarget, segment);
1091

1092
    KJ_REQUIRE(ref->kind() == WirePointer::LIST,
1093 1094 1095
        "Called getList{Field,Element}() but existing pointer is not a list.") {
      goto useDefault;
    }
1096

1097
    ElementSize oldSize = ref->listRef.elementSize();
1098

1099
    if (oldSize == ElementSize::INLINE_COMPOSITE) {
1100 1101 1102 1103
      // The existing element size is INLINE_COMPOSITE, though we expected a list of primitives.
      // The existing data must have been written with a newer version of the protocol.  We
      // therefore never need to upgrade the data in this case, but we do need to validate that it
      // is a valid upgrade from what we expected.
1104

1105 1106
      // Read the tag to get the actual element count.
      WirePointer* tag = reinterpret_cast<WirePointer*>(ptr);
1107
      KJ_REQUIRE(tag->kind() == WirePointer::STRUCT,
1108 1109
          "INLINE_COMPOSITE list with non-STRUCT elements not supported.");
      ptr += POINTER_SIZE_IN_WORDS;
1110

1111 1112
      WordCount dataSize = tag->structRef.dataSize.get();
      WirePointerCount pointerCount = tag->structRef.ptrCount.get();
1113

1114
      switch (elementSize) {
1115
        case ElementSize::VOID:
1116 1117
          // Anything is a valid upgrade from Void.
          break;
1118

1119
        case ElementSize::BIT:
1120 1121 1122 1123 1124 1125 1126
          KJ_FAIL_REQUIRE(
              "Found struct list where bit list was expected; upgrading boolean lists to structs "
              "is no longer supported.") {
            goto useDefault;
          }
          break;

1127 1128 1129 1130
        case ElementSize::BYTE:
        case ElementSize::TWO_BYTES:
        case ElementSize::FOUR_BYTES:
        case ElementSize::EIGHT_BYTES:
1131 1132 1133 1134
          KJ_REQUIRE(dataSize >= 1 * WORDS,
                     "Existing list value is incompatible with expected type.") {
            goto useDefault;
          }
1135
          break;
1136

1137
        case ElementSize::POINTER:
1138 1139 1140 1141
          KJ_REQUIRE(pointerCount >= 1 * POINTERS,
                     "Existing list value is incompatible with expected type.") {
            goto useDefault;
          }
1142 1143 1144
          // Adjust the pointer to point at the reference segment.
          ptr += dataSize;
          break;
1145

1146
        case ElementSize::INLINE_COMPOSITE:
1147
          KJ_UNREACHABLE;
1148
      }
1149

1150
      // OK, looks valid.
1151

1152 1153 1154
      return ListBuilder(segment, ptr,
                         tag->structRef.wordSize() * BITS_PER_WORD / ELEMENTS,
                         tag->inlineCompositeListElementCount(),
1155
                         dataSize * BITS_PER_WORD, pointerCount, ElementSize::INLINE_COMPOSITE);
1156 1157 1158
    } else {
      BitCount dataSize = dataBitsPerElement(oldSize) * ELEMENTS;
      WirePointerCount pointerCount = pointersPerElement(oldSize) * ELEMENTS;
1159

1160 1161
      if (elementSize == ElementSize::BIT) {
        KJ_REQUIRE(oldSize == ElementSize::BIT,
1162 1163 1164 1165
            "Found non-bit list where bit list was expected.") {
          goto useDefault;
        }
      } else {
1166
        KJ_REQUIRE(oldSize != ElementSize::BIT,
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
            "Found bit list where non-bit list was expected.") {
          goto useDefault;
        }
        KJ_REQUIRE(dataSize >= dataBitsPerElement(elementSize) * ELEMENTS,
                   "Existing list value is incompatible with expected type.") {
          goto useDefault;
        }
        KJ_REQUIRE(pointerCount >= pointersPerElement(elementSize) * ELEMENTS,
                   "Existing list value is incompatible with expected type.") {
          goto useDefault;
        }
1178
      }
1179

1180 1181
      auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS;
      return ListBuilder(segment, ptr, step, ref->listRef.elementCount(),
1182
                         dataSize, pointerCount, oldSize);
1183
    }
1184 1185
  }

1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
  static KJ_ALWAYS_INLINE(ListBuilder getWritableListPointerAnySize(
      WirePointer* origRef, SegmentBuilder* origSegment, const word* defaultValue)) {
    return getWritableListPointerAnySize(origRef, origRef->target(), origSegment, defaultValue);
  }

  static KJ_ALWAYS_INLINE(ListBuilder getWritableListPointerAnySize(
      WirePointer* origRef, word* origRefTarget, SegmentBuilder* origSegment,
      const word* defaultValue, BuilderArena* orphanArena = nullptr)) {
    if (origRef->isNull()) {
    useDefault:
      if (defaultValue == nullptr ||
          reinterpret_cast<const WirePointer*>(defaultValue)->isNull()) {
        return ListBuilder();
      }
      origRefTarget = copyMessage(
          origSegment, origRef, reinterpret_cast<const WirePointer*>(defaultValue));
      defaultValue = nullptr;  // If the default value is itself invalid, don't use it again.
    }

    WirePointer* ref = origRef;
    SegmentBuilder* segment = origSegment;
    word* ptr = followFars(ref, origRefTarget, segment);

    KJ_REQUIRE(ref->kind() == WirePointer::LIST,
        "Called getList{Field,Element}() but existing pointer is not a list.") {
      goto useDefault;
    }

1214
    ElementSize elementSize = ref->listRef.elementSize();
1215

1216
    if (elementSize == ElementSize::INLINE_COMPOSITE) {
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
      // Read the tag to get the actual element count.
      WirePointer* tag = reinterpret_cast<WirePointer*>(ptr);
      KJ_REQUIRE(tag->kind() == WirePointer::STRUCT,
          "INLINE_COMPOSITE list with non-STRUCT elements not supported.");
      ptr += POINTER_SIZE_IN_WORDS;

      return ListBuilder(segment, ptr,
                         tag->structRef.wordSize() * BITS_PER_WORD / ELEMENTS,
                         tag->inlineCompositeListElementCount(),
                         tag->structRef.dataSize.get() * BITS_PER_WORD,
1227
                         tag->structRef.ptrCount.get(), ElementSize::INLINE_COMPOSITE);
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
    } else {
      BitCount dataSize = dataBitsPerElement(elementSize) * ELEMENTS;
      WirePointerCount pointerCount = pointersPerElement(elementSize) * ELEMENTS;

      auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS;
      return ListBuilder(segment, ptr, step, ref->listRef.elementCount(),
                         dataSize, pointerCount, elementSize);
    }
  }

1238
  static KJ_ALWAYS_INLINE(ListBuilder getWritableStructListPointer(
1239 1240
      WirePointer* origRef, SegmentBuilder* origSegment, StructSize elementSize,
      const word* defaultValue)) {
1241 1242 1243 1244 1245
    return getWritableStructListPointer(origRef, origRef->target(), origSegment, elementSize,
                                        defaultValue);
  }
  static KJ_ALWAYS_INLINE(ListBuilder getWritableStructListPointer(
      WirePointer* origRef, word* origRefTarget, SegmentBuilder* origSegment,
1246
      StructSize elementSize, const word* defaultValue, BuilderArena* orphanArena = nullptr)) {
1247 1248 1249 1250 1251 1252
    if (origRef->isNull()) {
    useDefault:
      if (defaultValue == nullptr ||
          reinterpret_cast<const WirePointer*>(defaultValue)->isNull()) {
        return ListBuilder();
      }
1253 1254
      origRefTarget = copyMessage(
          origSegment, origRef, reinterpret_cast<const WirePointer*>(defaultValue));
1255 1256
      defaultValue = nullptr;  // If the default value is itself invalid, don't use it again.
    }
1257

1258
    // We must verify that the pointer has the right size and potentially upgrade it if not.
1259

1260 1261
    WirePointer* oldRef = origRef;
    SegmentBuilder* oldSegment = origSegment;
1262
    word* oldPtr = followFars(oldRef, origRefTarget, oldSegment);
1263

1264 1265
    KJ_REQUIRE(oldRef->kind() == WirePointer::LIST,
               "Called getList{Field,Element}() but existing pointer is not a list.") {
1266 1267 1268
      goto useDefault;
    }

1269
    ElementSize oldSize = oldRef->listRef.elementSize();
1270

1271
    if (oldSize == ElementSize::INLINE_COMPOSITE) {
1272
      // Existing list is INLINE_COMPOSITE, but we need to verify that the sizes match.
1273

1274 1275
      WirePointer* oldTag = reinterpret_cast<WirePointer*>(oldPtr);
      oldPtr += POINTER_SIZE_IN_WORDS;
1276 1277
      KJ_REQUIRE(oldTag->kind() == WirePointer::STRUCT,
                 "INLINE_COMPOSITE list with non-STRUCT elements not supported.") {
1278 1279 1280
        goto useDefault;
      }

1281 1282 1283 1284
      WordCount oldDataSize = oldTag->structRef.dataSize.get();
      WirePointerCount oldPointerCount = oldTag->structRef.ptrCount.get();
      auto oldStep = (oldDataSize + oldPointerCount * WORDS_PER_POINTER) / ELEMENTS;
      ElementCount elementCount = oldTag->inlineCompositeListElementCount();
1285

1286 1287 1288
      if (oldDataSize >= elementSize.data && oldPointerCount >= elementSize.pointers) {
        // Old size is at least as large as we need.  Ship it.
        return ListBuilder(oldSegment, oldPtr, oldStep * BITS_PER_WORD, elementCount,
1289
                           oldDataSize * BITS_PER_WORD, oldPointerCount,
1290
                           ElementSize::INLINE_COMPOSITE);
1291
      }
1292

1293 1294
      // The structs in this list are smaller than expected, probably written using an older
      // version of the protocol.  We need to make a copy and expand them.
1295

1296 1297
      WordCount newDataSize = kj::max(oldDataSize, elementSize.data);
      WirePointerCount newPointerCount = kj::max(oldPointerCount, elementSize.pointers);
1298 1299
      auto newStep = (newDataSize + newPointerCount * WORDS_PER_POINTER) / ELEMENTS;
      WordCount totalSize = newStep * elementCount;
1300

1301 1302
      // Don't let allocate() zero out the object just yet.
      zeroPointerAndFars(origSegment, origRef);
1303

1304
      word* newPtr = allocate(origRef, origSegment, totalSize + POINTER_SIZE_IN_WORDS,
1305
                              WirePointer::LIST, orphanArena);
1306
      origRef->listRef.setInlineComposite(totalSize);
1307

1308 1309 1310 1311
      WirePointer* newTag = reinterpret_cast<WirePointer*>(newPtr);
      newTag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, elementCount);
      newTag->structRef.set(newDataSize, newPointerCount);
      newPtr += POINTER_SIZE_IN_WORDS;
1312

1313 1314 1315 1316 1317
      word* src = oldPtr;
      word* dst = newPtr;
      for (uint i = 0; i < elementCount / ELEMENTS; i++) {
        // Copy data section.
        memcpy(dst, src, oldDataSize * BYTES_PER_WORD / BYTES);
1318

1319 1320 1321
        // Copy pointer section.
        WirePointer* newPointerSection = reinterpret_cast<WirePointer*>(dst + newDataSize);
        WirePointer* oldPointerSection = reinterpret_cast<WirePointer*>(src + oldDataSize);
1322 1323
        for (uint j = 0; j < oldPointerCount / POINTERS; j++) {
          transferPointer(origSegment, newPointerSection + j, oldSegment, oldPointerSection + j);
1324 1325
        }

1326 1327 1328
        dst += newStep * (1 * ELEMENTS);
        src += oldStep * (1 * ELEMENTS);
      }
1329

1330 1331
      // Zero out old location.  See explanation in getWritableStructPointer().
      memset(oldPtr, 0, oldStep * elementCount * BYTES_PER_WORD / BYTES);
1332

1333
      return ListBuilder(origSegment, newPtr, newStep * BITS_PER_WORD, elementCount,
1334
                         newDataSize * BITS_PER_WORD, newPointerCount, ElementSize::INLINE_COMPOSITE);
1335
    } else {
1336
      // We're upgrading from a non-struct list.
1337

1338 1339 1340 1341
      BitCount oldDataSize = dataBitsPerElement(oldSize) * ELEMENTS;
      WirePointerCount oldPointerCount = pointersPerElement(oldSize) * ELEMENTS;
      auto oldStep = (oldDataSize + oldPointerCount * BITS_PER_POINTER) / ELEMENTS;
      ElementCount elementCount = oldRef->listRef.elementCount();
1342

1343
      if (oldSize == ElementSize::VOID) {
1344 1345
        // Nothing to copy, just allocate a new list.
        return initStructListPointer(origRef, origSegment, elementCount, elementSize);
1346
      } else {
1347
        // Upgrading to an inline composite list.
1348

1349
        KJ_REQUIRE(oldSize != ElementSize::BIT,
1350 1351 1352 1353 1354
            "Found bit list where struct list was expected; upgrading boolean lists to structs "
            "is no longer supported.") {
          goto useDefault;
        }

1355 1356
        WordCount newDataSize = elementSize.data;
        WirePointerCount newPointerCount = elementSize.pointers;
1357

1358
        if (oldSize == ElementSize::POINTER) {
1359
          newPointerCount = kj::max(newPointerCount, 1 * POINTERS);
1360 1361
        } else {
          // Old list contains data elements, so we need at least 1 word of data.
1362
          newDataSize = kj::max(newDataSize, 1 * WORDS);
1363
        }
1364

1365 1366
        auto newStep = (newDataSize + newPointerCount * WORDS_PER_POINTER) / ELEMENTS;
        WordCount totalWords = elementCount * newStep;
1367

1368 1369
        // Don't let allocate() zero out the object just yet.
        zeroPointerAndFars(origSegment, origRef);
1370

1371
        word* newPtr = allocate(origRef, origSegment, totalWords + POINTER_SIZE_IN_WORDS,
1372
                                WirePointer::LIST, orphanArena);
1373
        origRef->listRef.setInlineComposite(totalWords);
1374

1375 1376 1377 1378
        WirePointer* tag = reinterpret_cast<WirePointer*>(newPtr);
        tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, elementCount);
        tag->structRef.set(newDataSize, newPointerCount);
        newPtr += POINTER_SIZE_IN_WORDS;
1379

1380
        if (oldSize == ElementSize::POINTER) {
1381 1382 1383 1384 1385 1386
          WirePointer* dst = reinterpret_cast<WirePointer*>(newPtr + newDataSize);
          WirePointer* src = reinterpret_cast<WirePointer*>(oldPtr);
          for (uint i = 0; i < elementCount / ELEMENTS; i++) {
            transferPointer(origSegment, dst, oldSegment, src);
            dst += newStep / WORDS_PER_POINTER * (1 * ELEMENTS);
            ++src;
1387
          }
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
        } else {
          word* dst = newPtr;
          char* src = reinterpret_cast<char*>(oldPtr);
          ByteCount oldByteStep = oldDataSize / BITS_PER_BYTE;
          for (uint i = 0; i < elementCount / ELEMENTS; i++) {
            memcpy(dst, src, oldByteStep / BYTES);
            src += oldByteStep / BYTES;
            dst += newStep * (1 * ELEMENTS);
          }
        }
1398

1399
        // Zero out old location.  See explanation in getWritableStructPointer().
1400
        memset(oldPtr, 0, roundBitsUpToBytes(oldStep * elementCount) / BYTES);
1401

1402
        return ListBuilder(origSegment, newPtr, newStep * BITS_PER_WORD, elementCount,
1403
                           newDataSize * BITS_PER_WORD, newPointerCount,
1404
                           ElementSize::INLINE_COMPOSITE);
1405
      }
1406 1407 1408
    }
  }

1409 1410 1411
  static KJ_ALWAYS_INLINE(SegmentAnd<Text::Builder> initTextPointer(
      WirePointer* ref, SegmentBuilder* segment, ByteCount size,
      BuilderArena* orphanArena = nullptr)) {
Kenton Varda's avatar
Kenton Varda committed
1412 1413 1414 1415
    // The byte list must include a NUL terminator.
    ByteCount byteSize = size + 1 * BYTES;

    // Allocate the space.
1416 1417
    word* ptr = allocate(
        ref, segment, roundBytesUpToWords(byteSize), WirePointer::LIST, orphanArena);
Kenton Varda's avatar
Kenton Varda committed
1418

1419
    // Initialize the pointer.
1420
    ref->listRef.set(ElementSize::BYTE, byteSize * (1 * ELEMENTS / BYTES));
Kenton Varda's avatar
Kenton Varda committed
1421 1422

    // Build the Text::Builder.  This will initialize the NUL terminator.
1423
    return { segment, Text::Builder(reinterpret_cast<char*>(ptr), size / BYTES) };
Kenton Varda's avatar
Kenton Varda committed
1424 1425
  }

1426 1427 1428 1429 1430 1431
  static KJ_ALWAYS_INLINE(SegmentAnd<Text::Builder> setTextPointer(
      WirePointer* ref, SegmentBuilder* segment, Text::Reader value,
      BuilderArena* orphanArena = nullptr)) {
    auto allocation = initTextPointer(ref, segment, value.size() * BYTES, orphanArena);
    memcpy(allocation.value.begin(), value.begin(), value.size());
    return allocation;
Kenton Varda's avatar
Kenton Varda committed
1432 1433
  }

1434
  static KJ_ALWAYS_INLINE(Text::Builder getWritableTextPointer(
1435
      WirePointer* ref, SegmentBuilder* segment,
Kenton Varda's avatar
Kenton Varda committed
1436
      const void* defaultValue, ByteCount defaultSize)) {
1437 1438 1439 1440 1441 1442
    return getWritableTextPointer(ref, ref->target(), segment, defaultValue, defaultSize);
  }

  static KJ_ALWAYS_INLINE(Text::Builder getWritableTextPointer(
      WirePointer* ref, word* refTarget, SegmentBuilder* segment,
      const void* defaultValue, ByteCount defaultSize)) {
Kenton Varda's avatar
Kenton Varda committed
1443
    if (ref->isNull()) {
1444
    useDefault:
1445 1446 1447
      if (defaultSize == 0 * BYTES) {
        return nullptr;
      } else {
1448
        Text::Builder builder = initTextPointer(ref, segment, defaultSize).value;
1449 1450 1451
        memcpy(builder.begin(), defaultValue, defaultSize / BYTES);
        return builder;
      }
Kenton Varda's avatar
Kenton Varda committed
1452
    } else {
1453
      word* ptr = followFars(ref, refTarget, segment);
1454
      char* cptr = reinterpret_cast<char*>(ptr);
Kenton Varda's avatar
Kenton Varda committed
1455

1456
      KJ_REQUIRE(ref->kind() == WirePointer::LIST,
1457
          "Called getText{Field,Element}() but existing pointer is not a list.");
1458
      KJ_REQUIRE(ref->listRef.elementSize() == ElementSize::BYTE,
1459
          "Called getText{Field,Element}() but existing list pointer is not byte-sized.");
Kenton Varda's avatar
Kenton Varda committed
1460

1461 1462 1463 1464 1465 1466
      size_t size = ref->listRef.elementCount() / ELEMENTS;
      KJ_REQUIRE(size > 0 && cptr[size-1] == '\0', "Text blob missing NUL terminator.") {
        goto useDefault;
      }

      return Text::Builder(cptr, size - 1);
Kenton Varda's avatar
Kenton Varda committed
1467 1468 1469
    }
  }

1470 1471 1472
  static KJ_ALWAYS_INLINE(SegmentAnd<Data::Builder> initDataPointer(
      WirePointer* ref, SegmentBuilder* segment, ByteCount size,
      BuilderArena* orphanArena = nullptr)) {
Kenton Varda's avatar
Kenton Varda committed
1473
    // Allocate the space.
1474
    word* ptr = allocate(ref, segment, roundBytesUpToWords(size), WirePointer::LIST, orphanArena);
Kenton Varda's avatar
Kenton Varda committed
1475

1476
    // Initialize the pointer.
1477
    ref->listRef.set(ElementSize::BYTE, size * (1 * ELEMENTS / BYTES));
Kenton Varda's avatar
Kenton Varda committed
1478 1479

    // Build the Data::Builder.
1480
    return { segment, Data::Builder(reinterpret_cast<byte*>(ptr), size / BYTES) };
Kenton Varda's avatar
Kenton Varda committed
1481 1482
  }

1483 1484 1485 1486 1487 1488
  static KJ_ALWAYS_INLINE(SegmentAnd<Data::Builder> setDataPointer(
      WirePointer* ref, SegmentBuilder* segment, Data::Reader value,
      BuilderArena* orphanArena = nullptr)) {
    auto allocation = initDataPointer(ref, segment, value.size() * BYTES, orphanArena);
    memcpy(allocation.value.begin(), value.begin(), value.size());
    return allocation;
Kenton Varda's avatar
Kenton Varda committed
1489 1490
  }

1491
  static KJ_ALWAYS_INLINE(Data::Builder getWritableDataPointer(
1492
      WirePointer* ref, SegmentBuilder* segment,
Kenton Varda's avatar
Kenton Varda committed
1493
      const void* defaultValue, ByteCount defaultSize)) {
1494 1495 1496 1497 1498 1499
    return getWritableDataPointer(ref, ref->target(), segment, defaultValue, defaultSize);
  }

  static KJ_ALWAYS_INLINE(Data::Builder getWritableDataPointer(
      WirePointer* ref, word* refTarget, SegmentBuilder* segment,
      const void* defaultValue, ByteCount defaultSize)) {
Kenton Varda's avatar
Kenton Varda committed
1500
    if (ref->isNull()) {
1501 1502 1503
      if (defaultSize == 0 * BYTES) {
        return nullptr;
      } else {
1504
        Data::Builder builder = initDataPointer(ref, segment, defaultSize).value;
1505 1506 1507
        memcpy(builder.begin(), defaultValue, defaultSize / BYTES);
        return builder;
      }
Kenton Varda's avatar
Kenton Varda committed
1508
    } else {
1509
      word* ptr = followFars(ref, refTarget, segment);
Kenton Varda's avatar
Kenton Varda committed
1510

1511
      KJ_REQUIRE(ref->kind() == WirePointer::LIST,
1512
          "Called getData{Field,Element}() but existing pointer is not a list.");
1513
      KJ_REQUIRE(ref->listRef.elementSize() == ElementSize::BYTE,
1514
          "Called getData{Field,Element}() but existing list pointer is not byte-sized.");
Kenton Varda's avatar
Kenton Varda committed
1515

1516
      return Data::Builder(reinterpret_cast<byte*>(ptr), ref->listRef.elementCount() / ELEMENTS);
Kenton Varda's avatar
Kenton Varda committed
1517 1518 1519
    }
  }

1520 1521 1522
  static SegmentAnd<word*> setStructPointer(
      SegmentBuilder* segment, WirePointer* ref, StructReader value,
      BuilderArena* orphanArena = nullptr) {
1523
    WordCount dataSize = roundBitsUpToWords(value.dataSize);
1524 1525
    WordCount totalSize = dataSize + value.pointerCount * WORDS_PER_POINTER;

1526
    word* ptr = allocate(ref, segment, totalSize, WirePointer::STRUCT, orphanArena);
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
    ref->structRef.set(dataSize, value.pointerCount);

    if (value.dataSize == 1 * BITS) {
      *reinterpret_cast<char*>(ptr) = value.getDataField<bool>(0 * ELEMENTS);
    } else {
      memcpy(ptr, value.data, value.dataSize / BITS_PER_BYTE / BYTES);
    }

    WirePointer* pointerSection = reinterpret_cast<WirePointer*>(ptr + dataSize);
    for (uint i = 0; i < value.pointerCount / POINTERS; i++) {
1537 1538
      copyPointer(segment, pointerSection + i, value.segment, value.pointers + i,
                  value.nestingLimit);
1539
    }
1540

1541
    return { segment, ptr };
1542 1543
  }

1544
#if !CAPNP_LITE
1545
  static void setCapabilityPointer(
1546
      SegmentBuilder* segment, WirePointer* ref, kj::Own<ClientHook>&& cap,
1547 1548
      BuilderArena* orphanArena = nullptr) {
    if (orphanArena == nullptr) {
1549
      ref->setCap(segment->getArena()->injectCap(kj::mv(cap)));
1550
    } else {
1551
      ref->setCap(orphanArena->injectCap(kj::mv(cap)));
1552 1553
    }
  }
1554
#endif  // !CAPNP_LITE
1555

1556 1557 1558
  static SegmentAnd<word*> setListPointer(
      SegmentBuilder* segment, WirePointer* ref, ListReader value,
      BuilderArena* orphanArena = nullptr) {
1559
    WordCount totalSize = roundBitsUpToWords(value.elementCount * value.step);
1560

1561
    if (value.elementSize != ElementSize::INLINE_COMPOSITE) {
1562
      // List of non-structs.
1563
      word* ptr = allocate(ref, segment, totalSize, WirePointer::LIST, orphanArena);
1564

1565
      if (value.elementSize == ElementSize::POINTER) {
1566
        // List of pointers.
1567
        ref->listRef.set(ElementSize::POINTER, value.elementCount);
1568
        for (uint i = 0; i < value.elementCount / ELEMENTS; i++) {
1569 1570 1571
          copyPointer(segment, reinterpret_cast<WirePointer*>(ptr) + i,
                      value.segment, reinterpret_cast<const WirePointer*>(value.ptr) + i,
                      value.nestingLimit);
1572 1573 1574
        }
      } else {
        // List of data.
1575
        ref->listRef.set(value.elementSize, value.elementCount);
1576 1577
        memcpy(ptr, value.ptr, totalSize * BYTES_PER_WORD / BYTES);
      }
1578

1579
      return { segment, ptr };
1580 1581
    } else {
      // List of structs.
1582 1583
      word* ptr = allocate(ref, segment, totalSize + POINTER_SIZE_IN_WORDS, WirePointer::LIST,
                           orphanArena);
1584 1585
      ref->listRef.setInlineComposite(totalSize);

1586
      WordCount dataSize = roundBitsUpToWords(value.structDataSize);
1587 1588 1589 1590 1591
      WirePointerCount pointerCount = value.structPointerCount;

      WirePointer* tag = reinterpret_cast<WirePointer*>(ptr);
      tag->setKindAndInlineCompositeListElementCount(WirePointer::STRUCT, value.elementCount);
      tag->structRef.set(dataSize, pointerCount);
1592
      word* dst = ptr + POINTER_SIZE_IN_WORDS;
1593 1594 1595

      const word* src = reinterpret_cast<const word*>(value.ptr);
      for (uint i = 0; i < value.elementCount / ELEMENTS; i++) {
1596 1597
        memcpy(dst, src, value.structDataSize / BITS_PER_BYTE / BYTES);
        dst += dataSize;
1598 1599 1600
        src += dataSize;

        for (uint j = 0; j < pointerCount / POINTERS; j++) {
1601 1602
          copyPointer(segment, reinterpret_cast<WirePointer*>(dst),
              value.segment, reinterpret_cast<const WirePointer*>(src), value.nestingLimit);
1603
          dst += POINTER_SIZE_IN_WORDS;
1604 1605 1606
          src += POINTER_SIZE_IN_WORDS;
        }
      }
1607

1608
      return { segment, ptr };
1609 1610 1611
    }
  }

1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626
  static KJ_ALWAYS_INLINE(SegmentAnd<word*> copyPointer(
      SegmentBuilder* dstSegment, WirePointer* dst,
      SegmentReader* srcSegment, const WirePointer* src,
      int nestingLimit, BuilderArena* orphanArena = nullptr)) {
    return copyPointer(dstSegment, dst, srcSegment, src, src->target(), nestingLimit, orphanArena);
  }

  static SegmentAnd<word*> copyPointer(
      SegmentBuilder* dstSegment, WirePointer* dst,
      SegmentReader* srcSegment, const WirePointer* src, const word* srcTarget,
      int nestingLimit, BuilderArena* orphanArena = nullptr) {
    // Deep-copy the object pointed to by src into dst.  It turns out we can't reuse
    // readStructPointer(), etc. because they do type checking whereas here we want to accept any
    // valid pointer.

1627
    if (src->isNull()) {
1628
    useDefault:
1629 1630 1631 1632
      if (!dst->isNull()) {
        zeroObject(dstSegment, dst);
        memset(dst, 0, sizeof(*dst));
      }
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
      return { dstSegment, nullptr };
    }

    const word* ptr = WireHelpers::followFars(src, srcTarget, srcSegment);
    if (KJ_UNLIKELY(ptr == nullptr)) {
      // Already reported the error.
      goto useDefault;
    }

    switch (src->kind()) {
      case WirePointer::STRUCT:
        KJ_REQUIRE(nestingLimit > 0,
David Renshaw's avatar
David Renshaw committed
1645
              "Message is too deeply-nested or contains cycles.  See capnp::ReaderOptions.") {
1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657
          goto useDefault;
        }

        KJ_REQUIRE(boundsCheck(srcSegment, ptr, ptr + src->structRef.wordSize()),
                   "Message contained out-of-bounds struct pointer.") {
          goto useDefault;
        }
        return setStructPointer(dstSegment, dst,
            StructReader(srcSegment, ptr,
                         reinterpret_cast<const WirePointer*>(ptr + src->structRef.dataSize.get()),
                         src->structRef.dataSize.get() * BITS_PER_WORD,
                         src->structRef.ptrCount.get(),
1658
                         nestingLimit - 1),
1659 1660 1661
            orphanArena);

      case WirePointer::LIST: {
1662
        ElementSize elementSize = src->listRef.elementSize();
1663 1664

        KJ_REQUIRE(nestingLimit > 0,
David Renshaw's avatar
David Renshaw committed
1665
              "Message is too deeply-nested or contains cycles.  See capnp::ReaderOptions.") {
1666 1667 1668
          goto useDefault;
        }

1669
        if (elementSize == ElementSize::INLINE_COMPOSITE) {
1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
          WordCount wordCount = src->listRef.inlineCompositeWordCount();
          const WirePointer* tag = reinterpret_cast<const WirePointer*>(ptr);
          ptr += POINTER_SIZE_IN_WORDS;

          KJ_REQUIRE(boundsCheck(srcSegment, ptr - POINTER_SIZE_IN_WORDS, ptr + wordCount),
                     "Message contains out-of-bounds list pointer.") {
            goto useDefault;
          }

          KJ_REQUIRE(tag->kind() == WirePointer::STRUCT,
                     "INLINE_COMPOSITE lists of non-STRUCT type are not supported.") {
            goto useDefault;
          }

          ElementCount elementCount = tag->inlineCompositeListElementCount();
          auto wordsPerElement = tag->structRef.wordSize() / ELEMENTS;

1687
          KJ_REQUIRE(wordsPerElement * ElementCount64(elementCount) <= wordCount,
1688 1689 1690 1691
                     "INLINE_COMPOSITE list's elements overrun its word count.") {
            goto useDefault;
          }

1692 1693 1694 1695 1696 1697 1698 1699 1700
          if (wordsPerElement * (1 * ELEMENTS) == 0 * WORDS) {
            // Watch out for lists of zero-sized structs, which can claim to be arbitrarily large
            // without having sent actual data.
            KJ_REQUIRE(amplifiedRead(srcSegment, elementCount * (1 * WORDS / ELEMENTS)),
                       "Message contains amplified list pointer.") {
              goto useDefault;
            }
          }

1701 1702 1703
          return setListPointer(dstSegment, dst,
              ListReader(srcSegment, ptr, elementCount, wordsPerElement * BITS_PER_WORD,
                         tag->structRef.dataSize.get() * BITS_PER_WORD,
1704
                         tag->structRef.ptrCount.get(), ElementSize::INLINE_COMPOSITE,
1705
                         nestingLimit - 1),
1706 1707 1708 1709 1710 1711
              orphanArena);
        } else {
          BitCount dataSize = dataBitsPerElement(elementSize) * ELEMENTS;
          WirePointerCount pointerCount = pointersPerElement(elementSize) * ELEMENTS;
          auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS;
          ElementCount elementCount = src->listRef.elementCount();
1712
          WordCount64 wordCount = roundBitsUpToWords(ElementCount64(elementCount) * step);
1713 1714 1715 1716 1717 1718

          KJ_REQUIRE(boundsCheck(srcSegment, ptr, ptr + wordCount),
                     "Message contains out-of-bounds list pointer.") {
            goto useDefault;
          }

1719 1720 1721 1722 1723 1724 1725 1726 1727
          if (elementSize == ElementSize::VOID) {
            // Watch out for lists of void, which can claim to be arbitrarily large without having
            // sent actual data.
            KJ_REQUIRE(amplifiedRead(srcSegment, elementCount * (1 * WORDS / ELEMENTS)),
                       "Message contains amplified list pointer.") {
              goto useDefault;
            }
          }

1728
          return setListPointer(dstSegment, dst,
1729
              ListReader(srcSegment, ptr, elementCount, step, dataSize, pointerCount, elementSize,
1730 1731 1732 1733 1734
                         nestingLimit - 1),
              orphanArena);
        }
      }

1735 1736
      case WirePointer::FAR:
        KJ_FAIL_ASSERT("Far pointer should have been handled above.") {
1737 1738 1739
          goto useDefault;
        }

1740 1741
      case WirePointer::OTHER: {
        KJ_REQUIRE(src->isCapability(), "Unknown pointer type.") {
1742 1743 1744
          goto useDefault;
        }

1745
#if !CAPNP_LITE
1746 1747 1748
        KJ_IF_MAYBE(cap, srcSegment->getArena()->extractCap(src->capRef.index.get())) {
          setCapabilityPointer(dstSegment, dst, kj::mv(*cap), orphanArena);
          return { dstSegment, nullptr };
1749
        } else {
1750
#endif  // !CAPNP_LITE
1751
          KJ_FAIL_REQUIRE("Message contained invalid capability pointer.") {
1752 1753
            goto useDefault;
          }
1754
#if !CAPNP_LITE
1755
        }
1756
#endif  // !CAPNP_LITE
1757
      }
1758
    }
Kenton Varda's avatar
Kenton Varda committed
1759 1760

    KJ_UNREACHABLE;
1761 1762
  }

1763
  static void adopt(SegmentBuilder* segment, WirePointer* ref, OrphanBuilder&& value) {
1764
    KJ_REQUIRE(value.segment == nullptr || value.segment->getArena() == segment->getArena(),
1765 1766 1767 1768 1769 1770
               "Adopted object must live in the same message.");

    if (!ref->isNull()) {
      zeroObject(segment, ref);
    }

1771
    if (value == nullptr) {
1772 1773
      // Set null.
      memset(ref, 0, sizeof(*ref));
1774
    } else if (value.tagAsPtr()->isPositional()) {
1775
      WireHelpers::transferPointer(segment, ref, value.segment, value.tagAsPtr(), value.location);
1776 1777 1778
    } else {
      // FAR and OTHER pointers are position-independent, so we can just copy.
      memcpy(ref, value.tagAsPtr(), sizeof(WirePointer));
1779 1780 1781 1782 1783 1784 1785 1786 1787
    }

    // Take ownership away from the OrphanBuilder.
    memset(value.tagAsPtr(), 0, sizeof(WirePointer));
    value.location = nullptr;
    value.segment = nullptr;
  }

  static OrphanBuilder disown(SegmentBuilder* segment, WirePointer* ref) {
1788 1789 1790 1791
    word* location;

    if (ref->isNull()) {
      location = nullptr;
1792 1793 1794
    } else if (ref->kind() == WirePointer::OTHER) {
      KJ_REQUIRE(ref->isCapability(), "Unknown pointer type.") { break; }
      location = reinterpret_cast<word*>(ref);  // dummy so that it is non-null
1795 1796
    } else {
      WirePointer* refCopy = ref;
1797
      location = followFarsNoWritableCheck(refCopy, ref->target(), segment);
1798 1799 1800
    }

    OrphanBuilder result(ref, segment, location);
1801

1802
    if (!ref->isNull() && ref->isPositional()) {
1803
      result.tagAsPtr()->setKindForOrphan(ref->kind());
1804
    }
1805 1806 1807 1808 1809

    // Zero out the pointer that was disowned.
    memset(ref, 0, sizeof(*ref));

    return result;
1810 1811
  }

1812 1813
  // -----------------------------------------------------------------

1814
  static KJ_ALWAYS_INLINE(StructReader readStructPointer(
1815
      SegmentReader* segment, const WirePointer* ref, const word* defaultValue,
1816
      int nestingLimit)) {
1817 1818 1819 1820 1821 1822
    return readStructPointer(segment, ref, ref->target(), defaultValue, nestingLimit);
  }

  static KJ_ALWAYS_INLINE(StructReader readStructPointer(
      SegmentReader* segment, const WirePointer* ref, const word* refTarget,
      const word* defaultValue, int nestingLimit)) {
1823
    if (ref->isNull()) {
1824
    useDefault:
Kenton Varda's avatar
Kenton Varda committed
1825
      if (defaultValue == nullptr ||
1826
          reinterpret_cast<const WirePointer*>(defaultValue)->isNull()) {
1827
        return StructReader();
1828
      }
1829
      segment = nullptr;
1830
      ref = reinterpret_cast<const WirePointer*>(defaultValue);
1831
      refTarget = ref->target();
1832 1833
      defaultValue = nullptr;  // If the default value is itself invalid, don't use it again.
    }
1834

1835
    KJ_REQUIRE(nestingLimit > 0,
David Renshaw's avatar
David Renshaw committed
1836
               "Message is too deeply-nested or contains cycles.  See capnp::ReaderOptions.") {
1837 1838
      goto useDefault;
    }
1839

1840
    const word* ptr = followFars(ref, refTarget, segment);
1841
    if (KJ_UNLIKELY(ptr == nullptr)) {
1842 1843 1844
      // Already reported the error.
      goto useDefault;
    }
1845

1846 1847
    KJ_REQUIRE(ref->kind() == WirePointer::STRUCT,
               "Message contains non-struct pointer where struct pointer was expected.") {
1848 1849 1850
      goto useDefault;
    }

1851 1852
    KJ_REQUIRE(boundsCheck(segment, ptr, ptr + ref->structRef.wordSize()),
               "Message contained out-of-bounds struct pointer.") {
1853
      goto useDefault;
1854
    }
1855

1856
    return StructReader(
1857
        segment, ptr, reinterpret_cast<const WirePointer*>(ptr + ref->structRef.dataSize.get()),
1858
        ref->structRef.dataSize.get() * BITS_PER_WORD,
1859
        ref->structRef.ptrCount.get(),
1860
        nestingLimit - 1);
1861 1862
  }

1863
#if !CAPNP_LITE
1864 1865 1866 1867
  static KJ_ALWAYS_INLINE(kj::Own<ClientHook> readCapabilityPointer(
      SegmentReader* segment, const WirePointer* ref, int nestingLimit)) {
    kj::Maybe<kj::Own<ClientHook>> maybeCap;

1868 1869 1870 1871 1872 1873
    KJ_REQUIRE(brokenCapFactory != nullptr,
               "Trying to read capabilities without ever having created a capability context.  "
               "To read capabilities from a message, you must imbue it with CapReaderContext, or "
               "use the Cap'n Proto RPC system.");

    if (ref->isNull()) {
1874
      return brokenCapFactory->newBrokenCap("Calling null capability pointer.");
1875 1876 1877 1878 1879
    } else if (!ref->isCapability()) {
      KJ_FAIL_REQUIRE(
          "Message contains non-capability pointer where capability pointer was expected.") {
        break;
      }
1880
      return brokenCapFactory->newBrokenCap(
1881
          "Calling capability extracted from a non-capability pointer.");
1882
    } else KJ_IF_MAYBE(cap, segment->getArena()->extractCap(ref->capRef.index.get())) {
1883 1884
      return kj::mv(*cap);
    } else {
1885 1886 1887 1888
      KJ_FAIL_REQUIRE("Message contains invalid capability pointer.") {
        break;
      }
      return brokenCapFactory->newBrokenCap("Calling invalid capability pointer.");
1889 1890
    }
  }
1891
#endif  // !CAPNP_LITE
1892

1893
  static KJ_ALWAYS_INLINE(ListReader readListPointer(
1894
      SegmentReader* segment, const WirePointer* ref, const word* defaultValue,
1895
      ElementSize expectedElementSize, int nestingLimit, bool checkElementSize = true)) {
1896
    return readListPointer(segment, ref, ref->target(), defaultValue,
1897
                           expectedElementSize, nestingLimit, checkElementSize);
1898 1899 1900 1901
  }

  static KJ_ALWAYS_INLINE(ListReader readListPointer(
      SegmentReader* segment, const WirePointer* ref, const word* refTarget,
1902
      const word* defaultValue, ElementSize expectedElementSize, int nestingLimit,
1903
      bool checkElementSize = true)) {
1904
    if (ref->isNull()) {
1905
    useDefault:
Kenton Varda's avatar
Kenton Varda committed
1906
      if (defaultValue == nullptr ||
1907
          reinterpret_cast<const WirePointer*>(defaultValue)->isNull()) {
1908
        return ListReader();
1909
      }
1910
      segment = nullptr;
1911
      ref = reinterpret_cast<const WirePointer*>(defaultValue);
1912
      refTarget = ref->target();
1913 1914
      defaultValue = nullptr;  // If the default value is itself invalid, don't use it again.
    }
1915

1916
    KJ_REQUIRE(nestingLimit > 0,
David Renshaw's avatar
David Renshaw committed
1917
               "Message is too deeply-nested or contains cycles.  See capnp::ReaderOptions.") {
1918 1919
      goto useDefault;
    }
1920

1921
    const word* ptr = followFars(ref, refTarget, segment);
1922
    if (KJ_UNLIKELY(ptr == nullptr)) {
1923 1924 1925 1926
      // Already reported error.
      goto useDefault;
    }

1927 1928
    KJ_REQUIRE(ref->kind() == WirePointer::LIST,
               "Message contains non-list pointer where list pointer was expected.") {
1929
      goto useDefault;
1930 1931
    }

1932 1933
    ElementSize elementSize = ref->listRef.elementSize();
    if (elementSize == ElementSize::INLINE_COMPOSITE) {
1934 1935 1936 1937
#if _MSC_VER
      // TODO(msvc): MSVC thinks decltype(WORDS/ELEMENTS) is a const type. /eyeroll
      uint wordsPerElement;
#else
1938
      decltype(WORDS/ELEMENTS) wordsPerElement;
1939
#endif
1940
      ElementCount size;
1941

1942
      WordCount wordCount = ref->listRef.inlineCompositeWordCount();
1943

1944 1945 1946
      // An INLINE_COMPOSITE list points to a tag, which is formatted like a pointer.
      const WirePointer* tag = reinterpret_cast<const WirePointer*>(ptr);
      ptr += POINTER_SIZE_IN_WORDS;
1947

1948 1949
      KJ_REQUIRE(boundsCheck(segment, ptr - POINTER_SIZE_IN_WORDS, ptr + wordCount),
                 "Message contains out-of-bounds list pointer.") {
1950 1951
        goto useDefault;
      }
1952

1953 1954
      KJ_REQUIRE(tag->kind() == WirePointer::STRUCT,
                 "INLINE_COMPOSITE lists of non-STRUCT type are not supported.") {
1955 1956
        goto useDefault;
      }
1957

1958 1959
      size = tag->inlineCompositeListElementCount();
      wordsPerElement = tag->structRef.wordSize() / ELEMENTS;
1960

1961
      KJ_REQUIRE(ElementCount64(size) * wordsPerElement <= wordCount,
1962
                 "INLINE_COMPOSITE list's elements overrun its word count.") {
1963 1964
        goto useDefault;
      }
1965

1966 1967 1968 1969 1970 1971 1972 1973 1974
      if (wordsPerElement * (1 * ELEMENTS) == 0 * WORDS) {
        // Watch out for lists of zero-sized structs, which can claim to be arbitrarily large
        // without having sent actual data.
        KJ_REQUIRE(amplifiedRead(segment, size * (1 * WORDS / ELEMENTS)),
                   "Message contains amplified list pointer.") {
          goto useDefault;
        }
      }

1975 1976 1977 1978 1979
      if (checkElementSize) {
        // If a struct list was not expected, then presumably a non-struct list was upgraded to a
        // struct list.  We need to manipulate the pointer to point at the first field of the
        // struct.  Together with the "stepBits", this will allow the struct list to be accessed as
        // if it were a primitive list without branching.
1980

1981 1982
        // Check whether the size is compatible.
        switch (expectedElementSize) {
1983
          case ElementSize::VOID:
1984
            break;
1985

1986
          case ElementSize::BIT:
1987 1988 1989 1990 1991 1992
            KJ_FAIL_REQUIRE(
                "Found struct list where bit list was expected; upgrading boolean lists to structs "
                "is no longer supported.") {
              goto useDefault;
            }
            break;
1993

1994 1995 1996 1997
          case ElementSize::BYTE:
          case ElementSize::TWO_BYTES:
          case ElementSize::FOUR_BYTES:
          case ElementSize::EIGHT_BYTES:
1998 1999 2000 2001 2002
            KJ_REQUIRE(tag->structRef.dataSize.get() > 0 * WORDS,
                       "Expected a primitive list, but got a list of pointer-only structs.") {
              goto useDefault;
            }
            break;
2003

2004
          case ElementSize::POINTER:
2005 2006 2007 2008 2009 2010 2011 2012 2013
            // We expected a list of pointers but got a list of structs.  Assuming the first field
            // in the struct is the pointer we were looking for, we want to munge the pointer to
            // point at the first element's pointer section.
            ptr += tag->structRef.dataSize.get();
            KJ_REQUIRE(tag->structRef.ptrCount.get() > 0 * POINTERS,
                       "Expected a pointer list, but got a list of data-only structs.") {
              goto useDefault;
            }
            break;
2014

2015
          case ElementSize::INLINE_COMPOSITE:
2016 2017
            break;
        }
2018 2019
      }

2020
      return ListReader(
2021 2022
          segment, ptr, size, wordsPerElement * BITS_PER_WORD,
          tag->structRef.dataSize.get() * BITS_PER_WORD,
2023
          tag->structRef.ptrCount.get(), ElementSize::INLINE_COMPOSITE,
2024
          nestingLimit - 1);
2025 2026

    } else {
2027
      // This is a primitive or pointer list, but all such lists can also be interpreted as struct
2028
      // lists.  We need to compute the data size and pointer count for such structs.
2029
      BitCount dataSize = dataBitsPerElement(ref->listRef.elementSize()) * ELEMENTS;
2030
      WirePointerCount pointerCount =
2031
          pointersPerElement(ref->listRef.elementSize()) * ELEMENTS;
2032
      ElementCount elementCount = ref->listRef.elementCount();
2033
      auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS;
2034

2035 2036
      WordCount wordCount = roundBitsUpToWords(ElementCount64(elementCount) * step);
      KJ_REQUIRE(boundsCheck(segment, ptr, ptr + wordCount),
2037
                 "Message contains out-of-bounds list pointer.") {
2038
        goto useDefault;
2039 2040
      }

2041 2042 2043 2044 2045 2046 2047 2048 2049
      if (elementSize == ElementSize::VOID) {
        // Watch out for lists of void, which can claim to be arbitrarily large without having sent
        // actual data.
        KJ_REQUIRE(amplifiedRead(segment, elementCount * (1 * WORDS / ELEMENTS)),
                   "Message contains amplified list pointer.") {
          goto useDefault;
        }
      }

2050
      if (checkElementSize) {
2051
        if (elementSize == ElementSize::BIT && expectedElementSize != ElementSize::BIT) {
2052 2053 2054 2055 2056
          KJ_FAIL_REQUIRE(
              "Found bit list where struct list was expected; upgrading boolean lists to structs "
              "is no longer supported.") {
            goto useDefault;
          }
2057 2058
        }

2059 2060 2061 2062
        // Verify that the elements are at least as large as the expected type.  Note that if we
        // expected INLINE_COMPOSITE, the expected sizes here will be zero, because bounds checking
        // will be performed at field access time.  So this check here is for the case where we
        // expected a list of some primitive or pointer type.
2063

2064 2065 2066 2067
        BitCount expectedDataBitsPerElement =
            dataBitsPerElement(expectedElementSize) * ELEMENTS;
        WirePointerCount expectedPointersPerElement =
            pointersPerElement(expectedElementSize) * ELEMENTS;
2068

2069 2070 2071 2072 2073 2074 2075 2076
        KJ_REQUIRE(expectedDataBitsPerElement <= dataSize,
                   "Message contained list with incompatible element type.") {
          goto useDefault;
        }
        KJ_REQUIRE(expectedPointersPerElement <= pointerCount,
                   "Message contained list with incompatible element type.") {
          goto useDefault;
        }
2077
      }
2078

2079
      return ListReader(segment, ptr, elementCount, step,
2080
                        dataSize, pointerCount, elementSize, nestingLimit - 1);
2081 2082
    }
  }
Kenton Varda's avatar
Kenton Varda committed
2083

2084
  static KJ_ALWAYS_INLINE(Text::Reader readTextPointer(
2085
      SegmentReader* segment, const WirePointer* ref,
Kenton Varda's avatar
Kenton Varda committed
2086
      const void* defaultValue, ByteCount defaultSize)) {
2087 2088 2089 2090 2091 2092
    return readTextPointer(segment, ref, ref->target(), defaultValue, defaultSize);
  }

  static KJ_ALWAYS_INLINE(Text::Reader readTextPointer(
      SegmentReader* segment, const WirePointer* ref, const word* refTarget,
      const void* defaultValue, ByteCount defaultSize)) {
2093
    if (ref->isNull()) {
Kenton Varda's avatar
Kenton Varda committed
2094
    useDefault:
2095
      if (defaultValue == nullptr) defaultValue = "";
Kenton Varda's avatar
Kenton Varda committed
2096 2097
      return Text::Reader(reinterpret_cast<const char*>(defaultValue), defaultSize / BYTES);
    } else {
2098
      const word* ptr = followFars(ref, refTarget, segment);
Kenton Varda's avatar
Kenton Varda committed
2099

2100
      if (KJ_UNLIKELY(ptr == nullptr)) {
2101
        // Already reported error.
Kenton Varda's avatar
Kenton Varda committed
2102 2103 2104
        goto useDefault;
      }

2105 2106
      uint size = ref->listRef.elementCount() / ELEMENTS;

2107 2108
      KJ_REQUIRE(ref->kind() == WirePointer::LIST,
                 "Message contains non-list pointer where text was expected.") {
Kenton Varda's avatar
Kenton Varda committed
2109 2110 2111
        goto useDefault;
      }

2112
      KJ_REQUIRE(ref->listRef.elementSize() == ElementSize::BYTE,
2113
                 "Message contains list pointer of non-bytes where text was expected.") {
Kenton Varda's avatar
Kenton Varda committed
2114 2115 2116
        goto useDefault;
      }

2117
      KJ_REQUIRE(boundsCheck(segment, ptr, ptr +
2118
                     roundBytesUpToWords(ref->listRef.elementCount() * (1 * BYTES / ELEMENTS))),
2119
                 "Message contained out-of-bounds text pointer.") {
Kenton Varda's avatar
Kenton Varda committed
2120 2121 2122
        goto useDefault;
      }

2123
      KJ_REQUIRE(size > 0, "Message contains text that is not NUL-terminated.") {
2124 2125 2126
        goto useDefault;
      }

Kenton Varda's avatar
Kenton Varda committed
2127 2128 2129
      const char* cptr = reinterpret_cast<const char*>(ptr);
      --size;  // NUL terminator

2130
      KJ_REQUIRE(cptr[size] == '\0', "Message contains text that is not NUL-terminated.") {
Kenton Varda's avatar
Kenton Varda committed
2131 2132 2133 2134 2135 2136 2137
        goto useDefault;
      }

      return Text::Reader(cptr, size);
    }
  }

2138
  static KJ_ALWAYS_INLINE(Data::Reader readDataPointer(
2139
      SegmentReader* segment, const WirePointer* ref,
Kenton Varda's avatar
Kenton Varda committed
2140
      const void* defaultValue, ByteCount defaultSize)) {
2141 2142 2143 2144 2145 2146
    return readDataPointer(segment, ref, ref->target(), defaultValue, defaultSize);
  }

  static KJ_ALWAYS_INLINE(Data::Reader readDataPointer(
      SegmentReader* segment, const WirePointer* ref, const word* refTarget,
      const void* defaultValue, ByteCount defaultSize)) {
2147
    if (ref->isNull()) {
Kenton Varda's avatar
Kenton Varda committed
2148
    useDefault:
2149
      return Data::Reader(reinterpret_cast<const byte*>(defaultValue), defaultSize / BYTES);
Kenton Varda's avatar
Kenton Varda committed
2150
    } else {
2151
      const word* ptr = followFars(ref, refTarget, segment);
Kenton Varda's avatar
Kenton Varda committed
2152

2153
      if (KJ_UNLIKELY(ptr == nullptr)) {
2154
        // Already reported error.
Kenton Varda's avatar
Kenton Varda committed
2155 2156 2157
        goto useDefault;
      }

2158 2159
      uint size = ref->listRef.elementCount() / ELEMENTS;

2160 2161
      KJ_REQUIRE(ref->kind() == WirePointer::LIST,
                 "Message contains non-list pointer where data was expected.") {
Kenton Varda's avatar
Kenton Varda committed
2162 2163 2164
        goto useDefault;
      }

2165
      KJ_REQUIRE(ref->listRef.elementSize() == ElementSize::BYTE,
2166
                 "Message contains list pointer of non-bytes where data was expected.") {
Kenton Varda's avatar
Kenton Varda committed
2167 2168 2169
        goto useDefault;
      }

2170
      KJ_REQUIRE(boundsCheck(segment, ptr, ptr +
2171
                     roundBytesUpToWords(ref->listRef.elementCount() * (1 * BYTES / ELEMENTS))),
2172
                 "Message contained out-of-bounds data pointer.") {
Kenton Varda's avatar
Kenton Varda committed
2173 2174 2175
        goto useDefault;
      }

2176
      return Data::Reader(reinterpret_cast<const byte*>(ptr), size);
Kenton Varda's avatar
Kenton Varda committed
2177 2178
    }
  }
2179 2180 2181
};

// =======================================================================================
2182
// PointerBuilder
2183

2184 2185
StructBuilder PointerBuilder::initStruct(StructSize size) {
  return WireHelpers::initStructPointer(pointer, segment, size);
2186 2187
}

2188 2189
StructBuilder PointerBuilder::getStruct(StructSize size, const word* defaultValue) {
  return WireHelpers::getWritableStructPointer(pointer, segment, size, defaultValue);
2190 2191
}

2192
ListBuilder PointerBuilder::initList(ElementSize elementSize, ElementCount elementCount) {
2193
  return WireHelpers::initListPointer(pointer, segment, elementCount, elementSize);
2194 2195
}

2196 2197
ListBuilder PointerBuilder::initStructList(ElementCount elementCount, StructSize elementSize) {
  return WireHelpers::initStructListPointer(pointer, segment, elementCount, elementSize);
2198 2199
}

2200
ListBuilder PointerBuilder::getList(ElementSize elementSize, const word* defaultValue) {
2201
  return WireHelpers::getWritableListPointer(pointer, segment, elementSize, defaultValue);
2202
}
2203

2204 2205 2206 2207
ListBuilder PointerBuilder::getStructList(StructSize elementSize, const word* defaultValue) {
  return WireHelpers::getWritableStructListPointer(pointer, segment, elementSize, defaultValue);
}

2208 2209 2210 2211
ListBuilder PointerBuilder::getListAnySize(const word* defaultValue) {
  return WireHelpers::getWritableListPointerAnySize(pointer, segment, defaultValue);
}

2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222
template <>
Text::Builder PointerBuilder::initBlob<Text>(ByteCount size) {
  return WireHelpers::initTextPointer(pointer, segment, size).value;
}
template <>
void PointerBuilder::setBlob<Text>(Text::Reader value) {
  WireHelpers::setTextPointer(pointer, segment, value);
}
template <>
Text::Builder PointerBuilder::getBlob<Text>(const void* defaultValue, ByteCount defaultSize) {
  return WireHelpers::getWritableTextPointer(pointer, segment, defaultValue, defaultSize);
2223 2224
}

2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235
template <>
Data::Builder PointerBuilder::initBlob<Data>(ByteCount size) {
  return WireHelpers::initDataPointer(pointer, segment, size).value;
}
template <>
void PointerBuilder::setBlob<Data>(Data::Reader value) {
  WireHelpers::setDataPointer(pointer, segment, value);
}
template <>
Data::Builder PointerBuilder::getBlob<Data>(const void* defaultValue, ByteCount defaultSize) {
  return WireHelpers::getWritableDataPointer(pointer, segment, defaultValue, defaultSize);
2236 2237
}

2238 2239
void PointerBuilder::setStruct(const StructReader& value) {
  WireHelpers::setStructPointer(segment, pointer, value);
2240 2241
}

2242 2243
void PointerBuilder::setList(const ListReader& value) {
  WireHelpers::setListPointer(segment, pointer, value);
2244 2245
}

2246
#if !CAPNP_LITE
2247
kj::Own<ClientHook> PointerBuilder::getCapability() {
2248
  return WireHelpers::readCapabilityPointer(
2249
      segment, pointer, kj::maxValue);
2250 2251
}

2252
void PointerBuilder::setCapability(kj::Own<ClientHook>&& cap) {
2253 2254
  WireHelpers::setCapabilityPointer(segment, pointer, kj::mv(cap));
}
2255
#endif  // !CAPNP_LITE
2256

2257 2258
void PointerBuilder::adopt(OrphanBuilder&& value) {
  WireHelpers::adopt(segment, pointer, kj::mv(value));
Kenton Varda's avatar
Kenton Varda committed
2259
}
2260 2261 2262

OrphanBuilder PointerBuilder::disown() {
  return WireHelpers::disown(segment, pointer);
Kenton Varda's avatar
Kenton Varda committed
2263 2264
}

2265 2266 2267 2268 2269
void PointerBuilder::clear() {
  WireHelpers::zeroObject(segment, pointer);
  memset(pointer, 0, sizeof(WirePointer));
}

2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
PointerType PointerBuilder::getPointerType() {
  if(pointer->isNull()) {
    return PointerType::NULL_;
  } else {
    WirePointer* ptr = pointer;
    WireHelpers::followFars(ptr, ptr->target(), segment);
    switch(ptr->kind()) {
    case WirePointer::Kind::FAR:
      KJ_FAIL_REQUIRE();
    case WirePointer::Kind::STRUCT:
      return PointerType::STRUCT;
    case WirePointer::Kind::LIST:
      return PointerType::LIST;
    case WirePointer::Kind::OTHER:
      // TODO: make sure we're only looking at capability pointers
      return PointerType::CAPABILITY;
    }
  }
2288 2289
}

2290
void PointerBuilder::transferFrom(PointerBuilder other) {
2291 2292 2293 2294
  if (!pointer->isNull()) {
    WireHelpers::zeroObject(segment, pointer);
    memset(pointer, 0, sizeof(*pointer));
  }
2295 2296 2297 2298
  WireHelpers::transferPointer(segment, pointer, other.segment, other.pointer);
}

void PointerBuilder::copyFrom(PointerReader other) {
2299 2300 2301 2302 2303 2304 2305
  if (!pointer->isNull()) {
    WireHelpers::zeroObject(segment, pointer);
    memset(pointer, 0, sizeof(*pointer));
  }
  if (other.pointer != nullptr) {
    WireHelpers::copyPointer(segment, pointer, other.segment, other.pointer, other.nestingLimit);
  }
2306 2307 2308
}

PointerReader PointerBuilder::asReader() const {
2309
  return PointerReader(segment, pointer, kj::maxValue);
2310 2311
}

2312 2313
BuilderArena* PointerBuilder::getArena() const {
  return segment->getArena();
2314 2315
}

2316 2317 2318
// =======================================================================================
// PointerReader

Kenton Varda's avatar
Kenton Varda committed
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328
PointerReader PointerReader::getRoot(SegmentReader* segment, const word* location,
                                     int nestingLimit) {
  KJ_REQUIRE(WireHelpers::boundsCheck(segment, location, location + POINTER_SIZE_IN_WORDS),
             "Root location out-of-bounds.") {
    location = nullptr;
  }

  return PointerReader(segment, reinterpret_cast<const WirePointer*>(location), nestingLimit);
}

2329 2330 2331 2332 2333
StructReader PointerReader::getStruct(const word* defaultValue) const {
  const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer;
  return WireHelpers::readStructPointer(segment, ref, defaultValue, nestingLimit);
}

2334
ListReader PointerReader::getList(ElementSize expectedElementSize, const word* defaultValue) const {
2335 2336 2337 2338 2339
  const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer;
  return WireHelpers::readListPointer(
      segment, ref, defaultValue, expectedElementSize, nestingLimit);
}

2340 2341 2342
ListReader PointerReader::getListAnySize(const word* defaultValue) const {
  const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer;
  return WireHelpers::readListPointer(
2343
      segment, ref, defaultValue, ElementSize::VOID /* dummy */, nestingLimit, false);
2344 2345
}

2346
template <>
2347 2348 2349
Text::Reader PointerReader::getBlob<Text>(const void* defaultValue, ByteCount defaultSize) const {
  const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer;
  return WireHelpers::readTextPointer(segment, ref, defaultValue, defaultSize);
Kenton Varda's avatar
Kenton Varda committed
2350
}
2351

2352
template <>
2353 2354 2355
Data::Reader PointerReader::getBlob<Data>(const void* defaultValue, ByteCount defaultSize) const {
  const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer;
  return WireHelpers::readDataPointer(segment, ref, defaultValue, defaultSize);
Kenton Varda's avatar
Kenton Varda committed
2356 2357
}

2358
#if !CAPNP_LITE
2359
kj::Own<ClientHook> PointerReader::getCapability() const {
2360 2361 2362
  const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer;
  return WireHelpers::readCapabilityPointer(segment, ref, nestingLimit);
}
2363
#endif  // !CAPNP_LITE
2364

2365 2366 2367
const word* PointerReader::getUnchecked() const {
  KJ_REQUIRE(segment == nullptr, "getUncheckedPointer() only allowed on unchecked messages.");
  return reinterpret_cast<const word*>(pointer);
2368 2369
}

2370
MessageSizeCounts PointerReader::targetSize() const {
2371 2372
  return pointer == nullptr ? MessageSizeCounts { 0 * WORDS, 0 }
                            : WireHelpers::totalSize(segment, pointer, nestingLimit);
Kenton Varda's avatar
Kenton Varda committed
2373 2374
}

2375
PointerType PointerReader::getPointerType() const {
2376
  if(pointer == nullptr || pointer->isNull()) {
2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394
    return PointerType::NULL_;
  } else {
    word* refTarget = nullptr;
    const WirePointer* ptr = pointer;
    SegmentReader* sgmt = segment;
    WireHelpers::followFars(ptr, refTarget, sgmt);
    switch(ptr->kind()) {
    case WirePointer::Kind::FAR:
      KJ_FAIL_REQUIRE();
    case WirePointer::Kind::STRUCT:
      return PointerType::STRUCT;
    case WirePointer::Kind::LIST:
      return PointerType::LIST;
    case WirePointer::Kind::OTHER:
      // TODO: make sure we're only looking at capability pointers
      return PointerType::CAPABILITY;
    }
  }
2395 2396
}

2397 2398 2399 2400
kj::Maybe<Arena&> PointerReader::getArena() const {
  return segment == nullptr ? nullptr : segment->getArena();
}

2401 2402 2403
// =======================================================================================
// StructBuilder

2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416
void StructBuilder::clearAll() {
  if (dataSize == 1 * BITS) {
    setDataField<bool>(1 * ELEMENTS, false);
  } else {
    memset(data, 0, dataSize / BITS_PER_BYTE / BYTES);
  }

  for (uint i = 0; i < pointerCount / POINTERS; i++) {
    WireHelpers::zeroObject(segment, pointers + i);
  }
  memset(pointers, 0, pointerCount * BYTES_PER_POINTER / BYTES);
}

2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442
void StructBuilder::transferContentFrom(StructBuilder other) {
  // Determine the amount of data the builders have in common.
  BitCount sharedDataSize = kj::min(dataSize, other.dataSize);

  if (dataSize > sharedDataSize) {
    // Since the target is larger than the source, make sure to zero out the extra bits that the
    // source doesn't have.
    if (dataSize == 1 * BITS) {
      setDataField<bool>(0 * ELEMENTS, false);
    } else {
      byte* unshared = reinterpret_cast<byte*>(data) + sharedDataSize / BITS_PER_BYTE / BYTES;
      memset(unshared, 0, (dataSize - sharedDataSize) / BITS_PER_BYTE / BYTES);
    }
  }

  // Copy over the shared part.
  if (sharedDataSize == 1 * BITS) {
    setDataField<bool>(0 * ELEMENTS, other.getDataField<bool>(0 * ELEMENTS));
  } else {
    memcpy(data, other.data, sharedDataSize / BITS_PER_BYTE / BYTES);
  }

  // Zero out all pointers in the target.
  for (uint i = 0; i < pointerCount / POINTERS; i++) {
    WireHelpers::zeroObject(segment, pointers + i);
  }
2443
  memset(pointers, 0, pointerCount * BYTES_PER_POINTER / BYTES);
2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456

  // Transfer the pointers.
  WirePointerCount sharedPointerCount = kj::min(pointerCount, other.pointerCount);
  for (uint i = 0; i < sharedPointerCount / POINTERS; i++) {
    WireHelpers::transferPointer(segment, pointers + i, other.segment, other.pointers + i);
  }

  // Zero out the pointers that were transferred in the source because it no longer has ownership.
  // If the source had any extra pointers that the destination didn't have space for, we
  // intentionally leave them be, so that they'll be cleaned up later.
  memset(other.pointers, 0, sharedPointerCount * BYTES_PER_POINTER / BYTES);
}

2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487
void StructBuilder::copyContentFrom(StructReader other) {
  // Determine the amount of data the builders have in common.
  BitCount sharedDataSize = kj::min(dataSize, other.dataSize);

  if (dataSize > sharedDataSize) {
    // Since the target is larger than the source, make sure to zero out the extra bits that the
    // source doesn't have.
    if (dataSize == 1 * BITS) {
      setDataField<bool>(0 * ELEMENTS, false);
    } else {
      byte* unshared = reinterpret_cast<byte*>(data) + sharedDataSize / BITS_PER_BYTE / BYTES;
      memset(unshared, 0, (dataSize - sharedDataSize) / BITS_PER_BYTE / BYTES);
    }
  }

  // Copy over the shared part.
  if (sharedDataSize == 1 * BITS) {
    setDataField<bool>(0 * ELEMENTS, other.getDataField<bool>(0 * ELEMENTS));
  } else {
    memcpy(data, other.data, sharedDataSize / BITS_PER_BYTE / BYTES);
  }

  // Zero out all pointers in the target.
  for (uint i = 0; i < pointerCount / POINTERS; i++) {
    WireHelpers::zeroObject(segment, pointers + i);
  }
  memset(pointers, 0, pointerCount * BYTES_PER_POINTER / BYTES);

  // Copy the pointers.
  WirePointerCount sharedPointerCount = kj::min(pointerCount, other.pointerCount);
  for (uint i = 0; i < sharedPointerCount / POINTERS; i++) {
2488 2489
    WireHelpers::copyPointer(segment, pointers + i,
        other.segment, other.pointers + i, other.nestingLimit);
2490 2491 2492
  }
}

2493
StructReader StructBuilder::asReader() const {
2494
  return StructReader(segment, data, pointers,
2495
      dataSize, pointerCount, kj::maxValue);
2496 2497
}

2498 2499 2500 2501
BuilderArena* StructBuilder::getArena() {
  return segment->getArena();
}

2502 2503 2504
// =======================================================================================
// StructReader

2505 2506 2507
MessageSizeCounts StructReader::totalSize() const {
  MessageSizeCounts result = {
    WireHelpers::roundBitsUpToWords(dataSize) + pointerCount * WORDS_PER_POINTER, 0 };
2508 2509 2510 2511 2512 2513 2514 2515

  for (uint i = 0; i < pointerCount / POINTERS; i++) {
    result += WireHelpers::totalSize(segment, pointers + i, nestingLimit);
  }

  if (segment != nullptr) {
    // This traversal should not count against the read limit, because it's highly likely that
    // the caller is going to traverse the object again, e.g. to copy it.
2516
    segment->unread(result.wordCount);
2517 2518 2519 2520 2521
  }

  return result;
}

2522 2523 2524
// =======================================================================================
// ListBuilder

2525
Text::Builder ListBuilder::asText() {
2526 2527
  KJ_REQUIRE(structDataSize == 8 * BITS && structPointerCount == 0 * POINTERS,
             "Expected Text, got list of non-bytes.") {
2528 2529 2530 2531 2532
    return Text::Builder();
  }

  size_t size = elementCount / ELEMENTS;

2533
  KJ_REQUIRE(size > 0, "Message contains text that is not NUL-terminated.") {
2534 2535 2536 2537 2538 2539
    return Text::Builder();
  }

  char* cptr = reinterpret_cast<char*>(ptr);
  --size;  // NUL terminator

2540
  KJ_REQUIRE(cptr[size] == '\0', "Message contains text that is not NUL-terminated.") {
2541 2542 2543 2544 2545 2546 2547
    return Text::Builder();
  }

  return Text::Builder(cptr, size);
}

Data::Builder ListBuilder::asData() {
2548 2549
  KJ_REQUIRE(structDataSize == 8 * BITS && structPointerCount == 0 * POINTERS,
             "Expected Text, got list of non-bytes.") {
2550 2551 2552
    return Data::Builder();
  }

2553
  return Data::Builder(reinterpret_cast<byte*>(ptr), elementCount / ELEMENTS);
2554 2555
}

2556
StructBuilder ListBuilder::getStructElement(ElementCount index) {
2557 2558
  BitCount64 indexBit = ElementCount64(index) * step;
  byte* structData = ptr + indexBit / BITS_PER_BYTE;
2559
  KJ_DASSERT(indexBit % BITS_PER_BYTE == 0 * BITS);
2560
  return StructBuilder(segment, structData,
2561
      reinterpret_cast<WirePointer*>(structData + structDataSize / BITS_PER_BYTE),
2562
      structDataSize, structPointerCount);
2563 2564
}

2565
ListReader ListBuilder::asReader() const {
2566
  return ListReader(segment, ptr, elementCount, step, structDataSize, structPointerCount,
2567
                    elementSize, kj::maxValue);
2568 2569
}

2570 2571 2572 2573
BuilderArena* ListBuilder::getArena() {
  return segment->getArena();
}

2574 2575 2576
// =======================================================================================
// ListReader

2577
Text::Reader ListReader::asText() {
2578 2579
  KJ_REQUIRE(structDataSize == 8 * BITS && structPointerCount == 0 * POINTERS,
             "Expected Text, got list of non-bytes.") {
2580 2581 2582 2583 2584
    return Text::Reader();
  }

  size_t size = elementCount / ELEMENTS;

2585
  KJ_REQUIRE(size > 0, "Message contains text that is not NUL-terminated.") {
2586 2587 2588 2589 2590 2591
    return Text::Reader();
  }

  const char* cptr = reinterpret_cast<const char*>(ptr);
  --size;  // NUL terminator

2592
  KJ_REQUIRE(cptr[size] == '\0', "Message contains text that is not NUL-terminated.") {
2593 2594 2595 2596 2597 2598 2599
    return Text::Reader();
  }

  return Text::Reader(cptr, size);
}

Data::Reader ListReader::asData() {
2600 2601
  KJ_REQUIRE(structDataSize == 8 * BITS && structPointerCount == 0 * POINTERS,
             "Expected Text, got list of non-bytes.") {
2602 2603 2604
    return Data::Reader();
  }

2605
  return Data::Reader(reinterpret_cast<const byte*>(ptr), elementCount / ELEMENTS);
2606 2607
}

2608
kj::ArrayPtr<const byte> ListReader::asRawBytes() {
2609 2610
  KJ_REQUIRE(structPointerCount == 0 * POINTERS,
             "Expected data only, got pointers.") {
2611
    return kj::ArrayPtr<const byte>();
2612 2613
  }

2614
  return kj::ArrayPtr<const byte>(reinterpret_cast<const byte*>(ptr), structDataSize * elementCount / ELEMENTS);
2615 2616 2617
}


2618
StructReader ListReader::getStructElement(ElementCount index) const {
2619
  KJ_REQUIRE(nestingLimit > 0,
David Renshaw's avatar
David Renshaw committed
2620
             "Message is too deeply-nested or contains cycles.  See capnp::ReaderOptions.") {
2621
    return StructReader();
2622
  }
2623

2624 2625
  BitCount64 indexBit = ElementCount64(index) * step;
  const byte* structData = ptr + indexBit / BITS_PER_BYTE;
2626 2627
  const WirePointer* structPointers =
      reinterpret_cast<const WirePointer*>(structData + structDataSize / BITS_PER_BYTE);
2628 2629

  // This check should pass if there are no bugs in the list pointer validation code.
2630
  KJ_DASSERT(structPointerCount == 0 * POINTERS ||
Kenton Varda's avatar
Kenton Varda committed
2631
         (uintptr_t)structPointers % sizeof(void*) == 0,
2632
         "Pointer section of struct list element not aligned.");
2633

2634
  KJ_DASSERT(indexBit % BITS_PER_BYTE == 0 * BITS);
2635
  return StructReader(
2636
      segment, structData, structPointers,
2637
      structDataSize, structPointerCount,
2638
      nestingLimit - 1);
2639
}
2640

2641 2642 2643 2644 2645
// =======================================================================================
// OrphanBuilder

OrphanBuilder OrphanBuilder::initStruct(BuilderArena* arena, StructSize size) {
  OrphanBuilder result;
2646 2647
  StructBuilder builder = WireHelpers::initStructPointer(result.tagAsPtr(), nullptr, size, arena);
  result.segment = builder.segment;
2648
  result.location = builder.getLocation();
2649 2650 2651 2652
  return result;
}

OrphanBuilder OrphanBuilder::initList(
2653
    BuilderArena* arena, ElementCount elementCount, ElementSize elementSize) {
2654
  OrphanBuilder result;
2655 2656 2657
  ListBuilder builder = WireHelpers::initListPointer(
      result.tagAsPtr(), nullptr, elementCount, elementSize, arena);
  result.segment = builder.segment;
2658
  result.location = builder.getLocation();
2659 2660 2661 2662 2663
  return result;
}

OrphanBuilder OrphanBuilder::initStructList(
    BuilderArena* arena, ElementCount elementCount, StructSize elementSize) {
2664 2665 2666 2667 2668 2669
  OrphanBuilder result;
  ListBuilder builder = WireHelpers::initStructListPointer(
      result.tagAsPtr(), nullptr, elementCount, elementSize, arena);
  result.segment = builder.segment;
  result.location = builder.getLocation();
  return result;
2670 2671 2672 2673
}

OrphanBuilder OrphanBuilder::initText(BuilderArena* arena, ByteCount size) {
  OrphanBuilder result;
2674 2675 2676
  auto allocation = WireHelpers::initTextPointer(result.tagAsPtr(), nullptr, size, arena);
  result.segment = allocation.segment;
  result.location = reinterpret_cast<word*>(allocation.value.begin());
2677 2678 2679 2680 2681
  return result;
}

OrphanBuilder OrphanBuilder::initData(BuilderArena* arena, ByteCount size) {
  OrphanBuilder result;
2682 2683 2684
  auto allocation = WireHelpers::initDataPointer(result.tagAsPtr(), nullptr, size, arena);
  result.segment = allocation.segment;
  result.location = reinterpret_cast<word*>(allocation.value.begin());
2685 2686 2687 2688 2689
  return result;
}

OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, StructReader copyFrom) {
  OrphanBuilder result;
2690 2691 2692
  auto allocation = WireHelpers::setStructPointer(nullptr, result.tagAsPtr(), copyFrom, arena);
  result.segment = allocation.segment;
  result.location = reinterpret_cast<word*>(allocation.value);
2693 2694 2695 2696 2697
  return result;
}

OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, ListReader copyFrom) {
  OrphanBuilder result;
2698 2699 2700
  auto allocation = WireHelpers::setListPointer(nullptr, result.tagAsPtr(), copyFrom, arena);
  result.segment = allocation.segment;
  result.location = reinterpret_cast<word*>(allocation.value);
2701 2702 2703
  return result;
}

2704 2705
OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, PointerReader copyFrom) {
  OrphanBuilder result;
2706 2707
  auto allocation = WireHelpers::copyPointer(
      nullptr, result.tagAsPtr(), copyFrom.segment, copyFrom.pointer, copyFrom.nestingLimit, arena);
2708 2709 2710 2711 2712
  result.segment = allocation.segment;
  result.location = reinterpret_cast<word*>(allocation.value);
  return result;
}

2713 2714
OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, Text::Reader copyFrom) {
  OrphanBuilder result;
2715 2716 2717 2718
  auto allocation = WireHelpers::setTextPointer(
      result.tagAsPtr(), nullptr, copyFrom, arena);
  result.segment = allocation.segment;
  result.location = reinterpret_cast<word*>(allocation.value.begin());
2719 2720 2721 2722 2723
  return result;
}

OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, Data::Reader copyFrom) {
  OrphanBuilder result;
2724 2725 2726 2727
  auto allocation = WireHelpers::setDataPointer(
      result.tagAsPtr(), nullptr, copyFrom, arena);
  result.segment = allocation.segment;
  result.location = reinterpret_cast<word*>(allocation.value.begin());
2728 2729 2730
  return result;
}

2731
#if !CAPNP_LITE
2732
OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, kj::Own<ClientHook> copyFrom) {
2733
  OrphanBuilder result;
2734 2735 2736
  WireHelpers::setCapabilityPointer(nullptr, result.tagAsPtr(), kj::mv(copyFrom), arena);
  result.segment = arena->getSegment(SegmentId(0));
  result.location = &result.tag;  // dummy to make location non-null
2737 2738
  return result;
}
2739
#endif  // !CAPNP_LITE
2740

2741 2742 2743 2744 2745 2746 2747 2748 2749
OrphanBuilder OrphanBuilder::referenceExternalData(BuilderArena* arena, Data::Reader data) {
  KJ_REQUIRE(reinterpret_cast<uintptr_t>(data.begin()) % sizeof(void*) == 0,
             "Cannot referenceExternalData() that is not aligned.");

  auto wordCount = WireHelpers::roundBytesUpToWords(data.size() * BYTES);
  kj::ArrayPtr<const word> words(reinterpret_cast<const word*>(data.begin()), wordCount / WORDS);

  OrphanBuilder result;
  result.tagAsPtr()->setKindForOrphan(WirePointer::LIST);
2750
  result.tagAsPtr()->listRef.set(ElementSize::BYTE, data.size() * ELEMENTS);
2751 2752 2753 2754 2755 2756 2757 2758 2759
  result.segment = arena->addExternalSegment(words);

  // const_cast OK here because we will check whether the segment is writable when we try to get
  // a builder.
  result.location = const_cast<word*>(words.begin());

  return result;
}

2760
StructBuilder OrphanBuilder::asStruct(StructSize size) {
2761 2762
  KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));

2763
  StructBuilder result = WireHelpers::getWritableStructPointer(
2764
      tagAsPtr(), location, segment, size, nullptr, segment->getArena());
2765 2766

  // Watch out, the pointer could have been updated if the object had to be relocated.
2767
  location = reinterpret_cast<word*>(result.data);
2768 2769 2770 2771

  return result;
}

2772
ListBuilder OrphanBuilder::asList(ElementSize elementSize) {
2773 2774
  KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));

2775
  ListBuilder result = WireHelpers::getWritableListPointer(
2776
      tagAsPtr(), location, segment, elementSize, nullptr, segment->getArena());
2777 2778

  // Watch out, the pointer could have been updated if the object had to be relocated.
2779 2780 2781
  // (Actually, currently this is not true for primitive lists, but let's not turn into a bug if
  // it changes!)
  location = result.getLocation();
2782 2783 2784 2785 2786

  return result;
}

ListBuilder OrphanBuilder::asStructList(StructSize elementSize) {
2787 2788
  KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));

2789
  ListBuilder result = WireHelpers::getWritableStructListPointer(
2790
      tagAsPtr(), location, segment, elementSize, nullptr, segment->getArena());
2791 2792

  // Watch out, the pointer could have been updated if the object had to be relocated.
2793
  location = result.getLocation();
2794 2795 2796 2797 2798

  return result;
}

Text::Builder OrphanBuilder::asText() {
2799 2800
  KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));

2801 2802 2803 2804 2805
  // Never relocates.
  return WireHelpers::getWritableTextPointer(tagAsPtr(), location, segment, nullptr, 0 * BYTES);
}

Data::Builder OrphanBuilder::asData() {
2806 2807
  KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));

2808 2809 2810 2811
  // Never relocates.
  return WireHelpers::getWritableDataPointer(tagAsPtr(), location, segment, nullptr, 0 * BYTES);
}

2812
StructReader OrphanBuilder::asStructReader(StructSize size) const {
2813
  KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));
2814
  return WireHelpers::readStructPointer(
2815
      segment, tagAsPtr(), location, nullptr, kj::maxValue);
2816 2817
}

2818
ListReader OrphanBuilder::asListReader(ElementSize elementSize) const {
2819
  KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));
2820
  return WireHelpers::readListPointer(
2821
      segment, tagAsPtr(), location, nullptr, elementSize, kj::maxValue);
2822 2823
}

2824
#if !CAPNP_LITE
2825
kj::Own<ClientHook> OrphanBuilder::asCapability() const {
2826
  return WireHelpers::readCapabilityPointer(segment, tagAsPtr(), kj::maxValue);
2827
}
2828
#endif  // !CAPNP_LITE
2829

2830
Text::Reader OrphanBuilder::asTextReader() const {
2831
  KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));
2832 2833 2834 2835
  return WireHelpers::readTextPointer(segment, tagAsPtr(), location, nullptr, 0 * BYTES);
}

Data::Reader OrphanBuilder::asDataReader() const {
2836
  KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));
2837 2838 2839
  return WireHelpers::readDataPointer(segment, tagAsPtr(), location, nullptr, 0 * BYTES);
}

2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851
void OrphanBuilder::truncate(ElementCount size, bool isText) {
  if (isText) size += 1 * ELEMENTS;

  WirePointer* ref = tagAsPtr();
  SegmentBuilder* segment = this->segment;

  word* target = WireHelpers::followFars(ref, location, segment);

  KJ_REQUIRE(ref->kind() == WirePointer::LIST, "Can't truncate non-list.") {
    return;
  }

2852
  // TODO(someday): Implement truncation of all sizes.
2853
  KJ_ASSERT(ref->listRef.elementSize() == ElementSize::BYTE,
2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873
            "Not implemented: truncate non-blob.");

  auto oldSize = ref->listRef.elementCount();
  KJ_REQUIRE(size <= oldSize, "Truncate size must be smaller than existing size.") {
    return;
  }

  ref->listRef.set(ref->listRef.elementSize(), size);

  byte* begin = reinterpret_cast<byte*>(target);
  byte* truncPoint = begin + size * (1 * BYTES / ELEMENTS);
  byte* end = begin + oldSize * (1 * BYTES / ELEMENTS);
  memset(truncPoint - isText, 0, end - truncPoint + isText);

  word* truncWord = target + WireHelpers::roundBytesUpToWords(size * (1 * BYTES / ELEMENTS));
  word* endWord = target + WireHelpers::roundBytesUpToWords(oldSize * (1 * BYTES / ELEMENTS));

  segment->tryTruncate(endWord, truncWord);
}

2874
void OrphanBuilder::euthanize() {
2875 2876 2877
  // Carefully catch any exceptions and rethrow them as recoverable exceptions since we may be in
  // a destructor.
  auto exception = kj::runCatchingExceptions([&]() {
2878
    if (tagAsPtr()->isPositional()) {
2879
      WireHelpers::zeroObject(segment, tagAsPtr(), location);
2880 2881
    } else {
      WireHelpers::zeroObject(segment, tagAsPtr());
2882
    }
2883

2884
    memset(&tag, 0, sizeof(tag));
2885 2886 2887 2888 2889 2890 2891
    segment = nullptr;
    location = nullptr;
  });

  KJ_IF_MAYBE(e, exception) {
    kj::getExceptionCallback().onRecoverableException(kj::mv(*e));
  }
2892 2893
}

2894
}  // namespace _ (private)
2895
}  // namespace capnp