_ZN2mp11ProxyClientIN4test4fuzz8messages16IpcFuzzInterfaceEED2Ev:
   11|      1|ProxyClient<test::fuzz::messages::IpcFuzzInterface>::~ProxyClient() { clientDestroy(*this);  }
_ZN2mp11ProxyServerIN4test4fuzz8messages16IpcFuzzInterfaceEED2Ev:
   12|      1|ProxyServer<test::fuzz::messages::IpcFuzzInterface>::~ProxyServer() { serverDestroy(*this); }

_ZNK5capnp10AnyPointer6Reader15getPipelinedCapEN2kj8ArrayPtrIKNS_10PipelineOpEEE:
   39|      1|    kj::ArrayPtr<const PipelineOp> ops) const {
   40|      1|  _::PointerReader pointer = reader;
   41|       |
   42|      1|  for (auto& op: ops) {
  ------------------
  |  Branch (42:16): [True: 0, False: 1]
  ------------------
   43|      0|    switch (op.type) {
  ------------------
  |  Branch (43:13): [True: 0, False: 0]
  ------------------
   44|      0|      case PipelineOp::Type::NOOP:
  ------------------
  |  Branch (44:7): [True: 0, False: 0]
  ------------------
   45|      0|        break;
   46|       |
   47|      0|      case PipelineOp::Type::GET_POINTER_FIELD:
  ------------------
  |  Branch (47:7): [True: 0, False: 0]
  ------------------
   48|      0|        pointer = pointer.getStruct(nullptr).getPointerField(bounded(op.pointerIndex) * POINTERS);
   49|      0|        break;
   50|      0|    }
   51|      0|  }
   52|       |
   53|      1|  return pointer.getCapability();
   54|      1|}

_ZN5capnp1_5ArenaD2Ev:
   39|     11|Arena::~Arena() noexcept(false) {}
_ZN5capnp1_11ReaderArenaC2EPNS_13MessageReaderE:
  100|      3|    : ReaderArena(message, message->getSegment(0)) {}
_ZN5capnp1_11ReaderArenaD2Ev:
  102|      4|ReaderArena::~ReaderArena() noexcept(false) {}
_ZN5capnp1_11ReaderArena13tryGetSegmentEN2kj2IdIjNS0_7SegmentEEE:
  114|      4|SegmentReader* ReaderArena::tryGetSegment(SegmentId id) {
  115|      4|  if (id == SegmentId(0)) {
  ------------------
  |  Branch (115:7): [True: 4, False: 0]
  ------------------
  116|      4|    if (segment0.getArray() == nullptr) {
  ------------------
  |  Branch (116:9): [True: 0, False: 4]
  ------------------
  117|      0|      return nullptr;
  118|      4|    } else {
  119|      4|      return &segment0;
  120|      4|    }
  121|      4|  }
  122|       |
  123|      0|  auto lock = moreSegments.lockExclusive();
  124|       |
  125|      0|  SegmentMap* segments = nullptr;
  126|      0|  KJ_IF_MAYBE(s, *lock) {
  ------------------
  |  Branch (126:3): [True: 0, False: 0]
  ------------------
  127|      0|    KJ_IF_MAYBE(segment, s->find(id.value)) {
  ------------------
  |  Branch (127:5): [True: 0, False: 0]
  ------------------
  128|      0|      return *segment;
  129|      0|    }
  130|      0|    segments = s;
  131|      0|  }
  132|       |
  133|      0|  kj::ArrayPtr<const word> newSegment = message->getSegment(id.value);
  134|      0|  if (newSegment == nullptr) {
  ------------------
  |  Branch (134:7): [True: 0, False: 0]
  ------------------
  135|      0|    return nullptr;
  136|      0|  }
  137|       |
  138|      0|  SegmentWordCount newSegmentSize = verifySegment(newSegment);
  139|       |
  140|      0|  if (*lock == nullptr) {
  ------------------
  |  Branch (140:7): [True: 0, False: 0]
  ------------------
  141|       |    // OK, the segment exists, so allocate the map.
  142|      0|    segments = &lock->emplace();
  143|      0|  }
  144|       |
  145|      0|  auto segment = kj::heap<SegmentReader>(
  146|      0|      this, id, newSegment.begin(), newSegmentSize, &readLimiter);
  147|      0|  SegmentReader* result = segment;
  148|      0|  segments->insert(id.value, kj::mv(segment));
  149|      0|  return result;
  150|      0|}
_ZN5capnp1_12BuilderArenaC2EPNS_14MessageBuilderE:
  161|      4|    : message(message), segment0(nullptr, SegmentId(0), nullptr, nullptr) {}
_ZN5capnp1_12BuilderArenaD2Ev:
  192|      7|BuilderArena::~BuilderArena() noexcept(false) {}
_ZN5capnp1_12BuilderArena11sizeInWordsEv:
  194|      5|size_t BuilderArena::sizeInWords() {
  195|      5|  KJ_IF_MAYBE(segmentState, moreSegments) {
  ------------------
  |  Branch (195:3): [True: 0, False: 5]
  ------------------
  196|      0|    size_t total = segment0.currentlyAllocated().size();
  197|      0|    for (auto& builder: segmentState->get()->builders) {
  ------------------
  |  Branch (197:23): [True: 0, False: 0]
  ------------------
  198|      0|      total += builder->currentlyAllocated().size();
  199|      0|    }
  200|      0|    return total;
  201|      5|  } else {
  202|      5|    if (segment0.getArena() == nullptr) {
  ------------------
  |  Branch (202:9): [True: 0, False: 5]
  ------------------
  203|       |      // We haven't actually allocated any segments yet.
  204|      0|      return 0;
  205|      5|    } else {
  206|       |      // We have only one segment so far.
  207|      5|      return segment0.currentlyAllocated().size();
  208|      5|    }
  209|      5|  }
  210|      5|}
_ZN5capnp1_12BuilderArena8allocateEj:
  226|      4|BuilderArena::AllocateResult BuilderArena::allocate(SegmentWordCount amount) {
  227|      4|  if (segment0.getArena() == nullptr) {
  ------------------
  |  Branch (227:7): [True: 4, False: 0]
  ------------------
  228|       |    // We're allocating the first segment.
  229|      4|    kj::ArrayPtr<word> ptr = message->allocateSegment(unbound(amount / WORDS));
  230|      4|    auto actualSize = verifySegment(ptr);
  231|       |
  232|       |    // Re-allocate segment0 in-place.  This is a bit of a hack, but we have not returned any
  233|       |    // pointers to this segment yet, so it should be fine.
  234|      4|    kj::dtor(segment0);
  235|      4|    kj::ctor(segment0, this, SegmentId(0), ptr.begin(), actualSize, &this->dummyLimiter);
  236|       |
  237|      4|    segmentWithSpace = &segment0;
  238|      4|    return AllocateResult { &segment0, segment0.allocate(amount) };
  239|      4|  } else {
  240|      0|    if (segmentWithSpace != nullptr) {
  ------------------
  |  Branch (240:9): [True: 0, False: 0]
  ------------------
  241|       |      // Check if there is space in an existing segment.
  242|       |      // TODO(perf):  Check for available space in more than just the last segment.  We don't
  243|       |      //   want this to be O(n), though, so we'll need to maintain some sort of table.  Complicating
  244|       |      //   matters, we want SegmentBuilders::allocate() to be fast, so we can't update any such
  245|       |      //   table when allocation actually happens.  Instead, we could have a priority queue based
  246|       |      //   on the last-known available size, and then re-check the size when we pop segments off it
  247|       |      //   and shove them to the back of the queue if they have become too small.
  248|      0|      word* attempt = segmentWithSpace->allocate(amount);
  249|      0|      if (attempt != nullptr) {
  ------------------
  |  Branch (249:11): [True: 0, False: 0]
  ------------------
  250|      0|        return AllocateResult { segmentWithSpace, attempt };
  251|      0|      }
  252|      0|    }
  253|       |
  254|       |    // Need to allocate a new segment.
  255|      0|    SegmentBuilder* result = addSegmentInternal(message->allocateSegment(unbound(amount / WORDS)));
  256|       |
  257|       |    // Check this new segment first the next time we need to allocate.
  258|      0|    segmentWithSpace = result;
  259|       |
  260|       |    // Allocating from the new segment is guaranteed to succeed since we made it big enough.
  261|      0|    return AllocateResult { result, result->allocate(amount) };
  262|      0|  }
  263|      4|}
_ZN5capnp1_12BuilderArena20getSegmentsForOutputEv:
  300|      8|kj::ArrayPtr<const kj::ArrayPtr<const word>> BuilderArena::getSegmentsForOutput() {
  301|       |  // Although this is a read-only method, we shouldn't need to lock a mutex here because if this
  302|       |  // is called multiple times simultaneously, we should only be overwriting the array with the
  303|       |  // exact same data.  If the number or size of segments is actually changing due to an activity
  304|       |  // in another thread, then the caller has a problem regardless of locking here.
  305|       |
  306|      8|  KJ_IF_MAYBE(segmentState, moreSegments) {
  ------------------
  |  Branch (306:3): [True: 0, False: 8]
  ------------------
  307|      0|    KJ_DASSERT(segmentState->get()->forOutput.size() == segmentState->get()->builders.size() + 1,
  ------------------
  |  Branch (307:5): [Folded, False: 0]
  ------------------
  308|      0|        "segmentState->forOutput wasn't resized correctly when the last builder was added.",
  309|      0|        segmentState->get()->forOutput.size(), segmentState->get()->builders.size());
  310|       |
  311|      0|    kj::ArrayPtr<kj::ArrayPtr<const word>> result(
  312|      0|        &segmentState->get()->forOutput[0], segmentState->get()->forOutput.size());
  313|      0|    uint i = 0;
  314|      0|    result[i++] = segment0.currentlyAllocated();
  315|      0|    for (auto& builder: segmentState->get()->builders) {
  ------------------
  |  Branch (315:23): [True: 0, False: 0]
  ------------------
  316|      0|      result[i++] = builder->currentlyAllocated();
  317|      0|    }
  318|      0|    return result;
  319|      8|  } else {
  320|      8|    if (segment0.getArena() == nullptr) {
  ------------------
  |  Branch (320:9): [True: 0, False: 8]
  ------------------
  321|       |      // We haven't actually allocated any segments yet.
  322|      0|      return nullptr;
  323|      8|    } else {
  324|       |      // We have only one segment so far.
  325|      8|      segment0ForOutput = segment0.currentlyAllocated();
  326|      8|      return kj::arrayPtr(&segment0ForOutput, 1);
  327|      8|    }
  328|      8|  }
  329|      8|}
_ZN5capnp1_11ReaderArenaC2EPNS_13MessageReaderEN2kj8ArrayPtrIKNS_4wordEEE:
   97|      3|    : ReaderArena(message, firstSegment.begin(), verifySegment(firstSegment)) {}
_ZN5capnp1_11ReaderArenaC2EPNS_13MessageReaderEPKNS_4wordEj:
   92|      3|    : message(message),
   93|      3|      readLimiter(bounded(message->getOptions().traversalLimitInWords) * WORDS),
   94|      3|      segment0(this, SegmentId(0), firstSegment, firstSegmentSize, &readLimiter) {}
arena.c++:_ZN5capnp1_L13verifySegmentEN2kj8ArrayPtrIKNS_4wordEEE:
   74|      7|static SegmentWordCount verifySegment(kj::ArrayPtr<const word> segment) {
   75|      7|#if !CAPNP_ALLOW_UNALIGNED
   76|      7|  KJ_REQUIRE(reinterpret_cast<uintptr_t>(segment.begin()) % sizeof(void*) == 0,
  ------------------
  |  Branch (76:3): [True: 7, False: 0]
  ------------------
   77|      0|      "Detected unaligned data in Cap'n Proto message. Messages must be aligned to the "
   78|      0|      "architecture's word size. Yes, even on x86: Unaligned access is undefined behavior "
   79|      0|      "under the C/C++ language standard, and compilers can and do assume alignment for the "
   80|      0|      "purpose of optimizations. Unaligned access may lead to crashes or subtle corruption. "
   81|      0|      "For example, GCC will use SIMD instructions in optimizations, and those instrsuctions "
   82|      0|      "require alignment. If you really insist on taking your changes with unaligned data, "
   83|      0|      "compile the Cap'n Proto library with -DCAPNP_ALLOW_UNALIGNED to remove this check.") {
   84|      0|    break;
   85|      0|  }
   86|      7|#endif
   87|      7|  return verifySegmentSize(segment.size());
   88|      7|}
arena.c++:_ZN5capnp1_L17verifySegmentSizeEm:
   67|      7|static SegmentWordCount verifySegmentSize(size_t size) {
   68|      7|  auto gsize = bounded(size) * WORDS;
   69|      7|  return assertMaxBits<SEGMENT_WORD_COUNT_BITS>(gsize, [&]() {
   70|      7|    KJ_FAIL_REQUIRE("segment is too large", size);
   71|      7|  });
   72|      7|}

_ZN5capnp10ClientHookC2Ev:
   60|      1|ClientHook::ClientHook() {
   61|      1|  setGlobalBrokenCapFactoryForLayoutCpp(brokenCapFactory);
   62|      1|}
_ZN5capnp12ResponseHookD2Ev:
  112|      1|ResponseHook::~ResponseHook() noexcept(false) {}
_ZN5capnp21ReaderCapabilityTableC2EN2kj5ArrayINS1_5MaybeINS1_3OwnINS_10ClientHookEDnEEEEEE:
 1107|      1|    : table(kj::mv(table)) {
 1108|      1|  setGlobalBrokenCapFactoryForLayoutCpp(brokenCapFactory);
 1109|      1|}
_ZN5capnp21ReaderCapabilityTable10extractCapEj:
 1111|      1|kj::Maybe<kj::Own<ClientHook>> ReaderCapabilityTable::extractCap(uint index) {
 1112|      1|  if (index < table.size()) {
  ------------------
  |  Branch (1112:7): [True: 1, False: 0]
  ------------------
 1113|      1|    return table[index].map([](kj::Own<ClientHook>& cap) { return cap->addRef(); });
 1114|      1|  } else {
 1115|      0|    return nullptr;
 1116|      0|  }
 1117|      1|}
_ZN5capnp22BuilderCapabilityTable9injectCapEON2kj3OwnINS_10ClientHookEDnEE:
 1131|      1|uint BuilderCapabilityTable::injectCap(kj::Own<ClientHook>&& cap) {
 1132|      1|  uint result = table.size();
 1133|      1|  table.add(kj::mv(cap));
 1134|      1|  return result;
 1135|      1|}
_ZN5capnp11LocalClient11getResolvedEv:
  668|      2|  kj::Maybe<ClientHook&> getResolved() override {
  669|      2|    return resolved.map([](kj::Own<ClientHook>& hook) -> ClientHook& { return *hook; });
  670|      2|  }
_ZN5capnp11LocalClient16whenMoreResolvedEv:
  672|      1|  kj::Maybe<kj::Promise<kj::Own<ClientHook>>> whenMoreResolved() override {
  673|      1|    KJ_IF_MAYBE(r, resolved) {
  ------------------
  |  Branch (673:5): [True: 0, False: 1]
  ------------------
  674|      0|      return kj::Promise<kj::Own<ClientHook>>(r->get()->addRef());
  675|      1|    } else KJ_IF_MAYBE(t, resolveTask) {
  ------------------
  |  Branch (675:12): [True: 0, False: 1]
  ------------------
  676|      0|      return t->addBranch().then([this]() {
  677|      0|        return KJ_ASSERT_NONNULL(resolved)->addRef();
  678|      0|      });
  679|      1|    } else {
  680|      1|      return nullptr;
  681|      1|    }
  682|      1|  }
_ZN5capnp11LocalClient6addRefEv:
  684|      2|  kj::Own<ClientHook> addRef() override {
  685|      2|    return kj::addRef(*this);
  686|      2|  }
_ZN5capnp11LocalClient8getBrandEv:
  691|      2|  const void* getBrand() override {
  692|      2|    return &BRAND;
  693|      2|  }
_ZN5capnp11LocalClient5getFdEv:
  731|      1|  kj::Maybe<int> getFd() override {
  732|      1|    KJ_IF_MAYBE(s, server) {
  ------------------
  |  Branch (732:5): [True: 1, False: 0]
  ------------------
  733|      1|      return s->get()->getFd();
  734|      1|    } else {
  735|      0|      return nullptr;
  736|      0|    }
  737|      1|  }
_ZN5capnp11LocalClientD2Ev:
  559|      1|  ~LocalClient() noexcept(false) {
  560|      1|    KJ_IF_MAYBE(s, server) {
  ------------------
  |  Branch (560:5): [True: 1, False: 0]
  ------------------
  561|      1|      s->get()->thisHook = nullptr;
  562|      1|    }
  563|      1|  }
capability.c++:_ZZN5capnp21ReaderCapabilityTable10extractCapEjENK3$_0clERN2kj3OwnINS_10ClientHookEDnEE:
 1113|      1|    return table[index].map([](kj::Own<ClientHook>& cap) { return cap->addRef(); });

_ZN5capnp1_37setGlobalBrokenCapFactoryForLayoutCppERNS0_16BrokenCapFactoryE:
   41|      2|void setGlobalBrokenCapFactoryForLayoutCpp(BrokenCapFactory& factory) {
   42|       |  // Called from capability.c++ when the capability API is used, to make sure that layout.c++
   43|       |  // is ready for it.  May be called multiple times but always with the same value.
   44|      2|#if __GNUC__ || defined(__clang__)
   45|      2|  __atomic_store_n(&globalBrokenCapFactory, &factory, __ATOMIC_RELAXED);
   46|       |#elif _MSC_VER
   47|       |  *static_cast<BrokenCapFactory* volatile*>(&globalBrokenCapFactory) = &factory;
   48|       |#else
   49|       |#error "Platform not supported"
   50|       |#endif
   51|      2|}
_ZN5capnp1_14PointerBuilder10initStructENS0_10StructSizeE:
 2548|      5|StructBuilder PointerBuilder::initStruct(StructSize size) {
 2549|      5|  return WireHelpers::initStructPointer(pointer, segment, capTable, size);
 2550|      5|}
_ZN5capnp1_14PointerBuilder9getStructENS0_10StructSizeEPKNS_4wordE:
 2552|      3|StructBuilder PointerBuilder::getStruct(StructSize size, const word* defaultValue) {
 2553|      3|  return WireHelpers::getWritableStructPointer(pointer, segment, capTable, size, defaultValue);
 2554|      3|}
_ZN5capnp1_14PointerBuilder7setBlobINS_4TextEEEvNT_6ReaderE:
 2583|      2|void PointerBuilder::setBlob<Text>(Text::Reader value) {
 2584|      2|  WireHelpers::setTextPointer(pointer, segment, capTable, value);
 2585|      2|}
_ZN5capnp1_13PointerReader7getRootEPNS0_13SegmentReaderEPNS0_14CapTableReaderEPKNS_4wordEi:
 2706|      4|                                     const word* location, int nestingLimit) {
 2707|      4|  KJ_REQUIRE(WireHelpers::boundsCheck(segment, location, POINTER_SIZE_IN_WORDS),
  ------------------
  |  Branch (2707:3): [True: 4, False: 0]
  ------------------
 2708|      0|             "Root location out-of-bounds.") {
 2709|      0|    location = nullptr;
 2710|      0|  }
 2711|       |
 2712|      4|  return PointerReader(segment, capTable,
 2713|      4|      reinterpret_cast<const WirePointer*>(location), nestingLimit);
 2714|      4|}
_ZNK5capnp1_13PointerReader9getStructEPKNS_4wordE:
 2716|      7|StructReader PointerReader::getStruct(const word* defaultValue) const {
 2717|      7|  const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer;
  ------------------
  |  Branch (2717:28): [True: 0, False: 7]
  ------------------
 2718|      7|  return WireHelpers::readStructPointer(segment, capTable, ref, defaultValue, nestingLimit);
 2719|      7|}
_ZNK5capnp1_13PointerReader7getListENS_11ElementSizeEPKNS_4wordE:
 2721|      1|ListReader PointerReader::getList(ElementSize expectedElementSize, const word* defaultValue) const {
 2722|      1|  const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer;
  ------------------
  |  Branch (2722:28): [True: 0, False: 1]
  ------------------
 2723|      1|  return WireHelpers::readListPointer(
 2724|      1|      segment, capTable, ref, defaultValue, expectedElementSize, nestingLimit);
 2725|      1|}
_ZNK5capnp1_13PointerReader13getCapabilityEv:
 2747|      1|kj::Own<ClientHook> PointerReader::getCapability() const {
 2748|      1|  const WirePointer* ref = pointer == nullptr ? &zero.pointer : pointer;
  ------------------
  |  Branch (2748:28): [True: 0, False: 1]
  ------------------
 2749|      1|  return WireHelpers::readCapabilityPointer(segment, capTable, ref, nestingLimit);
 2750|      1|}
_ZNK5capnp1_13PointerReader5imbueEPNS0_14CapTableReaderE:
 2794|      1|PointerReader PointerReader::imbue(CapTableReader* capTable) const {
 2795|      1|  auto result = *this;
 2796|      1|  result.capTable = capTable;
 2797|      1|  return result;
 2798|      1|}
_ZNK5capnp1_10ListReader16getStructElementEj:
 3164|      1|StructReader ListReader::getStructElement(ElementCount index) const {
 3165|      1|  KJ_REQUIRE(nestingLimit > 0,
  ------------------
  |  Branch (3165:3): [True: 1, False: 0]
  ------------------
 3166|      0|             "Message is too deeply-nested or contains cycles.  See capnp::ReaderOptions.") {
 3167|      0|    return StructReader();
 3168|      0|  }
 3169|       |
 3170|      1|  auto indexBit = upgradeBound<uint64_t>(index) * step;
 3171|      1|  const byte* structData = ptr + indexBit / BITS_PER_BYTE;
 3172|      1|  const WirePointer* structPointers =
 3173|      1|      reinterpret_cast<const WirePointer*>(structData + structDataSize / BITS_PER_BYTE);
 3174|       |
 3175|       |  KJ_DASSERT(indexBit % BITS_PER_BYTE == ZERO * BITS);
  ------------------
  |  Branch (3175:3): [Folded, False: 1]
  ------------------
 3176|      1|  return StructReader(
 3177|      1|      segment, capTable, structData, structPointers,
 3178|      1|      structDataSize, structPointerCount,
 3179|      1|      nestingLimit - 1);
 3180|      1|}
_ZN5capnp1_11WireHelpers17initStructPointerEPNS0_11WirePointerEPNS0_14SegmentBuilderEPNS0_15CapTableBuilderENS0_10StructSizeEPNS0_12BuilderArenaE:
 1110|      8|      BuilderArena* orphanArena = nullptr)) {
 1111|       |    // Allocate space for the new struct.  Newly-allocated space is automatically zeroed.
 1112|      8|    word* ptr = allocate(ref, segment, capTable, size.total(), WirePointer::STRUCT, orphanArena);
 1113|       |
 1114|       |    // Initialize the pointer.
 1115|      8|    ref->structRef.set(size);
 1116|       |
 1117|       |    // Build the StructBuilder.
 1118|      8|    return StructBuilder(segment, capTable, ptr, reinterpret_cast<WirePointer*>(ptr + size.data),
 1119|      8|                         size.data * BITS_PER_WORD, size.pointers);
 1120|      8|  }
_ZN5capnp1_11WireHelpers8allocateERPNS0_11WirePointerERPNS0_14SegmentBuilderEPNS0_15CapTableBuilderEjNS2_4KindEPNS0_12BuilderArenaE:
  461|     10|      SegmentWordCount amount, WirePointer::Kind kind, BuilderArena* orphanArena)) {
  462|       |    // Allocate space in the message for a new object, creating far pointers if necessary. The
  463|       |    // space is guaranteed to be zero'd (because MessageBuilder implementations are required to
  464|       |    // return zero'd memory).
  465|       |    //
  466|       |    // * `ref` starts out being a reference to the pointer which shall be assigned to point at the
  467|       |    //   new object.  On return, `ref` points to a pointer which needs to be initialized with
  468|       |    //   the object's type information.  Normally this is the same pointer, but it can change if
  469|       |    //   a far pointer was allocated -- in this case, `ref` will end up pointing to the far
  470|       |    //   pointer's tag.  Either way, `allocate()` takes care of making sure that the original
  471|       |    //   pointer ends up leading to the new object.  On return, only the upper 32 bit of `*ref`
  472|       |    //   need to be filled in by the caller.
  473|       |    // * `segment` starts out pointing to the segment containing `ref`.  On return, it points to
  474|       |    //   the segment containing the allocated object, which is usually the same segment but could
  475|       |    //   be a different one if the original segment was out of space.
  476|       |    // * `amount` is the number of words to allocate.
  477|       |    // * `kind` is the kind of object to allocate.  It is used to initialize the pointer.  It
  478|       |    //   cannot be `FAR` -- far pointers are allocated automatically as needed.
  479|       |    // * `orphanArena` is usually null.  If it is non-null, then we're allocating an orphan object.
  480|       |    //   In this case, `segment` starts out null; the allocation takes place in an arbitrary
  481|       |    //   segment belonging to the arena.  `ref` will be initialized as a non-far pointer, but its
  482|       |    //   target offset will be set to zero.
  483|       |
  484|     10|    if (orphanArena == nullptr) {
  ------------------
  |  Branch (484:9): [True: 10, False: 0]
  ------------------
  485|     10|      if (!ref->isNull()) zeroObject(segment, capTable, ref);
  ------------------
  |  Branch (485:11): [True: 0, False: 10]
  ------------------
  486|       |
  487|     10|      if (amount == ZERO * WORDS && kind == WirePointer::STRUCT) {
  ------------------
  |  Branch (487:11): [True: 0, False: 10]
  |  Branch (487:37): [True: 0, False: 0]
  ------------------
  488|       |        // Note that the check for kind == WirePointer::STRUCT will hopefully cause this whole
  489|       |        // branch to be optimized away from all the call sites that are allocating non-structs.
  490|      0|        ref->setKindAndTargetForEmptyStruct();
  491|      0|        return reinterpret_cast<word*>(ref);
  492|      0|      }
  493|       |
  494|     10|      KJ_ASSUME(segment != nullptr);
  ------------------
  |  Branch (494:7): [True: 10, False: 0]
  |  Branch (494:7): [Folded, False: 10]
  ------------------
  495|     10|      word* ptr = segment->allocate(amount);
  496|       |
  497|     10|      if (ptr == nullptr) {
  ------------------
  |  Branch (497:11): [True: 0, False: 10]
  ------------------
  498|       |
  499|       |        // Need to allocate in a new segment.  We'll need to allocate an extra pointer worth of
  500|       |        // space to act as the landing pad for a far pointer.
  501|       |
  502|      0|        WordCount amountPlusRef = amount + POINTER_SIZE_IN_WORDS;
  503|      0|        auto allocation = segment->getArena()->allocate(
  504|      0|            assertMaxBits<SEGMENT_WORD_COUNT_BITS>(amountPlusRef, []() {
  505|      0|              KJ_FAIL_REQUIRE("requested object size exceeds maximum segment size");
  506|      0|            }));
  507|      0|        segment = allocation.segment;
  508|      0|        ptr = allocation.words;
  509|       |
  510|       |        // Set up the original pointer to be a far pointer to the new segment.
  511|      0|        ref->setFar(false, segment->getOffsetTo(ptr));
  512|      0|        ref->farRef.set(segment->getSegmentId());
  513|       |
  514|       |        // Initialize the landing pad to indicate that the data immediately follows the pad.
  515|      0|        ref = reinterpret_cast<WirePointer*>(ptr);
  516|      0|        ref->setKindAndTarget(kind, ptr + POINTER_SIZE_IN_WORDS, segment);
  517|       |
  518|       |        // Allocated space follows new pointer.
  519|      0|        return ptr + POINTER_SIZE_IN_WORDS;
  520|     10|      } else {
  521|     10|        ref->setKindAndTarget(kind, ptr, segment);
  522|     10|        return ptr;
  523|     10|      }
  524|     10|    } else {
  525|       |      // orphanArena is non-null.  Allocate an orphan.
  526|       |      KJ_DASSERT(ref->isNull());
  ------------------
  |  Branch (526:7): [Folded, False: 0]
  ------------------
  527|      0|      auto allocation = orphanArena->allocate(amount);
  528|      0|      segment = allocation.segment;
  529|      0|      ref->setKindForOrphan(kind);
  530|      0|      return allocation.words;
  531|      0|    }
  532|     10|  }
_ZN5capnp1_11WirePointer16setKindAndTargetENS1_4KindEPNS_4wordEPNS0_14SegmentBuilderE:
  155|     10|  KJ_ALWAYS_INLINE(void setKindAndTarget(Kind kind, word* target, SegmentBuilder* segment)) {
  156|       |    // Check that the target is really in the same segment, otherwise subtracting pointers is
  157|       |    // undefined behavior.  As it turns out, it's undefined behavior that actually produces
  158|       |    // unexpected results in a real-world situation that actually happened:  At one time,
  159|       |    // OrphanBuilder's "tag" (a WirePointer) was allowed to be initialized as if it lived in
  160|       |    // a particular segment when in fact it does not.  On 32-bit systems, where words might
  161|       |    // only be 32-bit aligned, it's possible that the difference between `this` and `target` is
  162|       |    // not a whole number of words.  But clang optimizes:
  163|       |    //     (target - (word*)this - 1) << 2
  164|       |    // to:
  165|       |    //     (((ptrdiff_t)target - (ptrdiff_t)this - 8) >> 1)
  166|       |    // So now when the pointers are not aligned the same, we can end up corrupting the bottom
  167|       |    // two bits, where `kind` is stored.  For example, this turns a struct into a far pointer.
  168|       |    // Ouch!
  169|     10|    KJ_DREQUIRE(reinterpret_cast<uintptr_t>(this) >=
  ------------------
  |  Branch (169:5): [Folded, False: 10]
  ------------------
  170|     10|                reinterpret_cast<uintptr_t>(segment->getStartPtr()));
  171|     10|    KJ_DREQUIRE(reinterpret_cast<uintptr_t>(this) <
  ------------------
  |  Branch (171:5): [Folded, False: 10]
  ------------------
  172|     10|                reinterpret_cast<uintptr_t>(segment->getStartPtr() + segment->getSize()));
  173|     10|    KJ_DREQUIRE(reinterpret_cast<uintptr_t>(target) >=
  ------------------
  |  Branch (173:5): [Folded, False: 10]
  ------------------
  174|     10|                reinterpret_cast<uintptr_t>(segment->getStartPtr()));
  175|       |    KJ_DREQUIRE(reinterpret_cast<uintptr_t>(target) <=
  ------------------
  |  Branch (175:5): [Folded, False: 10]
  ------------------
  176|     10|                reinterpret_cast<uintptr_t>(segment->getStartPtr() + segment->getSize()));
  177|     10|    offsetAndKind.set((static_cast<uint32_t>(target - reinterpret_cast<word*>(this) - 1) << 2) | kind);
  178|     10|  }
_ZN5capnp1_11WirePointer9StructRef3setENS0_10StructSizeE:
  251|      8|    KJ_ALWAYS_INLINE(void set(StructSize size)) {
  252|      8|      dataSize.set(size.data);
  253|      8|      ptrCount.set(size.pointers);
  254|      8|    }
_ZN5capnp1_11WireHelpers24getWritableStructPointerEPNS0_11WirePointerEPNS0_14SegmentBuilderEPNS0_15CapTableBuilderENS0_10StructSizeEPKNS_4wordE:
 1124|      3|      const word* defaultValue)) {
 1125|      3|    return getWritableStructPointer(ref, ref->target(), segment, capTable, size, defaultValue);
 1126|      3|  }
layout.c++:_ZN5capnp1_11WireHelpers15initTextPointerEPNS0_11WirePointerEPNS0_14SegmentBuilderEPNS0_15CapTableBuilderEjPNS0_12BuilderArenaE:
 1630|      2|      BuilderArena* orphanArena = nullptr)) {
 1631|       |    // The byte list must include a NUL terminator.
 1632|      2|    auto byteSize = size + ONE * BYTES;
 1633|       |
 1634|       |    // Allocate the space.
 1635|      2|    word* ptr = allocate(
 1636|      2|        ref, segment, capTable, roundBytesUpToWords(byteSize), WirePointer::LIST, orphanArena);
 1637|       |
 1638|       |    // Initialize the pointer.
 1639|      2|    ref->listRef.set(ElementSize::BYTE, byteSize * (ONE * ELEMENTS / BYTES));
 1640|       |
 1641|       |    // Build the Text::Builder. Note that since allocate()ed memory is pre-zero'd, we don't need
 1642|       |    // to initialize the NUL terminator.
 1643|      2|    return { segment, Text::Builder(reinterpret_cast<char*>(ptr), unbound(size / BYTES)) };
 1644|      2|  }
layout.c++:_ZN5capnp1_11WireHelpers14setTextPointerEPNS0_11WirePointerEPNS0_14SegmentBuilderEPNS0_15CapTableBuilderENS_4Text6ReaderEPNS0_12BuilderArenaE:
 1648|      2|      BuilderArena* orphanArena = nullptr)) {
 1649|      2|    TextSize size = assertMax<MAX_TEXT_SIZE>(bounded(value.size()),
 1650|      2|        []() { KJ_FAIL_REQUIRE("text blob too big"); }) * BYTES;
 1651|       |
 1652|      2|    auto allocation = initTextPointer(ref, segment, capTable, size, orphanArena);
 1653|      2|    copyMemory(allocation.value.begin(), value);
 1654|      2|    return allocation;
 1655|      2|  }
_ZN5capnp1_11WireHelpers10copyMemoryEPcN2kj9StringPtrE:
  444|      2|  static KJ_ALWAYS_INLINE(void copyMemory(char* to, kj::StringPtr from)) {
  445|      2|    if (from.size() != 0u) memcpy(to, from.begin(), from.size() * sizeof(from[0]));
  ------------------
  |  Branch (445:9): [True: 2, False: 0]
  ------------------
  446|      2|  }
_ZN5capnp1_11WireHelpers21readCapabilityPointerEPNS0_13SegmentReaderEPNS0_14CapTableReaderEPKNS0_11WirePointerEi:
 2221|      1|      const WirePointer* ref, int nestingLimit)) {
 2222|      1|    kj::Maybe<kj::Own<ClientHook>> maybeCap;
 2223|       |
 2224|      1|    auto brokenCapFactory = readGlobalBrokenCapFactoryForLayoutCpp();
 2225|       |
 2226|      1|    KJ_REQUIRE(brokenCapFactory != nullptr,
  ------------------
  |  Branch (2226:5): [True: 1, False: 0]
  ------------------
 2227|      0|               "Trying to read capabilities without ever having created a capability context.  "
 2228|      0|               "To read capabilities from a message, you must imbue it with CapReaderContext, or "
 2229|      0|               "use the Cap'n Proto RPC system.");
 2230|       |
 2231|      1|    if (ref->isNull()) {
  ------------------
  |  Branch (2231:9): [True: 0, False: 1]
  ------------------
 2232|      0|      return brokenCapFactory->newNullCap();
 2233|      1|    } else if (!ref->isCapability()) {
  ------------------
  |  Branch (2233:16): [True: 0, False: 1]
  ------------------
 2234|      0|      KJ_FAIL_REQUIRE(
 2235|      0|          "Schema mismatch: Message contains non-capability pointer where capability pointer was "
 2236|      0|          "expected.") {
 2237|      0|        break;
 2238|      0|      }
 2239|      0|      return brokenCapFactory->newBrokenCap(
 2240|      0|          "Calling capability extracted from a non-capability pointer.");
 2241|      1|    } else KJ_IF_MAYBE(cap, capTable->extractCap(ref->capRef.index.get())) {
  ------------------
  |  Branch (2241:12): [True: 1, False: 0]
  ------------------
 2242|      1|      return kj::mv(*cap);
 2243|      1|    } else {
 2244|      0|      KJ_FAIL_REQUIRE("Message contains invalid capability pointer.") {
 2245|      0|        break;
 2246|      0|      }
 2247|      0|      return brokenCapFactory->newBrokenCap("Calling invalid capability pointer.");
 2248|      0|    }
 2249|      1|  }
layout.c++:_ZN5capnp1_L38readGlobalBrokenCapFactoryForLayoutCppEv:
   53|      1|static BrokenCapFactory* readGlobalBrokenCapFactoryForLayoutCpp() {
   54|      1|#if __GNUC__ || defined(__clang__)
   55|       |  // Thread-sanitizer doesn't have the right information to know this is safe without doing an
   56|       |  // atomic read. https://groups.google.com/g/capnproto/c/634juhn5ap0/m/pyRiwWl1AAAJ
   57|      1|  return __atomic_load_n(&globalBrokenCapFactory, __ATOMIC_RELAXED);
   58|       |#else
   59|       |  return globalBrokenCapFactory;
   60|       |#endif
   61|      1|}
_ZNK5capnp1_11WirePointer9StructRef8wordSizeEv:
  243|      8|    inline WordCountN<17> wordSize() const {
  244|      8|      return upgradeBound<uint32_t>(dataSize.get()) + ptrCount.get() * WORDS_PER_POINTER;
  245|      8|    }
_ZNK5capnp1_11WirePointer6isNullEv:
  306|     22|  KJ_ALWAYS_INLINE(bool isNull() const) {
  307|       |    // If the upper 32 bits are zero, this is a pointer to an empty struct.  We consider that to be
  308|       |    // our "null" value.
  309|     22|    return (offsetAndKind.get() == 0) & (upper32Bits == 0);
  310|     22|  }
_ZN5capnp1_11WirePointer6targetEv:
  143|      3|  KJ_ALWAYS_INLINE(word* target()) {
  144|      3|    return reinterpret_cast<word*>(this) + 1 + (static_cast<int32_t>(offsetAndKind.get()) >> 2);
  145|      3|  }
_ZNK5capnp1_11WirePointer4kindEv:
  133|     17|  KJ_ALWAYS_INLINE(Kind kind() const) {
  134|     17|    return static_cast<Kind>(offsetAndKind.get() & 3);
  135|     17|  }
_ZNK5capnp1_11WirePointer12isCapabilityEv:
  139|      1|  KJ_ALWAYS_INLINE(bool isCapability() const) {
  140|      1|    return offsetAndKind.get() == OTHER;
  141|      1|  }
_ZN5capnp1_11WireHelpers11boundsCheckEPNS0_13SegmentReaderEPKNS_4wordEj:
  449|     12|      SegmentReader* segment, const word* start, WordCountN<31> size)) {
  450|       |    // If segment is null, this is an unchecked message, so we don't do bounds checks.
  451|     12|    return segment == nullptr || segment->checkObject(start, size);
  ------------------
  |  Branch (451:12): [True: 0, False: 12]
  |  Branch (451:34): [True: 12, False: 0]
  ------------------
  452|     12|  }
_ZN5capnp1_11WireHelpers17readStructPointerEPNS0_13SegmentReaderEPNS0_14CapTableReaderEPKNS0_11WirePointerEPKNS_4wordEi:
 2165|      7|      int nestingLimit)) {
 2166|      7|    return readStructPointer(segment, capTable, ref, ref->target(segment),
 2167|      7|                             defaultValue, nestingLimit);
 2168|      7|  }
_ZN5capnp1_11WireHelpers15readListPointerEPNS0_13SegmentReaderEPNS0_14CapTableReaderEPKNS0_11WirePointerEPKNS_4wordENS_11ElementSizeEib:
 2255|      1|      ElementSize expectedElementSize, int nestingLimit, bool checkElementSize = true)) {
 2256|      1|    return readListPointer(segment, capTable, ref, ref->target(segment), defaultValue,
 2257|      1|                           expectedElementSize, nestingLimit, checkElementSize);
 2258|      1|  }
_ZNK5capnp1_11WirePointer6targetEPNS0_13SegmentReaderE:
  146|      8|  KJ_ALWAYS_INLINE(const word* target(SegmentReader* segment) const) {
  147|      8|    if (segment == nullptr) {
  ------------------
  |  Branch (147:9): [True: 0, False: 8]
  ------------------
  148|      0|      return reinterpret_cast<const word*>(this + 1) +
  149|      0|          (static_cast<int32_t>(offsetAndKind.get()) >> 2);
  150|      8|    } else {
  151|      8|      return segment->checkOffset(reinterpret_cast<const word*>(this + 1),
  152|      8|                                  static_cast<int32_t>(offsetAndKind.get()) >> 2);
  153|      8|    }
  154|      8|  }
_ZN5capnp1_11WireHelpers10followFarsERPKNS0_11WirePointerEPKNS_4wordERPNS0_13SegmentReaderE:
  573|      8|      KJ_WARN_UNUSED_RESULT {
  574|       |    // Like the other followFars() but operates on readers.
  575|       |
  576|       |    // If the segment is null, this is an unchecked message, so there are no FAR pointers.
  577|      8|    if (segment != nullptr && ref->kind() == WirePointer::FAR) {
  ------------------
  |  Branch (577:9): [True: 8, False: 0]
  |  Branch (577:31): [True: 0, False: 8]
  ------------------
  578|       |      // Look up the segment containing the landing pad.
  579|      0|      segment = segment->getArena()->tryGetSegment(ref->farRef.segmentId.get());
  580|      0|      KJ_REQUIRE(segment != nullptr, "Message contains far pointer to unknown segment.") {
  ------------------
  |  Branch (580:7): [True: 0, False: 0]
  ------------------
  581|      0|        return nullptr;
  582|      0|      }
  583|       |
  584|       |      // Find the landing pad and check that it is within bounds.
  585|      0|      const word* ptr = ref->farTarget(segment);
  586|      0|      auto padWords = (ONE + bounded(ref->isDoubleFar())) * POINTER_SIZE_IN_WORDS;
  587|      0|      KJ_REQUIRE(boundsCheck(segment, ptr, padWords),
  ------------------
  |  Branch (587:7): [True: 0, False: 0]
  ------------------
  588|      0|                 "Message contains out-of-bounds far pointer. "
  589|      0|                 OUT_OF_BOUNDS_ERROR_DETAIL) {
  590|      0|        return nullptr;
  591|      0|      }
  592|       |
  593|      0|      const WirePointer* pad = reinterpret_cast<const WirePointer*>(ptr);
  594|       |
  595|       |      // If this is not a double-far then the landing pad is our final pointer.
  596|      0|      if (!ref->isDoubleFar()) {
  ------------------
  |  Branch (596:11): [True: 0, False: 0]
  ------------------
  597|      0|        ref = pad;
  598|      0|        return pad->target(segment);
  599|      0|      }
  600|       |
  601|       |      // Landing pad is another far pointer.  It is followed by a tag describing the pointed-to
  602|       |      // object.
  603|      0|      ref = pad + 1;
  604|       |
  605|      0|      SegmentReader* newSegment = segment->getArena()->tryGetSegment(pad->farRef.segmentId.get());
  606|      0|      KJ_REQUIRE(newSegment != nullptr,
  ------------------
  |  Branch (606:7): [True: 0, False: 0]
  ------------------
  607|      0|          "Message contains double-far pointer to unknown segment.") {
  608|      0|        return nullptr;
  609|      0|      }
  610|      0|      KJ_REQUIRE(pad->kind() == WirePointer::FAR,
  ------------------
  |  Branch (610:7): [True: 0, False: 0]
  ------------------
  611|      0|          "Second word of double-far pad must be far pointer.") {
  612|      0|        return nullptr;
  613|      0|      }
  614|       |
  615|      0|      segment = newSegment;
  616|      0|      return pad->farTarget(segment);
  617|      8|    } else {
  618|       |      KJ_DASSERT(refTarget != nullptr);
  ------------------
  |  Branch (618:7): [Folded, False: 8]
  ------------------
  619|      8|      return refTarget;
  620|      8|    }
  621|      8|  }
_ZNK5capnp1_11WirePointer7ListRef24inlineCompositeWordCountEv:
  266|      1|    KJ_ALWAYS_INLINE(WordCountN<29> inlineCompositeWordCount() const) {
  267|      1|      return elementCount() * (ONE * WORDS / ELEMENTS);
  268|      1|    }
_ZN5capnp1_11WireHelpers19roundBytesUpToWordsEj:
  377|      2|  static KJ_ALWAYS_INLINE(WordCount roundBytesUpToWords(ByteCount bytes)) {
  378|      2|    static_assert(sizeof(word) == 8, "This code assumes 64-bit words.");
  379|      2|    return (bytes + G(7) * BYTES) / BYTES_PER_WORD;
  ------------------
  |  |   76|      2|#define G(n) n
  ------------------
  380|      2|  }
_ZN5capnp1_11WirePointer7ListRef3setENS_11ElementSizeEj:
  270|      2|    KJ_ALWAYS_INLINE(void set(ElementSize es, ElementCountN<29> ec)) {
  271|      2|      elementSizeAndCount.set(unboundAs<uint32_t>((ec / ELEMENTS) << G(3)) |
  ------------------
  |  |   76|      2|#define G(n) n
  ------------------
  272|      2|                              static_cast<int>(es));
  273|      2|    }
_ZN5capnp1_11WireHelpers24getWritableStructPointerEPNS0_11WirePointerEPNS_4wordEPNS0_14SegmentBuilderEPNS0_15CapTableBuilderENS0_10StructSizeEPKS4_PNS0_12BuilderArenaE:
 1130|      3|      StructSize size, const word* defaultValue, BuilderArena* orphanArena = nullptr)) {
 1131|      3|    if (ref->isNull()) {
  ------------------
  |  Branch (1131:9): [True: 3, False: 0]
  ------------------
 1132|      3|    useDefault:
 1133|      3|      if (defaultValue == nullptr ||
  ------------------
  |  Branch (1133:11): [True: 3, False: 0]
  ------------------
 1134|      3|          reinterpret_cast<const WirePointer*>(defaultValue)->isNull()) {
  ------------------
  |  Branch (1134:11): [True: 0, False: 0]
  ------------------
 1135|      3|        return initStructPointer(ref, segment, capTable, size, orphanArena);
 1136|      3|      }
 1137|      0|      refTarget = copyMessage(segment, capTable, ref,
 1138|      0|          reinterpret_cast<const WirePointer*>(defaultValue));
 1139|      0|      defaultValue = nullptr;  // If the default value is itself invalid, don't use it again.
 1140|      0|    }
 1141|       |
 1142|      0|    WirePointer* oldRef = ref;
 1143|      0|    SegmentBuilder* oldSegment = segment;
 1144|      0|    word* oldPtr = followFars(oldRef, refTarget, oldSegment);
 1145|       |
 1146|      0|    KJ_REQUIRE(oldRef->kind() == WirePointer::STRUCT,
  ------------------
  |  Branch (1146:5): [True: 0, False: 0]
  ------------------
 1147|      0|        "Schema mismatch: Message contains non-struct pointer where struct pointer was expected.") {
 1148|      0|      goto useDefault;
 1149|      0|    }
 1150|       |
 1151|      0|    auto oldDataSize = oldRef->structRef.dataSize.get();
 1152|      0|    auto oldPointerCount = oldRef->structRef.ptrCount.get();
 1153|      0|    WirePointer* oldPointerSection =
 1154|      0|        reinterpret_cast<WirePointer*>(oldPtr + oldDataSize);
 1155|       |
 1156|      0|    if (oldDataSize < size.data || oldPointerCount < size.pointers) {
  ------------------
  |  Branch (1156:9): [True: 0, False: 0]
  |  Branch (1156:36): [True: 0, False: 0]
  ------------------
 1157|       |      // The space allocated for this struct is too small.  Unlike with readers, we can't just
 1158|       |      // run with it and do bounds checks at access time, because how would we handle writes?
 1159|       |      // Instead, we have to copy the struct to a new space now.
 1160|       |
 1161|      0|      auto newDataSize = kj::max(oldDataSize, size.data);
 1162|      0|      auto newPointerCount = kj::max(oldPointerCount, size.pointers);
 1163|      0|      auto totalSize = newDataSize + newPointerCount * WORDS_PER_POINTER;
 1164|       |
 1165|       |      // Don't let allocate() zero out the object just yet.
 1166|      0|      zeroPointerAndFars(segment, ref);
 1167|       |
 1168|      0|      word* ptr = allocate(ref, segment, capTable, totalSize, WirePointer::STRUCT, orphanArena);
 1169|      0|      ref->structRef.set(newDataSize, newPointerCount);
 1170|       |
 1171|       |      // Copy data section.
 1172|      0|      copyMemory(ptr, oldPtr, oldDataSize);
 1173|       |
 1174|       |      // Copy pointer section.
 1175|      0|      WirePointer* newPointerSection = reinterpret_cast<WirePointer*>(ptr + newDataSize);
 1176|      0|      for (auto i: kj::zeroTo(oldPointerCount)) {
  ------------------
  |  Branch (1176:18): [True: 0, False: 0]
  ------------------
 1177|      0|        transferPointer(segment, newPointerSection + i, oldSegment, oldPointerSection + i);
 1178|      0|      }
 1179|       |
 1180|       |      // Zero out old location.  This has two purposes:
 1181|       |      // 1) We don't want to leak the original contents of the struct when the message is written
 1182|       |      //    out as it may contain secrets that the caller intends to remove from the new copy.
 1183|       |      // 2) Zeros will be deflated by packing, making this dead memory almost-free if it ever
 1184|       |      //    hits the wire.
 1185|      0|      zeroMemory(oldPtr, oldDataSize + oldPointerCount * WORDS_PER_POINTER);
 1186|       |
 1187|      0|      return StructBuilder(segment, capTable, ptr, newPointerSection, newDataSize * BITS_PER_WORD,
 1188|      0|                           newPointerCount);
 1189|      0|    } else {
 1190|      0|      return StructBuilder(oldSegment, capTable, oldPtr, oldPointerSection,
 1191|      0|                           oldDataSize * BITS_PER_WORD, oldPointerCount);
 1192|      0|    }
 1193|      0|  }
_ZN5capnp1_11WireHelpers17readStructPointerEPNS0_13SegmentReaderEPNS0_14CapTableReaderEPKNS0_11WirePointerEPKNS_4wordESB_i:
 2173|      7|      const word* defaultValue, int nestingLimit)) {
 2174|      7|    if (ref->isNull()) {
  ------------------
  |  Branch (2174:9): [True: 0, False: 7]
  ------------------
 2175|      0|    useDefault:
 2176|      0|      if (defaultValue == nullptr ||
  ------------------
  |  Branch (2176:11): [True: 0, False: 0]
  ------------------
 2177|      0|          reinterpret_cast<const WirePointer*>(defaultValue)->isNull()) {
  ------------------
  |  Branch (2177:11): [True: 0, False: 0]
  ------------------
 2178|      0|        return StructReader();
 2179|      0|      }
 2180|      0|      segment = nullptr;
 2181|      0|      ref = reinterpret_cast<const WirePointer*>(defaultValue);
 2182|      0|      refTarget = ref->target(segment);
 2183|      0|      defaultValue = nullptr;  // If the default value is itself invalid, don't use it again.
 2184|      0|    }
 2185|       |
 2186|      7|    KJ_REQUIRE(nestingLimit > 0,
  ------------------
  |  Branch (2186:5): [True: 7, False: 0]
  ------------------
 2187|      0|               "Message is too deeply-nested or contains cycles.  See capnp::ReaderOptions.") {
 2188|      0|      goto useDefault;
 2189|      0|    }
 2190|       |
 2191|      7|    const word* ptr;
 2192|      7|    KJ_IF_MAYBE(p, followFars(ref, refTarget, segment)) {
  ------------------
  |  Branch (2192:5): [True: 7, False: 0]
  ------------------
 2193|      7|      ptr = p;
 2194|      7|    } else {
 2195|      0|      goto useDefault;
 2196|      0|    }
 2197|       |
 2198|      7|    KJ_REQUIRE(ref->kind() == WirePointer::STRUCT,
  ------------------
  |  Branch (2198:5): [True: 7, False: 0]
  ------------------
 2199|      0|               "Schema mismatch: Message contains non-struct pointer where struct pointer"
 2200|      0|               "was expected.") {
 2201|      0|      goto useDefault;
 2202|      0|    }
 2203|       |
 2204|      7|    KJ_REQUIRE(boundsCheck(segment, ptr, ref->structRef.wordSize()),
  ------------------
  |  Branch (2204:5): [True: 7, False: 0]
  ------------------
 2205|      0|               "Message contained out-of-bounds struct pointer. "
 2206|      0|               OUT_OF_BOUNDS_ERROR_DETAIL) {
 2207|      0|      goto useDefault;
 2208|      0|    }
 2209|       |
 2210|      7|    return StructReader(
 2211|      7|        segment, capTable,
 2212|      7|        ptr, reinterpret_cast<const WirePointer*>(ptr + ref->structRef.dataSize.get()),
 2213|      7|        ref->structRef.dataSize.get() * BITS_PER_WORD,
 2214|      7|        ref->structRef.ptrCount.get(),
 2215|      7|        nestingLimit - 1);
 2216|      7|  }
_ZN5capnp1_11WireHelpers15readListPointerEPNS0_13SegmentReaderEPNS0_14CapTableReaderEPKNS0_11WirePointerEPKNS_4wordESB_NS_11ElementSizeEib:
 2264|      1|      bool checkElementSize = true)) {
 2265|      1|    if (ref->isNull()) {
  ------------------
  |  Branch (2265:9): [True: 0, False: 1]
  ------------------
 2266|      0|    useDefault:
 2267|      0|      if (defaultValue == nullptr ||
  ------------------
  |  Branch (2267:11): [True: 0, False: 0]
  ------------------
 2268|      0|          reinterpret_cast<const WirePointer*>(defaultValue)->isNull()) {
  ------------------
  |  Branch (2268:11): [True: 0, False: 0]
  ------------------
 2269|      0|        return ListReader(expectedElementSize);
 2270|      0|      }
 2271|      0|      segment = nullptr;
 2272|      0|      ref = reinterpret_cast<const WirePointer*>(defaultValue);
 2273|      0|      refTarget = ref->target(segment);
 2274|      0|      defaultValue = nullptr;  // If the default value is itself invalid, don't use it again.
 2275|      0|    }
 2276|       |
 2277|      1|    KJ_REQUIRE(nestingLimit > 0,
  ------------------
  |  Branch (2277:5): [True: 1, False: 0]
  ------------------
 2278|      0|               "Message is too deeply-nested or contains cycles.  See capnp::ReaderOptions.") {
 2279|      0|      goto useDefault;
 2280|      0|    }
 2281|       |
 2282|      1|    const word* ptr;
 2283|      1|    KJ_IF_MAYBE(p, followFars(ref, refTarget, segment)) {
  ------------------
  |  Branch (2283:5): [True: 1, False: 0]
  ------------------
 2284|      1|      ptr = p;
 2285|      1|    } else {
 2286|      0|      goto useDefault;
 2287|      0|    }
 2288|       |
 2289|      1|    KJ_REQUIRE(ref->kind() == WirePointer::LIST,
  ------------------
  |  Branch (2289:5): [True: 1, False: 0]
  ------------------
 2290|      0|               "Schema mismatch: Message contains non-list pointer where list pointer was "
 2291|      0|               "expected.") {
 2292|      0|      goto useDefault;
 2293|      0|    }
 2294|       |
 2295|      1|    ElementSize elementSize = ref->listRef.elementSize();
 2296|      1|    if (elementSize == ElementSize::INLINE_COMPOSITE) {
  ------------------
  |  Branch (2296:9): [True: 1, False: 0]
  ------------------
 2297|      1|      auto wordCount = ref->listRef.inlineCompositeWordCount();
 2298|       |
 2299|       |      // An INLINE_COMPOSITE list points to a tag, which is formatted like a pointer.
 2300|      1|      const WirePointer* tag = reinterpret_cast<const WirePointer*>(ptr);
 2301|       |
 2302|      1|      KJ_REQUIRE(boundsCheck(segment, ptr, wordCount + POINTER_SIZE_IN_WORDS),
  ------------------
  |  Branch (2302:7): [True: 1, False: 0]
  ------------------
 2303|      0|                 "Message contains out-of-bounds list pointer. "
 2304|      0|                 OUT_OF_BOUNDS_ERROR_DETAIL) {
 2305|      0|        goto useDefault;
 2306|      0|      }
 2307|       |
 2308|      1|      ptr += POINTER_SIZE_IN_WORDS;
 2309|       |
 2310|      1|      KJ_REQUIRE(tag->kind() == WirePointer::STRUCT,
  ------------------
  |  Branch (2310:7): [True: 1, False: 0]
  ------------------
 2311|      0|                 "INLINE_COMPOSITE lists of non-STRUCT type are not supported.") {
 2312|      0|        goto useDefault;
 2313|      0|      }
 2314|       |
 2315|      1|      auto size = tag->inlineCompositeListElementCount();
 2316|      1|      auto wordsPerElement = tag->structRef.wordSize() / ELEMENTS;
 2317|       |
 2318|      1|      KJ_REQUIRE(upgradeBound<uint64_t>(size) * wordsPerElement <= wordCount,
  ------------------
  |  Branch (2318:7): [True: 1, False: 0]
  ------------------
 2319|      0|                 "INLINE_COMPOSITE list's elements overrun its word count.") {
 2320|      0|        goto useDefault;
 2321|      0|      }
 2322|       |
 2323|      1|      if (wordsPerElement * (ONE * ELEMENTS) == ZERO * WORDS) {
  ------------------
  |  Branch (2323:11): [True: 0, False: 1]
  ------------------
 2324|       |        // Watch out for lists of zero-sized structs, which can claim to be arbitrarily large
 2325|       |        // without having sent actual data.
 2326|      0|        KJ_REQUIRE(amplifiedRead(segment, size * (ONE * WORDS / ELEMENTS)),
  ------------------
  |  Branch (2326:9): [True: 0, False: 0]
  ------------------
 2327|      0|                   "Message contains amplified list pointer.") {
 2328|      0|          goto useDefault;
 2329|      0|        }
 2330|      0|      }
 2331|       |
 2332|      1|      if (checkElementSize) {
  ------------------
  |  Branch (2332:11): [True: 1, False: 0]
  ------------------
 2333|       |        // If a struct list was not expected, then presumably a non-struct list was upgraded to a
 2334|       |        // struct list. We need to manipulate the pointer to point at the first field of the
 2335|       |        // struct. Together with the `step` field, this will allow the struct list to be accessed
 2336|       |        // as if it were a primitive list without branching.
 2337|       |
 2338|       |        // Check whether the size is compatible.
 2339|      1|        switch (expectedElementSize) {
  ------------------
  |  Branch (2339:17): [True: 1, False: 0]
  ------------------
 2340|      0|          case ElementSize::VOID:
  ------------------
  |  Branch (2340:11): [True: 0, False: 1]
  ------------------
 2341|      0|            break;
 2342|       |
 2343|      0|          case ElementSize::BIT:
  ------------------
  |  Branch (2343:11): [True: 0, False: 1]
  ------------------
 2344|      0|            KJ_FAIL_REQUIRE(
 2345|      0|                "Found struct list where bit list was expected; upgrading boolean lists to structs "
 2346|      0|                "is no longer supported.") {
 2347|      0|              goto useDefault;
 2348|      0|            }
 2349|      0|            break;
 2350|       |
 2351|      0|          case ElementSize::BYTE:
  ------------------
  |  Branch (2351:11): [True: 0, False: 1]
  ------------------
 2352|      0|          case ElementSize::TWO_BYTES:
  ------------------
  |  Branch (2352:11): [True: 0, False: 1]
  ------------------
 2353|      0|          case ElementSize::FOUR_BYTES:
  ------------------
  |  Branch (2353:11): [True: 0, False: 1]
  ------------------
 2354|      0|          case ElementSize::EIGHT_BYTES:
  ------------------
  |  Branch (2354:11): [True: 0, False: 1]
  ------------------
 2355|      0|            KJ_REQUIRE(tag->structRef.dataSize.get() > ZERO * WORDS,
  ------------------
  |  Branch (2355:13): [True: 0, False: 0]
  ------------------
 2356|      0|                       "Schema mismatch: Expected a primitive list, but got a list of pointer-only "
 2357|      0|                       "structs.") {
 2358|      0|              goto useDefault;
 2359|      0|            }
 2360|      0|            break;
 2361|       |
 2362|      0|          case ElementSize::POINTER:
  ------------------
  |  Branch (2362:11): [True: 0, False: 1]
  ------------------
 2363|      0|            KJ_REQUIRE(tag->structRef.ptrCount.get() > ZERO * POINTERS,
  ------------------
  |  Branch (2363:13): [True: 0, False: 0]
  ------------------
 2364|      0|                       "Schema mismatch: Expected a pointer list, but got a list of data-only "
 2365|      0|                       "structs.") {
 2366|      0|              goto useDefault;
 2367|      0|            }
 2368|      0|            break;
 2369|       |
 2370|      1|          case ElementSize::INLINE_COMPOSITE:
  ------------------
  |  Branch (2370:11): [True: 1, False: 0]
  ------------------
 2371|      1|            break;
 2372|      1|        }
 2373|      1|      }
 2374|       |
 2375|      1|      return ListReader(
 2376|      1|          segment, capTable, ptr, size, wordsPerElement * BITS_PER_WORD,
 2377|      1|          tag->structRef.dataSize.get() * BITS_PER_WORD,
 2378|      1|          tag->structRef.ptrCount.get(), ElementSize::INLINE_COMPOSITE,
 2379|      1|          nestingLimit - 1);
 2380|       |
 2381|      1|    } else {
 2382|       |      // This is a primitive or pointer list, but all such lists can also be interpreted as struct
 2383|       |      // lists.  We need to compute the data size and pointer count for such structs.
 2384|      0|      auto dataSize = dataBitsPerElement(ref->listRef.elementSize()) * ELEMENTS;
 2385|      0|      auto pointerCount = pointersPerElement(ref->listRef.elementSize()) * ELEMENTS;
 2386|      0|      auto elementCount = ref->listRef.elementCount();
 2387|      0|      auto step = (dataSize + pointerCount * BITS_PER_POINTER) / ELEMENTS;
 2388|       |
 2389|      0|      auto wordCount = roundBitsUpToWords(upgradeBound<uint64_t>(elementCount) * step);
 2390|      0|      KJ_REQUIRE(boundsCheck(segment, ptr, wordCount),
  ------------------
  |  Branch (2390:7): [True: 0, False: 0]
  ------------------
 2391|      0|            "Message contains out-of-bounds list pointer. "
 2392|      0|            OUT_OF_BOUNDS_ERROR_DETAIL) {
 2393|      0|        goto useDefault;
 2394|      0|      }
 2395|       |
 2396|      0|      if (elementSize == ElementSize::VOID) {
  ------------------
  |  Branch (2396:11): [True: 0, False: 0]
  ------------------
 2397|       |        // Watch out for lists of void, which can claim to be arbitrarily large without having sent
 2398|       |        // actual data.
 2399|      0|        KJ_REQUIRE(amplifiedRead(segment, elementCount * (ONE * WORDS / ELEMENTS)),
  ------------------
  |  Branch (2399:9): [True: 0, False: 0]
  ------------------
 2400|      0|                   "Message contains amplified list pointer.") {
 2401|      0|          goto useDefault;
 2402|      0|        }
 2403|      0|      }
 2404|       |
 2405|      0|      if (checkElementSize) {
  ------------------
  |  Branch (2405:11): [True: 0, False: 0]
  ------------------
 2406|      0|        if (elementSize == ElementSize::BIT && expectedElementSize != ElementSize::BIT) {
  ------------------
  |  Branch (2406:13): [True: 0, False: 0]
  |  Branch (2406:48): [True: 0, False: 0]
  ------------------
 2407|      0|          KJ_FAIL_REQUIRE(
 2408|      0|              "Found bit list where struct list was expected; upgrading boolean lists to structs "
 2409|      0|              "is no longer supported.") {
 2410|      0|            goto useDefault;
 2411|      0|          }
 2412|      0|        }
 2413|       |
 2414|       |        // Verify that the elements are at least as large as the expected type.  Note that if we
 2415|       |        // expected INLINE_COMPOSITE, the expected sizes here will be zero, because bounds checking
 2416|       |        // will be performed at field access time.  So this check here is for the case where we
 2417|       |        // expected a list of some primitive or pointer type.
 2418|       |
 2419|      0|        BitCount expectedDataBitsPerElement =
 2420|      0|            dataBitsPerElement(expectedElementSize) * ELEMENTS;
 2421|      0|        WirePointerCount expectedPointersPerElement =
 2422|      0|            pointersPerElement(expectedElementSize) * ELEMENTS;
 2423|       |
 2424|      0|        KJ_REQUIRE(expectedDataBitsPerElement <= dataSize,
  ------------------
  |  Branch (2424:9): [True: 0, False: 0]
  ------------------
 2425|      0|                   "Schema mismatch: Message contained list with incompatible element type.") {
 2426|      0|          goto useDefault;
 2427|      0|        }
 2428|      0|        KJ_REQUIRE(expectedPointersPerElement <= pointerCount,
  ------------------
  |  Branch (2428:9): [True: 0, False: 0]
  ------------------
 2429|      0|                   "Schema mismatch: Message contained list with incompatible element type.") {
 2430|      0|          goto useDefault;
 2431|      0|        }
 2432|      0|      }
 2433|       |
 2434|      0|      return ListReader(segment, capTable, ptr, elementCount, step,
 2435|      0|                        dataSize, pointerCount, elementSize, nestingLimit - 1);
 2436|      0|    }
 2437|      1|  }
_ZNK5capnp1_11WirePointer7ListRef11elementSizeEv:
  260|      1|    KJ_ALWAYS_INLINE(ElementSize elementSize() const) {
  261|      1|      return static_cast<ElementSize>(elementSizeAndCount.get() & 7);
  262|      1|    }
_ZNK5capnp1_11WirePointer31inlineCompositeListElementCountEv:
  199|      1|  KJ_ALWAYS_INLINE(ListElementCount inlineCompositeListElementCount() const) {
  200|      1|    return ((bounded(offsetAndKind.get()) >> G(2))
  ------------------
  |  |   76|      1|#define G(n) n
  ------------------
  201|      1|            & G(kj::maxValueForBits<LIST_ELEMENT_COUNT_BITS>())) * ELEMENTS;
  ------------------
  |  |   76|      1|#define G(n) n
  ------------------
  202|      1|  }
_ZNK5capnp1_11WirePointer7ListRef12elementCountEv:
  263|      1|    KJ_ALWAYS_INLINE(ElementCountN<29> elementCount() const) {
  264|      1|      return (bounded(elementSizeAndCount.get()) >> G(3)) * ELEMENTS;
  ------------------
  |  |   76|      1|#define G(n) n
  ------------------
  265|      1|    }

_ZN5capnp13MessageReaderC2ENS_13ReaderOptionsE:
   48|      3|MessageReader::MessageReader(ReaderOptions options): options(options), allocatedArena(false) {}
_ZN5capnp13MessageReaderD2Ev:
   49|      4|MessageReader::~MessageReader() noexcept(false) {
   50|      4|  if (allocatedArena) {
  ------------------
  |  Branch (50:7): [True: 4, False: 0]
  ------------------
   51|      4|    arena()->~ReaderArena();
   52|      4|  }
   53|      4|}
_ZN5capnp13MessageReader15getRootInternalEv:
   89|      4|AnyPointer::Reader MessageReader::getRootInternal() {
   90|      4|  if (!allocatedArena) {
  ------------------
  |  Branch (90:7): [True: 3, False: 1]
  ------------------
   91|      3|    static_assert(sizeof(_::ReaderArena) <= sizeof(arenaSpace),
   92|      3|        "arenaSpace is too small to hold a ReaderArena.  Please increase it.  This will break "
   93|      3|        "ABI compatibility.");
   94|      3|    kj::ctor(*arena(), this);
   95|      3|    allocatedArena = true;
   96|      3|  }
   97|       |
   98|      4|  _::SegmentReader* segment = arena()->tryGetSegment(_::SegmentId(0));
   99|      4|  KJ_REQUIRE(segment != nullptr &&
  ------------------
  |  Branch (99:3): [True: 4, False: 0]
  ------------------
  100|      0|             segment->checkObject(segment->getStartPtr(), ONE * WORDS),
  101|      0|             "Message did not contain a root pointer.") {
  102|      0|    return AnyPointer::Reader();
  103|      0|  }
  104|       |
  105|       |  // const_cast here is safe because dummyCapTableReader has no state.
  106|      4|  return AnyPointer::Reader(_::PointerReader::getRoot(
  107|      4|      segment, const_cast<DummyCapTableReader*>(&dummyCapTableReader),
  108|      4|      segment->getStartPtr(), options.nestingLimit));
  109|      4|}
_ZN5capnp14MessageBuilderC2Ev:
  113|      4|MessageBuilder::MessageBuilder(): allocatedArena(false) {}
_ZN5capnp14MessageBuilderD2Ev:
  115|      7|MessageBuilder::~MessageBuilder() noexcept(false) {
  116|      7|  if (allocatedArena) {
  ------------------
  |  Branch (116:7): [True: 7, False: 0]
  ------------------
  117|      7|    kj::dtor(*arena());
  118|      7|  }
  119|      7|}
_ZN5capnp14MessageBuilder14getRootSegmentEv:
  127|      4|_::SegmentBuilder* MessageBuilder::getRootSegment() {
  128|      4|  if (allocatedArena) {
  ------------------
  |  Branch (128:7): [True: 0, False: 4]
  ------------------
  129|      0|    return arena()->getSegment(_::SegmentId(0));
  130|      4|  } else {
  131|      4|    static_assert(sizeof(_::BuilderArena) <= sizeof(arenaSpace),
  132|      4|        "arenaSpace is too small to hold a BuilderArena.  Please increase it.");
  133|      4|    kj::ctor(*arena(), this);
  134|      4|    allocatedArena = true;
  135|       |
  136|      4|    auto allocation = arena()->allocate(POINTER_SIZE_IN_WORDS);
  137|       |
  138|      4|    KJ_ASSERT(allocation.segment->getSegmentId() == _::SegmentId(0),
  ------------------
  |  Branch (138:5): [True: 4, False: 0]
  ------------------
  139|      0|        "First allocated word of new arena was not in segment ID 0.");
  140|      4|    KJ_ASSERT(allocation.words == allocation.segment->getPtrUnchecked(ZERO * WORDS),
  ------------------
  |  Branch (140:5): [True: 4, False: 0]
  ------------------
  141|      0|        "First allocated word of new arena was not the first word in its segment.");
  142|      4|    return allocation.segment;
  143|      4|  }
  144|      4|}
_ZN5capnp14MessageBuilder15getRootInternalEv:
  146|      4|AnyPointer::Builder MessageBuilder::getRootInternal() {
  147|      4|  _::SegmentBuilder* rootSegment = getRootSegment();
  148|      4|  return AnyPointer::Builder(_::PointerBuilder::getRoot(
  149|      4|      rootSegment, arena()->getLocalCapTable(), rootSegment->getPtrUnchecked(ZERO * WORDS)));
  150|      4|}
_ZN5capnp14MessageBuilder20getSegmentsForOutputEv:
  152|      8|kj::ArrayPtr<const kj::ArrayPtr<const word>> MessageBuilder::getSegmentsForOutput() {
  153|      8|  if (allocatedArena) {
  ------------------
  |  Branch (153:7): [True: 8, False: 0]
  ------------------
  154|      8|    return arena()->getSegmentsForOutput();
  155|      8|  } else {
  156|      0|    return nullptr;
  157|      0|  }
  158|      8|}
_ZN5capnp14MessageBuilder11sizeInWordsEv:
  186|      5|size_t MessageBuilder::sizeInWords() {
  187|      5|  return arena()->sizeInWords();
  188|      5|}
_ZN5capnp20MallocMessageBuilderC2EjNS_18AllocationStrategyE:
  214|      4|    : nextSize(firstSegmentWords), allocationStrategy(allocationStrategy),
  215|      4|      ownFirstSegment(true), returnedFirstSegment(false), firstSegment(nullptr) {}
_ZN5capnp20MallocMessageBuilderD2Ev:
  228|      7|MallocMessageBuilder::~MallocMessageBuilder() noexcept(false) {
  229|      7|  if (returnedFirstSegment) {
  ------------------
  |  Branch (229:7): [True: 7, False: 0]
  ------------------
  230|      7|    if (ownFirstSegment) {
  ------------------
  |  Branch (230:9): [True: 7, False: 0]
  ------------------
  231|      7|      free(firstSegment);
  232|      7|    } else {
  233|       |      // Must zero first segment.
  234|      0|      kj::ArrayPtr<const kj::ArrayPtr<const word>> segments = getSegmentsForOutput();
  235|      0|      if (segments.size() > 0) {
  ------------------
  |  Branch (235:11): [True: 0, False: 0]
  ------------------
  236|      0|        KJ_ASSERT(segments[0].begin() == firstSegment,
  ------------------
  |  Branch (236:9): [True: 0, False: 0]
  ------------------
  237|      0|            "First segment in getSegmentsForOutput() is not the first segment allocated?");
  238|      0|        memset(firstSegment, 0, segments[0].size() * sizeof(word));
  239|      0|      }
  240|      0|    }
  241|       |
  242|      7|    for (void* ptr: moreSegments) {
  ------------------
  |  Branch (242:19): [True: 0, False: 7]
  ------------------
  243|      0|      free(ptr);
  244|      0|    }
  245|      7|  }
  246|      7|}
_ZN5capnp20MallocMessageBuilder15allocateSegmentEj:
  248|      4|kj::ArrayPtr<word> MallocMessageBuilder::allocateSegment(uint minimumSize) {
  249|      4|  KJ_REQUIRE(bounded(minimumSize) * WORDS <= MAX_SEGMENT_WORDS,
  ------------------
  |  Branch (249:3): [True: 4, False: 0]
  ------------------
  250|      0|      "MallocMessageBuilder asked to allocate segment above maximum serializable size.");
  251|      4|  KJ_ASSERT(bounded(nextSize) * WORDS <= MAX_SEGMENT_WORDS,
  ------------------
  |  Branch (251:3): [True: 4, False: 0]
  ------------------
  252|      0|      "MallocMessageBuilder nextSize out of bounds.");
  253|       |
  254|      4|  if (!returnedFirstSegment && !ownFirstSegment) {
  ------------------
  |  Branch (254:7): [True: 4, False: 0]
  |  Branch (254:32): [True: 0, False: 4]
  ------------------
  255|      0|    kj::ArrayPtr<word> result = kj::arrayPtr(reinterpret_cast<word*>(firstSegment), nextSize);
  256|      0|    if (result.size() >= minimumSize) {
  ------------------
  |  Branch (256:9): [True: 0, False: 0]
  ------------------
  257|      0|      returnedFirstSegment = true;
  258|      0|      return result;
  259|      0|    }
  260|       |    // If the provided first segment wasn't big enough, we discard it and proceed to allocate
  261|       |    // our own.  This never happens in practice since minimumSize is always 1 for the first
  262|       |    // segment.
  263|      0|    ownFirstSegment = true;
  264|      0|  }
  265|       |
  266|      4|  uint size = kj::max(minimumSize, nextSize);
  267|       |
  268|      4|  void* result = calloc(size, sizeof(word));
  269|      4|  if (result == nullptr) {
  ------------------
  |  Branch (269:7): [True: 0, False: 4]
  ------------------
  270|      0|    KJ_FAIL_SYSCALL("calloc(size, sizeof(word))", ENOMEM, size);
  271|      0|  }
  272|       |
  273|      4|  if (!returnedFirstSegment) {
  ------------------
  |  Branch (273:7): [True: 4, False: 0]
  ------------------
  274|      4|    firstSegment = result;
  275|      4|    returnedFirstSegment = true;
  276|       |
  277|       |    // After the first segment, we want nextSize to equal the total size allocated so far.
  278|      4|    if (allocationStrategy == AllocationStrategy::GROW_HEURISTICALLY) nextSize = size;
  ------------------
  |  Branch (278:9): [True: 4, False: 0]
  ------------------
  279|      4|  } else {
  280|      0|    moreSegments.add(result);
  281|      0|    if (allocationStrategy == AllocationStrategy::GROW_HEURISTICALLY) {
  ------------------
  |  Branch (281:9): [True: 0, False: 0]
  ------------------
  282|       |      // set nextSize = min(nextSize+size, MAX_SEGMENT_WORDS)
  283|       |      // while protecting against possible overflow of (nextSize+size)
  284|      0|      nextSize = (size <= unbound(MAX_SEGMENT_WORDS / WORDS) - nextSize)
  ------------------
  |  Branch (284:18): [True: 0, False: 0]
  ------------------
  285|      0|          ? nextSize + size : unbound(MAX_SEGMENT_WORDS / WORDS);
  286|      0|    }
  287|      0|  }
  288|       |
  289|      4|  return kj::arrayPtr(reinterpret_cast<word*>(result), size);
  290|      4|}

_ZN5capnp18TwoPartyVatNetworkD2Ev:
   82|      2|TwoPartyVatNetwork::~TwoPartyVatNetwork() noexcept(false) {};
_ZN5capnp18TwoPartyVatNetwork9getStreamEv:
   84|      6|MessageStream& TwoPartyVatNetwork::getStream() {
   85|      6|  KJ_SWITCH_ONEOF(stream) {
  ------------------
  |  Branch (85:3): [True: 6, False: 0]
  ------------------
   86|      0|    KJ_CASE_ONEOF(s, MessageStream*) {
  ------------------
  |  Branch (86:5): [True: 0, False: 0]
  |  Branch (86:5): [True: 0, False: 6]
  ------------------
   87|      0|      return *s;
   88|      0|    }
   89|      6|    KJ_CASE_ONEOF(s, kj::Own<MessageStream>) {
  ------------------
  |  Branch (89:5): [True: 6, False: 0]
  |  Branch (89:5): [True: 6, False: 0]
  ------------------
   90|      6|      return *s;
   91|      6|    }
   92|      6|  }
   93|      6|  KJ_UNREACHABLE;
   94|      0|}
_ZNK5capnp18TwoPartyVatNetwork17FulfillerDisposer11disposeImplEPv:
   96|      2|void TwoPartyVatNetwork::FulfillerDisposer::disposeImpl(void* pointer) const {
   97|      2|  if (--refcount == 0) {
  ------------------
  |  Branch (97:7): [True: 2, False: 0]
  ------------------
   98|      2|    fulfiller->fulfill();
   99|      2|  }
  100|      2|}
_ZN5capnp18TwoPartyVatNetwork18newOutgoingMessageEj:
  301|      4|kj::Own<OutgoingRpcMessage> TwoPartyVatNetwork::newOutgoingMessage(uint firstSegmentWordSize) {
  302|      4|  return kj::refcounted<OutgoingMessageImpl>(*this, firstSegmentWordSize);
  303|      4|}
_ZN5capnp18TwoPartyVatNetwork22receiveIncomingMessageEv:
  305|      3|kj::Promise<kj::Maybe<kj::Own<IncomingRpcMessage>>> TwoPartyVatNetwork::receiveIncomingMessage() {
  306|      3|  return kj::evalLater([this]() -> kj::Promise<kj::Maybe<kj::Own<IncomingRpcMessage>>> {
  307|      3|    KJ_IF_MAYBE(e, readCancelReason) {
  308|       |      // A previous write failed; propagate the failure to reads, too.
  309|      3|      return kj::cp(*e);
  310|      3|    }
  311|       |
  312|      3|    kj::Array<kj::AutoCloseFd> fdSpace = nullptr;
  313|      3|    if(maxFdsPerMessage > 0) {
  314|      3|      fdSpace = kj::heapArray<kj::AutoCloseFd>(maxFdsPerMessage);
  315|      3|    }
  316|      3|    auto promise = readCanceler.wrap(getStream().tryReadMessage(fdSpace, receiveOptions));
  317|      3|    return promise.then([fdSpace = kj::mv(fdSpace)]
  318|      3|                        (kj::Maybe<MessageReaderAndFds>&& messageAndFds) mutable
  319|      3|                      -> kj::Maybe<kj::Own<IncomingRpcMessage>> {
  320|      3|      KJ_IF_MAYBE(m, messageAndFds) {
  321|      3|        if (m->fds.size() > 0) {
  322|      3|          return kj::Own<IncomingRpcMessage>(
  323|      3|              kj::heap<IncomingMessageImpl>(kj::mv(*m), kj::mv(fdSpace)));
  324|      3|        } else {
  325|      3|          return kj::Own<IncomingRpcMessage>(kj::heap<IncomingMessageImpl>(kj::mv(m->reader)));
  326|      3|        }
  327|      3|      } else {
  328|      3|        return nullptr;
  329|      3|      }
  330|      3|    });
  331|      3|  });
  332|      3|}
_ZN5capnp18TwoPartyVatNetwork8shutdownEv:
  334|      2|kj::Promise<void> TwoPartyVatNetwork::shutdown() {
  335|       |  kj::Promise<void> result = KJ_ASSERT_NONNULL(previousWrite, "already shut down").then([this]() {
  ------------------
  |  Branch (335:30): [True: 0, False: 2]
  ------------------
  336|      2|    return getStream().end();
  337|      2|  });
  338|      2|  previousWrite = nullptr;
  339|      2|  return kj::mv(result);
  340|      2|}
_ZN5capnp18TwoPartyVatNetwork19OutgoingMessageImplC2ERS0_j:
  132|      4|      : network(network),
  133|      4|        message(firstSegmentWordSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS : firstSegmentWordSize) {}
  ------------------
  |  Branch (133:17): [True: 0, False: 4]
  ------------------
_ZN5capnp18TwoPartyVatNetwork19OutgoingMessageImpl7getBodyEv:
  135|      4|  AnyPointer::Builder getBody() override {
  136|      4|    return message.getRoot<AnyPointer>();
  137|      4|  }
_ZN5capnp18TwoPartyVatNetwork19OutgoingMessageImpl6setFdsEN2kj5ArrayIiEE:
  139|      1|  void setFds(kj::Array<int> fds) override {
  140|      1|    if (network.maxFdsPerMessage > 0) {
  ------------------
  |  Branch (140:9): [True: 0, False: 1]
  ------------------
  141|      0|      this->fds = kj::mv(fds);
  142|      0|    }
  143|      1|  }
_ZN5capnp18TwoPartyVatNetwork19OutgoingMessageImpl4sendEv:
  145|      5|  void send() override {
  146|      5|    size_t size = 0;
  147|      5|    for (auto& segment: message.getSegmentsForOutput()) {
  ------------------
  |  Branch (147:23): [True: 5, False: 5]
  ------------------
  148|      5|      size += segment.size();
  149|      5|    }
  150|      5|    KJ_REQUIRE(size < network.receiveOptions.traversalLimitInWords, size,
  ------------------
  |  Branch (150:5): [True: 5, False: 0]
  ------------------
  151|      0|               "Trying to send Cap'n Proto message larger than our single-message size limit. The "
  152|      0|               "other side probably won't accept it (assuming its traversalLimitInWords matches "
  153|      0|               "ours) and would abort the connection, so I won't send it.") {
  154|      0|      return;
  155|      0|    }
  156|       |
  157|      5|    auto sendTime = network.clock.now();
  158|      5|    if (network.queuedMessages.size() == 0) {
  ------------------
  |  Branch (158:9): [True: 4, False: 1]
  ------------------
  159|       |      // Optimistically set sendTime when there's no messages in the queue. Without this, sending
  160|       |      // a message after a long delay could cause getOutgoingMessageWaitTime() to return excessively
  161|       |      // long wait times if it is called during the time period after send() is called,
  162|       |      // but before the write occurs, as we increment currentQueueCount synchronously, but
  163|       |      // asynchronously update currentOutgoingMessageSendTime.
  164|      4|      network.currentOutgoingMessageSendTime = sendTime;
  165|      4|    }
  166|       |
  167|       |    // Instead of sending each new message as soon as possible, we attempt to batch together small
  168|       |    // messages by delaying when we send them using evalLast. This allows us to group together
  169|       |    // related small messages, reducing the number of syscalls we make.
  170|      5|    auto& previousWrite = KJ_ASSERT_NONNULL(network.previousWrite, "already shut down");
  ------------------
  |  Branch (170:27): [True: 0, False: 5]
  ------------------
  171|      5|    bool alreadyPendingSend = !network.queuedMessages.empty();
  172|      5|    network.currentQueueSize += message.sizeInWords() * sizeof(word);
  173|      5|    network.queuedMessages.add(kj::addRef(*this));
  174|      5|    if (alreadyPendingSend) {
  ------------------
  |  Branch (174:9): [True: 1, False: 4]
  ------------------
  175|       |      // The first send sets up an evalLast that will clear out pendingMessages when it's sent.
  176|       |      // If pendingMessages is non-empty, then there must already be a callback waiting to send
  177|       |      // them.
  178|      1|      return;
  179|      1|    }
  180|       |
  181|       |    // On the other hand, if pendingMessages was empty, then we should set up the delayed write.
  182|      4|    network.previousWrite = previousWrite.then([this, sendTime]() {
  183|      4|      return kj::evalLast([this, sendTime]() -> kj::Promise<void> {
  184|      4|        network.currentOutgoingMessageSendTime = sendTime;
  185|       |        // Swap out the connection's pending messages and write all of them together.
  186|      4|        auto ownMessages = kj::mv(network.queuedMessages);
  187|      4|        network.currentQueueSize = 0;
  188|      4|        auto messages =
  189|      4|          kj::heapArray<MessageAndFds>(ownMessages.size());
  190|      4|        for (int i = 0; i < messages.size(); ++i) {
  191|      4|          messages[i].segments = ownMessages[i]->message.getSegmentsForOutput();
  192|      4|          messages[i].fds = ownMessages[i]->fds;
  193|      4|        }
  194|      4|        return network.getStream().writeMessages(messages).attach(kj::mv(ownMessages), kj::mv(messages));
  195|      4|      }).catch_([this](kj::Exception&& e) {
  196|       |        // Since no one checks write failures, we need to propagate them into read failures,
  197|       |        // otherwise we might get stuck sending all messages into a black hole and wondering why
  198|       |        // the peer never replies.
  199|      4|        network.readCancelReason = kj::cp(e);
  200|      4|        if (!network.readCanceler.isEmpty()) {
  201|      4|          network.readCanceler.cancel(kj::cp(e));
  202|      4|        }
  203|      4|        kj::throwRecoverableException(kj::mv(e));
  204|      4|      });
  205|      4|    }).attach(kj::addRef(*this))
  206|       |      // Note that it's important that the eagerlyEvaluate() come *after* the attach() because
  207|       |      // otherwise the message (and any capabilities in it) will not be released until a new
  208|       |      // message is written! (Kenton once spent all afternoon tracking this down...)
  209|      4|      .eagerlyEvaluate(nullptr);
  210|      4|  }
_ZZN5capnp18TwoPartyVatNetwork19OutgoingMessageImpl4sendEvENKUlvE_clEv:
  182|      3|    network.previousWrite = previousWrite.then([this, sendTime]() {
  183|      3|      return kj::evalLast([this, sendTime]() -> kj::Promise<void> {
  184|      3|        network.currentOutgoingMessageSendTime = sendTime;
  185|       |        // Swap out the connection's pending messages and write all of them together.
  186|      3|        auto ownMessages = kj::mv(network.queuedMessages);
  187|      3|        network.currentQueueSize = 0;
  188|      3|        auto messages =
  189|      3|          kj::heapArray<MessageAndFds>(ownMessages.size());
  190|      3|        for (int i = 0; i < messages.size(); ++i) {
  191|      3|          messages[i].segments = ownMessages[i]->message.getSegmentsForOutput();
  192|      3|          messages[i].fds = ownMessages[i]->fds;
  193|      3|        }
  194|      3|        return network.getStream().writeMessages(messages).attach(kj::mv(ownMessages), kj::mv(messages));
  195|      3|      }).catch_([this](kj::Exception&& e) {
  196|       |        // Since no one checks write failures, we need to propagate them into read failures,
  197|       |        // otherwise we might get stuck sending all messages into a black hole and wondering why
  198|       |        // the peer never replies.
  199|      3|        network.readCancelReason = kj::cp(e);
  200|      3|        if (!network.readCanceler.isEmpty()) {
  201|      3|          network.readCanceler.cancel(kj::cp(e));
  202|      3|        }
  203|      3|        kj::throwRecoverableException(kj::mv(e));
  204|      3|      });
  205|      3|    }).attach(kj::addRef(*this))
_ZZZN5capnp18TwoPartyVatNetwork19OutgoingMessageImpl4sendEvENKUlvE_clEvENKUlvE_clEv:
  183|      3|      return kj::evalLast([this, sendTime]() -> kj::Promise<void> {
  184|      3|        network.currentOutgoingMessageSendTime = sendTime;
  185|       |        // Swap out the connection's pending messages and write all of them together.
  186|      3|        auto ownMessages = kj::mv(network.queuedMessages);
  187|      3|        network.currentQueueSize = 0;
  188|      3|        auto messages =
  189|      3|          kj::heapArray<MessageAndFds>(ownMessages.size());
  190|      6|        for (int i = 0; i < messages.size(); ++i) {
  ------------------
  |  Branch (190:25): [True: 3, False: 3]
  ------------------
  191|      3|          messages[i].segments = ownMessages[i]->message.getSegmentsForOutput();
  192|      3|          messages[i].fds = ownMessages[i]->fds;
  193|      3|        }
  194|      3|        return network.getStream().writeMessages(messages).attach(kj::mv(ownMessages), kj::mv(messages));
  195|      3|      }).catch_([this](kj::Exception&& e) {
_ZZZN5capnp18TwoPartyVatNetwork19OutgoingMessageImpl4sendEvENKUlvE_clEvENKUlON2kj9ExceptionEE_clES5_:
  195|      1|      }).catch_([this](kj::Exception&& e) {
  196|       |        // Since no one checks write failures, we need to propagate them into read failures,
  197|       |        // otherwise we might get stuck sending all messages into a black hole and wondering why
  198|       |        // the peer never replies.
  199|      1|        network.readCancelReason = kj::cp(e);
  200|      1|        if (!network.readCanceler.isEmpty()) {
  ------------------
  |  Branch (200:13): [True: 0, False: 1]
  ------------------
  201|      0|          network.readCanceler.cancel(kj::cp(e));
  202|      0|        }
  203|      1|        kj::throwRecoverableException(kj::mv(e));
  204|      1|      });
rpc-twoparty.c++:_ZZN5capnp18TwoPartyVatNetwork22receiveIncomingMessageEvENK3$_0clEv:
  306|      3|  return kj::evalLater([this]() -> kj::Promise<kj::Maybe<kj::Own<IncomingRpcMessage>>> {
  307|      3|    KJ_IF_MAYBE(e, readCancelReason) {
  ------------------
  |  Branch (307:5): [True: 0, False: 3]
  ------------------
  308|       |      // A previous write failed; propagate the failure to reads, too.
  309|      0|      return kj::cp(*e);
  310|      0|    }
  311|       |
  312|      3|    kj::Array<kj::AutoCloseFd> fdSpace = nullptr;
  313|      3|    if(maxFdsPerMessage > 0) {
  ------------------
  |  Branch (313:8): [True: 0, False: 3]
  ------------------
  314|      0|      fdSpace = kj::heapArray<kj::AutoCloseFd>(maxFdsPerMessage);
  315|      0|    }
  316|      3|    auto promise = readCanceler.wrap(getStream().tryReadMessage(fdSpace, receiveOptions));
  317|      3|    return promise.then([fdSpace = kj::mv(fdSpace)]
  318|      3|                        (kj::Maybe<MessageReaderAndFds>&& messageAndFds) mutable
  319|      3|                      -> kj::Maybe<kj::Own<IncomingRpcMessage>> {
  320|      3|      KJ_IF_MAYBE(m, messageAndFds) {
  321|      3|        if (m->fds.size() > 0) {
  322|      3|          return kj::Own<IncomingRpcMessage>(
  323|      3|              kj::heap<IncomingMessageImpl>(kj::mv(*m), kj::mv(fdSpace)));
  324|      3|        } else {
  325|      3|          return kj::Own<IncomingRpcMessage>(kj::heap<IncomingMessageImpl>(kj::mv(m->reader)));
  326|      3|        }
  327|      3|      } else {
  328|      3|        return nullptr;
  329|      3|      }
  330|      3|    });
  331|      3|  });
rpc-twoparty.c++:_ZZZN5capnp18TwoPartyVatNetwork22receiveIncomingMessageEvENK3$_0clEvENUlON2kj5MaybeINS_19MessageReaderAndFdsEEEE_clES6_:
  319|      3|                      -> kj::Maybe<kj::Own<IncomingRpcMessage>> {
  320|      3|      KJ_IF_MAYBE(m, messageAndFds) {
  ------------------
  |  Branch (320:7): [True: 2, False: 1]
  ------------------
  321|      2|        if (m->fds.size() > 0) {
  ------------------
  |  Branch (321:13): [True: 0, False: 2]
  ------------------
  322|      0|          return kj::Own<IncomingRpcMessage>(
  323|      0|              kj::heap<IncomingMessageImpl>(kj::mv(*m), kj::mv(fdSpace)));
  324|      2|        } else {
  325|      2|          return kj::Own<IncomingRpcMessage>(kj::heap<IncomingMessageImpl>(kj::mv(m->reader)));
  326|      2|        }
  327|      2|      } else {
  328|      1|        return nullptr;
  329|      1|      }
  330|      3|    });
_ZN5capnp18TwoPartyVatNetwork19IncomingMessageImpl7getBodyEv:
  241|      2|  AnyPointer::Reader getBody() override {
  242|      2|    return message->getRoot<AnyPointer>();
  243|      2|  }
_ZN5capnp18TwoPartyVatNetwork19IncomingMessageImpl14getAttachedFdsEv:
  245|      1|  kj::ArrayPtr<kj::AutoCloseFd> getAttachedFds() override {
  246|      1|    return fds;
  247|      1|  }
_ZN5capnp18TwoPartyVatNetwork19IncomingMessageImplC2EN2kj3OwnINS_13MessageReaderEDnEE:
  232|      2|  IncomingMessageImpl(kj::Own<MessageReader> message): message(kj::mv(message)) {}

_ZN5capnp1_13RpcSystemBaseD2Ev:
 3689|      2|RpcSystemBase::~RpcSystemBase() noexcept(false) {}
_ZN5capnp18IncomingRpcMessage22isShortLivedRpcMessageENS_10AnyPointer6ReaderE:
 3855|      2|bool IncomingRpcMessage::isShortLivedRpcMessage(AnyPointer::Reader body) {
 3856|      2|  switch (body.getAs<rpc::Message>().which()) {
 3857|      0|    case rpc::Message::CALL:
  ------------------
  |  Branch (3857:5): [True: 0, False: 2]
  ------------------
 3858|      1|    case rpc::Message::RETURN:
  ------------------
  |  Branch (3858:5): [True: 1, False: 1]
  ------------------
 3859|      1|      return false;
 3860|      1|    default:
  ------------------
  |  Branch (3860:5): [True: 1, False: 1]
  ------------------
 3861|      1|      return true;
 3862|      2|  }
 3863|      2|}
rpc.c++:_ZZN5capnp1_13RpcSystemBase4Impl18getConnectionStateEON2kj3OwnINS0_14VatNetworkBase10ConnectionEDnEEENKUlNS0_12_GLOBAL__N_118RpcConnectionState14DisconnectInfoEE_clESB_:
 3639|      1|          .then([this,connectionPtr](RpcConnectionState::DisconnectInfo info) {
 3640|      1|        connections.erase(connectionPtr);
 3641|      1|        tasks.add(kj::mv(info.shutdownPromise));
 3642|      1|      }));
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState6AnswerC2Ev:
  602|      2|    Answer() = default;
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState6ImportC2Ev:
  653|      1|    Import() = default;
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState11messageLoopEv:
 2770|      3|  kj::Promise<void> messageLoop() {
 2771|      3|    if (!connection.is<Connected>()) {
  ------------------
  |  Branch (2771:9): [True: 0, False: 3]
  ------------------
 2772|      0|      return kj::READY_NOW;
 2773|      0|    }
 2774|       |
 2775|      3|    if (callWordsInFlight > flowLimit) {
  ------------------
  |  Branch (2775:9): [True: 0, False: 3]
  ------------------
 2776|      0|      auto paf = kj::newPromiseAndFulfiller<void>();
 2777|      0|      flowWaiter = kj::mv(paf.fulfiller);
 2778|      0|      return paf.promise.then([this]() {
 2779|      0|        return messageLoop();
 2780|      0|      });
 2781|      0|    }
 2782|       |
 2783|      3|    return canceler.wrap(connection.get<Connected>()->receiveIncomingMessage()).then(
 2784|      3|        [this](kj::Maybe<kj::Own<IncomingRpcMessage>>&& message) {
 2785|      3|      KJ_IF_MAYBE(m, message) {
 2786|      3|        handleMessage(kj::mv(*m));
 2787|      3|        return true;
 2788|      3|      } else {
 2789|      3|        tasks.add(KJ_EXCEPTION(DISCONNECTED, "Peer disconnected."));
 2790|      3|        return false;
 2791|      3|      }
 2792|      3|    }, [this](kj::Exception&& exception) {
 2793|      3|      receiveIncomingMessageError = true;
 2794|      3|      kj::throwRecoverableException(kj::mv(exception));
 2795|      3|      return false;
 2796|      3|    }).then([this](bool keepGoing) {
 2797|       |      // No exceptions; continue loop.
 2798|       |      //
 2799|       |      // (We do this in a separate continuation to handle the case where exceptions are
 2800|       |      // disabled.)
 2801|       |      //
 2802|       |      // TODO(perf): We add an evalLater() here so that anything we needed to do in reaction to
 2803|       |      //   the previous message has a chance to complete before the next message is handled. In
 2804|       |      //   particular, without this, I observed an ordering problem: I saw a case where a `Return`
 2805|       |      //   message was followed by a `Resolve` message, but the `PromiseClient` associated with the
 2806|       |      //   `Resolve` had its `resolve()` method invoked _before_ any `PromiseClient`s associated
 2807|       |      //   with pipelined capabilities resolved by the `Return`. This could lead to an
 2808|       |      //   incorrectly-ordered interaction between `PromiseClient`s when they resolve to each
 2809|       |      //   other. This is probably really a bug in the way `Return`s are handled -- apparently,
 2810|       |      //   resolution of `PromiseClient`s based on returned capabilities does not occur in a
 2811|       |      //   depth-first way, when it should. If we could fix that then we can probably remove this
 2812|       |      //   `evalLater()`. However, the `evalLater()` is not that bad and solves the problem...
 2813|      3|      if (keepGoing) tasks.add(kj::evalLater([this]() { return messageLoop(); }));
 2814|      3|    });
 2815|      3|  }
rpc.c++:_ZZN5capnp1_12_GLOBAL__N_118RpcConnectionState11messageLoopEvENKUlON2kj5MaybeINS3_3OwnINS_18IncomingRpcMessageEDnEEEEE_clES9_:
 2784|      3|        [this](kj::Maybe<kj::Own<IncomingRpcMessage>>&& message) {
 2785|      3|      KJ_IF_MAYBE(m, message) {
  ------------------
  |  Branch (2785:7): [True: 2, False: 1]
  ------------------
 2786|      2|        handleMessage(kj::mv(*m));
 2787|      2|        return true;
 2788|      2|      } else {
 2789|       |        tasks.add(KJ_EXCEPTION(DISCONNECTED, "Peer disconnected."));
 2790|      1|        return false;
 2791|      1|      }
 2792|      3|    }, [this](kj::Exception&& exception) {
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState13handleMessageEN2kj3OwnINS_18IncomingRpcMessageEDnEE:
 2817|      2|  void handleMessage(kj::Own<IncomingRpcMessage> message) {
 2818|      2|    auto reader = message->getBody().getAs<rpc::Message>();
 2819|       |
 2820|      2|    switch (reader.which()) {
 2821|      0|      case rpc::Message::UNIMPLEMENTED:
  ------------------
  |  Branch (2821:7): [True: 0, False: 2]
  ------------------
 2822|      0|        handleUnimplemented(reader.getUnimplemented());
 2823|      0|        break;
 2824|       |
 2825|      0|      case rpc::Message::ABORT:
  ------------------
  |  Branch (2825:7): [True: 0, False: 2]
  ------------------
 2826|      0|        handleAbort(reader.getAbort());
 2827|      0|        break;
 2828|       |
 2829|      0|      case rpc::Message::BOOTSTRAP:
  ------------------
  |  Branch (2829:7): [True: 0, False: 2]
  ------------------
 2830|      0|        handleBootstrap(kj::mv(message), reader.getBootstrap());
 2831|      0|        break;
 2832|       |
 2833|      0|      case rpc::Message::CALL:
  ------------------
  |  Branch (2833:7): [True: 0, False: 2]
  ------------------
 2834|      0|        handleCall(kj::mv(message), reader.getCall());
 2835|      0|        break;
 2836|       |
 2837|      1|      case rpc::Message::RETURN:
  ------------------
  |  Branch (2837:7): [True: 1, False: 1]
  ------------------
 2838|      1|        handleReturn(kj::mv(message), reader.getReturn());
 2839|      1|        break;
 2840|       |
 2841|      1|      case rpc::Message::FINISH:
  ------------------
  |  Branch (2841:7): [True: 1, False: 1]
  ------------------
 2842|      1|        handleFinish(reader.getFinish());
 2843|      1|        break;
 2844|       |
 2845|      0|      case rpc::Message::RESOLVE:
  ------------------
  |  Branch (2845:7): [True: 0, False: 2]
  ------------------
 2846|      0|        handleResolve(kj::mv(message), reader.getResolve());
 2847|      0|        break;
 2848|       |
 2849|      0|      case rpc::Message::RELEASE:
  ------------------
  |  Branch (2849:7): [True: 0, False: 2]
  ------------------
 2850|      0|        handleRelease(reader.getRelease());
 2851|      0|        break;
 2852|       |
 2853|      0|      case rpc::Message::DISEMBARGO:
  ------------------
  |  Branch (2853:7): [True: 0, False: 2]
  ------------------
 2854|      0|        handleDisembargo(reader.getDisembargo());
 2855|      0|        break;
 2856|       |
 2857|      0|      default: {
  ------------------
  |  Branch (2857:7): [True: 0, False: 2]
  ------------------
 2858|      0|        if (connection.is<Connected>()) {
  ------------------
  |  Branch (2858:13): [True: 0, False: 0]
  ------------------
 2859|      0|          auto message = connection.get<Connected>()->newOutgoingMessage(
 2860|      0|              firstSegmentSize(reader.totalSize(), messageSizeHint<void>()));
 2861|      0|          message->getBody().initAs<rpc::Message>().setUnimplemented(reader);
 2862|      0|          message->send();
 2863|      0|        }
 2864|      0|        break;
 2865|      0|      }
 2866|      2|    }
 2867|      2|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ExportTableIjNS1_18RpcConnectionState6ExportEE6isHighERj:
  197|      1|  bool isHigh(Id& id) {
  198|      1|    return (id & highBit<Id>()) != 0;
  199|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_17highBitIjEET_v:
  188|      5|static constexpr Id highBit() {
  189|      5|  return 1u << (sizeof(Id) * 8 - 1);
  190|      5|}
rpc.c++:_ZNK5capnp1_12_GLOBAL__N_118RpcConnectionState6ExportneEDn:
  649|      1|    inline bool operator!=(decltype(nullptr)) const { return refcount != 0; }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState15handleBootstrapEON2kj3OwnINS_18IncomingRpcMessageEDnEERKNS_3rpc9Bootstrap6ReaderE:
 2938|      0|                       const rpc::Bootstrap::Reader& bootstrap) {
 2939|      0|    AnswerId answerId = bootstrap.getQuestionId();
 2940|       |
 2941|      0|    if (!connection.is<Connected>()) {
  ------------------
  |  Branch (2941:9): [True: 0, False: 0]
  ------------------
 2942|       |      // Disconnected; ignore.
 2943|      0|      return;
 2944|      0|    }
 2945|       |
 2946|      0|    VatNetworkBase::Connection& conn = *connection.get<Connected>();
 2947|      0|    auto response = conn.newOutgoingMessage(
 2948|      0|        messageSizeHint<rpc::Return>() + sizeInWords<rpc::CapDescriptor>() + 32);
 2949|       |
 2950|      0|    rpc::Return::Builder ret = response->getBody().getAs<rpc::Message>().initReturn();
 2951|      0|    ret.setAnswerId(answerId);
 2952|       |
 2953|      0|    kj::Own<ClientHook> capHook;
 2954|      0|    kj::Array<ExportId> resultExports;
 2955|      0|    KJ_DEFER(releaseExports(resultExports));  // in case something goes wrong
 2956|       |
 2957|       |    // Call the restorer and initialize the answer.
 2958|      0|    KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
  ------------------
  |  Branch (2958:5): [True: 0, False: 0]
  ------------------
 2959|      0|      Capability::Client cap = nullptr;
 2960|       |
 2961|      0|      if (bootstrap.hasDeprecatedObjectId()) {
 2962|      0|        KJ_IF_MAYBE(r, restorer) {
 2963|      0|          cap = r->baseRestore(bootstrap.getDeprecatedObjectId());
 2964|      0|        } else {
 2965|      0|          KJ_FAIL_REQUIRE("This vat only supports a bootstrap interface, not the old "
 2966|      0|                          "Cap'n-Proto-0.4-style named exports.") { return; }
 2967|      0|        }
 2968|      0|      } else {
 2969|      0|        cap = bootstrapFactory.baseCreateFor(conn.baseGetPeerVatId());
 2970|      0|      }
 2971|       |
 2972|      0|      BuilderCapabilityTable capTable;
 2973|      0|      auto payload = ret.initResults();
 2974|      0|      capTable.imbue(payload.getContent()).setAs<Capability>(kj::mv(cap));
 2975|       |
 2976|      0|      auto capTableArray = capTable.getTable();
 2977|      0|      KJ_DASSERT(capTableArray.size() == 1);
 2978|      0|      kj::Vector<int> fds;
 2979|      0|      resultExports = writeDescriptors(capTableArray, payload, fds);
 2980|      0|      response->setFds(fds.releaseAsArray());
 2981|       |
 2982|       |      // If we're returning a capability that turns out to be an PromiseClient pointing back on
 2983|       |      // this same network, it's important we remove the `PromiseClient` layer and use the inner
 2984|       |      // capability instead. This achieves the same effect that `PostReturnRpcPipeline` does for
 2985|       |      // regular call returns.
 2986|       |      //
 2987|       |      // This single line of code represents two hours of my life.
 2988|      0|      capHook = getInnermostClient(*KJ_ASSERT_NONNULL(capTableArray[0]));
 2989|      0|    })) {
 2990|      0|      fromException(*exception, ret.initException());
 2991|      0|      capHook = newBrokenCap(kj::mv(*exception));
 2992|      0|    }
 2993|       |
 2994|      0|    message = nullptr;
 2995|       |
 2996|       |    // Add the answer to the answer table for pipelining and send the response.
 2997|      0|    auto& answer = answers[answerId];
 2998|  18.4E|    KJ_REQUIRE(!answer.active, "questionId is already in use", answerId) {
  ------------------
  |  Branch (2998:5): [True: 1, False: 18.4E]
  ------------------
 2999|      0|      return;
 3000|      0|    }
 3001|       |
 3002|      0|    answer.resultExports = kj::mv(resultExports);
 3003|      0|    answer.active = true;
 3004|      0|    answer.pipeline = kj::Own<PipelineHook>(kj::refcounted<SingleCapPipeline>(kj::mv(capHook)));
 3005|       |
 3006|      0|    response->send();
 3007|      0|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState16writeDescriptorsEN2kj8ArrayPtrINS3_5MaybeINS3_3OwnINS_10ClientHookEDnEEEEEENS_3rpc7Payload7BuilderERNS3_6VectorIiEE:
 1315|      1|                                       rpc::Payload::Builder payload, kj::Vector<int>& fds) {
 1316|      1|    if (capTable.size() == 0) {
  ------------------
  |  Branch (1316:9): [True: 0, False: 1]
  ------------------
 1317|       |      // Calling initCapTable(0) will still allocate a 1-word tag, which we'd like to avoid...
 1318|      0|      return nullptr;
 1319|      0|    }
 1320|       |
 1321|      1|    auto capTableBuilder = payload.initCapTable(capTable.size());
 1322|      1|    kj::Vector<ExportId> exports(capTable.size());
 1323|      1|    for (uint i: kj::indices(capTable)) {
  ------------------
  |  Branch (1323:16): [True: 1, False: 1]
  ------------------
 1324|      1|      KJ_IF_MAYBE(cap, capTable[i]) {
  ------------------
  |  Branch (1324:7): [True: 1, False: 0]
  ------------------
 1325|      1|        KJ_IF_MAYBE(exportId, writeDescriptor(**cap, capTableBuilder[i], fds)) {
  ------------------
  |  Branch (1325:9): [True: 1, False: 0]
  ------------------
 1326|      1|          exports.add(*exportId);
 1327|      1|        }
 1328|      1|      } else {
 1329|      0|        capTableBuilder[i].setNone();
 1330|      0|      }
 1331|      1|    }
 1332|      1|    return exports.releaseAsArray();
 1333|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState15writeDescriptorERNS_10ClientHookENS_3rpc13CapDescriptor7BuilderERN2kj6VectorIiEE:
 1261|      1|                                      kj::Vector<int>& fds) {
 1262|       |    // Write a descriptor for the given capability.
 1263|       |
 1264|       |    // Find the innermost wrapped capability.
 1265|      1|    ClientHook* inner = &cap;
 1266|      1|    for (;;) {
 1267|      1|      KJ_IF_MAYBE(resolved, inner->getResolved()) {
  ------------------
  |  Branch (1267:7): [True: 0, False: 1]
  ------------------
 1268|      0|        inner = resolved;
 1269|      1|      } else {
 1270|      1|        break;
 1271|      1|      }
 1272|      1|    }
 1273|       |
 1274|      1|    KJ_IF_MAYBE(fd, inner->getFd()) {
  ------------------
  |  Branch (1274:5): [True: 0, False: 1]
  ------------------
 1275|      0|      descriptor.setAttachedFd(fds.size());
 1276|      0|      fds.add(kj::mv(*fd));
 1277|      0|    }
 1278|       |
 1279|      1|    if (inner->getBrand() == this) {
  ------------------
  |  Branch (1279:9): [True: 0, False: 1]
  ------------------
 1280|      0|      return kj::downcast<RpcClient>(*inner).writeDescriptor(descriptor, fds);
 1281|      1|    } else {
 1282|      1|      auto iter = exportsByCap.find(inner);
 1283|      1|      if (iter != exportsByCap.end()) {
  ------------------
  |  Branch (1283:11): [True: 0, False: 1]
  ------------------
 1284|       |        // We've already seen and exported this capability before.  Just up the refcount.
 1285|      0|        auto& exp = KJ_ASSERT_NONNULL(exports.find(iter->second));
  ------------------
  |  Branch (1285:21): [True: 0, False: 0]
  ------------------
 1286|      0|        ++exp.refcount;
 1287|      0|        if (exp.resolveOp == nullptr) {
  ------------------
  |  Branch (1287:13): [True: 0, False: 0]
  ------------------
 1288|      0|          descriptor.setSenderHosted(iter->second);
 1289|      0|        } else {
 1290|      0|          descriptor.setSenderPromise(iter->second);
 1291|      0|        }
 1292|      0|        return iter->second;
 1293|      1|      } else {
 1294|       |        // This is the first time we've seen this capability.
 1295|      1|        ExportId exportId;
 1296|      1|        auto& exp = exports.next(exportId);
 1297|      1|        exportsByCap[inner] = exportId;
 1298|      1|        exp.refcount = 1;
 1299|      1|        exp.clientHook = inner->addRef();
 1300|       |
 1301|      1|        KJ_IF_MAYBE(wrapped, inner->whenMoreResolved()) {
  ------------------
  |  Branch (1301:9): [True: 0, False: 1]
  ------------------
 1302|       |          // This is a promise.  Arrange for the `Resolve` message to be sent later.
 1303|      0|          exp.resolveOp = resolveExportedPromise(exportId, kj::mv(*wrapped));
 1304|      0|          descriptor.setSenderPromise(exportId);
 1305|      1|        } else {
 1306|      1|          descriptor.setSenderHosted(exportId);
 1307|      1|        }
 1308|       |
 1309|      1|        return exportId;
 1310|      1|      }
 1311|      1|    }
 1312|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ExportTableIjNS1_18RpcConnectionState6ExportEE4nextERj:
  230|      1|  T& next(Id& id) {
  231|      1|    if (freeIds.empty()) {
  ------------------
  |  Branch (231:9): [True: 1, False: 0]
  ------------------
  232|      1|      id = slots.size();
  233|      1|      KJ_ASSERT(!isHigh(id), "2^31 concurrent questions?!!?!");
  ------------------
  |  Branch (233:7): [True: 1, False: 0]
  ------------------
  234|      1|      return slots.add();
  235|      1|    } else {
  236|      0|      id = freeIds.top();
  237|      0|      freeIds.pop();
  238|      0|      return slots[id];
  239|      0|    }
  240|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_117exceptionSizeHintERKN2kj9ExceptionE:
  174|      2|uint exceptionSizeHint(const kj::Exception& exception) {
  175|      2|  return sizeInWords<rpc::Exception>() + exception.getDescription().size() / sizeof(word) + 1;
  176|      2|}
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState18getInnermostClientERNS_10ClientHookE:
 1353|      1|  kj::Own<ClientHook> getInnermostClient(ClientHook& client) {
 1354|      1|    ClientHook* ptr = &client;
 1355|      1|    for (;;) {
 1356|      1|      KJ_IF_MAYBE(inner, ptr->getResolved()) {
  ------------------
  |  Branch (1356:7): [True: 0, False: 1]
  ------------------
 1357|      0|        ptr = inner;
 1358|      1|      } else {
 1359|      1|        break;
 1360|      1|      }
 1361|      1|    }
 1362|       |
 1363|      1|    if (ptr->getBrand() == this) {
  ------------------
  |  Branch (1363:9): [True: 0, False: 1]
  ------------------
 1364|      0|      return kj::downcast<RpcClient>(*ptr).getInnermostClient();
 1365|      1|    } else {
 1366|      1|      return ptr->addRef();
 1367|      1|    }
 1368|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState13fromExceptionERKN2kj9ExceptionENS_3rpc9Exception7BuilderE:
 1445|      2|  void fromException(const kj::Exception& exception, rpc::Exception::Builder builder) {
 1446|      2|    _::fromException(exception, builder, traceEncoder);
 1447|      2|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_113fromExceptionERKN2kj9ExceptionENS_3rpc9Exception7BuilderENS2_5MaybeIRNS2_8FunctionIFNS2_6StringES5_EEEEE:
  142|      2|                   kj::Maybe<kj::Function<kj::String(const kj::Exception&)>&> traceEncoder) {
  143|      2|  kj::StringPtr description = exception.getDescription();
  144|       |
  145|       |  // Include context, if any.
  146|      2|  kj::Vector<kj::String> contextLines;
  147|      2|  for (auto context = exception.getContext();;) {
  148|      2|    KJ_IF_MAYBE(c, context) {
  ------------------
  |  Branch (148:5): [True: 0, False: 2]
  ------------------
  149|      0|      contextLines.add(kj::str("context: ", c->file, ": ", c->line, ": ", c->description));
  150|      0|      context = c->next;
  151|      2|    } else {
  152|      2|      break;
  153|      2|    }
  154|      2|  }
  155|      2|  kj::String scratch;
  156|      2|  if (contextLines.size() > 0) {
  ------------------
  |  Branch (156:7): [True: 0, False: 2]
  ------------------
  157|      0|    scratch = kj::str(description, '\n', kj::strArray(contextLines, "\n"));
  158|      0|    description = scratch;
  159|      0|  }
  160|       |
  161|      2|  builder.setReason(description);
  162|      2|  builder.setType(static_cast<rpc::Exception::Type>(exception.getType()));
  163|       |
  164|      2|  KJ_IF_MAYBE(t, traceEncoder) {
  ------------------
  |  Branch (164:3): [True: 0, False: 2]
  ------------------
  165|      0|    builder.setTrace((*t)(exception));
  166|      0|  }
  167|       |
  168|      2|  if (exception.getType() == kj::Exception::Type::FAILED &&
  ------------------
  |  Branch (168:7): [True: 0, False: 2]
  |  Branch (168:7): [True: 0, False: 2]
  ------------------
  169|      0|      !exception.getDescription().startsWith("remote exception:")) {
  ------------------
  |  Branch (169:7): [True: 0, False: 0]
  ------------------
  170|       |    KJ_LOG(INFO, "returning failure over rpc", exception);
  ------------------
  |  Branch (170:5): [True: 0, False: 0]
  ------------------
  171|      0|  }
  172|      2|}
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ImportTableIjNS1_18RpcConnectionState6AnswerEEixEj:
  293|      1|  T& operator[](Id id) {
  294|      1|    if (id < kj::size(low)) {
  ------------------
  |  Branch (294:9): [True: 1, False: 0]
  ------------------
  295|      1|      return low[id];
  296|      1|    } else {
  297|      0|      return high[id];
  298|      0|    }
  299|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState17SingleCapPipelineC2EON2kj3OwnINS_10ClientHookEDnEE:
 2919|      1|        : cap(kj::mv(cap)) {}
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState14releaseExportsEN2kj8ArrayPtrIjEE:
 3440|      3|  void releaseExports(kj::ArrayPtr<ExportId> exports) {
 3441|      3|    for (auto exportId: exports) {
  ------------------
  |  Branch (3441:23): [True: 0, False: 3]
  ------------------
 3442|      0|      releaseExport(exportId, 1);
 3443|      0|    }
 3444|      3|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ImportTableIjNS1_18RpcConnectionState6AnswerEE4findEj:
  301|      1|  kj::Maybe<T&> find(Id id) {
  302|      1|    if (id < kj::size(low)) {
  ------------------
  |  Branch (302:9): [True: 1, False: 0]
  ------------------
  303|      1|      return low[id];
  304|      1|    } else {
  305|      0|      auto iter = high.find(id);
  306|      0|      if (iter == high.end()) {
  ------------------
  |  Branch (306:11): [True: 0, False: 0]
  ------------------
  307|      0|        return nullptr;
  308|      0|      } else {
  309|      0|        return iter->second;
  310|      0|      }
  311|      0|    }
  312|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState11receiveCapsENS_4ListINS_3rpc13CapDescriptorELNS_4KindE3EE6ReaderEN2kj8ArrayPtrINS9_11AutoCloseFdEEE:
 1649|      1|                                                        kj::ArrayPtr<kj::AutoCloseFd> fds) {
 1650|      1|    auto result = kj::heapArrayBuilder<kj::Maybe<kj::Own<ClientHook>>>(capTable.size());
 1651|      1|    for (auto cap: capTable) {
  ------------------
  |  Branch (1651:18): [True: 1, False: 1]
  ------------------
 1652|      1|      result.add(receiveCap(cap, fds));
 1653|      1|    }
 1654|      1|    return result.finish();
 1655|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState10receiveCapENS_3rpc13CapDescriptor6ReaderEN2kj8ArrayPtrINS6_11AutoCloseFdEEE:
 1589|      1|                                            kj::ArrayPtr<kj::AutoCloseFd> fds) {
 1590|      1|    uint fdIndex = descriptor.getAttachedFd();
 1591|      1|    kj::Maybe<kj::AutoCloseFd> fd;
 1592|      1|    if (fdIndex < fds.size() && fds[fdIndex] != nullptr) {
  ------------------
  |  Branch (1592:9): [True: 0, False: 1]
  |  Branch (1592:33): [True: 0, False: 0]
  ------------------
 1593|      0|      fd = kj::mv(fds[fdIndex]);
 1594|      0|    }
 1595|       |
 1596|      1|    switch (descriptor.which()) {
 1597|      0|      case rpc::CapDescriptor::NONE:
  ------------------
  |  Branch (1597:7): [True: 0, False: 1]
  ------------------
 1598|      0|        return nullptr;
 1599|       |
 1600|      1|      case rpc::CapDescriptor::SENDER_HOSTED:
  ------------------
  |  Branch (1600:7): [True: 1, False: 0]
  ------------------
 1601|      1|        return import(descriptor.getSenderHosted(), false, kj::mv(fd));
 1602|      0|      case rpc::CapDescriptor::SENDER_PROMISE:
  ------------------
  |  Branch (1602:7): [True: 0, False: 1]
  ------------------
 1603|      0|        return import(descriptor.getSenderPromise(), true, kj::mv(fd));
 1604|       |
 1605|      0|      case rpc::CapDescriptor::RECEIVER_HOSTED:
  ------------------
  |  Branch (1605:7): [True: 0, False: 1]
  ------------------
 1606|      0|        KJ_IF_MAYBE(exp, exports.find(descriptor.getReceiverHosted())) {
  ------------------
  |  Branch (1606:9): [True: 0, False: 0]
  ------------------
 1607|      0|          auto result = exp->clientHook->addRef();
 1608|      0|          if (result->getBrand() == this) {
  ------------------
  |  Branch (1608:15): [True: 0, False: 0]
  ------------------
 1609|      0|            result = kj::refcounted<TribbleRaceBlocker>(kj::mv(result));
 1610|      0|          }
 1611|      0|          return kj::mv(result);
 1612|      0|        } else {
 1613|      0|          return newBrokenCap("invalid 'receiverHosted' export ID");
 1614|      0|        }
 1615|       |
 1616|      0|      case rpc::CapDescriptor::RECEIVER_ANSWER: {
  ------------------
  |  Branch (1616:7): [True: 0, False: 1]
  ------------------
 1617|      0|        auto promisedAnswer = descriptor.getReceiverAnswer();
 1618|       |
 1619|      0|        KJ_IF_MAYBE(answer, answers.find(promisedAnswer.getQuestionId())) {
  ------------------
  |  Branch (1619:9): [True: 0, False: 0]
  ------------------
 1620|      0|          if (answer->active) {
  ------------------
  |  Branch (1620:15): [True: 0, False: 0]
  ------------------
 1621|      0|            KJ_IF_MAYBE(pipeline, answer->pipeline) {
  ------------------
  |  Branch (1621:13): [True: 0, False: 0]
  ------------------
 1622|      0|              KJ_IF_MAYBE(ops, toPipelineOps(promisedAnswer.getTransform())) {
  ------------------
  |  Branch (1622:15): [True: 0, False: 0]
  ------------------
 1623|      0|                auto result = pipeline->get()->getPipelinedCap(*ops);
 1624|      0|                if (result->getBrand() == this) {
  ------------------
  |  Branch (1624:21): [True: 0, False: 0]
  ------------------
 1625|      0|                  result = kj::refcounted<TribbleRaceBlocker>(kj::mv(result));
 1626|      0|                }
 1627|      0|                return kj::mv(result);
 1628|      0|              } else {
 1629|      0|                return newBrokenCap("unrecognized pipeline ops");
 1630|      0|              }
 1631|      0|            }
 1632|      0|          }
 1633|      0|        }
 1634|       |
 1635|      0|        return newBrokenCap("invalid 'receiverAnswer'");
 1636|      0|      }
 1637|       |
 1638|      0|      case rpc::CapDescriptor::THIRD_PARTY_HOSTED:
  ------------------
  |  Branch (1638:7): [True: 0, False: 1]
  ------------------
 1639|       |        // We don't support third-party caps, so use the vine instead.
 1640|      0|        return import(descriptor.getThirdPartyHosted().getVineId(), false, kj::mv(fd));
 1641|       |
 1642|      0|      default:
  ------------------
  |  Branch (1642:7): [True: 0, False: 1]
  ------------------
 1643|      0|        KJ_FAIL_REQUIRE("unknown CapDescriptor type") { break; }
 1644|      0|        return newBrokenCap("unknown CapDescriptor type");
 1645|      1|    }
 1646|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState6importEjbN2kj5MaybeINS3_11AutoCloseFdEEE:
 1452|      1|  kj::Own<ClientHook> import(ImportId importId, bool isPromise, kj::Maybe<kj::AutoCloseFd> fd) {
 1453|       |    // Receive a new import.
 1454|       |
 1455|      1|    auto& import = imports[importId];
 1456|      1|    kj::Own<ImportClient> importClient;
 1457|       |
 1458|       |    // Create the ImportClient, or if one already exists, use it.
 1459|      1|    KJ_IF_MAYBE(c, import.importClient) {
  ------------------
  |  Branch (1459:5): [True: 0, False: 1]
  ------------------
 1460|      0|      importClient = kj::addRef(*c);
 1461|       |
 1462|       |      // If the same import is introduced multiple times, and it is missing an FD the first time,
 1463|       |      // but it has one on a later attempt, we want to attach the later one. This could happen
 1464|       |      // because the first introduction was part of a message that had too many other FDs and went
 1465|       |      // over the per-message limit. Perhaps the protocol design is such that this other message
 1466|       |      // doesn't really care if the FDs are transferred or not, but the later message really does
 1467|       |      // care; it would be bad if the previous message blocked later messages from delivering the
 1468|       |      // FD just because it happened to reference the same capability.
 1469|      0|      importClient->setFdIfMissing(kj::mv(fd));
 1470|      1|    } else {
 1471|      1|      importClient = kj::refcounted<ImportClient>(*this, importId, kj::mv(fd));
 1472|      1|      import.importClient = *importClient;
 1473|      1|    }
 1474|       |
 1475|       |    // We just received a copy of this import ID, so the remote refcount has gone up.
 1476|      1|    importClient->addRemoteRef();
 1477|       |
 1478|      1|    if (isPromise) {
  ------------------
  |  Branch (1478:9): [True: 0, False: 1]
  ------------------
 1479|       |      // We need to construct a PromiseClient around this import, if we haven't already.
 1480|      0|      KJ_IF_MAYBE(c, import.appClient) {
  ------------------
  |  Branch (1480:7): [True: 0, False: 0]
  ------------------
 1481|       |        // Use the existing one.
 1482|      0|        return kj::addRef(*c);
 1483|      0|      } else {
 1484|       |        // Create a promise for this import's resolution.
 1485|      0|        auto paf = kj::newPromiseAndFulfiller<kj::Own<ClientHook>>();
 1486|      0|        import.promiseFulfiller = kj::mv(paf.fulfiller);
 1487|       |
 1488|       |        // Make sure the import is not destroyed while this promise exists.
 1489|      0|        paf.promise = paf.promise.attach(kj::addRef(*importClient));
 1490|       |
 1491|       |        // Create a PromiseClient around it and return it.
 1492|      0|        auto result = kj::refcounted<PromiseClient>(
 1493|      0|            *this, kj::mv(importClient), kj::mv(paf.promise), importId);
 1494|      0|        import.appClient = *result;
 1495|      0|        return kj::mv(result);
 1496|      0|      }
 1497|      1|    } else {
 1498|      1|      import.appClient = *importClient;
 1499|      1|      return kj::mv(importClient);
 1500|      1|    }
 1501|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ImportTableIjNS1_18RpcConnectionState6ImportEEixEj:
  293|      1|  T& operator[](Id id) {
  294|      1|    if (id < kj::size(low)) {
  ------------------
  |  Branch (294:9): [True: 1, False: 0]
  ------------------
  295|      1|      return low[id];
  296|      1|    } else {
  297|      0|      return high[id];
  298|      0|    }
  299|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState12ImportClientC2ERS2_jN2kj5MaybeINS5_11AutoCloseFdEEE:
  864|      1|        : RpcClient(connectionState), importId(importId), fd(kj::mv(fd)) {}
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState9RpcClientC2ERS2_:
  746|      1|        : connectionState(kj::addRef(connectionState)) {}
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState9RpcClientD2Ev:
  748|      3|    ~RpcClient() noexcept(false) {
  749|      3|      KJ_IF_MAYBE(f, this->flowController) {
  ------------------
  |  Branch (749:7): [True: 0, False: 3]
  ------------------
  750|       |        // Destroying the client should not cancel outstanding streaming calls.
  751|      0|        connectionState->tasks.add(f->get()->waitAllAcked().attach(kj::mv(*f)));
  752|      0|      }
  753|      3|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ExportTableIjNS1_18RpcConnectionState8QuestionEE6isHighERj:
  197|      4|  bool isHigh(Id& id) {
  198|      4|    return (id & highBit<Id>()) != 0;
  199|      4|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState11QuestionRefD2Ev:
 1670|      1|    ~QuestionRef() noexcept {
 1671|       |      // Contrary to KJ style, we declare this destructor `noexcept` because if anything in here
 1672|       |      // throws (without being caught) we're probably in pretty bad shape and going to be crashing
 1673|       |      // later anyway. Better to abort now.
 1674|       |
 1675|      1|      KJ_IF_MAYBE(c, connectionState) {
  ------------------
  |  Branch (1675:7): [True: 1, False: 0]
  ------------------
 1676|      1|        auto& connectionState = *c;
 1677|       |
 1678|      1|        auto& question = KJ_ASSERT_NONNULL(
  ------------------
  |  Branch (1678:26): [True: 0, False: 1]
  ------------------
 1679|      1|            connectionState->questions.find(id), "Question ID no longer on table?");
 1680|       |
 1681|       |        // Send the "Finish" message (if the connection is not already broken).
 1682|      1|        if (connectionState->connection.is<Connected>() && !question.skipFinish) {
  ------------------
  |  Branch (1682:13): [True: 1, False: 0]
  |  Branch (1682:60): [True: 1, False: 0]
  ------------------
 1683|      1|          KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() {
  ------------------
  |  Branch (1683:11): [True: 0, False: 1]
  ------------------
 1684|      1|            auto message = connectionState->connection.get<Connected>()->newOutgoingMessage(
 1685|      1|                messageSizeHint<rpc::Finish>());
 1686|      1|            auto builder = message->getBody().getAs<rpc::Message>().initFinish();
 1687|      1|            builder.setQuestionId(id);
 1688|       |            // If we're still awaiting a return, then this request is being canceled, and we're going
 1689|       |            // to ignore any capabilities in the return message, so set releaseResultCaps true. If we
 1690|       |            // already received the return, then we've already built local proxies for the caps and
 1691|       |            // will send Release messages when those are destroyed.
 1692|      1|            builder.setReleaseResultCaps(question.isAwaitingReturn);
 1693|       |
 1694|       |            // Let the peer know we don't have the early cancellation bug.
 1695|      1|            builder.setRequireEarlyCancellationWorkaround(false);
 1696|       |
 1697|      1|            message->send();
 1698|      1|          })) {
 1699|      0|            connectionState->tasks.add(kj::mv(*e));
 1700|      0|          }
 1701|      1|        }
 1702|       |
 1703|       |        // Check if the question has returned and, if so, remove it from the table.
 1704|       |        // Remove question ID from the table.  Must do this *after* sending `Finish` to ensure that
 1705|       |        // the ID is not re-allocated before the `Finish` message can be sent.
 1706|      1|        if (question.isAwaitingReturn) {
  ------------------
  |  Branch (1706:13): [True: 0, False: 1]
  ------------------
 1707|       |          // Still waiting for return, so just remove the QuestionRef pointer from the table.
 1708|      0|          question.selfRef = nullptr;
 1709|      1|        } else {
 1710|       |          // Call has already returned, so we can now remove it from the table.
 1711|      1|          connectionState->questions.erase(id, question);
 1712|      1|        }
 1713|      1|      }
 1714|      1|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ExportTableIjNS1_18RpcConnectionState8QuestionEE4findEj:
  201|      2|  kj::Maybe<T&> find(Id id) {
  202|      2|    if (isHigh(id)) {
  ------------------
  |  Branch (202:9): [True: 0, False: 2]
  ------------------
  203|      0|      return highSlots.find(id);
  204|      2|    } else if (id < slots.size() && slots[id] != nullptr) {
  ------------------
  |  Branch (204:16): [True: 2, False: 0]
  |  Branch (204:37): [True: 2, False: 0]
  ------------------
  205|      2|      return slots[id];
  206|      2|    } else {
  207|      0|      return nullptr;
  208|      0|    }
  209|      2|  }
rpc.c++:_ZNK5capnp1_12_GLOBAL__N_118RpcConnectionState8QuestionneEDn:
  598|      3|    inline bool operator!=(decltype(nullptr)) const { return !operator==(nullptr); }
rpc.c++:_ZNK5capnp1_12_GLOBAL__N_118RpcConnectionState8QuestioneqEDn:
  595|      3|    inline bool operator==(decltype(nullptr)) const {
  596|      3|      return !isAwaitingReturn && selfRef == nullptr;
  ------------------
  |  Branch (596:14): [True: 2, False: 1]
  |  Branch (596:35): [True: 1, False: 1]
  ------------------
  597|      3|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_115messageSizeHintINS_3rpc6FinishEEEjv:
   43|      1|inline constexpr uint messageSizeHint() {
   44|      1|  return 1 + sizeInWords<rpc::Message>() + sizeInWords<T>();
   45|      1|}
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ExportTableIjNS1_18RpcConnectionState8QuestionEE5eraseEjRS4_:
  211|      1|  T erase(Id id, T& entry) {
  212|       |    // Remove an entry from the table and return it.  We return it so that the caller can be
  213|       |    // careful to release it (possibly invoking arbitrary destructors) at a time that makes sense.
  214|       |    // `entry` is a reference to the entry being released -- we require this in order to prove
  215|       |    // that the caller has already done a find() to check that this entry exists.  We can't check
  216|       |    // ourselves because the caller may have nullified the entry in the meantime.
  217|       |
  218|      1|    if (isHigh(id)) {
  ------------------
  |  Branch (218:9): [True: 0, False: 1]
  ------------------
  219|      0|      auto& slot = KJ_REQUIRE_NONNULL(highSlots.findEntry(id));
  ------------------
  |  Branch (219:20): [True: 0, False: 0]
  ------------------
  220|      0|      return highSlots.release(slot).value;
  221|      1|    } else {
  222|       |      KJ_DREQUIRE(&entry == &slots[id]);
  ------------------
  |  Branch (222:7): [Folded, False: 1]
  ------------------
  223|      1|      T toRelease = kj::mv(slots[id]);
  224|      1|      slots[id] = T();
  225|      1|      freeIds.push(id);
  226|      1|      return toRelease;
  227|      1|    }
  228|      1|  }
rpc.c++:_ZZZN5capnp1_12_GLOBAL__N_118RpcConnectionState11RpcPipeline15getPipelinedCapEON2kj5ArrayINS_10PipelineOpEEEENKUlvE_clEvENKUlONS4_3OwnINS2_11RpcResponseEDnEEE_clESD_:
 2114|      1|                [ops = kj::heapArray(ops.asPtr())](kj::Own<RpcResponse>&& response) {
 2115|      1|                  return response->getResults().getPipelinedCap(kj::mv(ops));
 2116|      1|                });
rpc.c++:_ZZN5capnp1_12_GLOBAL__N_118RpcConnectionState13PromiseClientC1ERS2_N2kj3OwnINS2_9RpcClientEDnEENS5_7PromiseINS6_INS_10ClientHookEDnEEEENS5_5MaybeIjEEENKUlOSB_E_clESF_:
 1002|      1|              [this](kj::Own<ClientHook>&& resolution) {
 1003|      1|                return resolve(kj::mv(resolution));
 1004|      1|              }, [this](kj::Exception&& exception) {
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState13PromiseClient7resolveEN2kj3OwnINS_10ClientHookEDnEE:
 1134|      1|    kj::Promise<kj::Own<ClientHook>> resolve(kj::Own<ClientHook> replacement) {
 1135|      1|      KJ_DASSERT(!isResolved());
  ------------------
  |  Branch (1135:7): [Folded, False: 1]
  ------------------
 1136|       |
 1137|      1|      const void* replacementBrand = replacement->getBrand();
 1138|      1|      bool isSameConnection = replacementBrand == connectionState.get();
 1139|      1|      if (isSameConnection) {
  ------------------
  |  Branch (1139:11): [True: 1, False: 0]
  ------------------
 1140|       |        // We resolved to some other RPC capability hosted by the same peer.
 1141|      1|        KJ_IF_MAYBE(promise, replacement->whenMoreResolved()) {
  ------------------
  |  Branch (1141:9): [True: 0, False: 1]
  ------------------
 1142|       |          // We resolved to another remote promise. If *that* promise eventually resolves back
 1143|       |          // to us, we'll need a disembargo. Possibilities:
 1144|       |          // 1. The other promise hasn't resolved at all yet. In that case we can simply set its
 1145|       |          //    `receivedCall` flag and let it handle the disembargo later.
 1146|       |          // 2. The other promise has received a Resolve message and decided to initiate a
 1147|       |          //    disembargo which it is still waiting for. In that case we will certainly also need
 1148|       |          //    a disembargo for the same reason that the other promise did. And, we can't simply
 1149|       |          //    wait for their disembargo; we need to start a new one of our own.
 1150|       |          // 3. The other promise has resolved already (with or without a disembargo). In this
 1151|       |          //    case we should treat it as if we resolved directly to the other promise's result,
 1152|       |          //    possibly requiring a disembargo under the same conditions.
 1153|       |
 1154|       |          // We know the other object is a PromiseClient because it's the only ClientHook
 1155|       |          // type in the RPC implementation which returns non-null for `whenMoreResolved()`.
 1156|      0|          PromiseClient* other = &kj::downcast<PromiseClient>(*replacement);
 1157|      0|          while (other->resolutionType == MERGED) {
  ------------------
  |  Branch (1157:18): [True: 0, False: 0]
  ------------------
 1158|       |            // There's no need to resolve to a thing that's just going to resolve to another thing.
 1159|      0|            replacement = other->cap->addRef();
 1160|      0|            other = &kj::downcast<PromiseClient>(*replacement);
 1161|       |
 1162|       |            // Note that replacementBrand is unchanged since we'd only merge with other
 1163|       |            // PromiseClients on the same connection.
 1164|      0|            KJ_DASSERT(replacement->getBrand() == replacementBrand);
  ------------------
  |  Branch (1164:13): [Folded, False: 0]
  ------------------
 1165|      0|          }
 1166|       |
 1167|      0|          if (other->isResolved()) {
  ------------------
  |  Branch (1167:15): [True: 0, False: 0]
  ------------------
 1168|       |            // The other capability resolved already. If it determined that it resolved as
 1169|       |            // reflected, then we determine the same.
 1170|      0|            resolutionType = other->resolutionType;
 1171|      0|          } else {
 1172|       |            // The other capability hasn't resolved yet, so we can safely merge with it and do a
 1173|       |            // single combined disembargo if needed later.
 1174|      0|            other->receivedCall = other->receivedCall || receivedCall;
  ------------------
  |  Branch (1174:35): [True: 0, False: 0]
  |  Branch (1174:58): [True: 0, False: 0]
  ------------------
 1175|      0|            resolutionType = MERGED;
 1176|      0|          }
 1177|      1|        } else {
 1178|      1|          resolutionType = REMOTE;
 1179|      1|        }
 1180|      1|      } else {
 1181|      0|        if (replacementBrand == &ClientHook::NULL_CAPABILITY_BRAND ||
  ------------------
  |  Branch (1181:13): [True: 0, False: 0]
  ------------------
 1182|      0|            replacementBrand == &ClientHook::BROKEN_CAPABILITY_BRAND) {
  ------------------
  |  Branch (1182:13): [True: 0, False: 0]
  ------------------
 1183|       |          // We don't consider null or broken capabilities as "reflected" because they may have
 1184|       |          // been communicated to us literally as a null pointer or an exception on the wire,
 1185|       |          // rather than as a reference to one of our exports, in which case a disembargo won't
 1186|       |          // work. But also, call ordering is completely irrelevant with these so there's no need
 1187|       |          // to disembargo anyway.
 1188|      0|          resolutionType = BROKEN;
 1189|      0|        } else {
 1190|      0|          resolutionType = REFLECTED;
 1191|      0|        }
 1192|      0|      }
 1193|       |
 1194|       |      // Every branch above ends by setting resolutionType to something other than UNRESOLVED.
 1195|      1|      KJ_DASSERT(isResolved());
  ------------------
  |  Branch (1195:7): [Folded, False: 1]
  ------------------
 1196|       |
 1197|       |      // If the original capability was used for streaming calls, it will have a
 1198|       |      // `flowController` that might still be shepherding those calls. We'll need make sure that
 1199|       |      // it doesn't get thrown away. Note that we know that *cap is an RpcClient because resolve()
 1200|       |      // is only called once and our constructor required that the initial capability is an
 1201|       |      // RpcClient.
 1202|      1|      KJ_IF_MAYBE(f, kj::downcast<RpcClient>(*cap).flowController) {
  ------------------
  |  Branch (1202:7): [True: 0, False: 1]
  ------------------
 1203|      0|        if (isSameConnection) {
  ------------------
  |  Branch (1203:13): [True: 0, False: 0]
  ------------------
 1204|       |          // The new target is on the same connection. It would make a lot of sense to keep using
 1205|       |          // the same flow controller if possible.
 1206|      0|          kj::downcast<RpcClient>(*replacement).adoptFlowController(kj::mv(*f));
 1207|      0|        } else {
 1208|       |          // The new target is something else. The best we can do is wait for the controller to
 1209|       |          // drain. New calls will be flow-controlled in a new way without knowing about the old
 1210|       |          // controller.
 1211|      0|          connectionState->tasks.add(f->get()->waitAllAcked().attach(kj::mv(*f)));
 1212|      0|        }
 1213|      0|      }
 1214|       |
 1215|      1|      if (resolutionType == REFLECTED && receivedCall &&
  ------------------
  |  Branch (1215:11): [True: 0, False: 1]
  |  Branch (1215:42): [True: 0, False: 0]
  ------------------
 1216|      0|          connectionState->connection.is<Connected>()) {
  ------------------
  |  Branch (1216:11): [True: 0, False: 0]
  ------------------
 1217|       |        // The new capability is hosted locally, not on the remote machine.  And, we had made calls
 1218|       |        // to the promise.  We need to make sure those calls echo back to us before we allow new
 1219|       |        // calls to go directly to the local capability, so we need to set a local embargo and send
 1220|       |        // a `Disembargo` to echo through the peer.
 1221|       |
 1222|      0|        auto message = connectionState->connection.get<Connected>()->newOutgoingMessage(
 1223|      0|            messageSizeHint<rpc::Disembargo>() + MESSAGE_TARGET_SIZE_HINT);
 1224|       |
 1225|      0|        auto disembargo = message->getBody().initAs<rpc::Message>().initDisembargo();
 1226|       |
 1227|      0|        {
 1228|      0|          auto redirect = connectionState->writeTarget(*cap, disembargo.initTarget());
 1229|      0|          KJ_ASSERT(redirect == nullptr,
  ------------------
  |  Branch (1229:11): [True: 0, False: 0]
  ------------------
 1230|      0|                    "Original promise target should always be from this RPC connection.");
 1231|      0|        }
 1232|       |
 1233|      0|        EmbargoId embargoId;
 1234|      0|        Embargo& embargo = connectionState->embargoes.next(embargoId);
 1235|       |
 1236|      0|        disembargo.getContext().setSenderLoopback(embargoId);
 1237|       |
 1238|      0|        auto paf = kj::newPromiseAndFulfiller<void>();
 1239|      0|        embargo.fulfiller = kj::mv(paf.fulfiller);
 1240|       |
 1241|       |        // Make a promise which resolves to `replacement` as soon as the `Disembargo` comes back.
 1242|      0|        auto embargoPromise = paf.promise.then([replacement = kj::mv(replacement)]() mutable {
 1243|      0|          return kj::mv(replacement);
 1244|      0|        });
 1245|       |
 1246|       |        // We need to queue up calls in the meantime, so we'll resolve ourselves to a local promise
 1247|       |        // client instead.
 1248|      0|        replacement = newLocalPromiseClient(kj::mv(embargoPromise));
 1249|       |
 1250|       |        // Send the `Disembargo`.
 1251|      0|        message->send();
 1252|      0|      }
 1253|       |
 1254|      1|      cap = replacement->addRef();
 1255|       |
 1256|      1|      return kj::mv(replacement);
 1257|      1|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState13PromiseClientD2Ev:
 1015|      1|    ~PromiseClient() noexcept(false) {
 1016|      1|      KJ_IF_MAYBE(id, importId) {
  ------------------
  |  Branch (1016:7): [True: 0, False: 1]
  ------------------
 1017|       |        // This object is representing an import promise.  That means the import table may still
 1018|       |        // contain a pointer back to it.  Remove that pointer.  Note that we have to verify that
 1019|       |        // the import still exists and the pointer still points back to this object because this
 1020|       |        // object may actually outlive the import.
 1021|      0|        KJ_IF_MAYBE(import, connectionState->imports.find(*id)) {
  ------------------
  |  Branch (1021:9): [True: 0, False: 0]
  ------------------
 1022|      0|          KJ_IF_MAYBE(c, import->appClient) {
  ------------------
  |  Branch (1022:11): [True: 0, False: 0]
  ------------------
 1023|      0|            if (c == this) {
  ------------------
  |  Branch (1023:17): [True: 0, False: 0]
  ------------------
 1024|      0|              import->appClient = nullptr;
 1025|      0|            }
 1026|      0|          }
 1027|      0|        }
 1028|      0|      }
 1029|      1|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ImportTableIjNS1_18RpcConnectionState6ImportEE4findEj:
  301|      1|  kj::Maybe<T&> find(Id id) {
  302|      1|    if (id < kj::size(low)) {
  ------------------
  |  Branch (302:9): [True: 1, False: 0]
  ------------------
  303|      1|      return low[id];
  304|      1|    } else {
  305|      0|      auto iter = high.find(id);
  306|      0|      if (iter == high.end()) {
  ------------------
  |  Branch (306:11): [True: 0, False: 0]
  ------------------
  307|      0|        return nullptr;
  308|      0|      } else {
  309|      0|        return iter->second;
  310|      0|      }
  311|      0|    }
  312|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState12ImportClient16whenMoreResolvedEv:
  922|      1|    kj::Maybe<kj::Promise<kj::Own<ClientHook>>> whenMoreResolved() override {
  923|      1|      return nullptr;
  924|      1|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState9RpcClient6addRefEv:
  845|      2|    kj::Own<ClientHook> addRef() override {
  846|      2|      return kj::addRef(*this);
  847|      2|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState9RpcClient8getBrandEv:
  848|      1|    const void* getBrand() override {
  849|      1|      return connectionState.get();
  850|      1|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState12ImportClientD2Ev:
  866|      1|    ~ImportClient() noexcept(false) {
  867|      1|      unwindDetector.catchExceptionsIfUnwinding([&]() {
  868|       |        // Remove self from the import table, if the table is still pointing at us.
  869|      1|        KJ_IF_MAYBE(import, connectionState->imports.find(importId)) {
  870|      1|          KJ_IF_MAYBE(i, import->importClient) {
  871|      1|            if (i == this) {
  872|      1|              connectionState->imports.erase(importId);
  873|      1|            }
  874|      1|          }
  875|      1|        }
  876|       |
  877|       |        // Send a message releasing our remote references.
  878|      1|        if (remoteRefcount > 0 && connectionState->connection.is<Connected>()) {
  879|      1|          auto message = connectionState->connection.get<Connected>()->newOutgoingMessage(
  880|      1|              messageSizeHint<rpc::Release>());
  881|      1|          rpc::Release::Builder builder = message->getBody().initAs<rpc::Message>().initRelease();
  882|      1|          builder.setId(importId);
  883|      1|          builder.setReferenceCount(remoteRefcount);
  884|      1|          message->send();
  885|      1|        }
  886|      1|      });
  887|      1|    }
rpc.c++:_ZZN5capnp1_12_GLOBAL__N_118RpcConnectionState12ImportClientD1EvENKUlvE_clEv:
  867|      1|      unwindDetector.catchExceptionsIfUnwinding([&]() {
  868|       |        // Remove self from the import table, if the table is still pointing at us.
  869|      1|        KJ_IF_MAYBE(import, connectionState->imports.find(importId)) {
  ------------------
  |  Branch (869:9): [True: 1, False: 0]
  ------------------
  870|      1|          KJ_IF_MAYBE(i, import->importClient) {
  ------------------
  |  Branch (870:11): [True: 1, False: 0]
  ------------------
  871|      1|            if (i == this) {
  ------------------
  |  Branch (871:17): [True: 1, False: 0]
  ------------------
  872|      1|              connectionState->imports.erase(importId);
  873|      1|            }
  874|      1|          }
  875|      1|        }
  876|       |
  877|       |        // Send a message releasing our remote references.
  878|      1|        if (remoteRefcount > 0 && connectionState->connection.is<Connected>()) {
  ------------------
  |  Branch (878:13): [True: 1, False: 0]
  |  Branch (878:35): [True: 1, False: 0]
  ------------------
  879|      1|          auto message = connectionState->connection.get<Connected>()->newOutgoingMessage(
  880|      1|              messageSizeHint<rpc::Release>());
  881|      1|          rpc::Release::Builder builder = message->getBody().initAs<rpc::Message>().initRelease();
  882|      1|          builder.setId(importId);
  883|      1|          builder.setReferenceCount(remoteRefcount);
  884|      1|          message->send();
  885|      1|        }
  886|      1|      });
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ImportTableIjNS1_18RpcConnectionState6ImportEE5eraseEj:
  314|      1|  T erase(Id id) {
  315|       |    // Remove an entry from the table and return it.  We return it so that the caller can be
  316|       |    // careful to release it (possibly invoking arbitrary destructors) at a time that makes sense.
  317|      1|    if (id < kj::size(low)) {
  ------------------
  |  Branch (317:9): [True: 1, False: 0]
  ------------------
  318|      1|      T toRelease = kj::mv(low[id]);
  319|      1|      low[id] = T();
  320|      1|      return toRelease;
  321|      1|    } else {
  322|      0|      T toRelease = kj::mv(high[id]);
  323|      0|      high.erase(id);
  324|      0|      return toRelease;
  325|      0|    }
  326|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState6ImportC2EOS3_:
  655|      1|    Import(Import&&) = default;
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState6ImportaSEOS3_:
  656|      1|    Import& operator=(Import&&) = default;
rpc.c++:_ZN5capnp1_12_GLOBAL__N_115messageSizeHintINS_3rpc7ReleaseEEEjv:
   43|      1|inline constexpr uint messageSizeHint() {
   44|      1|  return 1 + sizeInWords<rpc::Message>() + sizeInWords<T>();
   45|      1|}
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState12ImportClient12addRemoteRefEv:
  895|      1|    void addRemoteRef() {
  896|       |      // Add a new RemoteRef and return a new ref to this client representing it.
  897|      1|      ++remoteRefcount;
  898|      1|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ImportTableIjNS1_18RpcConnectionState6AnswerEE5eraseEj:
  314|      1|  T erase(Id id) {
  315|       |    // Remove an entry from the table and return it.  We return it so that the caller can be
  316|       |    // careful to release it (possibly invoking arbitrary destructors) at a time that makes sense.
  317|      1|    if (id < kj::size(low)) {
  ------------------
  |  Branch (317:9): [True: 1, False: 0]
  ------------------
  318|      1|      T toRelease = kj::mv(low[id]);
  319|      1|      low[id] = T();
  320|      1|      return toRelease;
  321|      1|    } else {
  322|      0|      T toRelease = kj::mv(high[id]);
  323|      0|      high.erase(id);
  324|      0|      return toRelease;
  325|      0|    }
  326|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState6AnswerC2EOS3_:
  604|      1|    Answer(Answer&&) = default;
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState6AnsweraSEOS3_:
  605|      2|    Answer& operator=(Answer&&) = default;
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState12handleReturnEON2kj3OwnINS_18IncomingRpcMessageEDnEERKNS_3rpc6Return6ReaderE:
 3151|      1|  void handleReturn(kj::Own<IncomingRpcMessage>&& message, const rpc::Return::Reader& ret) {
 3152|       |    // Transitive destructors can end up manipulating the question table and invalidating our
 3153|       |    // pointer into it, so make sure these destructors run later.
 3154|      1|    kj::Array<ExportId> exportsToRelease;
 3155|      1|    KJ_DEFER(releaseExports(exportsToRelease));
 3156|      1|    kj::Maybe<decltype(Answer::task)> promiseToRelease;
 3157|       |
 3158|      1|    QuestionId questionId = ret.getAnswerId();
 3159|      1|    if (questions.isHigh(questionId)) {
  ------------------
  |  Branch (3159:9): [True: 0, False: 1]
  ------------------
 3160|       |      // We sent hints with this question saying we didn't want a `Return` but we got one anyway.
 3161|       |      // We cannot even look up the question on the question table because it's (remotely) possible
 3162|       |      // that we already removed it and re-allocated the ID to something else. So, we should ignore
 3163|       |      // the `Return`. But we might want to make note to stop using these hints, to protect against
 3164|       |      // the (again, remote) possibility of our ID space wrapping around and leading to confusion.
 3165|      0|      if (ret.getReleaseParamCaps() && sentCapabilitiesInPipelineOnlyCall) {
  ------------------
  |  Branch (3165:11): [True: 0, False: 0]
  |  Branch (3165:40): [True: 0, False: 0]
  ------------------
 3166|       |        // Oh no, it appears the peer wants us to release any capabilities in the params, something
 3167|       |        // which only a level 0 peer would request (no version of the C++ RPC system has ever done
 3168|       |        // this). And it appears we did send capabilities in at least one pipeline-only call
 3169|       |        // previously. But we have no record of which capabilities were sent in *this* call, so
 3170|       |        // we cannot release them. Log an error about the leak.
 3171|       |        //
 3172|       |        // This scenario is unlikely to happen in practice, because sendForPipeline() is not useful
 3173|       |        // when talking to a peer that doesn't support capability-passing -- they couldn't possibly
 3174|       |        // return a capability to pipeline on! So, I'm not going to spend time to find a solution
 3175|       |        // for this corner case. We will log an error, though, just in case someone hits this
 3176|       |        // somehow.
 3177|      0|        KJ_LOG(ERROR,
  ------------------
  |  Branch (3177:9): [True: 0, False: 0]
  ------------------
 3178|      0|            "sendForPipeline() was used when sending an RPC to a peer, the parameters of that "
 3179|      0|            "RPC included capabilities, but the peer seems to implement Cap'n Proto at level 0, "
 3180|      0|            "meaning it does not support capability passing (or, at least, it sent a `Return` "
 3181|      0|            "with `releaseParamCaps = true`). The capabilities that were sent may have been "
 3182|      0|            "leaked (they won't be dropped until the connection closes).");
 3183|       |
 3184|      0|        sentCapabilitiesInPipelineOnlyCall = false;  // don't log again
 3185|      0|      }
 3186|      0|      gotReturnForHighQuestionId = true;
 3187|      0|      return;
 3188|      0|    }
 3189|       |
 3190|      1|    KJ_IF_MAYBE(question, questions.find(questionId)) {
  ------------------
  |  Branch (3190:5): [True: 1, False: 0]
  ------------------
 3191|      1|      KJ_REQUIRE(question->isAwaitingReturn, "Duplicate Return.") { return; }
  ------------------
  |  Branch (3191:7): [True: 1, False: 0]
  ------------------
 3192|      1|      question->isAwaitingReturn = false;
 3193|       |
 3194|      1|      if (ret.getReleaseParamCaps()) {
  ------------------
  |  Branch (3194:11): [True: 1, False: 0]
  ------------------
 3195|      1|        exportsToRelease = kj::mv(question->paramExports);
 3196|      1|      } else {
 3197|      0|        question->paramExports = nullptr;
 3198|      0|      }
 3199|       |
 3200|      1|      if (ret.getNoFinishNeeded()) {
  ------------------
  |  Branch (3200:11): [True: 0, False: 1]
  ------------------
 3201|      0|        question->skipFinish = true;
 3202|      0|      }
 3203|       |
 3204|      1|      KJ_IF_MAYBE(questionRef, question->selfRef) {
  ------------------
  |  Branch (3204:7): [True: 1, False: 0]
  ------------------
 3205|      1|        switch (ret.which()) {
 3206|      1|          case rpc::Return::RESULTS: {
  ------------------
  |  Branch (3206:11): [True: 1, False: 0]
  ------------------
 3207|      1|            KJ_REQUIRE(!question->isTailCall,
  ------------------
  |  Branch (3207:13): [True: 1, False: 0]
  ------------------
 3208|      0|                "Tail call `Return` must set `resultsSentElsewhere`, not `results`.") {
 3209|      0|              return;
 3210|      0|            }
 3211|       |
 3212|      1|            auto payload = ret.getResults();
 3213|      1|            auto capTableArray = receiveCaps(payload.getCapTable(), message->getAttachedFds());
 3214|      1|            questionRef->fulfill(kj::refcounted<RpcResponseImpl>(
 3215|      1|                *this, kj::addRef(*questionRef), kj::mv(message),
 3216|      1|                kj::mv(capTableArray), payload.getContent()));
 3217|      1|            break;
 3218|      1|          }
 3219|       |
 3220|      0|          case rpc::Return::EXCEPTION:
  ------------------
  |  Branch (3220:11): [True: 0, False: 1]
  ------------------
 3221|      0|            KJ_REQUIRE(!question->isTailCall,
  ------------------
  |  Branch (3221:13): [True: 0, False: 0]
  ------------------
 3222|      0|                "Tail call `Return` must set `resultsSentElsewhere`, not `exception`.") {
 3223|      0|              return;
 3224|      0|            }
 3225|       |
 3226|      0|            questionRef->reject(toException(ret.getException()));
 3227|      0|            break;
 3228|       |
 3229|      0|          case rpc::Return::CANCELED:
  ------------------
  |  Branch (3229:11): [True: 0, False: 1]
  ------------------
 3230|      0|            KJ_FAIL_REQUIRE("Return message falsely claims call was canceled.") { return; }
 3231|      0|            break;
 3232|       |
 3233|      0|          case rpc::Return::RESULTS_SENT_ELSEWHERE:
  ------------------
  |  Branch (3233:11): [True: 0, False: 1]
  ------------------
 3234|      0|            KJ_REQUIRE(question->isTailCall,
  ------------------
  |  Branch (3234:13): [True: 0, False: 0]
  ------------------
 3235|      0|                "`Return` had `resultsSentElsewhere` but this was not a tail call.") {
 3236|      0|              return;
 3237|      0|            }
 3238|       |
 3239|       |            // Tail calls are fulfilled with a null pointer.
 3240|      0|            questionRef->fulfill(kj::Own<RpcResponse>());
 3241|      0|            break;
 3242|       |
 3243|      0|          case rpc::Return::TAKE_FROM_OTHER_QUESTION:
  ------------------
  |  Branch (3243:11): [True: 0, False: 1]
  ------------------
 3244|      0|            KJ_IF_MAYBE(answer, answers.find(ret.getTakeFromOtherQuestion())) {
  ------------------
  |  Branch (3244:13): [True: 0, False: 0]
  ------------------
 3245|      0|              KJ_IF_MAYBE(response, answer->task.tryGet<Answer::Redirected>()) {
  ------------------
  |  Branch (3245:15): [True: 0, False: 0]
  ------------------
 3246|      0|                questionRef->fulfill(kj::mv(*response));
 3247|      0|                answer->task = Answer::Finished();
 3248|       |
 3249|      0|                KJ_IF_MAYBE(context, answer->callContext) {
  ------------------
  |  Branch (3249:17): [True: 0, False: 0]
  ------------------
 3250|       |                  // Send the `Return` message  for the call of which we're taking ownership, so
 3251|       |                  // that the peer knows it can now tear down the call state.
 3252|      0|                  context->sendRedirectReturn();
 3253|      0|                }
 3254|      0|              } else {
 3255|      0|                KJ_FAIL_REQUIRE("`Return.takeFromOtherQuestion` referenced a call that did not "
 3256|      0|                                "use `sendResultsTo.yourself`.") { return; }
 3257|      0|              }
 3258|      0|            } else {
 3259|      0|              KJ_FAIL_REQUIRE("`Return.takeFromOtherQuestion` had invalid answer ID.") { return; }
 3260|      0|            }
 3261|       |
 3262|      0|            break;
 3263|       |
 3264|      0|          default:
  ------------------
  |  Branch (3264:11): [True: 0, False: 1]
  ------------------
 3265|      0|            KJ_FAIL_REQUIRE("Unknown 'Return' type.") { return; }
 3266|      1|        }
 3267|      1|      } else {
 3268|       |        // This is a response to a question that we canceled earlier.
 3269|       |
 3270|      0|        if (ret.isTakeFromOtherQuestion()) {
  ------------------
  |  Branch (3270:13): [True: 0, False: 0]
  ------------------
 3271|       |          // This turned out to be a tail call back to us! We now take ownership of the tail call.
 3272|       |          // Since the caller canceled, we need to cancel out the tail call, if it still exists.
 3273|       |
 3274|      0|          KJ_IF_MAYBE(answer, answers.find(ret.getTakeFromOtherQuestion())) {
  ------------------
  |  Branch (3274:11): [True: 0, False: 0]
  ------------------
 3275|       |            // Indeed, it does still exist.
 3276|       |
 3277|       |            // Throw away the result promise.
 3278|      0|            promiseToRelease = kj::mv(answer->task);
 3279|       |
 3280|      0|            KJ_IF_MAYBE(context, answer->callContext) {
  ------------------
  |  Branch (3280:13): [True: 0, False: 0]
  ------------------
 3281|       |              // Send the `Return` message  for the call of which we're taking ownership, so
 3282|       |              // that the peer knows it can now tear down the call state.
 3283|      0|              context->sendRedirectReturn();
 3284|      0|            }
 3285|      0|          }
 3286|      0|        }
 3287|       |
 3288|       |        // Looks like this question was canceled earlier, so `Finish` was already sent, with
 3289|       |        // `releaseResultCaps` set true so that we don't have to release them here.  We can go
 3290|       |        // ahead and delete it from the table.
 3291|      0|        questions.erase(ret.getAnswerId(), *question);
 3292|      0|      }
 3293|       |
 3294|      1|    } else {
 3295|      0|      KJ_FAIL_REQUIRE("Invalid question ID in Return message.") { return; }
 3296|      0|    }
 3297|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState11QuestionRef7fulfillEON2kj3OwnINS2_11RpcResponseEDnEE:
 1718|      1|    void fulfill(kj::Own<RpcResponse>&& response) {
 1719|      1|      KJ_IF_MAYBE(f, fulfiller) {
  ------------------
  |  Branch (1719:7): [True: 1, False: 0]
  ------------------
 1720|      1|        f->get()->fulfill(kj::mv(response));
 1721|      1|      }
 1722|      1|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState15RpcResponseImplC2ERS2_ON2kj3OwnINS2_11QuestionRefEDnEEONS6_INS_18IncomingRpcMessageEDnEENS5_5ArrayINS5_5MaybeINS6_INS_10ClientHookEDnEEEEEENS_10AnyPointer6ReaderE:
 2185|      1|        : connectionState(kj::addRef(connectionState)),
 2186|      1|          message(kj::mv(message)),
 2187|      1|          capTable(kj::mv(capTableArray)),
 2188|      1|          reader(capTable.imbue(results)),
 2189|      1|          questionRef(kj::mv(questionRef)) {}
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState15RpcResponseImpl10getResultsEv:
 2191|      1|    AnyPointer::Reader getResults() override {
 2192|      1|      return reader;
 2193|      1|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState15RpcResponseImpl6addRefEv:
 2195|      1|    kj::Own<RpcResponse> addRef() override {
 2196|      1|      return kj::addRef(*this);
 2197|      1|    }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState12handleFinishERKNS_3rpc6Finish6ReaderE:
 3299|      1|  void handleFinish(const rpc::Finish::Reader& finish) {
 3300|       |    // Delay release of these things until return so that transitive destructors don't accidentally
 3301|       |    // modify the answer table and invalidate our pointer into it.
 3302|      1|    kj::Array<ExportId> exportsToRelease;
 3303|      1|    KJ_DEFER(releaseExports(exportsToRelease));
 3304|      1|    Answer answerToRelease;
 3305|      1|    kj::Maybe<kj::Own<PipelineHook>> pipelineToRelease;
 3306|      1|    kj::Maybe<decltype(Answer::task)> promiseToRelease;
 3307|       |
 3308|      1|    KJ_IF_MAYBE(answer, answers.find(finish.getQuestionId())) {
  ------------------
  |  Branch (3308:5): [True: 1, False: 0]
  ------------------
 3309|      1|      if (!answer->active) {
  ------------------
  |  Branch (3309:11): [True: 0, False: 1]
  ------------------
 3310|       |        // Treat the same as if the answer wasn't in the table; see comment below.
 3311|      0|        return;
 3312|      0|      }
 3313|       |
 3314|      1|      if (finish.getReleaseResultCaps()) {
  ------------------
  |  Branch (3314:11): [True: 0, False: 1]
  ------------------
 3315|      0|        exportsToRelease = kj::mv(answer->resultExports);
 3316|      1|      } else {
 3317|      1|        answer->resultExports = nullptr;
 3318|      1|      }
 3319|       |
 3320|      1|      pipelineToRelease = kj::mv(answer->pipeline);
 3321|       |
 3322|      1|      KJ_IF_MAYBE(context, answer->callContext) {
  ------------------
  |  Branch (3322:7): [True: 0, False: 1]
  ------------------
 3323|       |        // Destroying answer->task will probably destroy the call context, but we can't prove that
 3324|       |        // since it's refcounted. Instead, inform the call context that it is now its job to
 3325|       |        // clean up the answer table. Then, cancel the task.
 3326|      0|        promiseToRelease = kj::mv(answer->task);
 3327|      0|        answer->task = Answer::Finished();
 3328|      0|        context->finish();
 3329|      1|      } else {
 3330|       |        // The call context is already gone so we can tear down the Answer here.
 3331|      1|        answerToRelease = answers.erase(finish.getQuestionId());
 3332|      1|      }
 3333|      1|    } else {
 3334|       |      // The `Finish` message targets a qusetion ID that isn't present in our answer table.
 3335|       |      // Probably, we send a `Return` with `noFinishNeeded = true`, but the other side didn't
 3336|       |      // recognize this hint and sent a `Finish` anyway, or the `Finish` was already in-flight at
 3337|       |      // the time we sent the `Return`. We can silently ignore this.
 3338|       |      //
 3339|       |      // It would be nice to detect invalid finishes somehow, but to do so we would have to
 3340|       |      // remember past answer IDs somewhere even when we said `noFinishNeeded`. Assuming the other
 3341|       |      // side respects the hint and doesn't send a `Finish`, we'd only be able to clean up these
 3342|       |      // records when the other end reuses the question ID, which might never happen.
 3343|      0|    }
 3344|       |
 3345|      1|    if (finish.getRequireEarlyCancellationWorkaround()) {
  ------------------
  |  Branch (3345:9): [True: 0, False: 1]
  ------------------
 3346|       |      // Defer actual cancellation of the call until the end of the event loop queue.
 3347|       |      //
 3348|       |      // This is needed for compatibility with older versions of Cap'n Proto (0.10 and prior) in
 3349|       |      // which the default was to prohibit cancellation until it was explicitly allowed. In newer
 3350|       |      // versions (1.0 and later) cancellation is allowed until explicitly prohibited, that is, if
 3351|       |      // we haven't actually delivered the call yet, it can be canceled. This requires less
 3352|       |      // bookkeeping and so improved performance.
 3353|       |      //
 3354|       |      // However, old clients might be inadvertently relying on the old behavior. For example, if
 3355|       |      // someone using and old version called `.send()` on a message and then promptly dropped the
 3356|       |      // returned Promise, the message would often be delivered. This was not intended to work, but
 3357|       |      // did, and could be relied upon by accident. Moreover, the original implementation of
 3358|       |      // streaming included a bug where streaming calls *always* sent an immediate Finish.
 3359|       |      //
 3360|       |      // By deferring cancellation until after a turn of the event loop, we provide an opportunity
 3361|       |      // for any `Call` messages we've received to actually be delivered, so that they can opt out
 3362|       |      // of cancellation if desired.
 3363|      0|      KJ_IF_MAYBE(task, promiseToRelease) {
  ------------------
  |  Branch (3363:7): [True: 0, False: 0]
  ------------------
 3364|      0|        KJ_IF_MAYBE(running, task->tryGet<Answer::Running>()) {
  ------------------
  |  Branch (3364:9): [True: 0, False: 0]
  ------------------
 3365|      0|          tasks.add(kj::evalLast([running = kj::mv(*running)]() {
 3366|       |            // Just drop `running` here to cancel the call.
 3367|      0|          }));
 3368|      0|        }
 3369|      0|      }
 3370|      0|    }
 3371|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_115messageSizeHintIvEEjv:
   47|      2|inline constexpr uint messageSizeHint<void>() {
   48|      2|  return 1 + sizeInWords<rpc::Message>();
   49|      2|}
rpc.c++:_ZZN5capnp1_12_GLOBAL__N_118RpcConnectionState11messageLoopEvENKUlbE_clEb:
 2796|      4|    }).then([this](bool keepGoing) {
 2797|       |      // No exceptions; continue loop.
 2798|       |      //
 2799|       |      // (We do this in a separate continuation to handle the case where exceptions are
 2800|       |      // disabled.)
 2801|       |      //
 2802|       |      // TODO(perf): We add an evalLater() here so that anything we needed to do in reaction to
 2803|       |      //   the previous message has a chance to complete before the next message is handled. In
 2804|       |      //   particular, without this, I observed an ordering problem: I saw a case where a `Return`
 2805|       |      //   message was followed by a `Resolve` message, but the `PromiseClient` associated with the
 2806|       |      //   `Resolve` had its `resolve()` method invoked _before_ any `PromiseClient`s associated
 2807|       |      //   with pipelined capabilities resolved by the `Return`. This could lead to an
 2808|       |      //   incorrectly-ordered interaction between `PromiseClient`s when they resolve to each
 2809|       |      //   other. This is probably really a bug in the way `Return`s are handled -- apparently,
 2810|       |      //   resolution of `PromiseClient`s based on returned capabilities does not occur in a
 2811|       |      //   depth-first way, when it should. If we could fix that then we can probably remove this
 2812|       |      //   `evalLater()`. However, the `evalLater()` is not that bad and solves the problem...
 2813|      4|      if (keepGoing) tasks.add(kj::evalLater([this]() { return messageLoop(); }));
  ------------------
  |  Branch (2813:11): [True: 3, False: 1]
  ------------------
 2814|      4|    });
rpc.c++:_ZZZN5capnp1_12_GLOBAL__N_118RpcConnectionState11messageLoopEvENKUlbE_clEbENKUlvE_clEv:
 2813|      3|      if (keepGoing) tasks.add(kj::evalLater([this]() { return messageLoop(); }));
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState10taskFailedEON2kj9ExceptionE:
  398|      1|  void taskFailed(kj::Exception&& exception) override {
  399|      1|    disconnect(kj::mv(exception));
  400|      1|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_118RpcConnectionState10disconnectEON2kj9ExceptionE:
  402|      2|  void disconnect(kj::Exception&& exception) {
  403|       |    // Shut down the connection with the given error.
  404|       |    //
  405|       |    // This will cancel `tasks`, so cannot be called from inside a task in `tasks`. Instead, use
  406|       |    // `tasks.add(exception)` to schedule a shutdown, since any error thrown by a task will be
  407|       |    // passed to `disconnect()` later.
  408|       |
  409|       |    // After disconnect(), the RpcSystem could be destroyed, making `traceEncoder` a dangling
  410|       |    // reference, so null it out before we return from here. We don't need it anymore once
  411|       |    // disconnected anyway.
  412|      2|    KJ_DEFER(traceEncoder = nullptr);
  413|       |
  414|      2|    if (!connection.is<Connected>()) {
  ------------------
  |  Branch (414:9): [True: 0, False: 2]
  ------------------
  415|       |      // Already disconnected.
  416|      0|      return;
  417|      0|    }
  418|       |
  419|      2|    kj::Exception networkException(kj::Exception::Type::DISCONNECTED,
  420|      2|        exception.getFile(), exception.getLine(), kj::heapString(exception.getDescription()));
  421|       |
  422|       |    // Don't throw away the stack trace.
  423|      2|    if (exception.getRemoteTrace() != nullptr) {
  ------------------
  |  Branch (423:9): [True: 0, False: 2]
  ------------------
  424|      0|      networkException.setRemoteTrace(kj::str(exception.getRemoteTrace()));
  425|      0|    }
  426|      2|    for (void* addr: exception.getStackTrace()) {
  ------------------
  |  Branch (426:20): [True: 0, False: 2]
  ------------------
  427|      0|      networkException.addTrace(addr);
  428|      0|    }
  429|       |    // If your stack trace points here, it means that the exception became the reason that the
  430|       |    // RPC connection was disconnected. The exception was then thrown by all in-flight calls and
  431|       |    // all future calls on this connection.
  432|      2|    networkException.addTraceHere();
  433|       |
  434|       |    // Set our connection state to Disconnected now so that no one tries to write any messages to
  435|       |    // it in their destructors.
  436|      2|    auto dyingConnection = kj::mv(connection.get<Connected>());
  437|      2|    connection.init<Disconnected>(kj::cp(networkException));
  438|       |
  439|      2|    KJ_IF_MAYBE(newException, kj::runCatchingExceptions([&]() {
  ------------------
  |  Branch (439:5): [True: 0, False: 2]
  ------------------
  440|       |      // Carefully pull all the objects out of the tables prior to releasing them because their
  441|       |      // destructors could come back and mess with the tables.
  442|      2|      kj::Vector<kj::Own<PipelineHook>> pipelinesToRelease;
  443|      2|      kj::Vector<kj::Own<ClientHook>> clientsToRelease;
  444|      2|      kj::Vector<decltype(Answer::task)> tasksToRelease;
  445|      2|      kj::Vector<kj::Promise<void>> resolveOpsToRelease;
  446|      2|      KJ_DEFER(tasks.clear());
  447|       |
  448|       |      // All current questions complete with exceptions.
  449|      2|      questions.forEach([&](QuestionId id, Question& question) {
  450|      2|        KJ_IF_MAYBE(questionRef, question.selfRef) {
  451|       |          // QuestionRef still present.
  452|      2|          questionRef->reject(kj::cp(networkException));
  453|       |
  454|       |          // We need to fully disconnect each QuestionRef otherwise it holds a reference back to
  455|       |          // the connection state. Meanwhile `tasks` may hold streaming calls that end up holding
  456|       |          // these QuestionRefs. Technically this is a cyclic reference, but as long as the cycle
  457|       |          // is broken on disconnect (which happens when the RpcSystem itself is destroyed), then
  458|       |          // we're OK.
  459|      2|          questionRef->disconnect();
  460|      2|        }
  461|      2|      });
  462|       |      // Since we've disconnected the QuestionRefs, they won't clean up the questions table for
  463|       |      // us, so do that here.
  464|      2|      questions.release();
  465|       |
  466|      2|      answers.forEach([&](AnswerId id, Answer& answer) {
  467|      2|        KJ_IF_MAYBE(p, answer.pipeline) {
  468|      2|          pipelinesToRelease.add(kj::mv(*p));
  469|      2|        }
  470|       |
  471|      2|        tasksToRelease.add(kj::mv(answer.task));
  472|       |
  473|      2|        KJ_IF_MAYBE(context, answer.callContext) {
  474|      2|          context->finish();
  475|      2|        }
  476|      2|      });
  477|       |
  478|      2|      exports.forEach([&](ExportId id, Export& exp) {
  479|      2|        clientsToRelease.add(kj::mv(exp.clientHook));
  480|      2|        KJ_IF_MAYBE(op, exp.resolveOp) {
  481|      2|          resolveOpsToRelease.add(kj::mv(*op));
  482|      2|        }
  483|      2|        exp = Export();
  484|      2|      });
  485|       |
  486|      2|      imports.forEach([&](ImportId id, Import& import) {
  487|      2|        KJ_IF_MAYBE(f, import.promiseFulfiller) {
  488|      2|          f->get()->reject(kj::cp(networkException));
  489|      2|        }
  490|      2|      });
  491|       |
  492|      2|      embargoes.forEach([&](EmbargoId id, Embargo& embargo) {
  493|      2|        KJ_IF_MAYBE(f, embargo.fulfiller) {
  494|      2|          f->get()->reject(kj::cp(networkException));
  495|      2|        }
  496|      2|      });
  497|      2|    })) {
  498|       |      // Some destructor must have thrown an exception.  There is no appropriate place to report
  499|       |      // these errors.
  500|      0|      KJ_LOG(ERROR, "Uncaught exception when destroying capabilities dropped by disconnect.",
  ------------------
  |  Branch (500:7): [True: 0, False: 0]
  ------------------
  501|      0|             *newException);
  502|      0|    }
  503|       |
  504|       |    // Send an abort message, but ignore failure.
  505|      2|    kj::runCatchingExceptions([&]() {
  506|      2|      auto message = dyingConnection->newOutgoingMessage(
  507|      2|          messageSizeHint<void>() + exceptionSizeHint(exception));
  508|      2|      fromException(exception, message->getBody().getAs<rpc::Message>().initAbort());
  509|      2|      message->send();
  510|      2|    });
  511|       |
  512|       |    // Indicate disconnect.
  513|      2|    auto shutdownPromise = dyingConnection->shutdown()
  514|      2|        .attach(kj::mv(dyingConnection))
  515|      2|        .then([]() -> kj::Promise<void> { return kj::READY_NOW; },
  516|      2|              [self = kj::addRef(*this), origException = kj::mv(exception)](
  517|      2|                  kj::Exception&& shutdownException) -> kj::Promise<void> {
  518|       |          // Don't report disconnects as an error.
  519|      2|          if (shutdownException.getType() == kj::Exception::Type::DISCONNECTED) {
  520|      2|            return kj::READY_NOW;
  521|      2|          }
  522|       |          // If the error is just what was passed in to disconnect(), don't report it back out
  523|       |          // since it shouldn't be anything the caller doesn't already know about.
  524|      2|          if (shutdownException.getType() == origException.getType() &&
  525|      2|              shutdownException.getDescription() == origException.getDescription()) {
  526|      2|            return kj::READY_NOW;
  527|      2|          }
  528|       |          // We are shutting down after receive error, ignore shutdown exception since underlying
  529|       |          // transport is probably broken.
  530|      2|          if (self->receiveIncomingMessageError) {
  531|      2|            return kj::READY_NOW;
  532|      2|          }
  533|      2|          return kj::mv(shutdownException);
  534|      2|        });
  535|      2|    disconnectFulfiller->fulfill(DisconnectInfo { kj::mv(shutdownPromise) });
  536|      2|    canceler.cancel(networkException);
  537|      2|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ExportTableIjNS1_18RpcConnectionState8QuestionEE7forEachIZZNS3_10disconnectEON2kj9ExceptionEENKUlvE0_clEvEUljRS4_E_EEvOT_:
  262|      2|  void forEach(Func&& func) {
  263|      3|    for (Id i = 0; i < slots.size(); i++) {
  ------------------
  |  Branch (263:20): [True: 1, False: 2]
  ------------------
  264|      1|      if (slots[i] != nullptr) {
  ------------------
  |  Branch (264:11): [True: 0, False: 1]
  ------------------
  265|      0|        func(i, slots[i]);
  266|      0|      }
  267|      1|    }
  268|      2|    for (auto& slot: highSlots) {
  ------------------
  |  Branch (268:20): [True: 0, False: 2]
  ------------------
  269|      0|      func(slot.key, slot.value);
  270|      0|    }
  271|      2|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ExportTableIjNS1_18RpcConnectionState8QuestionEE7releaseEv:
  273|      2|  void release() {
  274|       |    // Release memory backing the table.
  275|      2|    { auto drop = kj::mv(slots); }
  276|      2|    { auto drop = kj::mv(freeIds); }
  277|      2|    { auto drop = kj::mv(highSlots); }
  278|      2|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ImportTableIjNS1_18RpcConnectionState6AnswerEE7forEachIZZNS3_10disconnectEON2kj9ExceptionEENKUlvE0_clEvEUljRS4_E_EEvOT_:
  329|      2|  void forEach(Func&& func) {
  330|     32|    for (Id i: kj::indices(low)) {
  ------------------
  |  Branch (330:14): [True: 32, False: 2]
  ------------------
  331|     32|      func(i, low[i]);
  332|     32|    }
  333|      2|    for (auto& entry: high) {
  ------------------
  |  Branch (333:21): [True: 0, False: 2]
  ------------------
  334|      0|      func(entry.first, entry.second);
  335|      0|    }
  336|      2|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ExportTableIjNS1_18RpcConnectionState6ExportEE7forEachIZZNS3_10disconnectEON2kj9ExceptionEENKUlvE0_clEvEUljRS4_E_EEvOT_:
  262|      2|  void forEach(Func&& func) {
  263|      3|    for (Id i = 0; i < slots.size(); i++) {
  ------------------
  |  Branch (263:20): [True: 1, False: 2]
  ------------------
  264|      1|      if (slots[i] != nullptr) {
  ------------------
  |  Branch (264:11): [True: 1, False: 0]
  ------------------
  265|      1|        func(i, slots[i]);
  266|      1|      }
  267|      1|    }
  268|      2|    for (auto& slot: highSlots) {
  ------------------
  |  Branch (268:20): [True: 0, False: 2]
  ------------------
  269|      0|      func(slot.key, slot.value);
  270|      0|    }
  271|      2|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ImportTableIjNS1_18RpcConnectionState6ImportEE7forEachIZZNS3_10disconnectEON2kj9ExceptionEENKUlvE0_clEvEUljRS4_E_EEvOT_:
  329|      2|  void forEach(Func&& func) {
  330|     32|    for (Id i: kj::indices(low)) {
  ------------------
  |  Branch (330:14): [True: 32, False: 2]
  ------------------
  331|     32|      func(i, low[i]);
  332|     32|    }
  333|      2|    for (auto& entry: high) {
  ------------------
  |  Branch (333:21): [True: 0, False: 2]
  ------------------
  334|      0|      func(entry.first, entry.second);
  335|      0|    }
  336|      2|  }
rpc.c++:_ZN5capnp1_12_GLOBAL__N_111ExportTableIjNS1_18RpcConnectionState7EmbargoEE7forEachIZZNS3_10disconnectEON2kj9ExceptionEENKUlvE0_clEvEUljRS4_E_EEvOT_:
  262|      2|  void forEach(Func&& func) {
  263|      2|    for (Id i = 0; i < slots.size(); i++) {
  ------------------
  |  Branch (263:20): [True: 0, False: 2]
  ------------------
  264|      0|      if (slots[i] != nullptr) {
  ------------------
  |  Branch (264:11): [True: 0, False: 0]
  ------------------
  265|      0|        func(i, slots[i]);
  266|      0|      }
  267|      0|    }
  268|      2|    for (auto& slot: highSlots) {
  ------------------
  |  Branch (268:20): [True: 0, False: 2]
  ------------------
  269|      0|      func(slot.key, slot.value);
  270|      0|    }
  271|      2|  }
rpc.c++:_ZZN5capnp1_12_GLOBAL__N_118RpcConnectionState10disconnectEON2kj9ExceptionEENKUlvE1_clEv:
  505|      2|    kj::runCatchingExceptions([&]() {
  506|      2|      auto message = dyingConnection->newOutgoingMessage(
  507|      2|          messageSizeHint<void>() + exceptionSizeHint(exception));
  508|      2|      fromException(exception, message->getBody().getAs<rpc::Message>().initAbort());
  509|      2|      message->send();
  510|      2|    });
rpc.c++:_ZZN5capnp1_12_GLOBAL__N_118RpcConnectionState10disconnectEON2kj9ExceptionEENKUlS5_E_clES5_:
  517|      1|                  kj::Exception&& shutdownException) -> kj::Promise<void> {
  518|       |          // Don't report disconnects as an error.
  519|      1|          if (shutdownException.getType() == kj::Exception::Type::DISCONNECTED) {
  ------------------
  |  Branch (519:15): [True: 1, False: 0]
  ------------------
  520|      1|            return kj::READY_NOW;
  521|      1|          }
  522|       |          // If the error is just what was passed in to disconnect(), don't report it back out
  523|       |          // since it shouldn't be anything the caller doesn't already know about.
  524|      0|          if (shutdownException.getType() == origException.getType() &&
  ------------------
  |  Branch (524:15): [True: 0, False: 0]
  |  Branch (524:15): [True: 0, False: 0]
  ------------------
  525|      0|              shutdownException.getDescription() == origException.getDescription()) {
  ------------------
  |  Branch (525:15): [True: 0, False: 0]
  ------------------
  526|      0|            return kj::READY_NOW;
  527|      0|          }
  528|       |          // We are shutting down after receive error, ignore shutdown exception since underlying
  529|       |          // transport is probably broken.
  530|      0|          if (self->receiveIncomingMessageError) {
  ------------------
  |  Branch (530:15): [True: 0, False: 0]
  ------------------
  531|      0|            return kj::READY_NOW;
  532|      0|          }
  533|      0|          return kj::mv(shutdownException);
  534|      0|        });
_ZN5capnp1_13RpcSystemBase4ImplD2Ev:
 3565|      2|  ~Impl() noexcept(false) {
 3566|      2|    unwindDetector.catchExceptionsIfUnwinding([&]() {
 3567|       |      // std::unordered_map doesn't like it when elements' destructors throw, so carefully
 3568|       |      // disassemble it.
 3569|      2|      if (!connections.empty()) {
 3570|      2|        kj::Vector<kj::Own<RpcConnectionState>> deleteMe(connections.size());
 3571|      2|        kj::Exception shutdownException = KJ_EXCEPTION(DISCONNECTED, "RpcSystem was destroyed.");
 3572|      2|        for (auto& entry: connections) {
 3573|      2|          entry.second->disconnect(kj::cp(shutdownException));
 3574|      2|          deleteMe.add(kj::mv(entry.second));
 3575|      2|        }
 3576|      2|      }
 3577|      2|    });
 3578|      2|  }
_ZZN5capnp1_13RpcSystemBase4ImplD1EvENKUlvE_clEv:
 3566|      2|    unwindDetector.catchExceptionsIfUnwinding([&]() {
 3567|       |      // std::unordered_map doesn't like it when elements' destructors throw, so carefully
 3568|       |      // disassemble it.
 3569|      2|      if (!connections.empty()) {
  ------------------
  |  Branch (3569:11): [True: 1, False: 1]
  ------------------
 3570|      1|        kj::Vector<kj::Own<RpcConnectionState>> deleteMe(connections.size());
 3571|      1|        kj::Exception shutdownException = KJ_EXCEPTION(DISCONNECTED, "RpcSystem was destroyed.");
 3572|      1|        for (auto& entry: connections) {
  ------------------
  |  Branch (3572:25): [True: 1, False: 1]
  ------------------
 3573|      1|          entry.second->disconnect(kj::cp(shutdownException));
 3574|      1|          deleteMe.add(kj::mv(entry.second));
 3575|      1|        }
 3576|      1|      }
 3577|      2|    });
rpc.c++:_ZZN5capnp18IncomingRpcMessage21getShortLivedCallbackEvENK3$_0clERNS_13MessageReaderE:
 3866|      2|  return [](MessageReader& reader) {
 3867|      2|    return IncomingRpcMessage::isShortLivedRpcMessage(reader.getRoot<AnyPointer>());
 3868|      2|  };

_ZN5capnp13writeMessagesERN2kj17AsyncOutputStreamENS0_8ArrayPtrINS3_IKNS3_IKNS_4wordEEEEEEE:
  352|      3|    kj::ArrayPtr<kj::ArrayPtr<const kj::ArrayPtr<const word>>> messages) {
  353|      3|  return writeMessagesImpl(messages,
  354|      3|      [&](kj::ArrayPtr<const kj::ArrayPtr<const byte>> pieces) {
  355|      3|    return output.write(pieces);
  356|      3|  });
  357|      3|}
_ZN5capnp13MessageStream13writeMessagesEN2kj8ArrayPtrINS_13MessageAndFdsEEE:
  368|      3|kj::Promise<void> MessageStream::writeMessages(kj::ArrayPtr<MessageAndFds> messages) {
  369|      3|  if (messages.size() == 0) return kj::READY_NOW;
  ------------------
  |  Branch (369:7): [True: 0, False: 3]
  ------------------
  370|      3|  kj::ArrayPtr<MessageAndFds> remainingMessages;
  371|       |
  372|      3|  auto writeProm = [&]() {
  373|      3|    if (messages[0].fds.size() > 0) {
  374|       |      // We have a message with FDs attached. We need to write any bare messages we've accumulated,
  375|       |      // if any, then write the message with FDs, then continue on with any remaining messages.
  376|       |
  377|      3|      if (messages.size() > 1) {
  378|      3|        remainingMessages = messages.slice(1, messages.size());
  379|      3|      }
  380|       |
  381|      3|      return writeMessage(messages[0].fds, messages[0].segments);
  382|      3|    } else {
  383|      3|      kj::Vector<kj::ArrayPtr<const kj::ArrayPtr<const word>>> bareMessages(messages.size());
  384|      3|      for(auto i : kj::zeroTo(messages.size())) {
  385|      3|        if (messages[i].fds.size() > 0) {
  386|      3|          break;
  387|      3|        }
  388|      3|        bareMessages.add(messages[i].segments);
  389|      3|      }
  390|       |
  391|      3|      if (messages.size() > bareMessages.size()) {
  392|      3|        remainingMessages = messages.slice(bareMessages.size(), messages.size());
  393|      3|      }
  394|      3|      return writeMessages(bareMessages.asPtr()).attach(kj::mv(bareMessages));
  395|      3|    }
  396|      3|  }();
  397|       |
  398|      3|  if (remainingMessages.size() > 0) {
  ------------------
  |  Branch (398:7): [True: 0, False: 3]
  ------------------
  399|      0|    return writeProm.then([this, remainingMessages]() mutable {
  400|      0|      return writeMessages(remainingMessages);
  401|      0|    });
  402|      3|  } else {
  403|      3|    return writeProm;
  404|      3|  }
  405|      3|}
_ZN5capnp21BufferedMessageStream14tryReadMessageEN2kj8ArrayPtrINS1_11AutoCloseFdEEENS_13ReaderOptionsENS2_INS_4wordEEE:
  585|      3|    kj::ArrayPtr<kj::AutoCloseFd> fdSpace, ReaderOptions options, kj::ArrayPtr<word> scratchSpace) {
  586|      3|  return tryReadMessageImpl(fdSpace, 0, options, scratchSpace);
  587|      3|}
_ZN5capnp21BufferedMessageStream13writeMessagesEN2kj8ArrayPtrINS2_IKNS2_IKNS_4wordEEEEEEE:
  600|      3|    kj::ArrayPtr<kj::ArrayPtr<const kj::ArrayPtr<const word>>> messages) {
  601|      3|  return capnp::writeMessages(stream, messages);
  602|      3|}
_ZN5capnp21BufferedMessageStream18tryReadMessageImplEN2kj8ArrayPtrINS1_11AutoCloseFdEEEmNS_13ReaderOptionsENS2_INS_4wordEEE:
  615|      5|    ReaderOptions options, kj::ArrayPtr<word> scratchSpace) {
  616|      5|  KJ_REQUIRE(!hasOutstandingShortLivedMessage,
  ------------------
  |  Branch (616:3): [True: 5, False: 0]
  ------------------
  617|      0|      "can't read another message while the previous short-lived message still exists");
  618|       |
  619|      5|  kj::byte* beginDataBytes = reinterpret_cast<kj::byte*>(beginData);
  620|      5|  size_t dataByteSize = beginAvailable - beginDataBytes;
  621|      5|  kj::ArrayPtr<word> data = kj::arrayPtr(beginData, dataByteSize / sizeof(word));
  622|       |
  623|      5|  size_t expected = expectedSizeInWordsFromPrefix(data);
  624|       |
  625|      5|  if (!leftoverFds.empty() && expected * sizeof(word) >= dataByteSize) {
  ------------------
  |  Branch (625:7): [True: 0, False: 5]
  |  Branch (625:31): [True: 0, False: 0]
  ------------------
  626|       |    // We're about to return a message that consumes the rest of the data in the buffer, and
  627|       |    // `leftoverFds` is non-empty. Those FDs are considered attached to whatever message contains
  628|       |    // the last byte in the buffer. That's us! Let's consume them.
  629|       |
  630|       |    // `fdsSoFar` must be empty here because we shouldn't have performed any reads while
  631|       |    // `leftoverFds` was non-empty, so there shouldn't have been any other chance to add FDs to
  632|       |    // `fdSpace`.
  633|      0|    KJ_ASSERT(fdsSoFar == 0);
  ------------------
  |  Branch (633:5): [True: 0, False: 0]
  ------------------
  634|       |
  635|      0|    fdsSoFar = kj::min(leftoverFds.size(), fdSpace.size());
  636|      0|    for (auto i: kj::zeroTo(fdsSoFar)) {
  ------------------
  |  Branch (636:16): [True: 0, False: 0]
  ------------------
  637|      0|      fdSpace[i] = kj::mv(leftoverFds[i]);
  638|      0|    }
  639|      0|    leftoverFds.clear();
  640|      0|  }
  641|       |
  642|      5|  if (expected <= data.size()) {
  ------------------
  |  Branch (642:7): [True: 2, False: 3]
  ------------------
  643|       |    // The buffer contains at least one whole message, which we can just return without reading
  644|       |    // any more data.
  645|       |
  646|      2|    auto msgData = kj::arrayPtr(beginData, expected);
  647|      2|    auto reader = kj::heap<MessageReaderImpl>(*this, msgData, options);
  648|      2|    if (!isShortLivedCallback(*reader)) {
  ------------------
  |  Branch (648:9): [True: 1, False: 1]
  ------------------
  649|       |      // This message is long-lived, so we must make a copy to get it out of our buffer.
  650|      1|      if (msgData.size() <= scratchSpace.size()) {
  ------------------
  |  Branch (650:11): [True: 0, False: 1]
  ------------------
  651|       |        // Oh hey, we can use the provided scratch space.
  652|      0|        memcpy(scratchSpace.begin(), msgData.begin(), msgData.asBytes().size());
  653|      0|        reader = kj::heap<MessageReaderImpl>(scratchSpace, options);
  654|      1|      } else {
  655|      1|        auto ownMsgData = kj::heapArray<word>(msgData.size());
  656|      1|        memcpy(ownMsgData.begin(), msgData.begin(), msgData.asBytes().size());
  657|      1|        reader = kj::heap<MessageReaderImpl>(kj::mv(ownMsgData), options);
  658|      1|      }
  659|      1|    }
  660|       |
  661|      2|    beginData += expected;
  662|      2|    if (reinterpret_cast<byte*>(beginData) == beginAvailable) {
  ------------------
  |  Branch (662:9): [True: 2, False: 0]
  ------------------
  663|       |      // The buffer is empty. Let's opportunistically reset the pointers.
  664|      2|      beginData = buffer.begin();
  665|      2|      beginAvailable = buffer.asBytes().begin();
  666|      2|    } else if (fdsSoFar > 0) {
  ------------------
  |  Branch (666:16): [True: 0, False: 0]
  ------------------
  667|       |      // The buffer is NOT empty, and we received FDs when we were filling it. These FDs must
  668|       |      // actually belong to the last message in the buffer, because when the OS returns FDs
  669|       |      // attached to a read, it will make sure the read does not extend past the last byte to
  670|       |      // which those FDs were attached.
  671|       |      //
  672|       |      // So, we must set these FDs aside for the moment.
  673|      0|      for (auto i: kj::zeroTo(fdsSoFar)) {
  ------------------
  |  Branch (673:18): [True: 0, False: 0]
  ------------------
  674|      0|        leftoverFds.add(kj::mv(fdSpace[i]));
  675|      0|      }
  676|      0|      fdsSoFar = 0;
  677|      0|    }
  678|       |
  679|      2|    return kj::Maybe<MessageReaderAndFds>(MessageReaderAndFds {
  680|      2|      kj::mv(reader),
  681|      2|      fdSpace.slice(0, fdsSoFar)
  682|      2|    });
  683|      2|  }
  684|       |
  685|       |  // At this point, the buffer doesn't contain a complete message. We are going to need to perform
  686|       |  // a read.
  687|       |
  688|      3|  if (expected > buffer.size() / 2 || fdsSoFar > 0) {
  ------------------
  |  Branch (688:7): [True: 0, False: 3]
  |  Branch (688:39): [True: 0, False: 3]
  ------------------
  689|       |    // Read this message into its own separately-allocated buffer. We do this for:
  690|       |    // - Big messages, because they might not fit in the buffer and because big messages are
  691|       |    //   almost certainly going to be long-lived and so would require a copy later anyway.
  692|       |    // - Messages where we've already received some FDs, because these are also almost certainly
  693|       |    //   long-lived, and we want to avoid accidentally reading into the next message since we
  694|       |    //   could end up receiving FDs that were intended for that one.
  695|       |    //
  696|       |    // Optimization note: You might argue that if the expected size is more than half the buffer,
  697|       |    // but still less than the *whole* buffer, then we should still try to read into the buffer
  698|       |    // first. However, keep in mind that in the RPC system, all short-lived messages are
  699|       |    // relatively small, and hence we can assume that since this is a large message, it will
  700|       |    // end up being long-lived. Long-lived messages need to be copied out into their own buffer
  701|       |    // at some point anyway. So we might as well go ahead and allocate that separate buffer
  702|       |    // now, and read directly into it, rather than try to use the shared buffer. We choose to
  703|       |    // use buffer.size() / 2 as the cutoff because that ensures that we won't try to move the
  704|       |    // bytes of a known-large message to the beginning of the buffer (see next if() after this
  705|       |    // one).
  706|       |
  707|      0|    auto prefix = kj::arrayPtr(beginDataBytes, dataByteSize);
  708|       |
  709|       |    // We are consuming everything in the buffer here, so we can reset the pointers so the
  710|       |    // buffer appears empty on the next message read after this.
  711|      0|    beginData = buffer.begin();
  712|      0|    beginAvailable = buffer.asBytes().begin();
  713|       |
  714|      0|    return readEntireMessage(prefix, expected, fdSpace, fdsSoFar, options);
  715|      0|  }
  716|       |
  717|       |  // Set minBytes to at least complete the current message.
  718|      3|  size_t minBytes = expected * sizeof(word) - dataByteSize;
  719|       |
  720|       |  // minBytes must be less than half the buffer otherwise we would have taken the
  721|       |  // readEntireMessage() branch above.
  722|      3|  KJ_DASSERT(minBytes <= buffer.asBytes().size() / 2);
  ------------------
  |  Branch (722:3): [Folded, False: 3]
  ------------------
  723|       |
  724|       |  // Set maxBytes to the space we have available in the buffer.
  725|      3|  size_t maxBytes = buffer.asBytes().end() - beginAvailable;
  726|       |
  727|      3|  if (maxBytes < buffer.asBytes().size() / 2) {
  ------------------
  |  Branch (727:7): [True: 0, False: 3]
  ------------------
  728|       |    // We have less than half the buffer remaining to read into. Move the buffered data to the
  729|       |    // beginning of the buffer to make more space.
  730|      0|    memmove(buffer.begin(), beginData, dataByteSize);
  731|      0|    beginData = buffer.begin();
  732|      0|    beginDataBytes = buffer.asBytes().begin();
  733|      0|    beginAvailable = beginDataBytes + dataByteSize;
  734|       |
  735|      0|    maxBytes = buffer.asBytes().end() - beginAvailable;
  736|      0|  }
  737|       |
  738|       |  // maxBytes must now be more than half the buffer, because if it weren't we would have moved
  739|       |  // the existing data above, and the existing data cannot be more than half the buffer because
  740|       |  // if it were we would have taken the readEntireMesage() path earlier.
  741|      3|  KJ_DASSERT(maxBytes >= buffer.asBytes().size() / 2);
  ------------------
  |  Branch (741:3): [Folded, False: 3]
  ------------------
  742|       |
  743|       |  // Since minBytes is less that half the buffer and maxBytes is more then half, minBytes is
  744|       |  // definitely less than maxBytes.
  745|      3|  KJ_DASSERT(minBytes <= maxBytes);
  ------------------
  |  Branch (745:3): [Folded, False: 3]
  ------------------
  746|       |
  747|       |  // Read from underlying stream.
  748|      3|  return tryReadWithFds(beginAvailable, minBytes, maxBytes,
  749|      3|                        fdSpace.begin() + fdsSoFar, fdSpace.size() - fdsSoFar)
  750|      3|      .then([this,minBytes,fdSpace,fdsSoFar,options,scratchSpace]
  751|      3|            (kj::AsyncCapabilityStream::ReadResult result) mutable
  752|      3|            -> kj::Promise<kj::Maybe<MessageReaderAndFds>> {
  753|       |    // Account for new data received in the buffer.
  754|      3|    beginAvailable += result.byteCount;
  755|       |
  756|      3|    if (result.byteCount < minBytes) {
  757|       |      // Didn't reach minBytes, so we must have hit EOF. That's legal as long as it happened on
  758|       |      // a clean message boundray.
  759|      3|      if (beginAvailable > reinterpret_cast<kj::byte*>(beginData)) {
  760|       |        // We had received a partial message before EOF, so this should be considered an error.
  761|      3|        kj::throwRecoverableException(KJ_EXCEPTION(DISCONNECTED,
  762|      3|            "stream disconnected prematurely"));
  763|      3|      }
  764|      3|      return kj::Maybe<MessageReaderAndFds>(nullptr);
  765|      3|    }
  766|       |
  767|       |    // Loop!
  768|      3|    return tryReadMessageImpl(fdSpace, fdsSoFar + result.capCount, options, scratchSpace);
  769|      3|  });
  770|      3|}
_ZN5capnp21BufferedMessageStream14tryReadWithFdsEPvmmPN2kj11AutoCloseFdEm:
  828|      3|    void* buffer, size_t minBytes, size_t maxBytes, kj::AutoCloseFd* fdBuffer, size_t maxFds) {
  829|      3|  KJ_IF_MAYBE(cs, capStream) {
  ------------------
  |  Branch (829:3): [True: 0, False: 3]
  ------------------
  830|      0|    return cs->tryReadWithFds(buffer, minBytes, maxBytes, fdBuffer, maxFds);
  831|      3|  } else {
  832|       |    // Regular byte stream, no FDs.
  833|      3|    return stream.tryRead(buffer, minBytes, maxBytes)
  834|      3|        .then([](size_t amount) mutable -> kj::AsyncCapabilityStream::ReadResult {
  835|      3|      return { amount, 0 };
  836|      3|    });
  837|      3|  }
  838|      3|}
serialize-async.c++:_ZZN5capnp13MessageStream13writeMessagesEN2kj8ArrayPtrINS_13MessageAndFdsEEEENK3$_0clEv:
  372|      3|  auto writeProm = [&]() {
  373|      3|    if (messages[0].fds.size() > 0) {
  ------------------
  |  Branch (373:9): [True: 0, False: 3]
  ------------------
  374|       |      // We have a message with FDs attached. We need to write any bare messages we've accumulated,
  375|       |      // if any, then write the message with FDs, then continue on with any remaining messages.
  376|       |
  377|      0|      if (messages.size() > 1) {
  ------------------
  |  Branch (377:11): [True: 0, False: 0]
  ------------------
  378|      0|        remainingMessages = messages.slice(1, messages.size());
  379|      0|      }
  380|       |
  381|      0|      return writeMessage(messages[0].fds, messages[0].segments);
  382|      3|    } else {
  383|      3|      kj::Vector<kj::ArrayPtr<const kj::ArrayPtr<const word>>> bareMessages(messages.size());
  384|      3|      for(auto i : kj::zeroTo(messages.size())) {
  ------------------
  |  Branch (384:18): [True: 3, False: 3]
  ------------------
  385|      3|        if (messages[i].fds.size() > 0) {
  ------------------
  |  Branch (385:13): [True: 0, False: 3]
  ------------------
  386|      0|          break;
  387|      0|        }
  388|      3|        bareMessages.add(messages[i].segments);
  389|      3|      }
  390|       |
  391|      3|      if (messages.size() > bareMessages.size()) {
  ------------------
  |  Branch (391:11): [True: 0, False: 3]
  ------------------
  392|      0|        remainingMessages = messages.slice(bareMessages.size(), messages.size());
  393|      0|      }
  394|      3|      return writeMessages(bareMessages.asPtr()).attach(kj::mv(bareMessages));
  395|      3|    }
  396|      3|  }();
serialize-async.c++:_ZN5capnp12_GLOBAL__N_120tableSizeForSegmentsEm:
  254|      6|inline size_t tableSizeForSegments(size_t segmentsSize) {
  255|      6|  return (segmentsSize + 2) & ~size_t(1);
  256|      6|}
serialize-async.c++:_ZN5capnp12_GLOBAL__N_126fillWriteArraysWithMessageEN2kj8ArrayPtrIKNS2_IKNS_4wordEEEEENS2_INS_1_15DirectWireValueIjEEEENS2_INS2_IKhEEEE:
  262|      3|                                kj::ArrayPtr<kj::ArrayPtr<const byte>> pieces) {
  263|      3|  KJ_REQUIRE(segments.size() > 0, "Tried to serialize uninitialized message.");
  ------------------
  |  Branch (263:3): [True: 3, False: 0]
  ------------------
  264|       |
  265|       |  // We write the segment count - 1 because this makes the first word zero for single-segment
  266|       |  // messages, improving compression.  We don't bother doing this with segment sizes because
  267|       |  // one-word segments are rare anyway.
  268|      3|  table[0].set(segments.size() - 1);
  269|      6|  for (uint i = 0; i < segments.size(); i++) {
  ------------------
  |  Branch (269:20): [True: 3, False: 3]
  ------------------
  270|      3|    table[i + 1].set(segments[i].size());
  271|      3|  }
  272|      3|  if (segments.size() % 2 == 0) {
  ------------------
  |  Branch (272:7): [True: 0, False: 3]
  ------------------
  273|       |    // Set padding byte.
  274|      0|    table[segments.size() + 1].set(0);
  275|      0|  }
  276|       |
  277|      3|  KJ_ASSERT(pieces.size() == segments.size() + 1, "incorrectly sized pieces array during write");
  ------------------
  |  Branch (277:3): [True: 3, False: 0]
  ------------------
  278|      3|  pieces[0] = table.asBytes();
  279|      6|  for (uint i = 0; i < segments.size(); i++) {
  ------------------
  |  Branch (279:20): [True: 3, False: 3]
  ------------------
  280|      3|    pieces[i + 1] = segments[i].asBytes();
  281|      3|  }
  282|      3|}
serialize-async.c++:_ZN5capnp12_GLOBAL__N_117writeMessagesImplIZNS_13writeMessagesERN2kj17AsyncOutputStreamENS2_8ArrayPtrINS5_IKNS5_IKNS_4wordEEEEEEEE3$_0EENS2_7PromiseIvEESB_OT_:
  302|      3|    kj::ArrayPtr<kj::ArrayPtr<const kj::ArrayPtr<const word>>> messages, WriteFunc&& writeFunc) {
  303|      3|  KJ_REQUIRE(messages.size() > 0, "Tried to serialize zero messages.");
  ------------------
  |  Branch (303:3): [True: 3, False: 0]
  ------------------
  304|       |
  305|       |  // Determine how large the shared table and pieces arrays needs to be.
  306|      3|  size_t tableSize = 0;
  307|      3|  size_t piecesSize = 0;
  308|      3|  for (auto& segments : messages) {
  ------------------
  |  Branch (308:23): [True: 3, False: 3]
  ------------------
  309|      3|    tableSize += tableSizeForSegments(segments.size());
  310|      3|    piecesSize += segments.size() + 1;
  311|      3|  }
  312|      3|  auto table = kj::heapArray<_::WireValue<uint32_t>>(tableSize);
  313|      3|  auto pieces = kj::heapArray<kj::ArrayPtr<const byte>>(piecesSize);
  314|       |
  315|      3|  size_t tableValsWritten = 0;
  316|      3|  size_t piecesWritten = 0;
  317|      3|  for (auto i : kj::indices(messages)) {
  ------------------
  |  Branch (317:15): [True: 3, False: 3]
  ------------------
  318|      3|    const size_t tableValsToWrite = tableSizeForSegments(messages[i].size());
  319|      3|    const size_t piecesToWrite = messages[i].size() + 1;
  320|      3|    fillWriteArraysWithMessage(
  321|      3|        messages[i],
  322|      3|        table.slice(tableValsWritten, tableValsWritten + tableValsToWrite),
  323|      3|        pieces.slice(piecesWritten, piecesWritten + piecesToWrite));
  324|      3|    tableValsWritten += tableValsToWrite;
  325|      3|    piecesWritten += piecesToWrite;
  326|      3|  }
  327|       |
  328|      3|  auto promise = writeFunc(pieces);
  329|      3|  return promise.attach(kj::mv(table), kj::mv(pieces));
  330|      3|}
serialize-async.c++:_ZZN5capnp13writeMessagesERN2kj17AsyncOutputStreamENS0_8ArrayPtrINS3_IKNS3_IKNS_4wordEEEEEEEENK3$_0clENS3_IKNS3_IKhEEEE:
  354|      3|      [&](kj::ArrayPtr<const kj::ArrayPtr<const byte>> pieces) {
  355|      3|    return output.write(pieces);
  356|      3|  });
_ZN5capnp21BufferedMessageStream17MessageReaderImplC2ERS0_N2kj8ArrayPtrIKNS_4wordEEENS_13ReaderOptionsE:
  549|      2|      : FlatArrayMessageReader(data, options), state(&parent) {
  550|       |    KJ_DASSERT(!parent.hasOutstandingShortLivedMessage);
  ------------------
  |  Branch (550:5): [Folded, False: 2]
  ------------------
  551|      2|    parent.hasOutstandingShortLivedMessage = true;
  552|      2|  }
_ZN5capnp21BufferedMessageStream17MessageReaderImplD2Ev:
  558|      4|  ~MessageReaderImpl() noexcept(false) {
  559|      4|    KJ_IF_MAYBE(parent, state.tryGet<BufferedMessageStream*>()) {
  ------------------
  |  Branch (559:5): [True: 3, False: 1]
  ------------------
  560|      3|      (*parent)->hasOutstandingShortLivedMessage = false;
  561|      3|    }
  562|      4|  }
_ZN5capnp21BufferedMessageStream17MessageReaderImplC2EON2kj5ArrayINS_4wordEEENS_13ReaderOptionsE:
  554|      1|      : FlatArrayMessageReader(ownBuffer, options), state(kj::mv(ownBuffer)) {}
serialize-async.c++:_ZZN5capnp21BufferedMessageStream18tryReadMessageImplEN2kj8ArrayPtrINS1_11AutoCloseFdEEEmNS_13ReaderOptionsENS2_INS_4wordEEEEN3$_0clENS1_21AsyncCapabilityStream10ReadResultE:
  752|      3|            -> kj::Promise<kj::Maybe<MessageReaderAndFds>> {
  753|       |    // Account for new data received in the buffer.
  754|      3|    beginAvailable += result.byteCount;
  755|       |
  756|      3|    if (result.byteCount < minBytes) {
  ------------------
  |  Branch (756:9): [True: 1, False: 2]
  ------------------
  757|       |      // Didn't reach minBytes, so we must have hit EOF. That's legal as long as it happened on
  758|       |      // a clean message boundray.
  759|      1|      if (beginAvailable > reinterpret_cast<kj::byte*>(beginData)) {
  ------------------
  |  Branch (759:11): [True: 0, False: 1]
  ------------------
  760|       |        // We had received a partial message before EOF, so this should be considered an error.
  761|      0|        kj::throwRecoverableException(KJ_EXCEPTION(DISCONNECTED,
  762|      0|            "stream disconnected prematurely"));
  763|      0|      }
  764|      1|      return kj::Maybe<MessageReaderAndFds>(nullptr);
  765|      1|    }
  766|       |
  767|       |    // Loop!
  768|      2|    return tryReadMessageImpl(fdSpace, fdsSoFar + result.capCount, options, scratchSpace);
  769|      3|  });
serialize-async.c++:_ZZN5capnp21BufferedMessageStream14tryReadWithFdsEPvmmPN2kj11AutoCloseFdEmEN3$_0clEm:
  834|      3|        .then([](size_t amount) mutable -> kj::AsyncCapabilityStream::ReadResult {
  835|      3|      return { amount, 0 };
  836|      3|    });

_ZN5capnp22FlatArrayMessageReaderC2EN2kj8ArrayPtrIKNS_4wordEEENS_13ReaderOptionsE:
   35|      3|    : MessageReader(options), end(array.end()) {
   36|      3|  if (array.size() < 1) {
  ------------------
  |  Branch (36:7): [True: 0, False: 3]
  ------------------
   37|       |    // Assume empty message.
   38|      0|    return;
   39|      0|  }
   40|       |
   41|      3|  const _::WireValue<uint32_t>* table =
   42|      3|      reinterpret_cast<const _::WireValue<uint32_t>*>(array.begin());
   43|       |
   44|      3|  uint segmentCount = table[0].get() + 1;
   45|      3|  size_t offset = segmentCount / 2u + 1u;
   46|       |
   47|      3|  KJ_REQUIRE(segmentCount != 0, "Message segment count too large, caused overflow.") {
  ------------------
  |  Branch (47:3): [True: 3, False: 0]
  ------------------
   48|      0|    return;
   49|      0|  }
   50|       |
   51|      3|  KJ_REQUIRE(array.size() >= offset, "Message ends prematurely in segment table.") {
  ------------------
  |  Branch (51:3): [True: 3, False: 0]
  ------------------
   52|      0|    return;
   53|      0|  }
   54|       |
   55|      3|  {
   56|      3|    uint segmentSize = table[1].get();
   57|       |
   58|      3|    KJ_REQUIRE(array.size() - offset >= segmentSize,
  ------------------
  |  Branch (58:5): [True: 3, False: 0]
  ------------------
   59|      0|               "Message ends prematurely in first segment.") {
   60|      0|      return;
   61|      0|    }
   62|       |
   63|      3|    segment0 = array.slice(offset, offset + segmentSize);
   64|      3|    offset += segmentSize;
   65|      3|  }
   66|       |
   67|      3|  if (segmentCount > 1) {
  ------------------
  |  Branch (67:7): [True: 0, False: 3]
  ------------------
   68|      0|    moreSegments = kj::heapArray<kj::ArrayPtr<const word>>(segmentCount - 1);
   69|       |
   70|      0|    for (uint i = 1; i < segmentCount; i++) {
  ------------------
  |  Branch (70:22): [True: 0, False: 0]
  ------------------
   71|      0|      uint segmentSize = table[i + 1].get();
   72|       |
   73|      0|      KJ_REQUIRE(array.size() - offset >= segmentSize, "Message ends prematurely.") {
  ------------------
  |  Branch (73:7): [True: 0, False: 0]
  ------------------
   74|      0|        moreSegments = nullptr;
   75|      0|        return;
   76|      0|      }
   77|       |
   78|      0|      moreSegments[i - 1] = array.slice(offset, offset + segmentSize);
   79|      0|      offset += segmentSize;
   80|      0|    }
   81|      0|  }
   82|       |
   83|      3|  end = array.begin() + offset;
   84|      3|}
_ZN5capnp29expectedSizeInWordsFromPrefixEN2kj8ArrayPtrIKNS_4wordEEE:
   86|      5|size_t expectedSizeInWordsFromPrefix(kj::ArrayPtr<const word> array) {
   87|      5|  if (array.size() < 1) {
  ------------------
  |  Branch (87:7): [True: 3, False: 2]
  ------------------
   88|       |    // All messages are at least one word.
   89|      3|    return 1;
   90|      3|  }
   91|       |
   92|      2|  const _::WireValue<uint32_t>* table =
   93|      2|      reinterpret_cast<const _::WireValue<uint32_t>*>(array.begin());
   94|       |
   95|      2|  uint segmentCount = table[0].get() + 1;
   96|      2|  size_t offset = segmentCount / 2u + 1u;
   97|       |
   98|      2|  if (segmentCount == 0) {
  ------------------
  |  Branch (98:7): [True: 0, False: 2]
  ------------------
   99|       |    // Integer overflow in segmentCount. Any attempt to actually parse this will throw an
  100|       |    // exception. Only the first word is needed for the exception to be thrown, so we'll just say
  101|       |    // the expected size is 1. Think of this as: "The data is corrupt, and the corruption exists
  102|       |    // in the first word. We have no idea how long the message might be, but the first word is
  103|       |    // all we need to see that it is corrupt."
  104|      0|    return 1;
  105|      0|  }
  106|       |
  107|       |  // If the array is too small to contain the full segment table, truncate segmentCount to just
  108|       |  // what is available.
  109|      2|  segmentCount = kj::min(segmentCount, array.size() * 2 - 1u);
  110|       |
  111|      2|  size_t totalSize = offset;
  112|      4|  for (uint i = 0; i < segmentCount; i++) {
  ------------------
  |  Branch (112:20): [True: 2, False: 2]
  ------------------
  113|      2|    totalSize += table[i + 1].get();
  114|      2|  }
  115|      2|  return totalSize;
  116|      2|}
_ZN5capnp22FlatArrayMessageReader10getSegmentEj:
  118|      3|kj::ArrayPtr<const word> FlatArrayMessageReader::getSegment(uint id) {
  119|      3|  if (id == 0) {
  ------------------
  |  Branch (119:7): [True: 3, False: 0]
  ------------------
  120|      3|    return segment0;
  121|      3|  } else if (id <= moreSegments.size()) {
  ------------------
  |  Branch (121:14): [True: 0, False: 0]
  ------------------
  122|      0|    return moreSegments[id - 1];
  123|      0|  } else {
  124|      0|    return nullptr;
  125|      0|  }
  126|      3|}

_ZN2kj22ExceptionSafeArrayUtil9constructEmPFvPvE:
   27|      6|void ExceptionSafeArrayUtil::construct(size_t count, void (*constructElement)(void*)) {
   28|     15|  while (count > 0) {
  ------------------
  |  Branch (28:10): [True: 9, False: 6]
  ------------------
   29|      9|    constructElement(pos);
   30|      9|    pos += elementSize;
   31|      9|    ++constructedElementCount;
   32|      9|    --count;
   33|      9|  }
   34|      6|}
_ZN2kj22ExceptionSafeArrayUtil10destroyAllEv:
   36|     15|void ExceptionSafeArrayUtil::destroyAll() {
   37|     81|  while (constructedElementCount > 0) {
  ------------------
  |  Branch (37:10): [True: 66, False: 15]
  ------------------
   38|     66|    pos -= elementSize;
   39|     66|    --constructedElementCount;
   40|     66|    destroyElement(pos);
   41|     66|  }
   42|     15|}
_ZN2kj1_17HeapArrayDisposer12allocateImplEmmmPFvPvES4_:
   73|     38|                                      void (*destroyElement)(void*)) {
   74|     38|  AutoDeleter result(operator new(elementSize * capacity));
   75|       |
   76|     38|  if (constructElement == nullptr) {
  ------------------
  |  Branch (76:7): [True: 32, False: 6]
  ------------------
   77|       |    // Nothing to do.
   78|     32|  } else if (destroyElement == nullptr) {
  ------------------
  |  Branch (78:14): [True: 0, False: 6]
  ------------------
   79|      0|    byte* pos = reinterpret_cast<byte*>(result.ptr);
   80|      0|    while (elementCount > 0) {
  ------------------
  |  Branch (80:12): [True: 0, False: 0]
  ------------------
   81|      0|      constructElement(pos);
   82|      0|      pos += elementSize;
   83|      0|      --elementCount;
   84|      0|    }
   85|      6|  } else {
   86|      6|    ExceptionSafeArrayUtil guard(result.ptr, elementSize, 0, destroyElement);
   87|      6|    guard.construct(elementCount, constructElement);
   88|      6|    guard.release();
   89|      6|  }
   90|       |
   91|     38|  return result.release();
   92|     38|}
_ZNK2kj1_17HeapArrayDisposer11disposeImplEPvmmmPFvS2_E:
   96|     50|    void (*destroyElement)(void*)) const {
   97|       |  // Note that capacity is ignored since operator delete() doesn't care about it.
   98|     50|  AutoDeleter deleter(firstElement);
   99|       |
  100|     50|  if (destroyElement != nullptr) {
  ------------------
  |  Branch (100:7): [True: 15, False: 35]
  ------------------
  101|     15|    ExceptionSafeArrayUtil guard(firstElement, elementSize, elementCount, destroyElement);
  102|     15|    guard.destroyAll();
  103|     15|  }
  104|     50|}
_ZN2kj1_11AutoDeleterC2EPv:
   67|     88|  inline AutoDeleter(void* ptr): ptr(ptr) {}
_ZN2kj1_11AutoDeleter7releaseEv:
   66|     38|  inline void* release() { void* result = ptr; ptr = nullptr; return result; }
_ZN2kj1_11AutoDeleterD2Ev:
   68|     88|  inline ~AutoDeleter() { operator delete(ptr); }

async-io-unix.c++:_ZN2kj12_GLOBAL__N_119OwnedFileDescriptorD2Ev:
  130|      3|  ~OwnedFileDescriptor() noexcept(false) {
  131|       |    // Don't use SYSCALL() here because close() should not be repeated on EINTR.
  132|      3|    if ((flags & LowLevelAsyncIoProvider::TAKE_OWNERSHIP) && close(fd) < 0) {
  ------------------
  |  Branch (132:9): [True: 3, False: 0]
  |  Branch (132:62): [True: 0, False: 3]
  ------------------
  133|      0|      KJ_FAIL_SYSCALL("close", errno, fd) {
  134|       |        // Recoverable exceptions are safe in destructors.
  135|      0|        break;
  136|      0|      }
  137|      0|    }
  138|      3|  }
async-io-unix.c++:_ZN2kj12_GLOBAL__N_113AsyncStreamFd7tryReadEPvmm:
  157|      4|  Promise<size_t> tryRead(void* buffer, size_t minBytes, size_t maxBytes) override {
  158|      4|    return tryReadInternal(buffer, minBytes, maxBytes, nullptr, 0, {0,0})
  159|      4|        .then([](ReadResult r) { return r.byteCount; });
  160|      4|  }
async-io-unix.c++:_ZN2kj12_GLOBAL__N_113AsyncStreamFd15tryReadInternalEPvmmPNS_11AutoCloseFdEmNS_21AsyncCapabilityStream10ReadResultE:
  562|      9|                                      ReadResult alreadyRead) {
  563|       |    // `alreadyRead` is the number of bytes we have already received via previous reads -- minBytes,
  564|       |    // maxBytes, and buffer have already been adjusted to account for them, but this count must
  565|       |    // be included in the final return value.
  566|       |
  567|      9|    ssize_t n;
  568|      9|    if (maxFds == 0 && ancillaryMsgCallback == nullptr) {
  ------------------
  |  Branch (568:9): [True: 9, False: 0]
  |  Branch (568:24): [True: 9, False: 0]
  ------------------
  569|      9|      KJ_NONBLOCKING_SYSCALL(n = ::read(fd, buffer, maxBytes)) {
  ------------------
  |  Branch (569:7): [True: 9, False: 0]
  ------------------
  570|       |        // Error.
  571|       |
  572|       |        // We can't "return kj::READY_NOW;" inside this block because it causes a memory leak due to
  573|       |        // a bug that exists in both Clang and GCC:
  574|       |        //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33799
  575|       |        //   http://llvm.org/bugs/show_bug.cgi?id=12286
  576|      0|        goto error;
  577|      0|      }
  578|      9|    } else {
  579|      0|      struct msghdr msg;
  580|      0|      memset(&msg, 0, sizeof(msg));
  581|       |
  582|      0|      struct iovec iov;
  583|      0|      memset(&iov, 0, sizeof(iov));
  584|      0|      iov.iov_base = buffer;
  585|      0|      iov.iov_len = maxBytes;
  586|      0|      msg.msg_iov = &iov;
  587|      0|      msg.msg_iovlen = 1;
  588|       |
  589|       |      // Allocate space to receive a cmsg.
  590|      0|      size_t msgBytes;
  591|      0|      if (ancillaryMsgCallback == nullptr) {
  ------------------
  |  Branch (591:11): [True: 0, False: 0]
  ------------------
  592|       |#if __APPLE__ || __FreeBSD__
  593|       |        // Until very recently (late 2018 / early 2019), FreeBSD suffered from a bug in which when
  594|       |        // an SCM_RIGHTS message was truncated on delivery, it would not close the FDs that weren't
  595|       |        // delivered -- they would simply leak: https://bugs.freebsd.org/131876
  596|       |        //
  597|       |        // My testing indicates that MacOS has this same bug as of today (April 2019). I don't know
  598|       |        // if they plan to fix it or are even aware of it.
  599|       |        //
  600|       |        // To handle both cases, we will always provide space to receive 512 FDs. Hopefully, this is
  601|       |        // greater than the maximum number of FDs that these kernels will transmit in one message
  602|       |        // PLUS enough space for any other ancillary messages that could be sent before the
  603|       |        // SCM_RIGHTS message to push it back in the buffer. I couldn't find any firm documentation
  604|       |        // on these limits, though -- I only know that Linux is limited to 253, and I saw a hint in
  605|       |        // a comment in someone else's application that suggested FreeBSD is the same. Hopefully,
  606|       |        // then, this is sufficient to prevent attacks. But if not, there's nothing more we can do;
  607|       |        // it's really up to the kernel to fix this.
  608|       |        msgBytes = CMSG_SPACE(sizeof(int) * 512);
  609|       |#else
  610|      0|        msgBytes = CMSG_SPACE(sizeof(int) * maxFds);
  611|      0|#endif
  612|      0|      } else {
  613|       |        // If we want room for ancillary messages instead of or in addition to FDs, just use the
  614|       |        // same amount of cushion as in the MacOS/FreeBSD case above.
  615|       |        // Someday we may want to allow customization here, but there's no immediate use for it.
  616|      0|        msgBytes = CMSG_SPACE(sizeof(int) * 512);
  617|      0|      }
  618|       |
  619|       |      // On Linux, CMSG_SPACE will align to a word-size boundary, but on Mac it always aligns to a
  620|       |      // 32-bit boundary. I guess aligning to 32 bits helps avoid the problem where you
  621|       |      // surprisingly end up with space for two file descriptors when you only wanted one. However,
  622|       |      // cmsghdr's preferred alignment is word-size (it contains a size_t). If we stack-allocate
  623|       |      // the buffer, we need to make sure it is aligned properly (maybe not on x64, but maybe on
  624|       |      // other platforms), so we want to allocate an array of words (we use void*). So... we use
  625|       |      // CMSG_SPACE() and then additionally round up to deal with Mac.
  626|      0|      size_t msgWords = (msgBytes + sizeof(void*) - 1) / sizeof(void*);
  627|      0|      KJ_STACK_ARRAY(void*, cmsgSpace, msgWords, 16, 256);
  ------------------
  |  Branch (627:7): [True: 0, False: 0]
  |  Branch (627:7): [True: 0, False: 0]
  ------------------
  628|      0|      auto cmsgBytes = cmsgSpace.asBytes();
  629|      0|      memset(cmsgBytes.begin(), 0, cmsgBytes.size());
  630|      0|      msg.msg_control = cmsgBytes.begin();
  631|      0|      msg.msg_controllen = msgBytes;
  632|       |
  633|      0|#ifdef MSG_CMSG_CLOEXEC
  634|      0|      static constexpr int RECVMSG_FLAGS = MSG_CMSG_CLOEXEC;
  635|       |#else
  636|       |      static constexpr int RECVMSG_FLAGS = 0;
  637|       |#endif
  638|       |
  639|      0|      KJ_NONBLOCKING_SYSCALL(n = ::recvmsg(fd, &msg, RECVMSG_FLAGS)) {
  ------------------
  |  Branch (639:7): [True: 0, False: 0]
  ------------------
  640|       |        // Error.
  641|       |
  642|       |        // We can't "return kj::READY_NOW;" inside this block because it causes a memory leak due to
  643|       |        // a bug that exists in both Clang and GCC:
  644|       |        //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33799
  645|       |        //   http://llvm.org/bugs/show_bug.cgi?id=12286
  646|      0|        goto error;
  647|      0|      }
  648|       |
  649|      0|      if (n >= 0) {
  ------------------
  |  Branch (649:11): [True: 0, False: 0]
  ------------------
  650|       |        // Process all messages.
  651|       |        //
  652|       |        // WARNING DANGER: We have to be VERY careful not to miss a file descriptor here, because
  653|       |        // if we do, then that FD will never be closed, and a malicious peer could exploit this to
  654|       |        // fill up our FD table, creating a DoS attack. Some things to keep in mind:
  655|       |        // - CMSG_SPACE() could have rounded up the space for alignment purposes, and this could
  656|       |        //   mean we permitted the kernel to deliver more file descriptors than `maxFds`. We need
  657|       |        //   to close the extras.
  658|       |        // - We can receive multiple ancillary messages at once. In particular, there is also
  659|       |        //   SCM_CREDENTIALS. The sender decides what to send. They could send SCM_CREDENTIALS
  660|       |        //   first followed by SCM_RIGHTS. We need to make sure we see both.
  661|      0|        size_t nfds = 0;
  662|      0|        size_t spaceLeft = msg.msg_controllen;
  663|      0|        Vector<AncillaryMessage> ancillaryMessages;
  664|      0|        for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
  ------------------
  |  Branch (664:37): [True: 0, False: 0]
  ------------------
  665|      0|            cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
  ------------------
  |  Branch (665:13): [True: 0, False: 0]
  ------------------
  666|      0|          if (spaceLeft >= CMSG_LEN(0) &&
  ------------------
  |  Branch (666:15): [True: 0, False: 0]
  ------------------
  667|      0|              cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
  ------------------
  |  Branch (667:15): [True: 0, False: 0]
  |  Branch (667:49): [True: 0, False: 0]
  ------------------
  668|       |            // Some operating systems (like MacOS) do not adjust csmg_len when the message is
  669|       |            // truncated. We must do so ourselves or risk overrunning the buffer.
  670|      0|            auto len = kj::min(cmsg->cmsg_len, spaceLeft);
  671|      0|            auto data = arrayPtr(reinterpret_cast<int*>(CMSG_DATA(cmsg)),
  672|      0|                                 (len - CMSG_LEN(0)) / sizeof(int));
  673|      0|            kj::Vector<kj::AutoCloseFd> trashFds;
  674|      0|            for (auto fd: data) {
  ------------------
  |  Branch (674:25): [True: 0, False: 0]
  ------------------
  675|      0|              kj::AutoCloseFd ownFd(fd);
  676|      0|              if (nfds < maxFds) {
  ------------------
  |  Branch (676:19): [True: 0, False: 0]
  ------------------
  677|      0|                fdBuffer[nfds++] = kj::mv(ownFd);
  678|      0|              } else {
  679|      0|                trashFds.add(kj::mv(ownFd));
  680|      0|              }
  681|      0|            }
  682|      0|          } else if (spaceLeft >= CMSG_LEN(0) && ancillaryMsgCallback != nullptr) {
  ------------------
  |  Branch (682:22): [True: 0, False: 0]
  |  Branch (682:50): [True: 0, False: 0]
  ------------------
  683|      0|            auto len = kj::min(cmsg->cmsg_len, spaceLeft);
  684|      0|            auto data = ArrayPtr<const byte>(CMSG_DATA(cmsg), len - CMSG_LEN(0));
  685|      0|            ancillaryMessages.add(cmsg->cmsg_level, cmsg->cmsg_type, data);
  686|      0|          }
  687|       |
  688|      0|          if (spaceLeft >= CMSG_LEN(0) && spaceLeft >= cmsg->cmsg_len) {
  ------------------
  |  Branch (688:15): [True: 0, False: 0]
  |  Branch (688:43): [True: 0, False: 0]
  ------------------
  689|      0|            spaceLeft -= cmsg->cmsg_len;
  690|      0|          } else {
  691|      0|            spaceLeft = 0;
  692|      0|          }
  693|      0|        }
  694|       |
  695|       |#ifndef MSG_CMSG_CLOEXEC
  696|       |        for (size_t i = 0; i < nfds; i++) {
  697|       |          setCloseOnExec(fdBuffer[i]);
  698|       |        }
  699|       |#endif
  700|       |
  701|      0|        if (ancillaryMessages.size() > 0) {
  ------------------
  |  Branch (701:13): [True: 0, False: 0]
  ------------------
  702|      0|          KJ_IF_MAYBE(fn, ancillaryMsgCallback) {
  ------------------
  |  Branch (702:11): [True: 0, False: 0]
  ------------------
  703|      0|            (*fn)(ancillaryMessages.asPtr());
  704|      0|          }
  705|      0|        }
  706|       |
  707|      0|        alreadyRead.capCount += nfds;
  708|      0|        fdBuffer += nfds;
  709|      0|        maxFds -= nfds;
  710|      0|      }
  711|      0|    }
  712|       |
  713|      9|    if (false) {
  ------------------
  |  Branch (713:9): [Folded, False: 9]
  ------------------
  714|      0|    error:
  715|      0|      return alreadyRead;
  716|      0|    }
  717|       |
  718|      9|    if (n < 0) {
  ------------------
  |  Branch (718:9): [True: 4, False: 5]
  ------------------
  719|       |      // Read would block.
  720|      4|      return observer.whenBecomesReadable().then([=]() {
  721|      4|        return tryReadInternal(buffer, minBytes, maxBytes, fdBuffer, maxFds, alreadyRead);
  722|      4|      });
  723|      5|    } else if (n == 0) {
  ------------------
  |  Branch (723:16): [True: 1, False: 4]
  ------------------
  724|       |      // EOF -OR- maxBytes == 0.
  725|      1|      return alreadyRead;
  726|      4|    } else if (implicitCast<size_t>(n) >= minBytes) {
  ------------------
  |  Branch (726:16): [True: 4, False: 0]
  ------------------
  727|       |      // We read enough to stop here.
  728|      4|      alreadyRead.byteCount += n;
  729|      4|      return alreadyRead;
  730|      4|    } else {
  731|       |      // The kernel returned fewer bytes than we asked for (and fewer than we need).
  732|       |
  733|      0|      buffer = reinterpret_cast<byte*>(buffer) + n;
  734|      0|      minBytes -= n;
  735|      0|      maxBytes -= n;
  736|      0|      alreadyRead.byteCount += n;
  737|       |
  738|       |      // According to David Klempner, who works on Stubby at Google, we sadly CANNOT assume that
  739|       |      // we've consumed the whole read buffer here. If a signal is delivered in the middle of a
  740|       |      // read() -- yes, even a non-blocking read -- it can cause the kernel to return a partial
  741|       |      // result, with data still in the buffer.
  742|       |      //     https://bugzilla.kernel.org/show_bug.cgi?id=199131
  743|       |      //     https://twitter.com/CaptainSegfault/status/1112622245531144194
  744|       |      //
  745|       |      // Unfortunately, we have no choice but to issue more read()s until it either tells us EOF
  746|       |      // or EAGAIN. We used to have an optimization here using observer.atEndHint() (when it is
  747|       |      // non-null) to avoid a redundant call to read(). Alas...
  748|      0|      return tryReadInternal(buffer, minBytes, maxBytes, fdBuffer, maxFds, alreadyRead);
  749|      0|    }
  750|      9|  }
async-io-unix.c++:_ZZN2kj12_GLOBAL__N_113AsyncStreamFd15tryReadInternalEPvmmPNS_11AutoCloseFdEmNS_21AsyncCapabilityStream10ReadResultEENKUlvE1_clEv:
  720|      5|      return observer.whenBecomesReadable().then([=]() {
  721|      5|        return tryReadInternal(buffer, minBytes, maxBytes, fdBuffer, maxFds, alreadyRead);
  722|      5|      });
async-io-unix.c++:_ZZN2kj12_GLOBAL__N_113AsyncStreamFd7tryReadEPvmmENKUlNS_21AsyncCapabilityStream10ReadResultEE_clES4_:
  159|      5|        .then([](ReadResult r) { return r.byteCount; });
async-io-unix.c++:_ZN2kj12_GLOBAL__N_113AsyncStreamFd13writeInternalENS_8ArrayPtrIKhEENS2_IKS4_EENS2_IKiEE:
  754|      3|                              ArrayPtr<const int> fds) {
  755|      3|    const size_t iovmax = kj::miniposix::iovMax();
  756|       |    // If there are more than IOV_MAX pieces, we'll only write the first IOV_MAX for now, and
  757|       |    // then we'll loop later.
  758|      3|    KJ_STACK_ARRAY(struct iovec, iov, kj::min(1 + morePieces.size(), iovmax), 16, 128);
  ------------------
  |  Branch (758:5): [True: 3, False: 0]
  |  Branch (758:5): [True: 3, False: 0]
  ------------------
  759|      3|    size_t iovTotal = 0;
  760|       |
  761|       |    // writev() interface is not const-correct.  :(
  762|      3|    iov[0].iov_base = const_cast<byte*>(firstPiece.begin());
  763|      3|    iov[0].iov_len = firstPiece.size();
  764|      3|    iovTotal += iov[0].iov_len;
  765|      6|    for (uint i = 1; i < iov.size(); i++) {
  ------------------
  |  Branch (765:22): [True: 3, False: 3]
  ------------------
  766|      3|      iov[i].iov_base = const_cast<byte*>(morePieces[i - 1].begin());
  767|      3|      iov[i].iov_len = morePieces[i - 1].size();
  768|      3|      iovTotal += iov[i].iov_len;
  769|      3|    }
  770|       |
  771|      3|    if (iovTotal == 0) {
  ------------------
  |  Branch (771:9): [True: 0, False: 3]
  ------------------
  772|      0|      KJ_REQUIRE(fds.size() == 0, "can't write FDs without bytes");
  ------------------
  |  Branch (772:7): [True: 0, False: 0]
  ------------------
  773|      0|      return kj::READY_NOW;
  774|      0|    }
  775|       |
  776|      3|    ssize_t n;
  777|      3|    if (fds.size() == 0) {
  ------------------
  |  Branch (777:9): [True: 3, False: 0]
  ------------------
  778|      3|      KJ_NONBLOCKING_SYSCALL(n = ::writev(fd, iov.begin(), iov.size()), iovTotal, iov.size()) {
  ------------------
  |  Branch (778:7): [True: 2, False: 1]
  ------------------
  779|       |        // Error.
  780|       |
  781|       |        // We can't "return kj::READY_NOW;" inside this block because it causes a memory leak due to
  782|       |        // a bug that exists in both Clang and GCC:
  783|       |        //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33799
  784|       |        //   http://llvm.org/bugs/show_bug.cgi?id=12286
  785|      1|        goto error;
  786|      1|      }
  787|      3|    } else {
  788|      0|      struct msghdr msg;
  789|      0|      memset(&msg, 0, sizeof(msg));
  790|      0|      msg.msg_iov = iov.begin();
  791|      0|      msg.msg_iovlen = iov.size();
  792|       |
  793|       |      // Allocate space to send a cmsg.
  794|      0|      size_t msgBytes = CMSG_SPACE(sizeof(int) * fds.size());
  795|       |      // On Linux, CMSG_SPACE will align to a word-size boundary, but on Mac it always aligns to a
  796|       |      // 32-bit boundary. I guess aligning to 32 bits helps avoid the problem where you
  797|       |      // surprisingly end up with space for two file descriptors when you only wanted one. However,
  798|       |      // cmsghdr's preferred alignment is word-size (it contains a size_t). If we stack-allocate
  799|       |      // the buffer, we need to make sure it is aligned properly (maybe not on x64, but maybe on
  800|       |      // other platforms), so we want to allocate an array of words (we use void*). So... we use
  801|       |      // CMSG_SPACE() and then additionally round up to deal with Mac.
  802|      0|      size_t msgWords = (msgBytes + sizeof(void*) - 1) / sizeof(void*);
  803|      0|      KJ_STACK_ARRAY(void*, cmsgSpace, msgWords, 16, 256);
  ------------------
  |  Branch (803:7): [True: 0, False: 0]
  |  Branch (803:7): [True: 0, False: 0]
  ------------------
  804|      0|      auto cmsgBytes = cmsgSpace.asBytes();
  805|      0|      memset(cmsgBytes.begin(), 0, cmsgBytes.size());
  806|      0|      msg.msg_control = cmsgBytes.begin();
  807|      0|      msg.msg_controllen = msgBytes;
  808|       |
  809|      0|      struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
  ------------------
  |  Branch (809:30): [True: 0, False: 0]
  ------------------
  810|      0|      cmsg->cmsg_level = SOL_SOCKET;
  811|      0|      cmsg->cmsg_type = SCM_RIGHTS;
  812|      0|      cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
  813|      0|      memcpy(CMSG_DATA(cmsg), fds.begin(), fds.asBytes().size());
  814|       |
  815|      0|      KJ_NONBLOCKING_SYSCALL(n = ::sendmsg(fd, &msg, 0)) {
  ------------------
  |  Branch (815:7): [True: 0, False: 0]
  ------------------
  816|       |        // Error.
  817|       |
  818|       |        // We can't "return kj::READY_NOW;" inside this block because it causes a memory leak due to
  819|       |        // a bug that exists in both Clang and GCC:
  820|       |        //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33799
  821|       |        //   http://llvm.org/bugs/show_bug.cgi?id=12286
  822|      0|        goto error;
  823|      0|      }
  824|      0|    }
  825|       |
  826|      2|    if (false) {
  ------------------
  |  Branch (826:9): [Folded, False: 2]
  ------------------
  827|      0|    error:
  828|      0|      return kj::READY_NOW;
  829|      0|    }
  830|       |
  831|      2|    if (n < 0) {
  ------------------
  |  Branch (831:9): [True: 0, False: 2]
  ------------------
  832|       |      // Got EAGAIN. Nothing was written.
  833|      0|      return observer.whenBecomesWritable().then([=]() {
  834|      0|        return writeInternal(firstPiece, morePieces, fds);
  835|      0|      });
  836|      2|    } else if (n == 0) {
  ------------------
  |  Branch (836:16): [True: 0, False: 2]
  ------------------
  837|       |      // Why would a sendmsg() with a non-empty message ever return 0 when writing to a stream
  838|       |      // socket? If there's no room in the send buffer, it should fail with EAGAIN. If the
  839|       |      // connection is closed, it should fail with EPIPE. Various documents and forum posts around
  840|       |      // the internet claim this can happen but no one seems to know when. My guess is it can only
  841|       |      // happen if we try to send an empty message -- which we didn't. So I think this is
  842|       |      // impossible. If it is possible, we need to figure out how to correctly handle it, which
  843|       |      // depends on what caused it.
  844|       |      //
  845|       |      // Note in particular that if 0 is a valid return here, and we sent an SCM_RIGHTS message,
  846|       |      // we need to know whether the message was sent or not, in order to decide whether to retry
  847|       |      // sending it!
  848|      0|      KJ_FAIL_ASSERT("non-empty sendmsg() returned 0");
  849|      0|    }
  850|       |
  851|       |    // Non-zero bytes were written. This also implies that *all* FDs were written.
  852|       |
  853|       |    // Discard all data that was written, then issue a new write for what's left (if any).
  854|      4|    for (;;) {
  855|      4|      if (n < firstPiece.size()) {
  ------------------
  |  Branch (855:11): [True: 0, False: 4]
  ------------------
  856|       |        // Only part of the first piece was consumed.  Wait for buffer space and then write again.
  857|      0|        firstPiece = firstPiece.slice(n, firstPiece.size());
  858|      0|        iovTotal -= n;
  859|       |
  860|      0|        if (iovTotal == 0) {
  ------------------
  |  Branch (860:13): [True: 0, False: 0]
  ------------------
  861|       |          // Oops, what actually happened is that we hit the IOV_MAX limit. Don't wait.
  862|      0|          return writeInternal(firstPiece, morePieces, nullptr);
  863|      0|        }
  864|       |
  865|       |        // As with read(), we cannot assume that a short write() really means the write buffer is
  866|       |        // full (see comments in the read path above). We have to write again.
  867|      0|        return writeInternal(firstPiece, morePieces, nullptr);
  868|      4|      } else if (morePieces.size() == 0) {
  ------------------
  |  Branch (868:18): [True: 2, False: 2]
  ------------------
  869|       |        // First piece was fully-consumed and there are no more pieces, so we're done.
  870|      2|        KJ_DASSERT(n == firstPiece.size(), n);
  ------------------
  |  Branch (870:9): [Folded, False: 2]
  ------------------
  871|      2|        return READY_NOW;
  872|      2|      } else {
  873|       |        // First piece was fully consumed, so move on to the next piece.
  874|      2|        n -= firstPiece.size();
  875|      2|        iovTotal -= firstPiece.size();
  876|      2|        firstPiece = morePieces[0];
  877|      2|        morePieces = morePieces.slice(1, morePieces.size());
  878|      2|      }
  879|      4|    }
  880|      2|  }
async-io-unix.c++:_ZN2kj12_GLOBAL__N_113AsyncStreamFdD2Ev:
  155|      3|  virtual ~AsyncStreamFd() noexcept(false) {}
async-io-unix.c++:_ZN2kj12_GLOBAL__N_113AsyncStreamFd5writeENS_8ArrayPtrIKNS2_IKhEEEE:
  219|      3|  Promise<void> write(ArrayPtr<const ArrayPtr<const byte>> pieces) override {
  220|      3|    if (pieces.size() == 0) {
  ------------------
  |  Branch (220:9): [True: 0, False: 3]
  ------------------
  221|      0|      return writeInternal(nullptr, nullptr, nullptr);
  222|      3|    } else {
  223|      3|      return writeInternal(pieces[0], pieces.slice(1, pieces.size()), nullptr);
  224|      3|    }
  225|      3|  }

_ZN2kj16AsyncInputStream4readEPvmm:
   59|      1|Promise<size_t> AsyncInputStream::read(void* buffer, size_t minBytes, size_t maxBytes) {
   60|      1|  return tryRead(buffer, minBytes, maxBytes).then([=](size_t result) {
   61|      1|    if (result >= minBytes) {
   62|      1|      return result;
   63|      1|    } else {
   64|      1|      kj::throwRecoverableException(KJ_EXCEPTION(DISCONNECTED, "stream disconnected prematurely"));
   65|       |      // Pretend we read zeros from the input.
   66|      1|      memset(reinterpret_cast<byte*>(buffer) + result, 0, minBytes - result);
   67|      1|      return minBytes;
   68|      1|    }
   69|      1|  });
   70|      1|}
async-io.c++:_ZZN2kj16AsyncInputStream4readEPvmmENK3$_0clEm:
   60|      2|  return tryRead(buffer, minBytes, maxBytes).then([=](size_t result) {
   61|      2|    if (result >= minBytes) {
  ------------------
  |  Branch (61:9): [True: 2, False: 0]
  ------------------
   62|      2|      return result;
   63|      2|    } else {
   64|      0|      kj::throwRecoverableException(KJ_EXCEPTION(DISCONNECTED, "stream disconnected prematurely"));
   65|       |      // Pretend we read zeros from the input.
   66|      0|      memset(reinterpret_cast<byte*>(buffer) + result, 0, minBytes - result);
   67|      0|      return minBytes;
   68|      0|    }
   69|      2|  });

_ZN2kj13UnixEventPortD2Ev:
  437|      1|UnixEventPort::~UnixEventPort() noexcept(false) {
  438|      1|  if (childSet != nullptr) {
  ------------------
  |  Branch (438:7): [True: 0, False: 1]
  ------------------
  439|       |    // We had claimed the exclusive right to call onChildExit(). Release that right.
  440|      0|    threadClaimedChildExits = false;
  441|      0|  }
  442|      1|}
_ZN2kj13UnixEventPort10FdObserverD2Ev:
  465|      3|UnixEventPort::FdObserver::~FdObserver() noexcept(false) {
  466|      3|  KJ_SYSCALL(epoll_ctl(eventPort.epollFd, EPOLL_CTL_DEL, fd, nullptr)) { break; }
  ------------------
  |  Branch (466:3): [True: 3, False: 0]
  ------------------
  467|      3|}
_ZN2kj13UnixEventPort10FdObserver4fireEs:
  469|      6|void UnixEventPort::FdObserver::fire(short events) {
  470|      6|  if (events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR)) {
  ------------------
  |  Branch (470:7): [True: 5, False: 1]
  ------------------
  471|      5|    if (events & (EPOLLHUP | EPOLLRDHUP)) {
  ------------------
  |  Branch (471:9): [True: 1, False: 4]
  ------------------
  472|      1|      atEnd = true;
  473|      4|    } else {
  474|       |      // Since we didn't receive EPOLLRDHUP, we know that we're not at the end.
  475|      4|      atEnd = false;
  476|      4|    }
  477|       |
  478|      5|    KJ_IF_MAYBE(f, readFulfiller) {
  ------------------
  |  Branch (478:5): [True: 5, False: 0]
  ------------------
  479|      5|      f->get()->fulfill();
  480|      5|      readFulfiller = nullptr;
  481|      5|    }
  482|      5|  }
  483|       |
  484|      6|  if (events & (EPOLLOUT | EPOLLHUP | EPOLLERR)) {
  ------------------
  |  Branch (484:7): [True: 6, False: 0]
  ------------------
  485|      6|    KJ_IF_MAYBE(f, writeFulfiller) {
  ------------------
  |  Branch (485:5): [True: 0, False: 6]
  ------------------
  486|      0|      f->get()->fulfill();
  487|      0|      writeFulfiller = nullptr;
  488|      0|    }
  489|      6|  }
  490|       |
  491|      6|  if (events & (EPOLLHUP | EPOLLERR)) {
  ------------------
  |  Branch (491:7): [True: 1, False: 5]
  ------------------
  492|      1|    KJ_IF_MAYBE(f, hupFulfiller) {
  ------------------
  |  Branch (492:5): [True: 0, False: 1]
  ------------------
  493|      0|      f->get()->fulfill();
  494|      0|      hupFulfiller = nullptr;
  495|      0|    }
  496|      1|  }
  497|       |
  498|      6|  if (events & EPOLLPRI) {
  ------------------
  |  Branch (498:7): [True: 0, False: 6]
  ------------------
  499|      0|    KJ_IF_MAYBE(f, urgentFulfiller) {
  ------------------
  |  Branch (499:5): [True: 0, False: 0]
  ------------------
  500|      0|      f->get()->fulfill();
  501|      0|      urgentFulfiller = nullptr;
  502|      0|    }
  503|      0|  }
  504|      6|}
_ZN2kj13UnixEventPort10FdObserver19whenBecomesReadableEv:
  506|      4|Promise<void> UnixEventPort::FdObserver::whenBecomesReadable() {
  507|      4|  KJ_REQUIRE(flags & OBSERVE_READ, "FdObserver was not set to observe reads.");
  ------------------
  |  Branch (507:3): [True: 4, False: 0]
  ------------------
  508|       |
  509|      4|  auto paf = newPromiseAndFulfiller<void>();
  510|      4|  readFulfiller = kj::mv(paf.fulfiller);
  511|      4|  return kj::mv(paf.promise);
  512|      4|}
_ZN2kj13UnixEventPort4waitEv:
  544|      6|bool UnixEventPort::wait() {
  545|       |#ifdef KJ_DEBUG
  546|       |  // In debug mode, verify the current signal mask matches the original.
  547|       |  {
  548|       |    sigset_t currentMask;
  549|       |    memset(&currentMask, 0, sizeof(currentMask));
  550|       |    KJ_SYSCALL(sigprocmask(0, nullptr, &currentMask));
  551|       |    if (memcmp(&currentMask, &originalMask, sizeof(currentMask)) != 0) {
  552|       |      kj::Vector<kj::String> changes;
  553|       |      for (int i = 0; i <= SIGRTMAX; i++) {
  554|       |        if (sigismember(&currentMask, i) && !sigismember(&originalMask, i)) {
  555|       |          changes.add(kj::str("signal #", i, " (", strsignal(i), ") was added"));
  556|       |        } else if (!sigismember(&currentMask, i) && sigismember(&originalMask, i)) {
  557|       |          changes.add(kj::str("signal #", i, " (", strsignal(i), ") was removed"));
  558|       |        }
  559|       |      }
  560|       |
  561|       |      KJ_FAIL_REQUIRE(
  562|       |          "Signal mask has changed since UnixEventPort was constructed. You are required to "
  563|       |          "ensure that whenever control returns to the event loop, the signal mask is the same "
  564|       |          "as it was when UnixEventPort was created. In non-debug builds, this check is skipped, "
  565|       |          "and this situation may instead lead to unexpected results. In particular, while the "
  566|       |          "system is waiting for I/O events, the signal mask may be reverted to what it was at "
  567|       |          "construction time, ignoring your subsequent changes.", changes);
  568|       |    }
  569|       |  }
  570|       |#endif
  571|       |
  572|      6|  int timeout = timerImpl.timeoutToNextEvent(clock.now(), MILLISECONDS, int(maxValue))
  573|      6|          .map([](uint64_t t) -> int { return t; })
  574|      6|          .orDefault(-1);
  575|       |
  576|      6|  struct epoll_event events[16];
  577|      6|  int n;
  578|      6|  if (signalHead != nullptr || childSet != nullptr) {
  ------------------
  |  Branch (578:7): [True: 0, False: 6]
  |  Branch (578:32): [True: 0, False: 6]
  ------------------
  579|       |    // We are interested in some signals. Use epoll_pwait().
  580|       |    //
  581|       |    // Note: Once upon a time, we used signalfd for this. However, this turned out to be more
  582|       |    // trouble than it was worth. Some problems with signalfd:
  583|       |    // - It required opening an additional file descriptor per thread.
  584|       |    // - If the set of interesting signals changed, the signalfd would have to be updated before
  585|       |    //   calling epoll_wait(), which was an extra syscall.
  586|       |    // - When a signal arrives, it requires extra syscalls to read the signal info from the
  587|       |    //   signalfd, as well as code to translate from signalfd_siginfo to siginfo_t, which are
  588|       |    //   different for some reason.
  589|       |    // - signalfd suffers from surprising lock contention during epoll_wait or when the signalfd's
  590|       |    //   mask is updated in programs with many threads. Because the lock is a spinlock, this
  591|       |    //   could consume exorbitant CPU.
  592|       |    // - When a signalfd is in an epoll, it will be flagged readable based on signals which are
  593|       |    //   pending in the process/thread which called epoll_ctl_add() to register the signalfd.
  594|       |    //   This is mostly fine for our usage, except that it breaks one useful case that otherwise
  595|       |    //   works: many servers are designed to "daemonize" themselves by fork()ing and then having
  596|       |    //   the parent process exit while the child thread lives on. In this case, if a UnixEventPort
  597|       |    //   had been created before daemonizing, signal handling would be forever broken in the child.
  598|       |
  599|      0|    sigset_t waitMask = originalMask;
  600|       |
  601|       |    // Unblock the signals we care about.
  602|      0|    {
  603|      0|      auto ptr = signalHead;
  604|      0|      while (ptr != nullptr) {
  ------------------
  |  Branch (604:14): [True: 0, False: 0]
  ------------------
  605|      0|        KJ_SYSCALL(sigdelset(&waitMask, ptr->signum));
  ------------------
  |  Branch (605:9): [True: 0, False: 0]
  ------------------
  606|      0|        ptr = ptr->next;
  607|      0|      }
  608|      0|      if (childSet != nullptr) {
  ------------------
  |  Branch (608:11): [True: 0, False: 0]
  ------------------
  609|      0|        KJ_SYSCALL(sigdelset(&waitMask, SIGCHLD));
  ------------------
  |  Branch (609:9): [True: 0, False: 0]
  ------------------
  610|      0|      }
  611|      0|    }
  612|       |
  613|      0|    threadEventPort = this;
  614|      0|    n = epoll_pwait(epollFd, events, kj::size(events), timeout, &waitMask);
  615|      0|    threadEventPort = nullptr;
  616|      6|  } else {
  617|       |    // Not waiting on any signals. Regular epoll_wait() will be fine.
  618|      6|    n = epoll_wait(epollFd, events, kj::size(events), timeout);
  619|      6|  }
  620|       |
  621|      6|  if (n < 0) {
  ------------------
  |  Branch (621:7): [True: 0, False: 6]
  ------------------
  622|      0|    int error = errno;
  623|      0|    if (error == EINTR) {
  ------------------
  |  Branch (623:9): [True: 0, False: 0]
  ------------------
  624|       |      // We received a singal. The signal handler may have queued an event to the event loop. Even
  625|       |      // if it didn't, we can't simply restart the epoll call because we need to recompute the
  626|       |      // timeout. Instead, we pretend epoll_wait() returned zero events. This will cause the event
  627|       |      // loop to spin once, decide it has nothing to do, recompute timeouts, then return to waiting.
  628|      0|      n = 0;
  629|      0|    } else {
  630|      0|      KJ_FAIL_SYSCALL("epoll_pwait()", error);
  631|      0|    }
  632|      0|  }
  633|       |
  634|      6|  return processEpollEvents(events, n);
  635|      6|}
_ZN2kj13UnixEventPort18processEpollEventsEP11epoll_eventi:
  637|      6|bool UnixEventPort::processEpollEvents(struct epoll_event events[], int n) {
  638|      6|  bool woken = false;
  639|       |
  640|     12|  for (int i = 0; i < n; i++) {
  ------------------
  |  Branch (640:19): [True: 6, False: 6]
  ------------------
  641|      6|    if (events[i].data.u64 == 0) {
  ------------------
  |  Branch (641:9): [True: 0, False: 6]
  ------------------
  642|       |      // Someone called wake() from another thread. Consume the event.
  643|      0|      uint64_t value;
  644|      0|      ssize_t n;
  645|      0|      KJ_NONBLOCKING_SYSCALL(n = read(eventFd, &value, sizeof(value)));
  ------------------
  |  Branch (645:7): [True: 0, False: 0]
  ------------------
  646|      0|      KJ_ASSERT(n < 0 || n == sizeof(value));
  ------------------
  |  Branch (646:7): [True: 0, False: 0]
  ------------------
  647|       |
  648|       |      // We were woken. Need to return true.
  649|      0|      woken = true;
  650|      6|    } else {
  651|      6|      FdObserver* observer = reinterpret_cast<FdObserver*>(events[i].data.ptr);
  652|      6|      observer->fire(events[i].events);
  653|      6|    }
  654|      6|  }
  655|       |
  656|      6|  timerImpl.advanceTo(clock.now());
  657|       |
  658|      6|  return woken;
  659|      6|}

_ZN2kj11AsyncObjectD2Ev:
  123|    295|AsyncObject::~AsyncObject() {
  124|    295|  if (disallowAsyncDestructorsScope != nullptr) {
  ------------------
  |  Branch (124:7): [True: 0, False: 295]
  ------------------
  125|       |    // If we try to do the KJ_FAIL_REQUIRE here (declaring `~AsyncObject()` itself to be noexcept),
  126|       |    // it seems to have a non-negligible performance impact in the HTTP benchmark. My guess is that
  127|       |    // it's because it breaks inlining of `~AsyncObject()` into various subclass destructors that
  128|       |    // are defined inside this file, which are some of the biggest ones. By forcing the actual
  129|       |    // failure code out into a separate function we get a little performance boost.
  130|      0|    failed();
  131|      0|  }
  132|    295|}
_ZN2kj8CancelerD2Ev:
  208|      6|Canceler::~Canceler() noexcept(false) {
  209|      6|  if (isEmpty()) return;
  ------------------
  |  Branch (209:7): [True: 6, False: 0]
  ------------------
  210|      0|  cancel(getDestructionReason(
  211|      0|      reinterpret_cast<void*>(&END_CANCELER_STACK_START_CANCELEE_STACK),
  212|      0|      Exception::Type::DISCONNECTED, __FILE__, __LINE__, "operation canceled"_kj));
  213|      0|}
_ZN2kj8Canceler6cancelENS_9StringPtrE:
  215|      2|void Canceler::cancel(StringPtr cancelReason) {
  216|      2|  if (isEmpty()) return;
  ------------------
  |  Branch (216:7): [True: 2, False: 0]
  ------------------
  217|       |  // We can't use getDestructionReason() here because if an exception is in-flight, it would use
  218|       |  // that exception, totally discarding the reason given by the caller. This would probably be
  219|       |  // unexpected. The caller can always use getDestructionReason() themselves if desired.
  220|      0|  cancel(Exception(Exception::Type::DISCONNECTED, __FILE__, __LINE__, kj::str(cancelReason)));
  221|      0|}
_ZN2kj8Canceler6cancelERKNS_9ExceptionE:
  223|      2|void Canceler::cancel(const Exception& exception) {
  224|      2|  for (;;) {
  225|      2|    KJ_IF_MAYBE(a, list) {
  ------------------
  |  Branch (225:5): [True: 0, False: 2]
  ------------------
  226|      0|      a->unlink();
  227|      0|      a->cancel(kj::cp(exception));
  228|      2|    } else {
  229|      2|      break;
  230|      2|    }
  231|      2|  }
  232|      2|}
_ZN2kj8Canceler11AdapterBaseC2ERS0_:
  245|      6|    : prev(canceler.list),
  246|      6|      next(canceler.list) {
  247|      6|  canceler.list = *this;
  248|      6|  KJ_IF_MAYBE(n, next) {
  ------------------
  |  Branch (248:3): [True: 0, False: 6]
  ------------------
  249|      0|    n->prev = next;
  250|      0|  }
  251|      6|}
_ZN2kj8Canceler11AdapterBaseD2Ev:
  253|      8|Canceler::AdapterBase::~AdapterBase() noexcept(false) {
  254|      8|  unlink();
  255|      8|}
_ZN2kj8Canceler11AdapterBase6unlinkEv:
  257|      8|void Canceler::AdapterBase::unlink() {
  258|      8|  KJ_IF_MAYBE(p, prev) {
  ------------------
  |  Branch (258:3): [True: 8, False: 0]
  ------------------
  259|      8|    *p = next;
  260|      8|  }
  261|      8|  KJ_IF_MAYBE(n, next) {
  ------------------
  |  Branch (261:3): [True: 0, False: 8]
  ------------------
  262|      0|    n->prev = prev;
  263|      0|  }
  264|      8|  next = nullptr;
  265|      8|  prev = nullptr;
  266|      8|}
_ZN2kj7TaskSetD2Ev:
  362|      8|TaskSet::~TaskSet() noexcept(false) {
  363|       |  // You could argue it is dubious, but some applications would like for the destructor of a
  364|       |  // task to be able to schedule new tasks. So when we cancel our tasks... we might find new
  365|       |  // tasks added! We'll have to repeatedly cancel. Additionally, we need to make sure that we destroy
  366|       |  // the items in a loop to prevent any issues with stack overflow.
  367|      9|  while (tasks != nullptr) {
  ------------------
  |  Branch (367:10): [True: 1, False: 8]
  ------------------
  368|       |    auto removed = KJ_REQUIRE_NONNULL(tasks)->pop();
  ------------------
  |  Branch (368:20): [True: 0, False: 1]
  ------------------
  369|      1|  }
  370|      8|}
_ZN2kj7TaskSet3addEONS_7PromiseIvEE:
  372|      6|void TaskSet::add(Promise<void>&& promise) {
  373|      6|  auto task = _::appendPromise<Task>(_::PromiseNode::from(kj::mv(promise)), *this);
  374|      6|  KJ_IF_MAYBE(head, tasks) {
  ------------------
  |  Branch (374:3): [True: 5, False: 1]
  ------------------
  375|      5|    head->get()->prev = &task->next;
  376|      5|    task->next = kj::mv(tasks);
  377|      5|  }
  378|      6|  task->prev = &tasks;
  379|      6|  tasks = kj::mv(task);
  380|      6|}
_ZN2kj7TaskSet5clearEv:
  414|      2|void TaskSet::clear() {
  415|      2|  tasks = nullptr;
  416|       |
  417|      2|  KJ_IF_MAYBE(fulfiller, emptyFulfiller) {
  ------------------
  |  Branch (417:3): [True: 0, False: 2]
  ------------------
  418|      0|    fulfiller->get()->fulfill();
  419|      0|  }
  420|      2|}
_ZN2kj9EventPort11setRunnableEb:
 1716|      3|void EventPort::setRunnable(bool runnable) {}
_ZN2kj9EventLoopD2Ev:
 1730|      1|EventLoop::~EventLoop() noexcept(false) {
 1731|       |  // Destroy all "daemon" tasks, noting that their destructors might register more daemon tasks.
 1732|      1|  while (!daemons->isEmpty()) {
  ------------------
  |  Branch (1732:10): [True: 0, False: 1]
  ------------------
 1733|      0|    auto oldDaemons = kj::mv(daemons);
 1734|      0|    daemons = kj::heap<TaskSet>(_::LoggingErrorHandler::instance);
 1735|      0|  }
 1736|      1|  daemons = nullptr;
 1737|       |
 1738|      1|  KJ_IF_MAYBE(e, executor) {
  ------------------
  |  Branch (1738:3): [True: 0, False: 1]
  ------------------
 1739|       |    // Cancel all outstanding cross-thread events.
 1740|      0|    e->get()->impl->disconnect();
 1741|      0|  }
 1742|       |
 1743|       |  // The application _should_ destroy everything using the EventLoop before destroying the
 1744|       |  // EventLoop itself, so if there are events on the loop, this indicates a memory leak.
 1745|      1|  KJ_REQUIRE(head == nullptr, "EventLoop destroyed with events still in the queue.  Memory leak?",
  ------------------
  |  Branch (1745:3): [True: 1, False: 0]
  ------------------
 1746|      0|             head->traceEvent()) {
 1747|       |    // Unlink all the events and hope that no one ever fires them...
 1748|      0|    _::Event* event = head;
 1749|      0|    while (event != nullptr) {
  ------------------
  |  Branch (1749:12): [True: 0, False: 0]
  ------------------
 1750|      0|      _::Event* next = event->next;
 1751|      0|      event->next = nullptr;
 1752|      0|      event->prev = nullptr;
 1753|      0|      event = next;
 1754|      0|    }
 1755|      0|    break;
 1756|      0|  }
 1757|       |
 1758|      1|  KJ_REQUIRE(threadLocalEventLoop != this,
  ------------------
  |  Branch (1758:3): [True: 1, False: 0]
  ------------------
 1759|      0|             "EventLoop destroyed while still current for the thread.") {
 1760|      0|    threadLocalEventLoop = nullptr;
 1761|      0|    break;
 1762|      0|  }
 1763|      1|}
_ZN2kj9EventLoop4turnEv:
 1778|     52|bool EventLoop::turn() {
 1779|     52|  _::Event* event = head;
 1780|       |
 1781|     52|  if (event == nullptr) {
  ------------------
  |  Branch (1781:7): [True: 6, False: 46]
  ------------------
 1782|       |    // No events in the queue.
 1783|      6|    return false;
 1784|     46|  } else {
 1785|     46|    head = event->next;
 1786|     46|    if (head != nullptr) {
  ------------------
  |  Branch (1786:9): [True: 14, False: 32]
  ------------------
 1787|     14|      head->prev = &head;
 1788|     14|    }
 1789|       |
 1790|     46|    depthFirstInsertPoint = &head;
 1791|     46|    if (breadthFirstInsertPoint == &event->next) {
  ------------------
  |  Branch (1791:9): [True: 32, False: 14]
  ------------------
 1792|     32|      breadthFirstInsertPoint = &head;
 1793|     32|    }
 1794|     46|    if (tail == &event->next) {
  ------------------
  |  Branch (1794:9): [True: 32, False: 14]
  ------------------
 1795|     32|      tail = &head;
 1796|     32|    }
 1797|       |
 1798|     46|    event->next = nullptr;
 1799|     46|    event->prev = nullptr;
 1800|       |
 1801|     46|    Maybe<Own<_::Event>> eventToDestroy;
 1802|     46|    {
 1803|     46|      event->firing = true;
 1804|     46|      KJ_DEFER(event->firing = false);
 1805|     46|      currentlyFiring = event;
 1806|     46|      KJ_DEFER(currentlyFiring = nullptr);
 1807|     46|      eventToDestroy = event->fire();
 1808|     46|    }
 1809|       |
 1810|     46|    depthFirstInsertPoint = &head;
 1811|     46|    return true;
 1812|     46|  }
 1813|     52|}
_ZN2kj9EventLoop10isRunnableEv:
 1815|      2|bool EventLoop::isRunnable() {
 1816|      2|  return head != nullptr;
 1817|      2|}
_ZN2kj9EventLoop11setRunnableEb:
 1827|     51|void EventLoop::setRunnable(bool runnable) {
 1828|     51|  if (runnable != lastRunnableState) {
  ------------------
  |  Branch (1828:7): [True: 3, False: 48]
  ------------------
 1829|      3|    KJ_IF_MAYBE(p, port) {
  ------------------
  |  Branch (1829:5): [True: 3, False: 0]
  ------------------
 1830|      3|      p->setRunnable(runnable);
 1831|      3|    }
 1832|      3|    lastRunnableState = runnable;
 1833|      3|  }
 1834|     51|}
_ZN2kj9EventLoop10leaveScopeEv:
 1841|      1|void EventLoop::leaveScope() {
 1842|      1|  KJ_REQUIRE(threadLocalEventLoop == this,
  ------------------
  |  Branch (1842:3): [True: 1, False: 0]
  ------------------
 1843|      0|             "WaitScope destroyed in a different thread than it was created in.") {
 1844|      0|    break;
 1845|      0|  }
 1846|      1|  threadLocalEventLoop = nullptr;
 1847|      1|}
_ZN2kj9EventLoop4waitEv:
 1849|      6|void EventLoop::wait() {
 1850|      6|  KJ_IF_MAYBE(p, port) {
  ------------------
  |  Branch (1850:3): [True: 6, False: 0]
  ------------------
 1851|      6|    if (p->wait()) {
  ------------------
  |  Branch (1851:9): [True: 0, False: 6]
  ------------------
 1852|       |      // Another thread called wake(). Check for cross-thread events.
 1853|      0|      KJ_IF_MAYBE(e, executor) {
  ------------------
  |  Branch (1853:7): [True: 0, False: 0]
  ------------------
 1854|      0|        e->get()->poll();
 1855|      0|      }
 1856|      0|    }
 1857|      6|  } else KJ_IF_MAYBE(e, executor) {
  ------------------
  |  Branch (1857:10): [True: 0, False: 0]
  ------------------
 1858|      0|    e->get()->wait();
 1859|      0|  } else {
 1860|      0|    KJ_FAIL_REQUIRE("Nothing to wait for; this thread would hang forever.");
 1861|      0|  }
 1862|      6|}
_ZN2kj1_8waitImplEONS_3OwnINS0_11PromiseNodeENS0_15PromiseDisposerEEERNS0_16ExceptionOrValueERNS_9WaitScopeENS_14SourceLocationE:
 1925|      1|              SourceLocation location) {
 1926|      1|  EventLoop& loop = waitScope.loop;
 1927|      1|  KJ_REQUIRE(&loop == threadLocalEventLoop, "WaitScope not valid for this thread.");
  ------------------
  |  Branch (1927:3): [True: 1, False: 0]
  ------------------
 1928|       |
 1929|      1|#if !KJ_NO_EXCEPTIONS
 1930|       |  // we don't support fibers when running without exceptions, so just remove the whole block
 1931|      1|  KJ_IF_MAYBE(fiber, waitScope.fiber) {
  ------------------
  |  Branch (1931:3): [True: 0, False: 1]
  ------------------
 1932|      0|    if (fiber->state == FiberBase::CANCELED) {
  ------------------
  |  Branch (1932:9): [True: 0, False: 0]
  ------------------
 1933|      0|      throw fiberCanceledException();
 1934|      0|    }
 1935|      0|    KJ_REQUIRE(fiber->state == FiberBase::RUNNING,
  ------------------
  |  Branch (1935:5): [True: 0, False: 0]
  ------------------
 1936|      0|        "This WaitScope can only be used within the fiber that created it.");
 1937|       |
 1938|      0|    node->setSelfPointer(&node);
 1939|      0|    node->onReady(fiber);
 1940|       |
 1941|      0|    fiber->currentInner = node;
 1942|      0|    KJ_DEFER(fiber->currentInner = nullptr);
 1943|       |
 1944|       |    // Switch to the main stack to run the event loop.
 1945|      0|    fiber->state = FiberBase::WAITING;
 1946|      0|    fiber->stack->switchToMain();
 1947|       |
 1948|       |    // The main stack switched back to us, meaning either the event we registered with
 1949|       |    // node->onReady() fired, or we are being canceled by FiberBase's destructor.
 1950|       |
 1951|      0|    if (fiber->state == FiberBase::CANCELED) {
  ------------------
  |  Branch (1951:9): [True: 0, False: 0]
  ------------------
 1952|      0|      throw fiberCanceledException();
 1953|      0|    }
 1954|       |
 1955|      0|    KJ_ASSERT(fiber->state == FiberBase::RUNNING);
  ------------------
  |  Branch (1955:5): [True: 0, False: 0]
  ------------------
 1956|      1|  } else {
 1957|      1|#endif
 1958|      1|    KJ_REQUIRE(!loop.running, "wait() is not allowed from within event callbacks.");
  ------------------
  |  Branch (1958:5): [True: 1, False: 0]
  ------------------
 1959|       |
 1960|      1|    RootEvent doneEvent(node, reinterpret_cast<void*>(&waitImpl), location);
 1961|      1|    node->setSelfPointer(&node);
 1962|      1|    node->onReady(&doneEvent);
 1963|       |
 1964|      1|    loop.running = true;
 1965|      1|    KJ_DEFER(loop.running = false);
 1966|       |
 1967|      7|    for (;;) {
 1968|      7|      waitScope.runOnStackPool([&]() {
 1969|      7|        uint counter = 0;
 1970|      7|        while (!doneEvent.fired) {
 1971|      7|          if (!loop.turn()) {
 1972|       |            // No events in the queue.  Wait for callback.
 1973|      7|            return;
 1974|      7|          } else if (++counter > waitScope.busyPollInterval) {
 1975|       |            // Note: It's intentional that if busyPollInterval is kj::maxValue, we never poll.
 1976|      7|            counter = 0;
 1977|      7|            loop.poll();
 1978|      7|          }
 1979|      7|        }
 1980|      7|      });
 1981|       |
 1982|      7|      if (doneEvent.fired) {
  ------------------
  |  Branch (1982:11): [True: 2, False: 5]
  ------------------
 1983|      2|        break;
 1984|      5|      } else {
 1985|      5|        loop.wait();
 1986|      5|      }
 1987|      7|    }
 1988|       |
 1989|      1|    loop.setRunnable(loop.isRunnable());
 1990|      1|#if !KJ_NO_EXCEPTIONS
 1991|      1|  }
 1992|      1|#endif
 1993|       |
 1994|      1|  waitScope.runOnStackPool([&]() {
 1995|      1|    node->get(result);
 1996|      1|    KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
 1997|      1|      node = nullptr;
 1998|      1|    })) {
 1999|      1|      result.addException(kj::mv(*exception));
 2000|      1|    }
 2001|      1|  });
 2002|      1|}
_ZN2kj1_5yieldEv:
 2040|      7|Promise<void> yield() {
 2041|      7|  class YieldPromiseNode final: public _::PromiseNode {
 2042|      7|  public:
 2043|      7|    void destroy() override {}
 2044|       |
 2045|      7|    void onReady(_::Event* event) noexcept override {
 2046|      7|      if (event) event->armBreadthFirst();
 2047|      7|    }
 2048|      7|    void get(_::ExceptionOrValue& output) noexcept override {
 2049|      7|      output.as<_::Void>() = _::Void();
 2050|      7|    }
 2051|      7|    void tracePromise(_::TraceBuilder& builder, bool stopAtNextEvent) override {
 2052|      7|      builder.add(reinterpret_cast<void*>(&kj::evalLater<DummyFunctor>));
 2053|      7|    }
 2054|      7|  };
 2055|       |
 2056|      7|  static YieldPromiseNode NODE;
 2057|      7|  return _::PromiseNode::to<Promise<void>>(OwnPromiseNode(&NODE));
 2058|      7|}
_ZN2kj1_11yieldHarderEv:
 2060|      3|Promise<void> yieldHarder() {
 2061|      3|  class YieldHarderPromiseNode final: public _::PromiseNode {
 2062|      3|  public:
 2063|      3|    void destroy() override {}
 2064|       |
 2065|      3|    void onReady(_::Event* event) noexcept override {
 2066|      3|      if (event) event->armLast();
 2067|      3|    }
 2068|      3|    void get(_::ExceptionOrValue& output) noexcept override {
 2069|      3|      output.as<_::Void>() = _::Void();
 2070|      3|    }
 2071|      3|    void tracePromise(_::TraceBuilder& builder, bool stopAtNextEvent) override {
 2072|      3|      builder.add(reinterpret_cast<void*>(&kj::evalLast<DummyFunctor>));
 2073|      3|    }
 2074|      3|  };
 2075|       |
 2076|      3|  static YieldHarderPromiseNode NODE;
 2077|      3|  return _::PromiseNode::to<Promise<void>>(OwnPromiseNode(&NODE));
 2078|      3|}
_ZN2kj1_8readyNowEv:
 2080|      3|OwnPromiseNode readyNow() {
 2081|      3|  class ReadyNowPromiseNode: public ImmediatePromiseNodeBase {
 2082|       |    // This is like `ConstPromiseNode<Void, Void{}>`, but the compiler won't let me pass a literal
 2083|       |    // value of type `Void` as a template parameter. (Might require C++20?)
 2084|       |
 2085|      3|  public:
 2086|      3|    void destroy() override {}
 2087|      3|    void get(ExceptionOrValue& output) noexcept override {
 2088|      3|      output.as<Void>() = Void();
 2089|      3|    }
 2090|      3|  };
 2091|       |
 2092|      3|  static ReadyNowPromiseNode NODE;
 2093|      3|  return OwnPromiseNode(&NODE);
 2094|      3|}
_ZN2kj1_5EventC2ENS_14SourceLocationE:
 2129|     41|    : loop(currentEventLoop()), next(nullptr), prev(nullptr), location(location) {}
_ZN2kj1_5EventD2Ev:
 2134|     63|Event::~Event() noexcept(false) {
 2135|     63|  live = 0;
 2136|       |
 2137|       |  // Prevent compiler from eliding this store above. This line probably isn't needed because there
 2138|       |  // are complex calls later in this destructor, and the compiler probably can't prove that they
 2139|       |  // won't come back and examine `live`, so it won't elide the write anyway. However, an
 2140|       |  // atomic_signal_fence is also sufficient to tell the compiler that a signal handler might access
 2141|       |  // `live`, so it won't optimize away the write. Note that a signal fence does not produce
 2142|       |  // any instructions, it just blocks compiler optimizations.
 2143|     63|  std::atomic_signal_fence(std::memory_order_acq_rel);
 2144|       |
 2145|     63|  disarm();
 2146|       |
 2147|     63|  KJ_REQUIRE(!firing, "Promise callback destroyed itself.");
  ------------------
  |  Branch (2147:3): [True: 63, False: 0]
  ------------------
 2148|     63|}
_ZN2kj1_5Event13armDepthFirstEv:
 2150|     19|void Event::armDepthFirst() {
 2151|     19|  KJ_REQUIRE(threadLocalEventLoop == &loop || threadLocalEventLoop == nullptr,
  ------------------
  |  Branch (2151:3): [True: 19, False: 0]
  ------------------
 2152|      0|             "Event armed from different thread than it was created in.  You must use "
 2153|      0|             "Executor to queue events cross-thread.");
 2154|     19|  if (live != MAGIC_LIVE_VALUE) {
  ------------------
  |  Branch (2154:7): [True: 0, False: 19]
  ------------------
 2155|      0|    ([this]() noexcept {
 2156|      0|      KJ_FAIL_ASSERT("tried to arm Event after it was destroyed", location);
 2157|      0|    })();
 2158|      0|  }
 2159|       |
 2160|     19|  if (prev == nullptr) {
  ------------------
  |  Branch (2160:7): [True: 19, False: 0]
  ------------------
 2161|     19|    next = *loop.depthFirstInsertPoint;
 2162|     19|    prev = loop.depthFirstInsertPoint;
 2163|     19|    *prev = this;
 2164|     19|    if (next != nullptr) {
  ------------------
  |  Branch (2164:9): [True: 4, False: 15]
  ------------------
 2165|      4|      next->prev = &next;
 2166|      4|    }
 2167|       |
 2168|     19|    loop.depthFirstInsertPoint = &next;
 2169|       |
 2170|     19|    if (loop.breadthFirstInsertPoint == prev) {
  ------------------
  |  Branch (2170:9): [True: 15, False: 4]
  ------------------
 2171|     15|      loop.breadthFirstInsertPoint = &next;
 2172|     15|    }
 2173|     19|    if (loop.tail == prev) {
  ------------------
  |  Branch (2173:9): [True: 15, False: 4]
  ------------------
 2174|     15|      loop.tail = &next;
 2175|     15|    }
 2176|       |
 2177|     19|    loop.setRunnable(true);
 2178|     19|  }
 2179|     19|}
_ZN2kj1_5Event15armBreadthFirstEv:
 2181|     27|void Event::armBreadthFirst() {
 2182|     27|  KJ_REQUIRE(threadLocalEventLoop == &loop || threadLocalEventLoop == nullptr,
  ------------------
  |  Branch (2182:3): [True: 27, False: 0]
  ------------------
 2183|      0|             "Event armed from different thread than it was created in.  You must use "
 2184|      0|             "Executor to queue events cross-thread.");
 2185|     27|  if (live != MAGIC_LIVE_VALUE) {
  ------------------
  |  Branch (2185:7): [True: 0, False: 27]
  ------------------
 2186|      0|    ([this]() noexcept {
 2187|      0|      KJ_FAIL_ASSERT("tried to arm Event after it was destroyed", location);
 2188|      0|    })();
 2189|      0|  }
 2190|       |
 2191|     27|  if (prev == nullptr) {
  ------------------
  |  Branch (2191:7): [True: 27, False: 0]
  ------------------
 2192|     27|    next = *loop.breadthFirstInsertPoint;
 2193|     27|    prev = loop.breadthFirstInsertPoint;
 2194|     27|    *prev = this;
 2195|     27|    if (next != nullptr) {
  ------------------
  |  Branch (2195:9): [True: 1, False: 26]
  ------------------
 2196|      1|      next->prev = &next;
 2197|      1|    }
 2198|       |
 2199|     27|    loop.breadthFirstInsertPoint = &next;
 2200|       |
 2201|     27|    if (loop.tail == prev) {
  ------------------
  |  Branch (2201:9): [True: 26, False: 1]
  ------------------
 2202|     26|      loop.tail = &next;
 2203|     26|    }
 2204|       |
 2205|     27|    loop.setRunnable(true);
 2206|     27|  }
 2207|     27|}
_ZN2kj1_5Event7armLastEv:
 2209|      3|void Event::armLast() {
 2210|      3|  KJ_REQUIRE(threadLocalEventLoop == &loop || threadLocalEventLoop == nullptr,
  ------------------
  |  Branch (2210:3): [True: 3, False: 0]
  ------------------
 2211|      0|             "Event armed from different thread than it was created in.  You must use "
 2212|      0|             "Executor to queue events cross-thread.");
 2213|      3|  if (live != MAGIC_LIVE_VALUE) {
  ------------------
  |  Branch (2213:7): [True: 0, False: 3]
  ------------------
 2214|      0|    ([this]() noexcept {
 2215|      0|      KJ_FAIL_ASSERT("tried to arm Event after it was destroyed", location);
 2216|      0|    })();
 2217|      0|  }
 2218|       |
 2219|      3|  if (prev == nullptr) {
  ------------------
  |  Branch (2219:7): [True: 3, False: 0]
  ------------------
 2220|      3|    next = *loop.breadthFirstInsertPoint;
 2221|      3|    prev = loop.breadthFirstInsertPoint;
 2222|      3|    *prev = this;
 2223|      3|    if (next != nullptr) {
  ------------------
  |  Branch (2223:9): [True: 0, False: 3]
  ------------------
 2224|      0|      next->prev = &next;
 2225|      0|    }
 2226|       |
 2227|       |    // We don't update loop.breadthFirstInsertPoint because we want further inserts to go *before*
 2228|       |    // this event.
 2229|       |
 2230|      3|    if (loop.tail == prev) {
  ------------------
  |  Branch (2230:9): [True: 3, False: 0]
  ------------------
 2231|      3|      loop.tail = &next;
 2232|      3|    }
 2233|       |
 2234|      3|    loop.setRunnable(true);
 2235|      3|  }
 2236|      3|}
_ZN2kj1_5Event6disarmEv:
 2242|     63|void Event::disarm() {
 2243|     63|  if (prev != nullptr) {
  ------------------
  |  Branch (2243:7): [True: 3, False: 60]
  ------------------
 2244|      3|    if (threadLocalEventLoop != &loop && threadLocalEventLoop != nullptr) {
  ------------------
  |  Branch (2244:9): [True: 0, False: 3]
  |  Branch (2244:42): [True: 0, False: 0]
  ------------------
 2245|      0|      KJ_LOG(FATAL, "Promise destroyed from a different thread than it was created in.");
  ------------------
  |  Branch (2245:7): [True: 0, False: 0]
  ------------------
 2246|       |      // There's no way out of this place without UB, so abort now.
 2247|      0|      abort();
 2248|      0|    }
 2249|       |
 2250|      3|    if (loop.tail == &next) {
  ------------------
  |  Branch (2250:9): [True: 2, False: 1]
  ------------------
 2251|      2|      loop.tail = prev;
 2252|      2|    }
 2253|      3|    if (loop.depthFirstInsertPoint == &next) {
  ------------------
  |  Branch (2253:9): [True: 1, False: 2]
  ------------------
 2254|      1|      loop.depthFirstInsertPoint = prev;
 2255|      1|    }
 2256|      3|    if (loop.breadthFirstInsertPoint == &next) {
  ------------------
  |  Branch (2256:9): [True: 2, False: 1]
  ------------------
 2257|      2|      loop.breadthFirstInsertPoint = prev;
 2258|      2|    }
 2259|       |
 2260|      3|    *prev = next;
 2261|      3|    if (next != nullptr) {
  ------------------
  |  Branch (2261:9): [True: 1, False: 2]
  ------------------
 2262|      1|      next->prev = prev;
 2263|      1|    }
 2264|       |
 2265|      3|    prev = nullptr;
 2266|      3|    next = nullptr;
 2267|      3|  }
 2268|     63|}
_ZN2kj1_11PromiseNode14setSelfPointerEPNS_3OwnIS1_NS0_15PromiseDisposerEEE:
 2312|    105|void PromiseNode::setSelfPointer(OwnPromiseNode* selfPtr) noexcept {}
_ZN2kj1_11PromiseNode12OnReadyEvent4initEPNS0_5EventE:
 2314|     15|void PromiseNode::OnReadyEvent::init(Event* newEvent) {
 2315|     15|  if (event == _kJ_ALREADY_READY) {
  ------------------
  |  |  166|     15|#define _kJ_ALREADY_READY reinterpret_cast< ::kj::_::Event*>(1)
  ------------------
  |  Branch (2315:7): [True: 3, False: 12]
  ------------------
 2316|       |    // A new continuation was added to a promise that was already ready.  In this case, we schedule
 2317|       |    // breadth-first, to make it difficult for applications to accidentally starve the event loop
 2318|       |    // by repeatedly waiting on immediate promises.
 2319|      3|    if (newEvent) newEvent->armBreadthFirst();
  ------------------
  |  Branch (2319:9): [True: 3, False: 0]
  ------------------
 2320|     12|  } else {
 2321|     12|    event = newEvent;
 2322|     12|  }
 2323|     15|}
_ZN2kj1_11PromiseNode12OnReadyEvent3armEv:
 2325|     27|void PromiseNode::OnReadyEvent::arm() {
 2326|     27|  KJ_ASSERT(event != _kJ_ALREADY_READY, "arm() should only be called once");
  ------------------
  |  Branch (2326:3): [True: 27, False: 0]
  ------------------
 2327|       |
 2328|     27|  if (event != nullptr) {
  ------------------
  |  Branch (2328:7): [True: 19, False: 8]
  ------------------
 2329|       |    // A promise resolved and an event is already waiting on it.  In this case, arm in depth-first
 2330|       |    // order so that the event runs immediately after the current one.  This way, chained promises
 2331|       |    // execute together for better cache locality and lower latency.
 2332|     19|    event->armDepthFirst();
 2333|     19|  }
 2334|       |
 2335|     27|  event = _kJ_ALREADY_READY;
  ------------------
  |  |  166|     27|#define _kJ_ALREADY_READY reinterpret_cast< ::kj::_::Event*>(1)
  ------------------
 2336|     27|}
_ZN2kj1_24ImmediatePromiseNodeBaseC2Ev:
 2351|     13|ImmediatePromiseNodeBase::ImmediatePromiseNodeBase() {}
_ZN2kj1_24ImmediatePromiseNodeBaseD2Ev:
 2352|     14|ImmediatePromiseNodeBase::~ImmediatePromiseNodeBase() noexcept(false) {}
_ZN2kj1_24ImmediatePromiseNodeBase7onReadyEPNS0_5EventE:
 2354|     17|void ImmediatePromiseNodeBase::onReady(Event* event) noexcept {
 2355|     17|  if (event) event->armBreadthFirst();
  ------------------
  |  Branch (2355:7): [True: 17, False: 0]
  ------------------
 2356|     17|}
_ZN2kj1_26ImmediateBrokenPromiseNodeC2EONS_9ExceptionE:
 2365|      3|    : exception(kj::mv(exception)) {}
_ZN2kj1_26ImmediateBrokenPromiseNode7destroyEv:
 2367|      3|void ImmediateBrokenPromiseNode::destroy() { freePromise(this); }
_ZN2kj1_26ImmediateBrokenPromiseNode3getERNS0_16ExceptionOrValueE:
 2369|      3|void ImmediateBrokenPromiseNode::get(ExceptionOrValue& output) noexcept {
 2370|      3|  output.exception = kj::mv(exception);
 2371|      3|}
_ZN2kj1_25AttachmentPromiseNodeBaseC2EONS_3OwnINS0_11PromiseNodeENS0_15PromiseDisposerEEE:
 2376|     12|    : dependency(kj::mv(dependencyParam)) {
 2377|     12|  dependency->setSelfPointer(&dependency);
 2378|     12|}
_ZN2kj1_25AttachmentPromiseNodeBase7onReadyEPNS0_5EventE:
 2380|     12|void AttachmentPromiseNodeBase::onReady(Event* event) noexcept {
 2381|     12|  dependency->onReady(event);
 2382|     12|}
_ZN2kj1_25AttachmentPromiseNodeBase3getERNS0_16ExceptionOrValueE:
 2384|     11|void AttachmentPromiseNodeBase::get(ExceptionOrValue& output) noexcept {
 2385|     11|  dependency->get(output);
 2386|     11|}
_ZN2kj1_25AttachmentPromiseNodeBase14dropDependencyEv:
 2395|     13|void AttachmentPromiseNodeBase::dropDependency() {
 2396|     13|  dependency = nullptr;
 2397|     13|}
_ZN2kj1_24TransformPromiseNodeBaseC2EONS_3OwnINS0_11PromiseNodeENS0_15PromiseDisposerEEEPv:
 2403|     51|    : dependency(kj::mv(dependencyParam)), continuationTracePtr(continuationTracePtr) {
 2404|     51|  dependency->setSelfPointer(&dependency);
 2405|     51|}
_ZN2kj1_24TransformPromiseNodeBase7onReadyEPNS0_5EventE:
 2407|     51|void TransformPromiseNodeBase::onReady(Event* event) noexcept {
 2408|     51|  dependency->onReady(event);
 2409|     51|}
_ZN2kj1_24TransformPromiseNodeBase3getERNS0_16ExceptionOrValueE:
 2411|     56|void TransformPromiseNodeBase::get(ExceptionOrValue& output) noexcept {
 2412|     56|  KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
  ------------------
  |  Branch (2412:3): [True: 2, False: 54]
  ------------------
 2413|     56|    getImpl(output);
 2414|     56|    dropDependency();
 2415|     56|  })) {
 2416|      2|    output.addException(kj::mv(*exception));
 2417|      2|  }
 2418|     56|}
_ZN2kj1_24TransformPromiseNodeBase14dropDependencyEv:
 2431|    133|void TransformPromiseNodeBase::dropDependency() {
 2432|    133|  dependency = nullptr;
 2433|    133|}
_ZN2kj1_24TransformPromiseNodeBase12getDepResultERNS0_16ExceptionOrValueE:
 2435|     56|void TransformPromiseNodeBase::getDepResult(ExceptionOrValue& output) {
 2436|     56|  dependency->get(output);
 2437|     56|  KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
  ------------------
  |  Branch (2437:3): [True: 0, False: 56]
  ------------------
 2438|     56|    dependency = nullptr;
 2439|     56|  })) {
 2440|      0|    output.addException(kj::mv(*exception));
 2441|      0|  }
 2442|       |
 2443|     56|  KJ_IF_MAYBE(e, output.exception) {
  ------------------
  |  Branch (2443:3): [True: 3, False: 53]
  ------------------
 2444|      3|    e->addTrace(continuationTracePtr);
 2445|      3|  }
 2446|     56|}
_ZN2kj1_14ForkBranchBaseD2Ev:
 2462|      2|ForkBranchBase::~ForkBranchBase() noexcept(false) {
 2463|      2|  if (prevPtr != nullptr) {
  ------------------
  |  Branch (2463:7): [True: 0, False: 2]
  ------------------
 2464|       |    // Remove from hub's linked list of branches.
 2465|      0|    *prevPtr = next;
 2466|      0|    (next == nullptr ? hub->tailBranch : next->prevPtr) = prevPtr;
  ------------------
  |  Branch (2466:6): [True: 0, False: 0]
  ------------------
 2467|      0|  }
 2468|      2|}
_ZN2kj1_14ForkBranchBase8hubReadyEv:
 2470|      2|void ForkBranchBase::hubReady() noexcept {
 2471|      2|  onReadyEvent.arm();
 2472|      2|}
_ZN2kj1_14ForkBranchBase10releaseHubERNS0_16ExceptionOrValueE:
 2474|      2|void ForkBranchBase::releaseHub(ExceptionOrValue& output) {
 2475|      2|  KJ_IF_MAYBE(exception, kj::runCatchingExceptions([this]() {
  ------------------
  |  Branch (2475:3): [True: 0, False: 2]
  ------------------
 2476|      2|    hub = nullptr;
 2477|      2|  })) {
 2478|      0|    output.addException(kj::mv(*exception));
 2479|      0|  }
 2480|      2|}
_ZN2kj1_11ForkHubBase4fireEv:
 2506|      3|Maybe<Own<Event>> ForkHubBase::fire() {
 2507|       |  // Dependency is ready.  Fetch its result and then delete the node.
 2508|      3|  inner->get(resultRef);
 2509|      3|  KJ_IF_MAYBE(exception, kj::runCatchingExceptions([this]() {
  ------------------
  |  Branch (2509:3): [True: 0, False: 3]
  ------------------
 2510|      3|    inner = nullptr;
 2511|      3|  })) {
 2512|      0|    resultRef.addException(kj::mv(*exception));
 2513|      0|  }
 2514|       |
 2515|      5|  for (auto branch = headBranch; branch != nullptr; branch = branch->next) {
  ------------------
  |  Branch (2515:34): [True: 2, False: 3]
  ------------------
 2516|      2|    branch->hubReady();
 2517|      2|    *branch->prevPtr = nullptr;
 2518|      2|    branch->prevPtr = nullptr;
 2519|      2|  }
 2520|      3|  *tailBranch = nullptr;
 2521|       |
 2522|       |  // Indicate that the list is no longer active.
 2523|      3|  tailBranch = nullptr;
 2524|       |
 2525|      3|  return nullptr;
 2526|      3|}
_ZN2kj1_16ChainPromiseNodeC2ENS_3OwnINS0_11PromiseNodeENS0_15PromiseDisposerEEENS_14SourceLocationE:
 2542|     24|    : Event(location), state(STEP1), inner(kj::mv(innerParam)) {
 2543|     24|  inner->setSelfPointer(&inner);
 2544|     24|  inner->onReady(this);
 2545|     24|}
_ZN2kj1_16ChainPromiseNodeD2Ev:
 2547|     31|ChainPromiseNode::~ChainPromiseNode() noexcept(false) {}
_ZN2kj1_16ChainPromiseNode7destroyEv:
 2549|     31|void ChainPromiseNode::destroy() { freePromise(this); }
_ZN2kj1_16ChainPromiseNode7onReadyEPNS0_5EventE:
 2551|     23|void ChainPromiseNode::onReady(Event* event) noexcept {
 2552|     23|  switch (state) {
  ------------------
  |  Branch (2552:11): [True: 23, False: 0]
  ------------------
 2553|     23|    case STEP1:
  ------------------
  |  Branch (2553:5): [True: 23, False: 0]
  ------------------
 2554|     23|      onReadyEvent = event;
 2555|     23|      return;
 2556|      0|    case STEP2:
  ------------------
  |  Branch (2556:5): [True: 0, False: 23]
  ------------------
 2557|      0|      inner->onReady(event);
 2558|      0|      return;
 2559|     23|  }
 2560|     23|  KJ_UNREACHABLE;
 2561|      0|}
_ZN2kj1_16ChainPromiseNode14setSelfPointerEPNS_3OwnINS0_11PromiseNodeENS0_15PromiseDisposerEEE:
 2563|     23|void ChainPromiseNode::setSelfPointer(OwnPromiseNode* selfPtr) noexcept {
 2564|     23|  if (state == STEP2) {
  ------------------
  |  Branch (2564:7): [True: 0, False: 23]
  ------------------
 2565|      0|    *selfPtr = kj::mv(inner);  // deletes this!
 2566|      0|    selfPtr->get()->setSelfPointer(selfPtr);
 2567|     23|  } else {
 2568|     23|    this->selfPtr = selfPtr;
 2569|     23|  }
 2570|     23|}
_ZN2kj1_16ChainPromiseNode4fireEv:
 2588|     24|Maybe<Own<Event>> ChainPromiseNode::fire() {
 2589|     24|  KJ_REQUIRE(state != STEP2);
  ------------------
  |  Branch (2589:3): [True: 24, False: 0]
  ------------------
 2590|       |
 2591|     24|  static_assert(sizeof(Promise<int>) == sizeof(PromiseBase),
 2592|     24|      "This code assumes Promise<T> does not add any new members to PromiseBase.");
 2593|       |
 2594|     24|  ExceptionOr<PromiseBase> intermediate;
 2595|     24|  inner->get(intermediate);
 2596|       |
 2597|     24|  KJ_IF_MAYBE(exception, kj::runCatchingExceptions([this]() {
  ------------------
  |  Branch (2597:3): [True: 0, False: 24]
  ------------------
 2598|     24|    inner = nullptr;
 2599|     24|  })) {
 2600|      0|    intermediate.addException(kj::mv(*exception));
 2601|      0|  }
 2602|       |
 2603|     24|  KJ_IF_MAYBE(exception, intermediate.exception) {
  ------------------
  |  Branch (2603:3): [True: 2, False: 22]
  ------------------
 2604|       |    // There is an exception.  If there is also a value, delete it.
 2605|      2|    kj::runCatchingExceptions([&]() { intermediate.value = nullptr; });
 2606|       |    // Now set step2 to a rejected promise.
 2607|      2|    inner = allocPromise<ImmediateBrokenPromiseNode>(kj::mv(*exception));
 2608|     24|  } else KJ_IF_MAYBE(value, intermediate.value) {
  ------------------
  |  Branch (2608:10): [True: 22, False: 0]
  ------------------
 2609|       |    // There is a value and no exception.  The value is itself a promise.  Adopt it as our
 2610|       |    // step2.
 2611|     22|    inner = _::PromiseNode::from(kj::mv(*value));
 2612|     22|  } else {
 2613|       |    // We can only get here if inner->get() returned neither an exception nor a
 2614|       |    // value, which never actually happens.
 2615|      0|    KJ_FAIL_ASSERT("Inner node returned empty value.");
 2616|      0|  }
 2617|     24|  state = STEP2;
 2618|       |
 2619|     24|  if (selfPtr != nullptr) {
  ------------------
  |  Branch (2619:7): [True: 24, False: 0]
  ------------------
 2620|       |    // Hey, we can shorten the chain here.
 2621|     24|    auto chain = selfPtr->downcast<ChainPromiseNode>();
 2622|     24|    *selfPtr = kj::mv(inner);
 2623|     24|    selfPtr->get()->setSelfPointer(selfPtr);
 2624|     24|    if (onReadyEvent != nullptr) {
  ------------------
  |  Branch (2624:9): [True: 24, False: 0]
  ------------------
 2625|     24|      selfPtr->get()->onReady(onReadyEvent);
 2626|     24|    }
 2627|       |
 2628|       |    // Return our self-pointer so that the caller takes care of deleting it.
 2629|     24|    return Own<Event>(kj::Own<ChainPromiseNode>(kj::mv(chain)));
 2630|     24|  } else {
 2631|      0|    inner->setSelfPointer(&inner);
 2632|      0|    if (onReadyEvent != nullptr) {
  ------------------
  |  Branch (2632:9): [True: 0, False: 0]
  ------------------
 2633|      0|      inner->onReady(onReadyEvent);
 2634|      0|    }
 2635|       |
 2636|      0|    return nullptr;
 2637|      0|  }
 2638|     24|}
_ZN2kj1_20EagerPromiseNodeBaseC2EONS_3OwnINS0_11PromiseNodeENS0_15PromiseDisposerEEERNS0_16ExceptionOrValueENS_14SourceLocationE:
 2862|     10|    : Event(location), dependency(kj::mv(dependencyParam)), resultRef(resultRef) {
 2863|     10|  dependency->setSelfPointer(&dependency);
 2864|     10|  dependency->onReady(this);
 2865|     10|}
_ZN2kj1_20EagerPromiseNodeBase7onReadyEPNS0_5EventE:
 2867|      5|void EagerPromiseNodeBase::onReady(Event* event) noexcept {
 2868|      5|  onReadyEvent.init(event);
 2869|      5|}
_ZN2kj1_20EagerPromiseNodeBase4fireEv:
 2889|      9|Maybe<Own<Event>> EagerPromiseNodeBase::fire() {
 2890|      9|  dependency->get(resultRef);
 2891|      9|  KJ_IF_MAYBE(exception, kj::runCatchingExceptions([this]() {
  ------------------
  |  Branch (2891:3): [True: 0, False: 9]
  ------------------
 2892|      9|    dependency = nullptr;
 2893|      9|  })) {
 2894|      0|    resultRef.addException(kj::mv(*exception));
 2895|      0|  }
 2896|       |
 2897|      9|  onReadyEvent.arm();
 2898|      9|  return nullptr;
 2899|      9|}
_ZN2kj1_22AdapterPromiseNodeBase7onReadyEPNS0_5EventE:
 2903|     10|void AdapterPromiseNodeBase::onReady(Event* event) noexcept {
 2904|     10|  onReadyEvent.init(event);
 2905|     10|}
_ZNK2kj1_17WeakFulfillerBase11disposeImplEPv:
 2917|     13|void WeakFulfillerBase::disposeImpl(void* pointer) const {
 2918|     13|  if (inner == nullptr) {
  ------------------
  |  Branch (2918:7): [True: 7, False: 6]
  ------------------
 2919|       |    // Already detached.
 2920|      7|    delete this;
 2921|      7|  } else {
 2922|      6|    if (inner->isWaiting()) {
  ------------------
  |  Branch (2922:9): [True: 0, False: 6]
  ------------------
 2923|       |      // Let's find out if there's an exception being thrown. If so, we'll use it to reject the
 2924|       |      // promise.
 2925|      0|      inner->reject(getDestructionReason(
 2926|      0|          reinterpret_cast<void*>(&END_FULFILLER_STACK_START_LISTENER_STACK),
 2927|      0|          kj::Exception::Type::FAILED, __FILE__, __LINE__,
 2928|      0|          "PromiseFulfiller was destroyed without fulfilling the promise."_kj));
 2929|      0|    }
 2930|      6|    inner = nullptr;
 2931|      6|  }
 2932|     13|}
_ZN2kj7TaskSet4Task3popEv:
  297|     10|  OwnTask pop() {
  298|     10|    KJ_IF_MAYBE(n, next) { n->get()->prev = prev; }
  ------------------
  |  Branch (298:5): [True: 0, False: 10]
  ------------------
  299|     10|    OwnTask self = kj::mv(KJ_ASSERT_NONNULL(*prev));
  ------------------
  |  Branch (299:27): [True: 0, False: 10]
  ------------------
  300|     10|    KJ_ASSERT(self.get() == this);
  ------------------
  |  Branch (300:5): [True: 10, False: 0]
  ------------------
  301|     10|    *prev = kj::mv(next);
  302|     10|    next = nullptr;
  303|     10|    prev = nullptr;
  304|     10|    return self;
  305|     10|  }
async.c++:_ZN2kj12_GLOBAL__N_116currentEventLoopEv:
  168|     41|EventLoop& currentEventLoop() {
  169|     41|  EventLoop* loop = threadLocalEventLoop;
  170|     41|  KJ_REQUIRE(loop != nullptr, "No event loop is running on this thread.");
  ------------------
  |  Branch (170:3): [True: 41, False: 0]
  ------------------
  171|     41|  return *loop;
  172|     41|}
async.c++:_ZN2kj12_GLOBAL__N_19RootEventC2EPNS_1_11PromiseNodeEPvNS_14SourceLocationE:
  177|      1|      : Event(location), node(node), traceAddr(traceAddr) {}
async.c++:_ZN2kj12_GLOBAL__N_19RootEvent4fireEv:
  181|      2|  Maybe<Own<_::Event>> fire() override {
  182|      2|    fired = true;
  183|      2|    return nullptr;
  184|      2|  }
async.c++:_ZZN2kj1_8readyNowEvEN19ReadyNowPromiseNode7destroyEv:
 2086|      4|    void destroy() override {}
async.c++:_ZZN2kj1_8readyNowEvEN19ReadyNowPromiseNode3getERNS0_16ExceptionOrValueE:
 2087|      4|    void get(ExceptionOrValue& output) noexcept override {
 2088|      4|      output.as<Void>() = Void();
 2089|      4|    }
_ZN2kj7TaskSet4TaskC2EONS_3OwnINS_1_11PromiseNodeENS3_15PromiseDisposerEEERS0_:
  290|      6|      : Event(taskSet.location), taskSet(taskSet), node(kj::mv(nodeParam)) {
  291|      6|    node->setSelfPointer(&node);
  292|      6|    node->onReady(this);
  293|      6|  }
_ZN2kj7TaskSet4Task7destroyEv:
  295|     11|  void destroy() override { freePromise(this); }
_ZN2kj7TaskSet4Task4fireEv:
  318|      8|  Maybe<Own<Event>> fire() override {
  319|       |    // Get the result.
  320|      8|    _::ExceptionOr<_::Void> result;
  321|      8|    node->get(result);
  322|       |
  323|       |    // Delete the node, catching any exceptions.
  324|      8|    KJ_IF_MAYBE(exception, kj::runCatchingExceptions([this]() {
  ------------------
  |  Branch (324:5): [True: 0, False: 8]
  ------------------
  325|      8|      node = nullptr;
  326|      8|    })) {
  327|      0|      result.addException(kj::mv(*exception));
  328|      0|    }
  329|       |
  330|       |    // Remove from the task list. Do this before calling taskFailed(), so that taskFailed() can
  331|       |    // safely call clear().
  332|      8|    auto self = pop();
  333|       |
  334|       |    // We'll also process onEmpty() now, just in case `taskFailed()` actually destroys the whole
  335|       |    // `TaskSet`.
  336|      8|    KJ_IF_MAYBE(f, taskSet.emptyFulfiller) {
  ------------------
  |  Branch (336:5): [True: 0, False: 8]
  ------------------
  337|      0|      if (taskSet.tasks == nullptr) {
  ------------------
  |  Branch (337:11): [True: 0, False: 0]
  ------------------
  338|      0|        f->get()->fulfill();
  339|      0|        taskSet.emptyFulfiller = nullptr;
  340|      0|      }
  341|      0|    }
  342|       |
  343|       |    // Call the error handler if there was an exception.
  344|      8|    KJ_IF_MAYBE(e, result.exception) {
  ------------------
  |  Branch (344:5): [True: 1, False: 7]
  ------------------
  345|      1|      taskSet.errorHandler.taskFailed(kj::mv(*e));
  346|      1|    }
  347|       |
  348|      8|    return Own<Event>(mv(self));
  349|      8|  }
async.c++:_ZZN2kj1_8waitImplEONS_3OwnINS0_11PromiseNodeENS0_15PromiseDisposerEEERNS0_16ExceptionOrValueERNS_9WaitScopeENS_14SourceLocationEENK3$_2clEv:
 1968|      7|      waitScope.runOnStackPool([&]() {
 1969|      7|        uint counter = 0;
 1970|     53|        while (!doneEvent.fired) {
  ------------------
  |  Branch (1970:16): [True: 52, False: 1]
  ------------------
 1971|     52|          if (!loop.turn()) {
  ------------------
  |  Branch (1971:15): [True: 6, False: 46]
  ------------------
 1972|       |            // No events in the queue.  Wait for callback.
 1973|      6|            return;
 1974|     46|          } else if (++counter > waitScope.busyPollInterval) {
  ------------------
  |  Branch (1974:22): [True: 0, False: 46]
  ------------------
 1975|       |            // Note: It's intentional that if busyPollInterval is kj::maxValue, we never poll.
 1976|      0|            counter = 0;
 1977|      0|            loop.poll();
 1978|      0|          }
 1979|     52|        }
 1980|      7|      });
async.c++:_ZZN2kj1_8waitImplEONS_3OwnINS0_11PromiseNodeENS0_15PromiseDisposerEEERNS0_16ExceptionOrValueERNS_9WaitScopeENS_14SourceLocationEENK3$_3clEv:
 1994|      2|  waitScope.runOnStackPool([&]() {
 1995|      2|    node->get(result);
 1996|      2|    KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
  ------------------
  |  Branch (1996:5): [True: 0, False: 2]
  ------------------
 1997|      2|      node = nullptr;
 1998|      2|    })) {
 1999|      0|      result.addException(kj::mv(*exception));
 2000|      0|    }
 2001|      2|  });
async.c++:_ZZN2kj1_16ChainPromiseNode4fireEvENK3$_1clEv:
 2605|      2|    kj::runCatchingExceptions([&]() { intermediate.value = nullptr; });
async.c++:_ZZN2kj1_5yieldEvEN16YieldPromiseNode7destroyEv:
 2043|      7|    void destroy() override {}
async.c++:_ZZN2kj1_5yieldEvEN16YieldPromiseNode7onReadyEPNS0_5EventE:
 2045|      7|    void onReady(_::Event* event) noexcept override {
 2046|      7|      if (event) event->armBreadthFirst();
  ------------------
  |  Branch (2046:11): [True: 7, False: 0]
  ------------------
 2047|      7|    }
async.c++:_ZZN2kj1_5yieldEvEN16YieldPromiseNode3getERNS0_16ExceptionOrValueE:
 2048|      7|    void get(_::ExceptionOrValue& output) noexcept override {
 2049|      7|      output.as<_::Void>() = _::Void();
 2050|      7|    }
async.c++:_ZZN2kj1_11yieldHarderEvEN22YieldHarderPromiseNode7destroyEv:
 2063|      3|    void destroy() override {}
async.c++:_ZZN2kj1_11yieldHarderEvEN22YieldHarderPromiseNode7onReadyEPNS0_5EventE:
 2065|      3|    void onReady(_::Event* event) noexcept override {
 2066|      3|      if (event) event->armLast();
  ------------------
  |  Branch (2066:11): [True: 3, False: 0]
  ------------------
 2067|      3|    }
async.c++:_ZZN2kj1_11yieldHarderEvEN22YieldHarderPromiseNode3getERNS0_16ExceptionOrValueE:
 2068|      3|    void get(_::ExceptionOrValue& output) noexcept override {
 2069|      3|      output.as<_::Void>() = _::Void();
 2070|      3|    }

_ZN2kj1_5Debug5FaultD2Ev:
  359|      1|Debug::Fault::~Fault() noexcept(false) {
  360|      1|  if (exception != nullptr) {
  ------------------
  |  Branch (360:7): [True: 1, False: 0]
  ------------------
  361|      1|    Exception copy = mv(*exception);
  362|      1|    delete exception;
  363|      1|    throwRecoverableException(mv(copy), 1);
  364|      1|  }
  365|      1|}
_ZN2kj1_5Debug5Fault4initEPKciiS4_S4_NS_8ArrayPtrINS_6StringEEE:
  384|      1|    const char* condition, const char* macroArgs, ArrayPtr<String> argValues) {
  385|      1|  exception = new Exception(typeOfErrno(osErrorNumber), file, line,
  386|      1|      makeDescriptionImpl(SYSCALL, condition, osErrorNumber, nullptr, macroArgs, argValues));
  387|      1|}
_ZN2kj1_5Debug23makeDescriptionInternalEPKcNS_8ArrayPtrINS_6StringEEE:
  421|      2|String Debug::makeDescriptionInternal(const char* macroArgs, ArrayPtr<String> argValues) {
  422|      2|  return makeDescriptionImpl(LOG, nullptr, 0, nullptr, macroArgs, argValues);
  423|      2|}
_ZN2kj1_5Debug16getOsErrorNumberEb:
  425|      5|int Debug::getOsErrorNumber(bool nonblocking) {
  426|      5|  int result = errno;
  427|       |
  428|       |  // On many systems, EAGAIN and EWOULDBLOCK have the same value, but this is not strictly required
  429|       |  // by POSIX, so we need to check both.
  430|      5|  return result == EINTR ? -1
  ------------------
  |  Branch (430:10): [True: 0, False: 5]
  ------------------
  431|      5|       : nonblocking && (result == EAGAIN || result == EWOULDBLOCK) ? 0
  ------------------
  |  Branch (431:10): [True: 5, False: 0]
  |  Branch (431:26): [True: 4, False: 1]
  |  Branch (431:46): [True: 0, False: 1]
  ------------------
  432|      5|       : result;
  433|      5|}
debug.c++:_ZN2kj1_12_GLOBAL__N_119makeDescriptionImplENS1_16DescriptionStyleEPKciS4_S4_NS_8ArrayPtrINS_6StringEEE:
  179|      3|                                  ArrayPtr<String> argValues) {
  180|      3|  KJ_STACK_ARRAY(ArrayPtr<const char>, argNames, argValues.size(), 8, 64);
  ------------------
  |  Branch (180:3): [True: 3, False: 0]
  |  Branch (180:3): [True: 3, False: 0]
  ------------------
  181|       |
  182|      3|  if (argValues.size() > 0) {
  ------------------
  |  Branch (182:7): [True: 3, False: 0]
  ------------------
  183|      3|    size_t index = 0;
  184|      3|    const char* start = macroArgs;
  185|      3|    while (isspace(*start)) ++start;
  ------------------
  |  Branch (185:12): [True: 0, False: 3]
  ------------------
  186|      3|    const char* pos = start;
  187|      3|    uint depth = 0;
  188|      3|    bool quoted = false;
  189|     68|    while (char c = *pos++) {
  ------------------
  |  Branch (189:17): [True: 65, False: 3]
  ------------------
  190|     65|      if (quoted) {
  ------------------
  |  Branch (190:11): [True: 44, False: 21]
  ------------------
  191|     44|        if (c == '\\' && *pos != '\0') {
  ------------------
  |  Branch (191:13): [True: 0, False: 44]
  |  Branch (191:26): [True: 0, False: 0]
  ------------------
  192|      0|          ++pos;
  193|     44|        } else if (c == '\"') {
  ------------------
  |  Branch (193:20): [True: 2, False: 42]
  ------------------
  194|      2|          quoted = false;
  195|      2|        }
  196|     44|      } else {
  197|     21|        if (c == '(') {
  ------------------
  |  Branch (197:13): [True: 1, False: 20]
  ------------------
  198|      1|          ++depth;
  199|     20|        } else if (c == ')') {
  ------------------
  |  Branch (199:20): [True: 1, False: 19]
  ------------------
  200|      1|          --depth;
  201|     19|        } else if (c == '\"') {
  ------------------
  |  Branch (201:20): [True: 2, False: 17]
  ------------------
  202|      2|          quoted = true;
  203|     17|        } else if (c == ',' && depth == 0) {
  ------------------
  |  Branch (203:20): [True: 1, False: 16]
  |  Branch (203:32): [True: 1, False: 0]
  ------------------
  204|      1|          if (index < argValues.size()) {
  ------------------
  |  Branch (204:15): [True: 1, False: 0]
  ------------------
  205|      1|            argNames[index++] = arrayPtr(start, pos - 1);
  206|      1|          }
  207|      2|          while (isspace(*pos)) ++pos;
  ------------------
  |  Branch (207:18): [True: 1, False: 1]
  ------------------
  208|      1|          start = pos;
  209|      1|          if (*pos == '\0') {
  ------------------
  |  Branch (209:15): [True: 0, False: 1]
  ------------------
  210|       |            // ignore trailing comma
  211|      0|            break;
  212|      0|          }
  213|      1|        }
  214|     21|      }
  215|     65|    }
  216|      3|    if (index < argValues.size()) {
  ------------------
  |  Branch (216:9): [True: 3, False: 0]
  ------------------
  217|      3|      argNames[index++] = arrayPtr(start, pos - 1);
  218|      3|    }
  219|       |
  220|      3|    if (index != argValues.size()) {
  ------------------
  |  Branch (220:9): [True: 0, False: 3]
  ------------------
  221|      0|      getExceptionCallback().logMessage(LogSeverity::ERROR, __FILE__, __LINE__, 0,
  222|      0|          str("Failed to parse logging macro args into ",
  223|      0|              argValues.size(), " names: ", macroArgs, '\n'));
  224|      0|    }
  225|      3|  }
  226|       |
  227|      3|  if (style == SYSCALL) {
  ------------------
  |  Branch (227:7): [True: 1, False: 2]
  ------------------
  228|       |    // Strip off leading "foo = " from code, since callers will sometimes write things like:
  229|       |    //   ssize_t n;
  230|       |    //   RECOVERABLE_SYSCALL(n = read(fd, buffer, sizeof(buffer))) { return ""; }
  231|       |    //   return std::string(buffer, n);
  232|      1|    const char* equalsPos = strchr(code, '=');
  233|      1|    if (equalsPos != nullptr && equalsPos[1] != '=') {
  ------------------
  |  Branch (233:9): [True: 1, False: 0]
  |  Branch (233:33): [True: 1, False: 0]
  ------------------
  234|      1|      code = equalsPos + 1;
  235|      2|      while (isspace(*code)) ++code;
  ------------------
  |  Branch (235:14): [True: 1, False: 1]
  ------------------
  236|      1|    }
  237|      1|  }
  238|       |
  239|      3|  if (style == ASSERTION && code == nullptr) {
  ------------------
  |  Branch (239:7): [True: 0, False: 3]
  |  Branch (239:29): [True: 0, False: 0]
  ------------------
  240|      0|    style = LOG;
  241|      0|  }
  242|       |
  243|      3|  {
  244|      3|    StringPtr expected = "expected ";
  245|      3|    StringPtr codeArray = style == LOG ? nullptr : StringPtr(code);
  ------------------
  |  Branch (245:27): [True: 2, False: 1]
  ------------------
  246|      3|    StringPtr sep = " = ";
  247|      3|    StringPtr delim = "; ";
  248|      3|    StringPtr colon = ": ";
  249|      3|    StringPtr openBracket = " [";
  250|      3|    StringPtr closeBracket = "]";
  251|       |
  252|      3|    StringPtr sysErrorArray;
  253|       |// On android before marshmallow only the posix version of stderror_r was
  254|       |// available, even with __USE_GNU.
  255|      3|#if __USE_GNU && !(defined(__ANDROID_API__) && __ANDROID_API__ < 23)
  256|      3|    char buffer[256];
  257|      3|    if (style == SYSCALL) {
  ------------------
  |  Branch (257:9): [True: 1, False: 2]
  ------------------
  258|      1|      if (sysErrorString == nullptr) {
  ------------------
  |  Branch (258:11): [True: 1, False: 0]
  ------------------
  259|      1|        sysErrorArray = strerror_r(errorNumber, buffer, sizeof(buffer));
  260|      1|      } else {
  261|      0|        sysErrorArray = sysErrorString;
  262|      0|      }
  263|      1|    }
  264|       |#else
  265|       |    char buffer[256];
  266|       |    if (style == SYSCALL) {
  267|       |      if (sysErrorString == nullptr) {
  268|       |        strerror_r(errorNumber, buffer, sizeof(buffer));
  269|       |        sysErrorArray = buffer;
  270|       |      } else {
  271|       |        sysErrorArray = sysErrorString;
  272|       |      }
  273|       |    }
  274|       |#endif
  275|       |
  276|      3|    size_t totalSize = 0;
  277|      3|    switch (style) {
  ------------------
  |  Branch (277:13): [True: 3, False: 0]
  ------------------
  278|      2|      case LOG:
  ------------------
  |  Branch (278:7): [True: 2, False: 1]
  ------------------
  279|      2|        break;
  280|      0|      case ASSERTION:
  ------------------
  |  Branch (280:7): [True: 0, False: 3]
  ------------------
  281|      0|        totalSize += expected.size() + codeArray.size();
  282|      0|        break;
  283|      1|      case SYSCALL:
  ------------------
  |  Branch (283:7): [True: 1, False: 2]
  ------------------
  284|      1|        totalSize += codeArray.size() + colon.size() + sysErrorArray.size();
  285|      1|        break;
  286|      3|    }
  287|       |
  288|      3|    auto needsLabel = [](ArrayPtr<const char> &argName) -> bool {
  289|      3|      return (argName.size() > 0 && argName[0] != '\"' &&
  290|      3|          !(argName.size() >= 8 && memcmp(argName.begin(), "kj::str(", 8) == 0));
  291|      3|    };
  292|       |
  293|      7|    for (size_t i = 0; i < argValues.size(); i++) {
  ------------------
  |  Branch (293:24): [True: 4, False: 3]
  ------------------
  294|      4|      if (argNames[i] == "_kjCondition"_kj) {
  ------------------
  |  Branch (294:11): [True: 0, False: 4]
  ------------------
  295|       |        // Special handling: don't output delimiter, we want to append this to the previous item,
  296|       |        // in brackets. Also, if it's just "[false]" (meaning we didn't manage to extract a
  297|       |        // comparison), don't add it at all.
  298|      0|        if (argValues[i] != "false") {
  ------------------
  |  Branch (298:13): [True: 0, False: 0]
  ------------------
  299|      0|          totalSize += openBracket.size() + argValues[i].size() + closeBracket.size();
  300|      0|        }
  301|      0|        continue;
  302|      0|      }
  303|       |
  304|      4|      if (i > 0 || style != LOG) {
  ------------------
  |  Branch (304:11): [True: 1, False: 3]
  |  Branch (304:20): [True: 1, False: 2]
  ------------------
  305|      2|        totalSize += delim.size();
  306|      2|      }
  307|      4|      if (needsLabel(argNames[i])) {
  ------------------
  |  Branch (307:11): [True: 2, False: 2]
  ------------------
  308|      2|        totalSize += argNames[i].size() + sep.size();
  309|      2|      }
  310|      4|      totalSize += argValues[i].size();
  311|      4|    }
  312|       |
  313|      3|    String result = heapString(totalSize);
  314|      3|    char* pos = result.begin();
  315|       |
  316|      3|    switch (style) {
  ------------------
  |  Branch (316:13): [True: 3, False: 0]
  ------------------
  317|      2|      case LOG:
  ------------------
  |  Branch (317:7): [True: 2, False: 1]
  ------------------
  318|      2|        break;
  319|      0|      case ASSERTION:
  ------------------
  |  Branch (319:7): [True: 0, False: 3]
  ------------------
  320|      0|        pos = _::fill(pos, expected, codeArray);
  321|      0|        break;
  322|      1|      case SYSCALL:
  ------------------
  |  Branch (322:7): [True: 1, False: 2]
  ------------------
  323|      1|        pos = _::fill(pos, codeArray, colon, sysErrorArray);
  324|      1|        break;
  325|      3|    }
  326|       |
  327|      7|    for (size_t i = 0; i < argValues.size(); i++) {
  ------------------
  |  Branch (327:24): [True: 4, False: 3]
  ------------------
  328|      4|      if (argNames[i] == "_kjCondition"_kj) {
  ------------------
  |  Branch (328:11): [True: 0, False: 4]
  ------------------
  329|       |        // Special handling: don't output delimiter, we want to append this to the previous item,
  330|       |        // in brackets. Also, if it's just "[false]" (meaning we didn't manage to extract a
  331|       |        // comparison), don't add it at all.
  332|      0|        if (argValues[i] != "false") {
  ------------------
  |  Branch (332:13): [True: 0, False: 0]
  ------------------
  333|      0|          pos = _::fill(pos, openBracket, argValues[i], closeBracket);
  334|      0|        }
  335|      0|        continue;
  336|      0|      }
  337|       |
  338|      4|      if (i > 0 || style != LOG) {
  ------------------
  |  Branch (338:11): [True: 1, False: 3]
  |  Branch (338:20): [True: 1, False: 2]
  ------------------
  339|      2|        pos = _::fill(pos, delim);
  340|      2|      }
  341|      4|      if (needsLabel(argNames[i])) {
  ------------------
  |  Branch (341:11): [True: 2, False: 2]
  ------------------
  342|      2|        pos = _::fill(pos, argNames[i], sep);
  343|      2|      }
  344|      4|      pos = _::fill(pos, argValues[i]);
  345|      4|    }
  346|       |
  347|      3|    return result;
  348|      3|  }
  349|      3|}
debug.c++:_ZZN2kj1_12_GLOBAL__N_119makeDescriptionImplENS1_16DescriptionStyleEPKciS4_S4_NS_8ArrayPtrINS_6StringEEEENK3$_0clERNS5_IS3_EE:
  288|      8|    auto needsLabel = [](ArrayPtr<const char> &argName) -> bool {
  289|      8|      return (argName.size() > 0 && argName[0] != '\"' &&
  ------------------
  |  Branch (289:15): [True: 8, False: 0]
  |  Branch (289:37): [True: 4, False: 4]
  ------------------
  290|      4|          !(argName.size() >= 8 && memcmp(argName.begin(), "kj::str(", 8) == 0));
  ------------------
  |  Branch (290:13): [True: 4, False: 0]
  |  Branch (290:36): [True: 0, False: 4]
  ------------------
  291|      8|    };
debug.c++:_ZN2kj1_12_GLOBAL__N_111typeOfErrnoEi:
   49|      1|Exception::Type typeOfErrno(int error) {
   50|      1|  switch (error) {
   51|      0|#ifdef EDQUOT
   52|      0|    case EDQUOT:
  ------------------
  |  Branch (52:5): [True: 0, False: 1]
  ------------------
   53|      0|#endif
   54|      0|#ifdef EMFILE
   55|      0|    case EMFILE:
  ------------------
  |  Branch (55:5): [True: 0, False: 1]
  ------------------
   56|      0|#endif
   57|      0|#ifdef ENFILE
   58|      0|    case ENFILE:
  ------------------
  |  Branch (58:5): [True: 0, False: 1]
  ------------------
   59|      0|#endif
   60|      0|#ifdef ENOBUFS
   61|      0|    case ENOBUFS:
  ------------------
  |  Branch (61:5): [True: 0, False: 1]
  ------------------
   62|      0|#endif
   63|      0|#ifdef ENOLCK
   64|      0|    case ENOLCK:
  ------------------
  |  Branch (64:5): [True: 0, False: 1]
  ------------------
   65|      0|#endif
   66|      0|#ifdef ENOMEM
   67|      0|    case ENOMEM:
  ------------------
  |  Branch (67:5): [True: 0, False: 1]
  ------------------
   68|      0|#endif
   69|      0|#ifdef ENOSPC
   70|      0|    case ENOSPC:
  ------------------
  |  Branch (70:5): [True: 0, False: 1]
  ------------------
   71|      0|#endif
   72|      0|#ifdef ETIMEDOUT
   73|      0|    case ETIMEDOUT:
  ------------------
  |  Branch (73:5): [True: 0, False: 1]
  ------------------
   74|      0|#endif
   75|      0|#ifdef EUSERS
   76|      0|    case EUSERS:
  ------------------
  |  Branch (76:5): [True: 0, False: 1]
  ------------------
   77|      0|#endif
   78|      0|      return Exception::Type::OVERLOADED;
   79|       |
   80|      0|#ifdef ENOTCONN
   81|      0|    case ENOTCONN:
  ------------------
  |  Branch (81:5): [True: 0, False: 1]
  ------------------
   82|      0|#endif
   83|      0|#ifdef ECONNABORTED
   84|      0|    case ECONNABORTED:
  ------------------
  |  Branch (84:5): [True: 0, False: 1]
  ------------------
   85|      0|#endif
   86|      0|#ifdef ECONNREFUSED
   87|      0|    case ECONNREFUSED:
  ------------------
  |  Branch (87:5): [True: 0, False: 1]
  ------------------
   88|      0|#endif
   89|      0|#ifdef ECONNRESET
   90|      0|    case ECONNRESET:
  ------------------
  |  Branch (90:5): [True: 0, False: 1]
  ------------------
   91|      0|#endif
   92|      0|#ifdef EHOSTDOWN
   93|      0|    case EHOSTDOWN:
  ------------------
  |  Branch (93:5): [True: 0, False: 1]
  ------------------
   94|      0|#endif
   95|      0|#ifdef EHOSTUNREACH
   96|      0|    case EHOSTUNREACH:
  ------------------
  |  Branch (96:5): [True: 0, False: 1]
  ------------------
   97|      0|#endif
   98|      0|#ifdef ENETDOWN
   99|      0|    case ENETDOWN:
  ------------------
  |  Branch (99:5): [True: 0, False: 1]
  ------------------
  100|      0|#endif
  101|      0|#ifdef ENETRESET
  102|      0|    case ENETRESET:
  ------------------
  |  Branch (102:5): [True: 0, False: 1]
  ------------------
  103|      0|#endif
  104|      0|#ifdef ENETUNREACH
  105|      0|    case ENETUNREACH:
  ------------------
  |  Branch (105:5): [True: 0, False: 1]
  ------------------
  106|      0|#endif
  107|      0|#ifdef ENONET
  108|      0|    case ENONET:
  ------------------
  |  Branch (108:5): [True: 0, False: 1]
  ------------------
  109|      0|#endif
  110|      0|#ifdef EPIPE
  111|      1|    case EPIPE:
  ------------------
  |  Branch (111:5): [True: 1, False: 0]
  ------------------
  112|      1|#endif
  113|      1|      return Exception::Type::DISCONNECTED;
  114|       |
  115|      0|#ifdef ENOSYS
  116|      0|    case ENOSYS:
  ------------------
  |  Branch (116:5): [True: 0, False: 1]
  ------------------
  117|      0|#endif
  118|      0|#ifdef ENOTSUP
  119|      0|    case ENOTSUP:
  ------------------
  |  Branch (119:5): [True: 0, False: 1]
  ------------------
  120|      0|#endif
  121|       |#if defined(EOPNOTSUPP) && EOPNOTSUPP != ENOTSUP
  122|       |    case EOPNOTSUPP:
  123|       |#endif
  124|      0|#ifdef ENOPROTOOPT
  125|      0|    case ENOPROTOOPT:
  ------------------
  |  Branch (125:5): [True: 0, False: 1]
  ------------------
  126|      0|#endif
  127|      0|#ifdef ENOTSOCK
  128|       |    // This is really saying "syscall not implemented for non-sockets".
  129|      0|    case ENOTSOCK:
  ------------------
  |  Branch (129:5): [True: 0, False: 1]
  ------------------
  130|      0|#endif
  131|      0|      return Exception::Type::UNIMPLEMENTED;
  132|       |
  133|      0|    default:
  ------------------
  |  Branch (133:5): [True: 0, False: 1]
  ------------------
  134|      0|      return Exception::Type::FAILED;
  135|      1|  }
  136|      1|}

_ZN2kj13getStackTraceENS_8ArrayPtrIPvEEj:
  235|      4|ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount) {
  236|      4|  if (getExceptionCallback().stackTraceMode() == ExceptionCallback::StackTraceMode::NONE) {
  ------------------
  |  Branch (236:7): [True: 0, False: 4]
  ------------------
  237|      0|    return nullptr;
  238|      0|  }
  239|       |
  240|       |#if KJ_USE_WIN32_DBGHELP
  241|       |  CONTEXT context;
  242|       |  RtlCaptureContext(&context);
  243|       |  return getStackTrace(space, ignoreCount, GetCurrentThread(), context);
  244|       |#elif KJ_USE_BACKTRACE
  245|      4|  size_t size = backtrace(space.begin(), space.size());
  246|     57|  for (auto& addr: space.slice(0, size)) {
  ------------------
  |  Branch (246:18): [True: 57, False: 4]
  ------------------
  247|       |    // The addresses produced by backtrace() are return addresses, which means they point to the
  248|       |    // instruction immediately after the call. Invoking addr2line on these can be confusing because
  249|       |    // it often points to the next line. If the next instruction is inlined from another function,
  250|       |    // the trace can be extra-confusing, since now it claims to be in a function that was not
  251|       |    // actually on the call stack. If we subtract 1 from each address, though, we get a much more
  252|       |    // reasonable trace. This may cause the addresses to be invalid instruction pointers if the
  253|       |    // instructions were multi-byte, but it appears addr2line is able to cope with this.
  254|     57|    addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - 1);
  255|     57|  }
  256|      4|  return space.slice(kj::min(ignoreCount + 1, size), size);
  257|       |#else
  258|       |  return nullptr;
  259|       |#endif
  260|      4|}
_ZN2kj18trimSourceFilenameENS_9StringPtrE:
  680|      5|kj::StringPtr trimSourceFilename(kj::StringPtr filename) {
  681|       |  // Removes noisy prefixes from source code file name.
  682|       |  //
  683|       |  // The goal here is to produce the "canonical" filename given the filename returned by e.g.
  684|       |  // addr2line. addr2line gives us the full path of the file as passed on the compiler
  685|       |  // command-line, which in turn is affected by build system and by whether and where we're
  686|       |  // performing an out-of-tree build.
  687|       |  //
  688|       |  // To deal with all this, we look for directory names in the path which we recognize to be
  689|       |  // locations that represent roots of the source tree. We strip said root and everything before
  690|       |  // it.
  691|       |  //
  692|       |  // On Windows, we often get filenames containing backslashes. Since we aren't allowed to allocate
  693|       |  // a new string here, we can't do much about this, so our returned "canonical" name will
  694|       |  // unfortunately end up with backslashes.
  695|       |
  696|      5|  static constexpr const char* ROOTS[] = {
  697|      5|    "ekam-provider/canonical/",  // Ekam source file.
  698|      5|    "ekam-provider/c++header/",  // Ekam include file.
  699|      5|    "src/",                      // Non-Ekam source root.
  700|      5|    "tmp/",                      // Non-Ekam generated code.
  701|       |#if _WIN32
  702|       |    "src\\",                     // Win32 source root.
  703|       |    "tmp\\",                     // Win32 generated code.
  704|       |#endif
  705|      5|  };
  706|       |
  707|      8|retry:
  708|     90|  for (size_t i: kj::indices(filename)) {
  ------------------
  |  Branch (708:16): [True: 90, False: 5]
  ------------------
  709|     90|    if (i == 0 || filename[i-1] == '/'
  ------------------
  |  Branch (709:9): [True: 8, False: 82]
  |  Branch (709:19): [True: 11, False: 71]
  ------------------
  710|       |#if _WIN32
  711|       |               || filename[i-1] == '\\'
  712|       |#endif
  713|     90|        ) {
  714|       |      // We're at the start of a directory name. Check for valid prefixes.
  715|     73|      for (kj::StringPtr root: ROOTS) {
  ------------------
  |  Branch (715:30): [True: 73, False: 16]
  ------------------
  716|     73|        if (filename.slice(i).startsWith(root)) {
  ------------------
  |  Branch (716:13): [True: 3, False: 70]
  ------------------
  717|      3|          filename = filename.slice(i + root.size());
  718|       |
  719|       |          // We should keep searching to find the last instance of a root name. `i` is no longer
  720|       |          // a valid index for `filename` so start the loop over.
  721|      3|          goto retry;
  722|      3|        }
  723|     73|      }
  724|     19|    }
  725|     90|  }
  726|       |
  727|      5|  return filename;
  728|      8|}
_ZN2kj9ExceptionC2ENS0_4TypeEPKciNS_6StringE:
  808|      5|    : file(trimSourceFilename(file).cStr()), line(line), type(type), description(mv(description)),
  809|      5|      traceCount(0) {}
_ZN2kj9ExceptionC2ERKS0_:
  816|      4|    : file(other.file), line(other.line), type(other.type),
  817|      4|      description(heapString(other.description)), traceCount(other.traceCount) {
  818|      4|  if (file == other.ownFile.cStr()) {
  ------------------
  |  Branch (818:7): [True: 0, False: 4]
  ------------------
  819|      0|    ownFile = heapString(other.ownFile);
  820|      0|    file = ownFile.cStr();
  821|      0|  }
  822|       |
  823|      4|  if (other.remoteTrace != nullptr) {
  ------------------
  |  Branch (823:7): [True: 0, False: 4]
  ------------------
  824|      0|    remoteTrace = kj::str(other.remoteTrace);
  825|      0|  }
  826|       |
  827|      4|  memcpy(trace, other.trace, sizeof(trace[0]) * traceCount);
  828|       |
  829|      4|  KJ_IF_MAYBE(c, other.context) {
  ------------------
  |  Branch (829:3): [True: 0, False: 4]
  ------------------
  830|      0|    context = heap(**c);
  831|      0|  }
  832|      4|}
_ZN2kj9ExceptionD2Ev:
  834|     40|Exception::~Exception() noexcept {}
_ZN2kj9Exception11extendTraceEjj:
  847|      2|void Exception::extendTrace(uint ignoreCount, uint limit) {
  848|      2|  if (isFullTrace) {
  ------------------
  |  Branch (848:7): [True: 0, False: 2]
  ------------------
  849|       |    // Awkward: extendTrace() was called twice without truncating in between. This should probably
  850|       |    // be an error, but historically we didn't check for this so I'm hesitant to make it an error
  851|       |    // now. We shouldn't actually extend the trace, though, as our current trace is presumably
  852|       |    // rooted in main() and it'd be weird to append frames "above" that.
  853|       |    // TODO(cleanup): Abort here and see what breaks?
  854|      0|    return;
  855|      0|  }
  856|       |
  857|      2|  KJ_STACK_ARRAY(void*, newTraceSpace, kj::min(kj::size(trace), limit) + ignoreCount + 1,
  ------------------
  |  Branch (857:3): [True: 2, False: 0]
  |  Branch (857:3): [True: 2, False: 0]
  ------------------
  858|      2|      sizeof(trace)/sizeof(trace[0]) + 8, 128);
  859|       |
  860|      2|  auto newTrace = kj::getStackTrace(newTraceSpace, ignoreCount + 1);
  861|      2|  if (newTrace.size() > ignoreCount + 2) {
  ------------------
  |  Branch (861:7): [True: 2, False: 0]
  ------------------
  862|       |    // Remove suffix that won't fit into our static-sized trace.
  863|      2|    newTrace = newTrace.slice(0, kj::min(kj::size(trace) - traceCount, newTrace.size()));
  864|       |
  865|       |    // Copy the rest into our trace.
  866|      2|    memcpy(trace + traceCount, newTrace.begin(), newTrace.asBytes().size());
  867|      2|    traceCount += newTrace.size();
  868|      2|    isFullTrace = true;
  869|      2|  }
  870|      2|}
_ZN2kj9Exception19truncateCommonTraceEv:
  872|      2|void Exception::truncateCommonTrace() {
  873|      2|  if (isFullTrace) {
  ------------------
  |  Branch (873:7): [True: 2, False: 0]
  ------------------
  874|       |    // We're truncating the common portion of the full trace, turning it back into a limited
  875|       |    // trace.
  876|      2|    isFullTrace = false;
  877|      2|  } else {
  878|       |    // If the trace was never extended in the first place, trying to truncate it is at best a waste
  879|       |    // of time and at worst might remove information for no reason. So, don't.
  880|       |    //
  881|       |    // This comes up in particular in coroutines, when the exception originated from a co_awaited
  882|       |    // promise. In that case we manually add the one relevant frame to the trace, rather than
  883|       |    // call extendTrace() just to have to truncate most of it again a moment later in the
  884|       |    // unhandled_exception() callback.
  885|      0|    return;
  886|      0|  }
  887|       |
  888|      2|  if (traceCount > 0) {
  ------------------
  |  Branch (888:7): [True: 2, False: 0]
  ------------------
  889|       |    // Create a "reference" stack trace that is a little bit deeper than the one in the exception.
  890|      2|    void* refTraceSpace[sizeof(this->trace) / sizeof(this->trace[0]) + 4];
  891|      2|    auto refTrace = kj::getStackTrace(refTraceSpace, 0);
  892|       |
  893|       |    // We expect that the deepest frame in the exception's stack trace should be somewhere in our
  894|       |    // own trace, since our own trace has a deeper limit. Search for it.
  895|      2|    for (uint i = refTrace.size(); i > 0; i--) {
  ------------------
  |  Branch (895:36): [True: 2, False: 0]
  ------------------
  896|      2|      if (refTrace[i-1] == trace[traceCount-1]) {
  ------------------
  |  Branch (896:11): [True: 2, False: 0]
  ------------------
  897|       |        // See how many frames match.
  898|     18|        for (uint j = 0; j < i; j++) {
  ------------------
  |  Branch (898:26): [True: 18, False: 0]
  ------------------
  899|     18|          if (j >= traceCount) {
  ------------------
  |  Branch (899:15): [True: 0, False: 18]
  ------------------
  900|       |            // We matched the whole trace, apparently?
  901|      0|            traceCount = 0;
  902|      0|            return;
  903|     18|          } else if (refTrace[i-j-1] != trace[traceCount-j-1]) {
  ------------------
  |  Branch (903:22): [True: 2, False: 16]
  ------------------
  904|       |            // Found mismatching entry.
  905|       |
  906|       |            // If we matched more than half of the reference trace, guess that this is in fact
  907|       |            // the prefix we're looking for.
  908|      2|            if (j > refTrace.size() / 2) {
  ------------------
  |  Branch (908:17): [True: 2, False: 0]
  ------------------
  909|       |              // Delete the matching suffix. Also delete one non-matched entry on the assumption
  910|       |              // that both traces contain that stack frame but are simply at different points in
  911|       |              // the function.
  912|      2|              traceCount -= j + 1;
  913|      2|              return;
  914|      2|            }
  915|      2|          }
  916|     18|        }
  917|      2|      }
  918|      2|    }
  919|       |
  920|       |    // No match. Ignore.
  921|      2|  }
  922|      2|}
_ZN2kj9Exception8addTraceEPv:
  924|      5|void Exception::addTrace(void* ptr) {
  925|       |  // TODO(cleanup): Abort here if isFullTrace is true, and see what breaks. This method only makes
  926|       |  // sense to call on partial traces.
  927|       |
  928|      5|  if (traceCount < kj::size(trace)) {
  ------------------
  |  Branch (928:7): [True: 5, False: 0]
  ------------------
  929|      5|    trace[traceCount++] = ptr;
  930|      5|  }
  931|      5|}
_ZN2kj9Exception12addTraceHereEv:
  933|      2|void Exception::addTraceHere() {
  934|      2|#if __GNUC__
  935|      2|  addTrace(__builtin_return_address(0));
  936|       |#elif _MSC_VER
  937|       |  addTrace(_ReturnAddress());
  938|       |#else
  939|       |  #error "please implement for your compiler"
  940|       |#endif
  941|      2|}
_ZN2kj17ExceptionCallbackC2ERS0_:
 1059|      1|ExceptionCallback::ExceptionCallback(ExceptionCallback& next): next(next) {}
_ZN2kj20getExceptionCallbackEv:
 1171|      6|ExceptionCallback& getExceptionCallback() {
 1172|      6|  static auto defaultCallback = lsanIgnoreObjectAndReturn(
 1173|      6|      new ExceptionCallback::RootExceptionCallback());
 1174|       |  // We allocate on the heap because some objects may throw in their destructors. If those objects
 1175|       |  // had static storage, they might get fully constructed before the root callback. If they however
 1176|       |  // then throw an exception during destruction, there would be a lifetime issue because their
 1177|       |  // destructor would end up getting registered after the root callback's destructor. One solution
 1178|       |  // is to just leak this pointer & allocate on first-use. The cost is that the initialization is
 1179|       |  // mildly more expensive (+ we need to annotate sanitizers to ignore the problem). A great
 1180|       |  // compiler annotation that would simply things would be one that allowed static variables to have
 1181|       |  // their destruction omitted wholesale. That would allow us to avoid the heap but still have the
 1182|       |  // same robust safety semantics leaking would give us. A practical alternative that could be
 1183|       |  // implemented without new compilers would be to define another static root callback in
 1184|       |  // RootExceptionCallback's destructor (+ a separate pointer to share its value with this
 1185|       |  // function). Since this would end up getting constructed during exit unwind, it would have the
 1186|       |  // nice property of effectively being guaranteed to be evicted last.
 1187|       |  //
 1188|       |  // All this being said, I came back to leaking the object is the easiest tweak here:
 1189|       |  //  * Can't go wrong
 1190|       |  //  * Easy to maintain
 1191|       |  //  * Throwing exceptions is bound to do be expensive and malloc-happy anyway, so the incremental
 1192|       |  //    cost of 1 heap allocation is minimal.
 1193|       |  //
 1194|       |  // TODO(cleanup): Harris has an excellent suggestion in
 1195|       |  //  https://github.com/capnproto/capnproto/pull/1255 that should ensure we initialize the root
 1196|       |  //  callback once on first use as a global & never destroy it.
 1197|       |
 1198|      6|  ExceptionCallback* scoped = threadLocalCallback;
 1199|      6|  return scoped != nullptr ? *scoped : *defaultCallback;
  ------------------
  |  Branch (1199:10): [True: 0, False: 6]
  ------------------
 1200|      6|}
_ZN2kj25throwRecoverableExceptionEONS_9ExceptionEj:
 1208|      2|void throwRecoverableException(kj::Exception&& exception, uint ignoreCount) {
 1209|      2|  if (ignoreCount != (uint)kj::maxValue) exception.extendTrace(ignoreCount + 1);
  ------------------
  |  Branch (1209:7): [True: 2, False: 0]
  ------------------
 1210|      2|  getExceptionCallback().onRecoverableException(kj::mv(exception));
 1211|      2|}
_ZN2kj1_22uncaughtExceptionCountEv:
 1219|      6|uint uncaughtExceptionCount() {
 1220|      6|  return std::uncaught_exceptions();
 1221|      6|}
_ZN2kj14UnwindDetectorC2Ev:
 1293|      1|UnwindDetector::UnwindDetector(): uncaughtCount(_::uncaughtExceptionCount()) {}
_ZNK2kj14UnwindDetector11isUnwindingEv:
 1295|      3|bool UnwindDetector::isUnwinding() const {
 1296|      3|  return _::uncaughtExceptionCount() > uncaughtCount;
 1297|      3|}
_ZN2kj22getCaughtExceptionAsKjEv:
 1410|      2|kj::Exception getCaughtExceptionAsKj() {
 1411|      2|  try {
 1412|      2|    throw;
 1413|      2|  } catch (Exception& e) {
 1414|      2|    e.truncateCommonTrace();
 1415|      2|    return kj::mv(e);
 1416|      2|  } catch (CanceledException) {
 1417|      0|    throw;
 1418|      0|  } catch (std::bad_alloc& e) {
 1419|      0|    return Exception(Exception::Type::OVERLOADED,
 1420|      0|                     "(unknown)", -1, str("std::bad_alloc: ", e.what()));
 1421|      0|  } catch (std::exception& e) {
 1422|      0|    return Exception(Exception::Type::FAILED,
 1423|      0|                     "(unknown)", -1, str("std::exception: ", e.what()));
 1424|      0|  } catch (TopLevelProcessContext::CleanShutdownException) {
 1425|      0|    throw;
 1426|      0|  } catch (...) {
 1427|      0|#if __GNUC__ && !KJ_NO_RTTI
 1428|      0|    return Exception(Exception::Type::FAILED, "(unknown)", -1, str(
 1429|      0|        "unknown non-KJ exception of type: ", getCaughtExceptionType()));
 1430|       |#else
 1431|       |    return Exception(Exception::Type::FAILED, "(unknown)", -1, str("unknown non-KJ exception"));
 1432|       |#endif
 1433|      0|  }
 1434|      2|}
_ZN2kj17ExceptionCallback21RootExceptionCallbackC2Ev:
 1094|      1|  RootExceptionCallback(): ExceptionCallback(*this) {}
_ZN2kj17ExceptionCallback21RootExceptionCallback22onRecoverableExceptionEONS_9ExceptionE:
 1096|      2|  void onRecoverableException(Exception&& exception) override {
 1097|       |#if KJ_NO_EXCEPTIONS
 1098|       |    logException(LogSeverity::ERROR, mv(exception));
 1099|       |#else
 1100|      2|    if (_::uncaughtExceptionCount() > 0) {
  ------------------
  |  Branch (1100:9): [True: 0, False: 2]
  ------------------
 1101|       |      // Bad time to throw an exception.  Just log instead.
 1102|       |      //
 1103|       |      // TODO(someday): We should really compare uncaughtExceptionCount() against the count at
 1104|       |      //   the innermost runCatchingExceptions() frame in this thread to tell if exceptions are
 1105|       |      //   being caught correctly.
 1106|      0|      logException(LogSeverity::ERROR, mv(exception));
 1107|      2|    } else {
 1108|      2|      throw ExceptionImpl(mv(exception));
 1109|      2|    }
 1110|      2|#endif
 1111|      2|  }
_ZN2kj13ExceptionImplC2EONS_9ExceptionE:
  953|      2|  inline ExceptionImpl(Exception&& other): Exception(mv(other)) {
  954|      2|    insertIntoCurrentExceptions();
  955|      2|  }
_ZN2kj13ExceptionImpl27insertIntoCurrentExceptionsEv:
  980|      2|  void insertIntoCurrentExceptions() {
  981|      2|    nextCurrentException = currentException;
  982|      2|    currentException = this;
  983|      2|  }
_ZN2kj17ExceptionCallback21RootExceptionCallback14stackTraceModeEv:
 1138|      4|  StackTraceMode stackTraceMode() override {
 1139|       |#ifdef KJ_DEBUG
 1140|       |    return StackTraceMode::FULL;
 1141|       |#else
 1142|      4|    return StackTraceMode::ADDRESS_ONLY;
 1143|      4|#endif
 1144|      4|  }
_ZN2kj13ExceptionImplD2Ev:
  960|      2|  ~ExceptionImpl() {
  961|       |    // Look for ourselves in the list.
  962|      2|    for (auto* ptr = &currentException; *ptr != nullptr; ptr = &(*ptr)->nextCurrentException) {
  ------------------
  |  Branch (962:41): [True: 2, False: 0]
  ------------------
  963|      2|      if (*ptr == this) {
  ------------------
  |  Branch (963:11): [True: 2, False: 0]
  ------------------
  964|      2|        *ptr = nextCurrentException;
  965|      2|        return;
  966|      2|      }
  967|      2|    }
  968|       |
  969|       |    // Possibly the ExceptionImpl was destroyed on a different thread than created it? That's
  970|       |    // pretty bad, we'd better abort.
  971|      0|    abort();
  972|      2|  }
exception.c++:_ZN12_GLOBAL__N_125lsanIgnoreObjectAndReturnIN2kj17ExceptionCallback21RootExceptionCallbackEEEPT_S5_:
  105|      1|inline T* lsanIgnoreObjectAndReturn(T* ptr) {
  106|       |  // Defensively lsan_ignore_object since the documentation doesn't explicitly specify what happens
  107|       |  // if you call this multiple times on the same object.
  108|       |  // TODO(cleanup): Remove this per https://github.com/capnproto/capnproto/pull/1255.
  109|      1|  __lsan_ignore_object(ptr);
  110|      1|  return ptr;
  111|      1|}
exception.c++:_ZL20__lsan_ignore_objectPKv:
   98|      1|static void __lsan_ignore_object(const void* p) {}

_ZN2kj11AutoCloseFdD2Ev:
  328|      2|AutoCloseFd::~AutoCloseFd() noexcept(false) {
  329|      2|  if (fd >= 0) {
  ------------------
  |  Branch (329:7): [True: 2, False: 0]
  ------------------
  330|       |    // Don't use SYSCALL() here because close() should not be repeated on EINTR.
  331|      2|    if (miniposix::close(fd) < 0) {
  ------------------
  |  Branch (331:9): [True: 0, False: 2]
  ------------------
  332|      0|      KJ_FAIL_SYSCALL("close", errno, fd) {
  333|       |        // This ensures we don't throw an exception if unwinding.
  334|      0|        break;
  335|      0|      }
  336|      0|    }
  337|      2|  }
  338|      2|}

_ZN2kj1_5MutexC2Ev:
  210|      3|Mutex::Mutex(): futex(0) {}
_ZN2kj1_5MutexD2Ev:
  211|      3|Mutex::~Mutex() {
  212|       |  // This will crash anyway, might as well crash with a nice error message.
  213|      3|  KJ_ASSERT(futex == 0, "Mutex destroyed while locked.") { break; }
  ------------------
  |  Branch (213:3): [True: 3, False: 0]
  ------------------
  214|      3|}

_ZN2kj10RefcountedD2Ev:
   37|     16|Refcounted::~Refcounted() noexcept(false) {
   38|     16|  KJ_ASSERT(refcount == 0, "Refcounted object deleted with non-zero refcount.");
  ------------------
  |  Branch (38:3): [True: 16, False: 0]
  ------------------
   39|     16|}
_ZNK2kj10Refcounted11disposeImplEPv:
   41|     38|void Refcounted::disposeImpl(void* pointer) const {
   42|     38|  if (--refcount == 0) {
  ------------------
  |  Branch (42:7): [True: 16, False: 22]
  ------------------
   43|     16|    delete this;
   44|     16|  }
   45|     38|}

_ZN2kj10heapStringEm:
  138|      7|String heapString(size_t size) {
  139|      7|  char* buffer = _::HeapArrayDisposer::allocate<char>(size + 1);
  140|      7|  buffer[size] = '\0';
  141|      7|  return String(buffer, size, _::HeapArrayDisposer::instance);
  142|      7|}
_ZN2kj10heapStringEPKcm:
  144|      6|String heapString(const char* value, size_t size) {
  145|      6|  char* buffer = _::HeapArrayDisposer::allocate<char>(size + 1);
  146|      6|  if (size != 0u) {
  ------------------
  |  Branch (146:7): [True: 6, False: 0]
  ------------------
  147|      6|    memcpy(buffer, value, size);
  148|      6|  }
  149|      6|  buffer[size] = '\0';
  150|      6|  return String(buffer, size, _::HeapArrayDisposer::instance);
  151|      6|}
_ZNK2kj1_11StringifiermlEm:
  230|      2|CappedArray<char, sizeof(type) * 3 + 2> Stringifier::operator*(type i) const { \
  231|      2|  return stringifyImpl<type, unsigned>(i); \
  232|      2|}
string.c++:_ZN2kj1_L13stringifyImplImmEENS_11CappedArrayIcXplmlstT_Li3ELi2EEEES3_:
  200|      2|static CappedArray<char, sizeof(T) * 3 + 2> stringifyImpl(T i) {
  201|       |  // We don't use sprintf() because it's not async-signal-safe (for strPreallocated()).
  202|      2|  CappedArray<char, sizeof(T) * 3 + 2> result;
  203|      2|  bool negative = i < 0;
  204|       |  // Note that if `i` is the most-negative value, negating it produces the same bit value. But
  205|       |  // since it's a signed integer, this is considered an overflow. We therefore must make it
  206|       |  // unsigned first, then negate it, to avoid ubsan complaining.
  207|      2|  Unsigned u = i;
  208|      2|  if (negative) u = -u;
  ------------------
  |  Branch (208:7): [True: 0, False: 2]
  ------------------
  209|      2|  uint8_t reverse[sizeof(T) * 3 + 1];
  210|      2|  uint8_t* p = reverse;
  211|      2|  if (u == 0) {
  ------------------
  |  Branch (211:7): [True: 0, False: 2]
  ------------------
  212|      0|    *p++ = 0;
  213|      2|  } else {
  214|      5|    while (u > 0) {
  ------------------
  |  Branch (214:12): [True: 3, False: 2]
  ------------------
  215|      3|      *p++ = u % 10;
  216|      3|      u /= 10;
  217|      3|    }
  218|      2|  }
  219|       |
  220|      2|  char* p2 = result.begin();
  221|      2|  if (negative) *p2++ = '-';
  ------------------
  |  Branch (221:7): [True: 0, False: 2]
  ------------------
  222|      5|  while (p > reverse) {
  ------------------
  |  Branch (222:10): [True: 3, False: 2]
  ------------------
  223|      3|    *p2++ = '0' + *--p;
  224|      3|  }
  225|      2|  result.setSize(p2 - result.begin());
  226|      2|  return result;
  227|      2|}

time.c++:_ZNK2kj12_GLOBAL__N_119PosixMonotonicClock3nowEv:
  205|     16|  TimePoint now() const override {
  206|     16|    struct timespec ts;
  207|     16|    KJ_SYSCALL(clock_gettime(clockId, &ts));
  ------------------
  |  Branch (207:5): [True: 16, False: 0]
  ------------------
  208|     16|    return kj::origin<TimePoint>() + ts.tv_sec * kj::SECONDS + ts.tv_nsec * kj::NANOSECONDS;
  209|     16|  }

_ZN2kj9TimerImplD2Ev:
   84|      1|TimerImpl::~TimerImpl() noexcept(false) {}
_ZN2kj9TimerImpl9nextEventEv:
   86|      6|Maybe<TimePoint> TimerImpl::nextEvent() {
   87|      6|  auto iter = impl->timers.begin();
   88|      6|  if (iter == impl->timers.end()) {
  ------------------
  |  Branch (88:7): [True: 6, False: 0]
  ------------------
   89|      6|    return nullptr;
   90|      6|  } else {
   91|      0|    return (*iter)->time;
   92|      0|  }
   93|      6|}
_ZN2kj9TimerImpl18timeoutToNextEventENS_8AbsoluteINS_8QuantityIlNS_1_15NanosecondLabelEEENS3_9TimeLabelEEES5_m:
   95|      6|Maybe<uint64_t> TimerImpl::timeoutToNextEvent(TimePoint start, Duration unit, uint64_t max) {
   96|      6|  return nextEvent().map([&](TimePoint nextTime) -> uint64_t {
   97|      6|    if (nextTime <= start) return 0;
   98|       |
   99|      6|    Duration timeout = nextTime - start;
  100|       |
  101|      6|    uint64_t result = timeout / unit;
  102|      6|    bool roundUp = timeout % unit > 0 * SECONDS;
  103|       |
  104|      6|    if (result >= max) {
  105|      6|      return max;
  106|      6|    } else {
  107|      6|      return result + roundUp;
  108|      6|    }
  109|      6|  });
  110|      6|}
_ZN2kj9TimerImpl9advanceToENS_8AbsoluteINS_8QuantityIlNS_1_15NanosecondLabelEEENS3_9TimeLabelEEE:
  112|      6|void TimerImpl::advanceTo(TimePoint newTime) {
  113|       |  // It has been observed that clock_gettime 
  114|       |  // may return non monotonic time, even when CLOCK_MONOTONIC is used.
  115|       |  // We use kj::max to guard against this rare issue.
  116|       |  // - on mac: https://github.com/capnproto/capnproto/issues/1693
  117|       |  // - on linux: https://github.com/capnproto/capnproto/issues/2261
  118|      6|  time = kj::max(time, newTime);
  119|       |
  120|      6|  for (;;) {
  121|      6|    auto front = impl->timers.begin();
  122|      6|    if (front == impl->timers.end() || (*front)->time > time) {
  ------------------
  |  Branch (122:9): [True: 6, False: 0]
  |  Branch (122:9): [True: 6, False: 0]
  |  Branch (122:40): [True: 0, False: 0]
  ------------------
  123|      6|      break;
  124|      6|    }
  125|      0|    (*front)->fulfill();
  126|      0|  }
  127|      6|}

_ZN11ArgsManagerD2Ev:
  130|      2|ArgsManager::~ArgsManager() = default;
_ZN11ArgsManager11ForceSetArgERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_:
  628|      1|{
  629|      1|    LOCK(cs_args);
  ------------------
  |  |  268|      1|#define LOCK(cs) UniqueLock BITCOIN_UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
  |  |  ------------------
  |  |  |  |   11|      1|#define BITCOIN_UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
  |  |  |  |  ------------------
  |  |  |  |  |  |    9|      1|#define PASTE2(x, y) PASTE(x, y)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |    8|      1|#define PASTE(x, y) x ## y
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  630|      1|    m_settings.forced_settings[SettingName(strArg)] = strValue;
  631|      1|}
_ZN11ArgsManager9ClearArgsEv:
  694|      1|{
  695|      1|    LOCK(cs_args);
  ------------------
  |  |  268|      1|#define LOCK(cs) UniqueLock BITCOIN_UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
  |  |  ------------------
  |  |  |  |   11|      1|#define BITCOIN_UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
  |  |  |  |  ------------------
  |  |  |  |  |  |    9|      1|#define PASTE2(x, y) PASTE(x, y)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |    8|      1|#define PASTE(x, y) x ## y
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  696|      1|    m_settings = {};
  697|      1|    m_available_args.clear();
  698|      1|    m_command_args.clear();
  699|      1|    m_network_only_args.clear();
  700|      1|    m_config_sections.clear();
  701|      1|}
args.cpp:_ZL11SettingNameRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
   63|      1|{
   64|      1|    return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg;
  ------------------
  |  Branch (64:12): [True: 1, False: 0]
  |  Branch (64:30): [True: 1, False: 0]
  ------------------
   65|      1|}

_ZN15ChaCha20AlignedD2Ev:
   42|      3|{
   43|      3|    memory_cleanse(input, sizeof(input));
   44|      3|}
_ZN8ChaCha20D2Ev:
  332|      3|{
  333|      3|    memory_cleanse(m_buffer.data(), m_buffer.size());
  334|      3|}

_ZN9ChainCodeD2Ev:
   28|      1|    ~ChainCode() { memory_cleanse(data(), size()); }

_ZN10interfaces5ChainD2Ev:
  119|      1|    virtual ~Chain() = default;

ipc.cpp:_ZZN2mp10Connection12onDisconnectIZZN12_GLOBAL__N_112IpcFuzzSetupC1EvENKUlvE_clEvEUlvE_EEvOT_ENUlvE_clEv:
  472|      1|            [f = std::forward<F>(f), this]() mutable { m_loop->m_task_set->add(kj::evalLater(kj::mv(f))); }));
_ZZN2mp15ProxyClientBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationEC1ENS4_6ClientEPNS_10ConnectionEbENKUlvE0_clEv:
  556|      1|    m_context.cleanup_fns.emplace_front([this, destroy_connection, disconnect_cb]{
  557|      1|    {
  558|       |        // If the capnp interface defines a destroy method, call it to destroy
  559|       |        // the remote object, waiting for it to be deleted server side. If the
  560|       |        // capnp interface does not define a destroy method, this will just call
  561|       |        // an empty stub defined in the ProxyClientBase class and do nothing.
  562|       |        // Exceptions are caught and logged rather than propagated because
  563|       |        // ~ProxyClientBase is noexcept and the peer may be gone by the time
  564|       |        // this runs.
  565|      1|        if (kj::runCatchingExceptions([&]{ Sub::destroy(*this); }) != nullptr) {
  ------------------
  |  Branch (565:13): [True: 0, False: 1]
  ------------------
  566|      0|            MP_LOG(*m_context.loop, Log::Warning) << "Remote destroy call failed during cleanup. Continuing.";
  ------------------
  |  |  212|      0|#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
  |  |  ------------------
  |  |  |  |  210|      0|#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (210:87): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  567|      0|        }
  568|       |
  569|       |        // FIXME: Could just invoke removed addCleanup fn here instead of duplicating code
  570|      1|        m_context.loop->sync([&]() {
  571|       |            // Remove disconnect callback on cleanup so it doesn't run and try
  572|       |            // to access this object after it's destroyed. This call needs to
  573|       |            // run inside loop->sync() on the event loop thread because
  574|       |            // otherwise, if there were an ill-timed disconnect, the
  575|       |            // onDisconnect handler could fire and delete the Connection object
  576|       |            // before the removeSyncCleanup call.
  577|      1|            if (m_context.connection) m_context.connection->removeSyncCleanup(disconnect_cb);
  578|       |
  579|       |            // Release client capability by move-assigning to temporary.
  580|      1|            {
  581|      1|                typename Interface::Client(std::move(m_client));
  582|      1|            }
  583|      1|            if (destroy_connection) {
  584|      1|                delete m_context.connection;
  585|      1|                m_context.connection = nullptr;
  586|      1|            }
  587|      1|        });
  588|      1|    }
  589|      1|    });
_ZZZN2mp15ProxyClientBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationEC1ENS4_6ClientEPNS_10ConnectionEbENKUlvE0_clEvENKUlvE_clEv:
  565|      1|        if (kj::runCatchingExceptions([&]{ Sub::destroy(*this); }) != nullptr) {
_ZN2mp9EventLoop4syncIZZNS_15ProxyClientBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationEC1ENS6_6ClientEPNS_10ConnectionEbENKUlvE0_clEvEUlvE0_EEvOT_:
  273|      1|    {
  274|      1|        post(std::forward<Callable>(callable));
  275|      1|    }
_ZZZN2mp15ProxyClientBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationEC1ENS4_6ClientEPNS_10ConnectionEbENKUlvE0_clEvENKUlvE0_clEv:
  570|      1|        m_context.loop->sync([&]() {
  571|       |            // Remove disconnect callback on cleanup so it doesn't run and try
  572|       |            // to access this object after it's destroyed. This call needs to
  573|       |            // run inside loop->sync() on the event loop thread because
  574|       |            // otherwise, if there were an ill-timed disconnect, the
  575|       |            // onDisconnect handler could fire and delete the Connection object
  576|       |            // before the removeSyncCleanup call.
  577|      1|            if (m_context.connection) m_context.connection->removeSyncCleanup(disconnect_cb);
  ------------------
  |  Branch (577:17): [True: 1, False: 0]
  ------------------
  578|       |
  579|       |            // Release client capability by move-assigning to temporary.
  580|      1|            {
  581|      1|                typename Interface::Client(std::move(m_client));
  582|      1|            }
  583|      1|            if (destroy_connection) {
  ------------------
  |  Branch (583:17): [True: 1, False: 0]
  ------------------
  584|      1|                delete m_context.connection;
  585|      1|                m_context.connection = nullptr;
  586|      1|            }
  587|      1|        });
_ZN2mplsIRA13_KcEERNS_6LoggerES5_OT_:
  183|      2|    {
  184|      2|        if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
  ------------------
  |  Branch (184:13): [True: 2, False: 0]
  ------------------
  185|      2|        return logger;
  186|      2|    }
_ZN2mplsIRA12_KcEERNS_6LoggerES5_OT_:
  183|      2|    {
  184|      2|        if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
  ------------------
  |  Branch (184:13): [True: 2, False: 0]
  ------------------
  185|      2|        return logger;
  186|      2|    }
_ZN2mp15ProxyClientBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationED2Ev:
  595|      1|{
  596|      1|    MP_LOG(*m_context.loop, Log::Debug) << "Cleaning up " << CxxTypeName(*this) << " " << this;
  ------------------
  |  |  212|      1|#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
  |  |  ------------------
  |  |  |  |  210|      8|#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (210:87): [True: 1, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  597|      1|    CleanupRun(m_context.cleanup_fns);
  598|      1|    MP_LOG(*m_context.loop, Log::Debug) << "Destroying " << CxxTypeName(*this) << " " << this;
  ------------------
  |  |  212|      1|#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
  |  |  ------------------
  |  |  |  |  210|      8|#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (210:87): [True: 1, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  599|      1|}
_ZN2mplsIPNS_15ProxyClientBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationEEEERNS_6LoggerESA_OT_:
  183|      2|    {
  184|      2|        if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
  ------------------
  |  Branch (184:13): [True: 2, False: 0]
  ------------------
  185|      2|        return logger;
  186|      2|    }
_ZN2mp15ProxyServerBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationED2Ev:
  623|      1|{
  624|      1|    MP_LOG(*m_context.loop, Log::Debug) << "Cleaning up " << CxxTypeName(*this) << " " << this;
  ------------------
  |  |  212|      1|#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
  |  |  ------------------
  |  |  |  |  210|      8|#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (210:87): [True: 1, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  625|      1|    if (m_impl) {
  ------------------
  |  Branch (625:9): [True: 1, False: 0]
  ------------------
  626|       |        // If impl is non-null at this point, it means no client is waiting for
  627|       |        // the m_impl server object to be destroyed synchronously. This can
  628|       |        // happen either if the interface did not define a "destroy" method (see
  629|       |        // invokeDestroy method below), or if a destroy method was defined, but
  630|       |        // the connection was broken before it could be called.
  631|       |        //
  632|       |        // In either case, be conservative and run the cleanup on an
  633|       |        // asynchronous thread, to avoid destructors or cleanup functions
  634|       |        // blocking or deadlocking the current EventLoop thread, since they
  635|       |        // could be making IPC calls.
  636|       |        //
  637|       |        // Technically this is a little too conservative since if the interface
  638|       |        // defines a "destroy" method, but the destroy method does not accept a
  639|       |        // Context parameter specifying a worker thread, the cleanup method
  640|       |        // would run on the EventLoop thread normally (when connection is
  641|       |        // unbroken), but will not run on the EventLoop thread now (when
  642|       |        // connection is broken). Probably some refactoring of the destructor
  643|       |        // and invokeDestroy function is possible to make this cleaner and more
  644|       |        // consistent.
  645|      1|        m_context.loop->addAsyncCleanup([impl=std::move(m_impl), fns=std::move(m_context.cleanup_fns)]() mutable {
  646|      1|            impl.reset();
  647|      1|            CleanupRun(fns);
  648|      1|        });
  649|      1|    }
  650|      1|    assert(m_context.cleanup_fns.empty());
  ------------------
  |  Branch (650:5): [True: 1, False: 0]
  ------------------
  651|      1|    MP_LOG(*m_context.loop, Log::Debug) << "Destroying " << CxxTypeName(*this) << " " << this;
  ------------------
  |  |  212|      1|#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
  |  |  ------------------
  |  |  |  |  210|      8|#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (210:87): [True: 1, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  652|      1|}
_ZN2mplsIPNS_15ProxyServerBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationEEEERNS_6LoggerESA_OT_:
  183|      2|    {
  184|      2|        if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
  ------------------
  |  Branch (184:13): [True: 2, False: 0]
  ------------------
  185|      2|        return logger;
  186|      2|    }
_ZZN2mp15ProxyServerBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationED1EvENUlvE_clEv:
  645|      1|        m_context.loop->addAsyncCleanup([impl=std::move(m_impl), fns=std::move(m_context.cleanup_fns)]() mutable {
  646|      1|            impl.reset();
  647|      1|            CleanupRun(fns);
  648|      1|        });
_ZN2mplsIRA20_KcEERNS_6LoggerES5_OT_:
  183|      2|    {
  184|      2|        if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
  ------------------
  |  Branch (184:13): [True: 2, False: 0]
  ------------------
  185|      2|        return logger;
  186|      2|    }
_ZN2mp6LoggerC2ERKNS_10LogOptionsENS_3LogE:
  169|      8|    Logger(const LogOptions& options, Log log_level) : m_options(options), m_log_level(log_level) {}
_ZNK2mp6LoggercvbEv:
  195|      8|    {
  196|      8|        return enabled();
  197|      8|    }
_ZNK2mp6Logger7enabledEv:
  201|     62|    {
  202|     62|        return m_options.log_fn && m_log_level >= m_options.log_level;
  ------------------
  |  Branch (202:16): [True: 62, False: 0]
  |  Branch (202:36): [True: 62, False: 0]
  ------------------
  203|     62|    }
_ZN2mp6LoggerD2Ev:
  177|      8|    {
  178|      8|        if (enabled()) m_options.log_fn({std::move(m_buffer).str(), m_log_level});
  ------------------
  |  Branch (178:13): [True: 8, False: 0]
  ------------------
  179|      8|    }
_ZN2mplsIRA2_KcEERNS_6LoggerES5_OT_:
  183|     12|    {
  184|     12|        if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
  ------------------
  |  Branch (184:13): [True: 12, False: 0]
  ------------------
  185|     12|        return logger;
  186|     12|    }
_ZN2mplsINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEERNS_6LoggerES9_OT_:
  183|     14|    {
  184|     14|        if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
  ------------------
  |  Branch (184:13): [True: 14, False: 0]
  ------------------
  185|     14|        return logger;
  186|     14|    }
_ZN2mplsIRA3_KcEERNS_6LoggerES5_OT_:
  183|      8|    {
  184|      8|        if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
  ------------------
  |  Branch (184:13): [True: 8, False: 0]
  ------------------
  185|      8|        return logger;
  186|      8|    }
_ZN2mplsIRA50_KcEERNS_6LoggerES5_OT_:
  183|      1|    {
  184|      1|        if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
  ------------------
  |  Branch (184:13): [True: 1, False: 0]
  ------------------
  185|      1|        return logger;
  186|      1|    }
_ZN2mplsIRA21_KcEERNS_6LoggerES5_OT_:
  183|      1|    {
  184|      1|        if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
  ------------------
  |  Branch (184:13): [True: 1, False: 0]
  ------------------
  185|      1|        return logger;
  186|      1|    }

_ZN2mp13clientDestroyINS_11ProxyClientIN4test4fuzz8messages16IpcFuzzInterfaceEEEEEvRT_:
  672|      1|{
  673|      1|    MP_LOG(*client.m_context.loop, Log::Debug) << "IPC client destroy " << CxxTypeName(client);
  ------------------
  |  |  212|      1|#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
  |  |  ------------------
  |  |  |  |  210|      6|#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (210:87): [True: 1, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  674|      1|}
_ZN2mp13serverDestroyINS_11ProxyServerIN4test4fuzz8messages16IpcFuzzInterfaceEEEEEvRT_:
  678|      1|{
  679|      1|    MP_LOG(*server.m_context.loop, Log::Debug) << "IPC server destroy " << CxxTypeName(server);
  ------------------
  |  |  212|      1|#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
  |  |  ------------------
  |  |  |  |  210|      6|#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (210:87): [True: 1, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  680|      1|}

_ZN2mp15ProxyClientBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationE7destroyERS6_:
  130|      1|    static void destroy(Super&) {}
_ZN2mp12EventLoopRefD2Ev:
   58|      6|    ~EventLoopRef() { reset(); }
_ZN2mp10CleanupRunERNSt3__14listINS0_8functionIFvvEEENS0_9allocatorIS4_EEEE:
   39|      2|inline void CleanupRun(CleanupList& fns) {
   40|      3|    while (!fns.empty()) {
  ------------------
  |  Branch (40:12): [True: 1, False: 2]
  ------------------
   41|      1|        auto fn = std::move(fns.front());
   42|      1|        fns.pop_front();
   43|      1|        fn();
   44|      1|    }
   45|      2|}
_ZNK2mp12EventLoopRefdeEv:
   59|     12|    EventLoop& operator*() const { assert(m_loop); return *m_loop; }
  ------------------
  |  Branch (59:36): [True: 12, False: 0]
  ------------------
_ZNK2mp12EventLoopRefptEv:
   60|      9|    EventLoop* operator->() const { assert(m_loop); return m_loop; }
  ------------------
  |  Branch (60:37): [True: 9, False: 0]
  ------------------

_ZN2mp11CxxTypeNameINS_15ProxyClientBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationEEEENSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEERKT_:
  297|      2|{
  298|      2|#ifdef __cpp_rtti
  299|      2|    return _demangle(typeid(std::decay_t<T>).name());
  300|       |#else
  301|       |    return "<type information unavailable without rtti>";
  302|       |#endif
  303|      2|}
_ZN2mp11CxxTypeNameINS_15ProxyServerBaseIN4test4fuzz8messages16IpcFuzzInterfaceE21IpcFuzzImplementationEEEENSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEERKT_:
  297|      2|{
  298|      2|#ifdef __cpp_rtti
  299|      2|    return _demangle(typeid(std::decay_t<T>).name());
  300|       |#else
  301|       |    return "<type information unavailable without rtti>";
  302|       |#endif
  303|      2|}
_ZN2mp11CxxTypeNameINS_11ProxyClientIN4test4fuzz8messages16IpcFuzzInterfaceEEEEENSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKT_:
  297|      1|{
  298|      1|#ifdef __cpp_rtti
  299|      1|    return _demangle(typeid(std::decay_t<T>).name());
  300|       |#else
  301|       |    return "<type information unavailable without rtti>";
  302|       |#endif
  303|      1|}
_ZN2mp11CxxTypeNameINS_11ProxyServerIN4test4fuzz8messages16IpcFuzzInterfaceEEEEENSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKT_:
  297|      1|{
  298|      1|#ifdef __cpp_rtti
  299|      1|    return _demangle(typeid(std::decay_t<T>).name());
  300|       |#else
  301|       |    return "<type information unavailable without rtti>";
  302|       |#endif
  303|      1|}
_ZN2mp4Lock13assert_lockedERNS_5MutexE:
  184|      8|    {
  185|      8|        assert(m_lock.mutex() == &mutex.m_mutex);
  ------------------
  |  Branch (185:9): [True: 8, False: 0]
  ------------------
  186|      8|        assert(m_lock);
  ------------------
  |  Branch (186:9): [True: 8, False: 0]
  ------------------
  187|      8|    }
_ZN2mp4Lock6unlockEv:
  181|      4|    void unlock() MP_RELEASE() { m_lock.unlock(); }
_ZN2mp4Lock4lockEv:
  182|      3|    void lock() MP_ACQUIRE() { m_lock.lock(); }
_ZN2mp4LockC2ERNS_5MutexE:
  179|     14|    explicit Lock(Mutex& m) MP_ACQUIRE(m) : m_lock(m.m_mutex) {}
_ZN2mp4LockD2Ev:
  180|     14|    ~Lock() MP_RELEASE() = default;
_ZN2mp9_demangleEPKc:
  285|      6|{
  286|      6|    int status = 0;
  287|      6|    std::unique_ptr<char, void(*)(void*)> p{
  288|      6|        abi::__cxa_demangle(m, /*output_buffer=*/nullptr, /*length=*/nullptr, &status), std::free};
  289|      6|    return (status == 0 && p) ? p.get() : m;   // fall back on mangled if needed
  ------------------
  |  Branch (289:13): [True: 6, False: 0]
  |  Branch (289:28): [True: 6, False: 0]
  ------------------
  290|      6|}
_ZN2mp10PtrOrValueINS_4LockEEC2IJRNS_5MutexEEEEPS1_DpOT_:
  145|      8|    PtrOrValue(T* ptr, Args&&... args) : data(ptr ? ptr : std::variant<T*, T>{std::in_place_type<T>, std::forward<Args>(args)...}) {}
  ------------------
  |  Branch (145:47): [True: 4, False: 4]
  ------------------
_ZN2mp10PtrOrValueINS_4LockEEptEv:
  148|      9|    T* operator->() { return &**this; }
_ZN2mp10PtrOrValueINS_4LockEEdeEv:
  147|      9|    T& operator*() { return data.index() ? std::get<T>(data) : *std::get<T*>(data); }
  ------------------
  |  Branch (147:29): [True: 5, False: 4]
  ------------------
_ZN2mp11UnlockGuardINS_4LockEEC2ERS1_:
  207|      3|    UnlockGuard(Lock& lock) : m_lock(lock) { m_lock.unlock(); }
_ZN2mp11UnlockGuardINS_4LockEED2Ev:
  208|      3|    ~UnlockGuard() { m_lock.lock(); }
_ZN2mp6UnlockINS_4LockERN2kj8FunctionIFvvEEEEEvRT_OT0_:
  214|      1|{
  215|      1|    const UnlockGuard<Lock> unlock(lock);
  216|      1|    callback();
  217|      1|}
proxy.cpp:_ZN2mp6UnlockINS_4LockEZNS_9EventLoop4postEN2kj8FunctionIFvvEEEE3$_1EEvRT_OT0_:
  214|      1|{
  215|      1|    const UnlockGuard<Lock> unlock(lock);
  216|      1|    callback();
  217|      1|}
_ZN2mp6UnlockINS_4LockERKNSt3__18functionIFvvEEEEEvRT_OT0_:
  214|      1|{
  215|      1|    const UnlockGuard<Lock> unlock(lock);
  216|      1|    callback();
  217|      1|}

_ZN2mp12EventLoopRefC2ERNS_9EventLoopEPNS_4LockE:
   52|      2|EventLoopRef::EventLoopRef(EventLoop& loop, Lock* lock) : m_loop(&loop), m_lock(lock)
   53|      2|{
   54|      2|    auto loop_lock{PtrOrValue{m_lock, m_loop->m_mutex}};
   55|      2|    loop_lock->assert_locked(m_loop->m_mutex);
   56|      2|    m_loop->m_num_refs += 1;
   57|      2|}
_ZN2mp12EventLoopRef5resetEb:
   63|      7|{
   64|      7|    if (auto* loop{m_loop}) {
  ------------------
  |  Branch (64:15): [True: 6, False: 1]
  ------------------
   65|      6|        m_loop = nullptr;
   66|      6|        auto loop_lock{PtrOrValue{m_lock, loop->m_mutex}};
   67|      6|        loop_lock->assert_locked(loop->m_mutex);
   68|      6|        assert(loop->m_num_refs > 0);
  ------------------
  |  Branch (68:9): [True: 6, False: 0]
  ------------------
   69|      6|        loop->m_num_refs -= 1;
   70|      6|        if (loop->done()) {
  ------------------
  |  Branch (70:13): [True: 1, False: 5]
  ------------------
   71|      1|            loop->m_cv.notify_all();
   72|      1|            int post_fd{loop->m_post_fd};
   73|      1|            loop_lock->unlock();
   74|      1|            char buffer = 0;
   75|      1|            KJ_SYSCALL(write(post_fd, &buffer, 1)); // NOLINT(bugprone-suspicious-semicolon)
  ------------------
  |  Branch (75:13): [True: 1, False: 0]
  ------------------
   76|       |            // By default, do not try to relock `loop_lock` after writing,
   77|       |            // because the event loop could wake up and destroy itself and the
   78|       |            // mutex might no longer exist.
   79|      1|            if (relock) loop_lock->lock();
  ------------------
  |  Branch (79:17): [True: 0, False: 1]
  ------------------
   80|      1|        }
   81|      6|    }
   82|      7|}
_ZN2mp10ConnectionD2Ev:
   87|      2|{
   88|       |    // Connection destructor is always called on the event loop thread. If this
   89|       |    // is a local disconnect, it will trigger I/O, so this needs to run on the
   90|       |    // event loop thread, and if there was a remote disconnect, this is called
   91|       |    // by an onDisconnect callback directly from the event loop thread.
   92|      2|    assert(std::this_thread::get_id() == m_loop->m_thread_id);
  ------------------
  |  Branch (92:5): [True: 2, False: 0]
  ------------------
   93|       |
   94|       |    // Try to cancel any calls that may be executing.
   95|      2|    m_canceler.cancel("Interrupted by disconnect");
   96|       |
   97|       |    // Shut down RPC system first, since this will garbage collect any
   98|       |    // ProxyServer objects that were not freed before the connection was closed.
   99|       |    // Typically all ProxyServer objects associated with this connection will be
  100|       |    // freed before this call returns. However that will not be the case if
  101|       |    // there are asynchronous IPC calls over this connection still currently
  102|       |    // executing. In that case, Cap'n Proto will destroy the ProxyServer objects
  103|       |    // after the calls finish.
  104|      2|    m_rpc_system.reset();
  105|       |
  106|       |    // ProxyClient cleanup handlers are in sync list, and ProxyServer cleanup
  107|       |    // handlers are in the async list.
  108|       |    //
  109|       |    // The ProxyClient cleanup handlers are synchronous because they are fast
  110|       |    // and don't do anything besides release capnp resources and reset state so
  111|       |    // future calls to client methods immediately throw exceptions instead of
  112|       |    // trying to communicate across the socket. The synchronous callbacks set
  113|       |    // ProxyClient capability pointers to null, so new method calls on client
  114|       |    // objects fail without triggering i/o or relying on event loop which may go
  115|       |    // out of scope or trigger obscure capnp i/o errors.
  116|       |    //
  117|       |    // The ProxyServer cleanup handlers call user defined destructors on the server
  118|       |    // object, which can run arbitrary blocking bitcoin code so they have to run
  119|       |    // asynchronously in a different thread. The asynchronous cleanup functions
  120|       |    // intentionally aren't started until after the synchronous cleanup
  121|       |    // functions run, so client objects are fully disconnected before bitcoin
  122|       |    // code in the destructors are run. This way if the bitcoin code tries to
  123|       |    // make client requests the requests will just fail immediately instead of
  124|       |    // sending i/o or accessing the event loop.
  125|       |    //
  126|       |    // The context where Connection objects are destroyed and this destructor is invoked
  127|       |    // is different depending on whether this is an outgoing connection being used
  128|       |    // to make an Init.makeX call() (e.g. Init.makeNode or Init.makeWalletClient) or an incoming
  129|       |    // connection implementing the Init interface and handling the Init.makeX() calls.
  130|       |    //
  131|       |    // Either way when a connection is closed, capnp behavior is to call all
  132|       |    // ProxyServer object destructors first, and then trigger an onDisconnect
  133|       |    // callback.
  134|       |    //
  135|       |    // On incoming side of the connection, the onDisconnect callback is written
  136|       |    // to delete the Connection object from the m_incoming_connections and call
  137|       |    // this destructor which calls Connection::disconnect.
  138|       |    //
  139|       |    // On the outgoing side, the Connection object is owned by top level client
  140|       |    // object client, which onDisconnect handler doesn't have ready access to,
  141|       |    // so onDisconnect handler just calls Connection::disconnect directly
  142|       |    // instead.
  143|       |    //
  144|       |    // Either way disconnect code runs in the event loop thread and called both
  145|       |    // on clean and unclean shutdowns. In unclean shutdown case when the
  146|       |    // connection is broken, sync and async cleanup lists will be filled with
  147|       |    // callbacks. In the clean shutdown case both lists will be empty.
  148|      2|    Lock lock{m_loop->m_mutex};
  149|      2|    while (!m_sync_cleanup_fns.empty()) {
  ------------------
  |  Branch (149:12): [True: 0, False: 2]
  ------------------
  150|      0|        CleanupList fn;
  151|      0|        fn.splice(fn.begin(), m_sync_cleanup_fns, m_sync_cleanup_fns.begin());
  152|      0|        Unlock(lock, fn.front());
  153|      0|    }
  154|      2|}
_ZN2mp10Connection17removeSyncCleanupENSt3__115__list_iteratorINS1_8functionIFvvEEEPvEE:
  171|      1|{
  172|       |    // Require cleanup functions to be removed on the event loop thread to avoid
  173|       |    // needing to deal with them being removed in the middle of a disconnect.
  174|      1|    assert(std::this_thread::get_id() == m_loop->m_thread_id);
  ------------------
  |  Branch (174:5): [True: 1, False: 0]
  ------------------
  175|      1|    const Lock lock(m_loop->m_mutex);
  176|      1|    m_sync_cleanup_fns.erase(it);
  177|      1|}
_ZN2mp9EventLoop15addAsyncCleanupENSt3__18functionIFvvEEE:
  180|      1|{
  181|      1|    const Lock lock(m_mutex);
  182|       |    // Add async cleanup callbacks to the back of the list. Unlike the sync
  183|       |    // cleanup list, this list order is more significant because it determines
  184|       |    // the order server objects are destroyed when there is a sudden disconnect,
  185|       |    // and it is possible objects may need to be destroyed in a certain order.
  186|       |    // This function is called in ProxyServerBase destructors, and since capnp
  187|       |    // destroys ProxyServer objects in LIFO order, we should preserve this
  188|       |    // order, and add cleanup callbacks to the end of the list so they can be
  189|       |    // run starting from the beginning of the list.
  190|       |    //
  191|       |    // In bitcoin core, running these callbacks in the right order is
  192|       |    // particularly important for the wallet process, because it uses blocking
  193|       |    // shared_ptrs and requires Chain::Notification pointers owned by the node
  194|       |    // process to be destroyed before the WalletLoader objects owned by the node
  195|       |    // process, otherwise shared pointer counts of the CWallet objects (which
  196|       |    // inherit from Chain::Notification) will not be 1 when WalletLoader
  197|       |    // destructor runs and it will wait forever for them to be released.
  198|      1|    m_async_fns->emplace_back(std::move(fn));
  199|      1|    startAsyncThread();
  200|      1|}
_ZN2mp9EventLoopD2Ev:
  216|      1|{
  217|      1|    if (m_async_thread.joinable()) m_async_thread.join();
  ------------------
  |  Branch (217:9): [True: 1, False: 0]
  ------------------
  218|      1|    const Lock lock(m_mutex);
  219|      1|    KJ_ASSERT(m_post_fn == nullptr);
  ------------------
  |  Branch (219:5): [True: 1, False: 0]
  ------------------
  220|      1|    KJ_ASSERT(!m_async_fns);
  ------------------
  |  Branch (220:5): [True: 1, False: 0]
  ------------------
  221|      1|    KJ_ASSERT(m_wait_fd == -1);
  ------------------
  |  Branch (221:5): [True: 1, False: 0]
  ------------------
  222|      1|    KJ_ASSERT(m_post_fd == -1);
  ------------------
  |  Branch (222:5): [True: 1, False: 0]
  ------------------
  223|      1|    KJ_ASSERT(m_num_refs == 0);
  ------------------
  |  Branch (223:5): [True: 1, False: 0]
  ------------------
  224|       |
  225|       |    // Spin event loop. wait for any promises triggered by RPC shutdown.
  226|       |    // auto cleanup = kj::evalLater([]{});
  227|       |    // cleanup.wait(m_io_context.waitScope);
  228|      1|}
_ZN2mp9EventLoop4loopEv:
  231|      0|{
  232|      0|    assert(!g_thread_context.loop_thread);
  ------------------
  |  Branch (232:5): [True: 0, False: 0]
  ------------------
  233|      0|    g_thread_context.loop_thread = true;
  234|      0|    KJ_DEFER(g_thread_context.loop_thread = false);
  235|       |
  236|      0|    {
  237|      0|        const Lock lock(m_mutex);
  238|      0|        assert(!m_async_fns);
  ------------------
  |  Branch (238:9): [True: 0, False: 0]
  ------------------
  239|      0|        m_async_fns.emplace();
  240|      0|    }
  241|       |
  242|      0|    kj::Own<kj::AsyncIoStream> wait_stream{
  243|      0|        m_io_context.lowLevelProvider->wrapSocketFd(m_wait_fd, kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP)};
  244|      0|    int post_fd{m_post_fd};
  245|      0|    char buffer = 0;
  246|      1|    for (;;) {
  247|      1|        const size_t read_bytes = wait_stream->read(&buffer, 0, 1).wait(m_io_context.waitScope);
  248|      1|        if (read_bytes != 1) throw std::logic_error("EventLoop wait_stream closed unexpectedly");
  ------------------
  |  Branch (248:13): [True: 0, False: 1]
  ------------------
  249|      1|        Lock lock(m_mutex);
  250|      1|        if (m_post_fn) {
  ------------------
  |  Branch (250:13): [True: 1, False: 0]
  ------------------
  251|       |            // m_post_fn throwing is never expected. If it does happen, the caller
  252|       |            // of EventLoop::post() will return without any indication of failure,
  253|       |            // which will likely cause other bugs. Log the error and continue.
  254|      1|            KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() MP_REQUIRES(m_mutex) { Unlock(lock, *m_post_fn); })) {
  ------------------
  |  Branch (254:13): [True: 0, False: 1]
  ------------------
  255|      0|                MP_LOG(*this, Log::Error) << "EventLoop: m_post_fn threw: " << kj::str(*exception).cStr();
  ------------------
  |  |  212|      0|#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
  |  |  ------------------
  |  |  |  |  210|      0|#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (210:87): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  256|      0|            }
  257|      1|            m_post_fn = nullptr;
  258|      1|            m_cv.notify_all();
  259|      1|        } else if (done()) {
  ------------------
  |  Branch (259:20): [True: 1, False: 18.4E]
  ------------------
  260|       |            // Intentionally do not break if m_post_fn was set, even if done()
  261|       |            // would return true, to ensure that the EventLoopRef write(post_fd)
  262|       |            // call always succeeds and the loop does not exit between the time
  263|       |            // that the done condition is set and the write call is made.
  264|      1|            break;
  265|      1|        }
  266|      1|    }
  267|      1|    MP_LOG(*this, Log::Info) << "EventLoop::loop done, cancelling event listeners.";
  ------------------
  |  |  212|      0|#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
  |  |  ------------------
  |  |  |  |  210|      4|#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (210:87): [True: 1, False: 18.4E]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  268|      0|    m_task_set.reset();
  269|      1|    MP_LOG(*this, Log::Info) << "EventLoop::loop bye.";
  ------------------
  |  |  212|      0|#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
  |  |  ------------------
  |  |  |  |  210|      4|#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (210:87): [True: 1, False: 18.4E]
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  270|      0|    wait_stream = nullptr;
  271|  18.4E|    KJ_SYSCALL(::close(post_fd));
  ------------------
  |  Branch (271:5): [True: 1, False: 18.4E]
  ------------------
  272|      0|    const Lock lock(m_mutex);
  273|      0|    m_wait_fd = -1;
  274|      0|    m_post_fd = -1;
  275|      0|    m_async_fns.reset();
  276|      0|    m_cv.notify_all();
  277|      0|}
_ZN2mp9EventLoop4postEN2kj8FunctionIFvvEEE:
  280|      1|{
  281|      1|    if (std::this_thread::get_id() == m_thread_id) {
  ------------------
  |  Branch (281:9): [True: 0, False: 1]
  ------------------
  282|      0|        fn();
  283|      0|        return;
  284|      0|    }
  285|      1|    Lock lock(m_mutex);
  286|      1|    EventLoopRef ref(*this, &lock);
  287|      1|    m_cv.wait(lock.m_lock, [this]() MP_REQUIRES(m_mutex) { return m_post_fn == nullptr; });
  288|      1|    m_post_fn = &fn;
  289|      1|    int post_fd{m_post_fd};
  290|      1|    Unlock(lock, [&] {
  291|      1|        char buffer = 0;
  292|      1|        KJ_SYSCALL(write(post_fd, &buffer, 1));
  293|      1|    });
  294|      1|    m_cv.wait(lock.m_lock, [this, &fn]() MP_REQUIRES(m_mutex) { return m_post_fn != &fn; });
  295|      1|}
_ZN2mp9EventLoop16startAsyncThreadEv:
  298|      1|{
  299|      1|    assert (std::this_thread::get_id() == m_thread_id);
  ------------------
  |  Branch (299:5): [True: 1, False: 0]
  ------------------
  300|      1|    if (m_async_thread.joinable()) {
  ------------------
  |  Branch (300:9): [True: 0, False: 1]
  ------------------
  301|       |        // Notify to wake up the async thread if it is already running.
  302|      0|        m_cv.notify_all();
  303|      1|    } else if (!m_async_fns->empty()) {
  ------------------
  |  Branch (303:16): [True: 1, False: 0]
  ------------------
  304|      1|        m_async_thread = std::thread([this] {
  305|      1|            Lock lock(m_mutex);
  306|      1|            while (m_async_fns) {
  307|      1|                if (!m_async_fns->empty()) {
  308|      1|                    EventLoopRef ref{*this, &lock};
  309|      1|                    const std::function<void()> fn = std::move(m_async_fns->front());
  310|      1|                    m_async_fns->pop_front();
  311|      1|                    Unlock(lock, fn);
  312|       |                    // Important to relock because of the wait() call below.
  313|      1|                    ref.reset(/*relock=*/true);
  314|       |                    // Continue without waiting in case there are more async_fns
  315|      1|                    continue;
  316|      1|                }
  317|      1|                m_cv.wait(lock.m_lock);
  318|      1|            }
  319|      1|        });
  320|      1|    }
  321|      1|}
_ZNK2mp9EventLoop4doneEv:
  324|      7|{
  325|      7|    assert(m_num_refs >= 0);
  ------------------
  |  Branch (325:5): [True: 7, False: 0]
  ------------------
  326|      7|    return m_num_refs == 0 && m_async_fns->empty();
  ------------------
  |  Branch (326:12): [True: 2, False: 5]
  |  Branch (326:31): [True: 2, False: 0]
  ------------------
  327|      7|}
_ZN2mp14LongThreadNameEPKc:
  468|      8|{
  469|      8|    return g_thread_context.thread_name.empty() ? ThreadName(exe_name) : g_thread_context.thread_name;
  ------------------
  |  Branch (469:12): [True: 8, False: 0]
  ------------------
  470|      8|}
proxy.cpp:_ZZN2mp9EventLoop4postEN2kj8FunctionIFvvEEEENK3$_0clEv:
  287|      1|    m_cv.wait(lock.m_lock, [this]() MP_REQUIRES(m_mutex) { return m_post_fn == nullptr; });
proxy.cpp:_ZZN2mp9EventLoop4postEN2kj8FunctionIFvvEEEENK3$_1clEv:
  290|      1|    Unlock(lock, [&] {
  291|      1|        char buffer = 0;
  292|      1|        KJ_SYSCALL(write(post_fd, &buffer, 1));
  ------------------
  |  Branch (292:9): [True: 1, False: 0]
  ------------------
  293|      1|    });
proxy.cpp:_ZZN2mp9EventLoop4postEN2kj8FunctionIFvvEEEENK3$_2clEv:
  294|      2|    m_cv.wait(lock.m_lock, [this, &fn]() MP_REQUIRES(m_mutex) { return m_post_fn != &fn; });
proxy.cpp:_ZZN2mp9EventLoop16startAsyncThreadEvENK3$_0clEv:
  304|      1|        m_async_thread = std::thread([this] {
  305|      1|            Lock lock(m_mutex);
  306|      4|            while (m_async_fns) {
  ------------------
  |  Branch (306:20): [True: 3, False: 1]
  ------------------
  307|      3|                if (!m_async_fns->empty()) {
  ------------------
  |  Branch (307:21): [True: 1, False: 2]
  ------------------
  308|      1|                    EventLoopRef ref{*this, &lock};
  309|      1|                    const std::function<void()> fn = std::move(m_async_fns->front());
  310|      1|                    m_async_fns->pop_front();
  311|      1|                    Unlock(lock, fn);
  312|       |                    // Important to relock because of the wait() call below.
  313|      1|                    ref.reset(/*relock=*/true);
  314|       |                    // Continue without waiting in case there are more async_fns
  315|      1|                    continue;
  316|      1|                }
  317|      2|                m_cv.wait(lock.m_lock);
  318|      2|            }
  319|      1|        });

_ZN2mp10ThreadNameEPKc:
   65|      8|{
   66|      8|    char thread_name[16] = {0};
   67|      8|#ifdef HAVE_PTHREAD_GETNAME_NP
   68|      8|    pthread_getname_np(pthread_self(), thread_name, sizeof(thread_name));
   69|      8|#endif // HAVE_PTHREAD_GETNAME_NP
   70|       |
   71|      8|    std::ostringstream buffer;
   72|      8|    buffer << (exe_name ? exe_name : "") << "-" << getpid() << "/";
  ------------------
  |  Branch (72:16): [True: 8, False: 0]
  ------------------
   73|       |
   74|      8|    if (thread_name[0] != '\0') {
  ------------------
  |  Branch (74:9): [True: 8, False: 0]
  ------------------
   75|      8|        buffer << thread_name << "-";
   76|      8|    }
   77|       |
   78|       |    // Prefer platform specific thread ids over the standard C++11 ones because
   79|       |    // the former are shorter and are the same as what gdb prints "LWP ...".
   80|      8|#ifdef __linux__
   81|      8|    buffer << syscall(SYS_gettid);
   82|       |#elif defined(HAVE_PTHREAD_THREADID_NP)
   83|       |    uint64_t tid = 0;
   84|       |    pthread_threadid_np(nullptr, &tid);
   85|       |    buffer << tid;
   86|       |#elif defined(HAVE_PTHREAD_GETTHREADID_NP)
   87|       |    buffer << pthread_getthreadid_np();
   88|       |#else
   89|       |    buffer << std::this_thread::get_id();
   90|       |#endif
   91|       |
   92|      8|    return std::move(buffer).str();
   93|      8|}

ipc.cpp:_ZZZN12_GLOBAL__N_112IpcFuzzSetupC1EvENKUlvE_clEvENKUlN2mp10LogMessageEE_clES3_:
   34|      8|            mp::EventLoop loop("ipc-fuzz", [](mp::LogMessage message) {
   35|      8|                if (message.level == mp::Log::Raise) throw std::runtime_error(message.message);
  ------------------
  |  Branch (35:21): [True: 0, False: 8]
  ------------------
   36|      8|            });
ipc.cpp:_ZZZN12_GLOBAL__N_112IpcFuzzSetupC1EvENKUlvE_clEvENKUlvE_clEv:
   47|      1|            server_connection->onDisconnect([&] { server_connection.reset(); });
ipc.cpp:_ZN12_GLOBAL__N_112IpcFuzzSetupD2Ev:
   64|      1|    {
   65|      1|        m_client.reset();
   66|      1|        if (m_loop_thread.joinable()) m_loop_thread.join();
  ------------------
  |  Branch (66:13): [True: 1, False: 0]
  ------------------
   67|      1|    }

_ZN11ECC_ContextD2Ev:
  501|      1|{
  502|      1|    ECC_Stop();
  503|      1|}
key.cpp:_ZL8ECC_Stopv:
  486|      1|static void ECC_Stop() {
  487|      1|    secp256k1_context *ctx = secp256k1_context_sign;
  488|      1|    secp256k1_context_sign = nullptr;
  489|       |
  490|      1|    if (ctx) {
  ------------------
  |  Branch (490:9): [True: 1, False: 0]
  ------------------
  491|      1|        secp256k1_context_destroy(ctx);
  492|      1|    }
  493|      1|}

_Z11LogInstancev:
   27|      1|{
   28|       |/**
   29|       | * NOTE: the logger instances is leaked on exit. This is ugly, but will be
   30|       | * cleaned up by the OS/libc. Defining a logger as a global object doesn't work
   31|       | * since the order of destruction of static/global objects is undefined.
   32|       | * Consider if the logger gets destroyed, and then some later destructor calls
   33|       | * LogInfo, maybe indirectly, and you get a core dump at shutdown trying to
   34|       | * access the logger. When the shutdown sequence is fully audited and tested,
   35|       | * explicit destruction of these objects can be implemented by changing this
   36|       | * from a raw pointer to a std::unique_ptr.
   37|       | * Since the ~Logger() destructor is never called, the Logger class and all
   38|       | * its subclasses must have implicitly-defined destructors.
   39|       | *
   40|       | * This method of initialization was originally introduced in
   41|       | * ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c.
   42|       | */
   43|      1|    static BCLog::Logger* g_logger{new BCLog::Logger()};
   44|      1|    return *g_logger;
   45|      1|}
_ZN5BCLog6Logger20DisconnectTestLoggerEv:
  104|      1|{
  105|      1|    STDLOCK(m_cs);
  ------------------
  |  |   41|      1|#define STDLOCK(cs) StdMutex::Guard BITCOIN_UNIQUE_NAME(criticalblock){StdMutex::CheckNotHeld(cs)}
  |  |  ------------------
  |  |  |  |   11|      1|#define BITCOIN_UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
  |  |  |  |  ------------------
  |  |  |  |  |  |    9|      1|#define PASTE2(x, y) PASTE(x, y)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |    8|      1|#define PASTE(x, y) x ## y
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  106|      1|    m_buffering = true;
  107|      1|    if (m_fileout != nullptr) fclose(m_fileout);
  ------------------
  |  Branch (107:9): [True: 0, False: 1]
  ------------------
  108|      1|    m_fileout = nullptr;
  109|      1|    m_print_callbacks.clear();
  110|      1|    m_max_buffer_memusage = DEFAULT_MAX_LOG_BUFFER;
  111|      1|    m_cur_buffer_memusage = 0;
  112|      1|    m_buffer_lines_discarded = 0;
  113|      1|    m_msgs_before_open.clear();
  114|      1|}

_ZN11CNetCleanupD2Ev:
 3676|      1|    {
 3677|       |#ifdef WIN32
 3678|       |        // Shutdown Windows Sockets
 3679|       |        WSACleanup();
 3680|       |#endif
 3681|      1|    }

_ZN4node11NodeContextD2Ev:
   27|      1|NodeContext::~NodeContext() = default;

_ZNK9prevectorILj16EhjiE9is_directEv:
  126|      8|    bool is_direct() const { return _size <= N; }
_ZN9prevectorILj16EhjiED2Ev:
  422|      8|    ~prevector() {
  423|      8|        if (!is_direct()) {
  ------------------
  |  Branch (423:13): [True: 0, False: 8]
  ------------------
  424|      0|            free(_union.indirect_contents.indirect);
  425|      0|            _union.indirect_contents.indirect = nullptr;
  426|      0|        }
  427|      8|    }
_ZNK9prevectorILj36EhjiE9is_directEv:
  126|     10|    bool is_direct() const { return _size <= N; }
_ZN9prevectorILj36EhjiED2Ev:
  422|     10|    ~prevector() {
  423|     10|        if (!is_direct()) {
  ------------------
  |  Branch (423:13): [True: 2, False: 8]
  ------------------
  424|      2|            free(_union.indirect_contents.indirect);
  425|      2|            _union.indirect_contents.indirect = nullptr;
  426|      2|        }
  427|     10|    }

random.cpp:_ZN12_GLOBAL__N_18RNGStateD2Ev:
  367|      1|    ~RNGState() = default;

_ZN20BaseSignatureCheckerD2Ev:
  298|      1|    virtual ~BaseSignatureChecker() = default;

_ZN20BaseSignatureCreatorD2Ev:
   41|      2|    virtual ~BaseSignatureCreator() = default;

_ZN15SigningProviderD2Ev:
  170|      1|    virtual ~SigningProvider() = default;

secp256k1.c:secp256k1_ecmult_gen_context_clear:
   26|      1|static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
   27|      1|    ctx->built = 0;
   28|      1|    secp256k1_scalar_clear(&ctx->scalar_offset);
   29|      1|    secp256k1_ge_clear(&ctx->ge_offset);
   30|      1|    secp256k1_fe_clear(&ctx->proj_blind);
   31|      1|}
secp256k1.c:secp256k1_ecmult_gen_context_is_built:
   22|      2|static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) {
   23|      2|    return ctx->built;
   24|      2|}

secp256k1.c:secp256k1_fe_clear:
   21|      1|SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
   22|      1|    secp256k1_memclear_explicit(a, sizeof(secp256k1_fe));
   23|      1|}

secp256k1.c:secp256k1_ge_clear:
  343|      1|static void secp256k1_ge_clear(secp256k1_ge *r) {
  344|      1|    secp256k1_memclear_explicit(r, sizeof(secp256k1_ge));
  345|      1|}

secp256k1.c:secp256k1_scalar_clear:
   30|      1|SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) {
   31|      1|    secp256k1_memclear_explicit(r, sizeof(secp256k1_scalar));
   32|      1|}

secp256k1_context_preallocated_destroy:
  178|      1|void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
  179|      1|    ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
  ------------------
  |  |   52|      1|#define ARG_CHECK_VOID(cond) do { \
  |  |   53|      1|    if (EXPECT(!(cond), 0)) { \
  |  |  ------------------
  |  |  |  |  146|      2|#define EXPECT(x,c) __builtin_expect((x),(c))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (146:21): [True: 0, False: 1]
  |  |  |  |  |  Branch (146:39): [True: 0, False: 1]
  |  |  |  |  |  Branch (146:39): [True: 1, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   54|      0|        secp256k1_callback_call(&ctx->illegal_callback, #cond); \
  |  |   55|      0|        return; \
  |  |   56|      0|    } \
  |  |   57|      1|} while(0)
  |  |  ------------------
  |  |  |  Branch (57:9): [Folded, False: 1]
  |  |  ------------------
  ------------------
  180|       |
  181|       |    /* Defined as noop */
  182|      1|    if (ctx == NULL) {
  ------------------
  |  Branch (182:9): [True: 0, False: 1]
  ------------------
  183|      0|        return;
  184|      0|    }
  185|       |
  186|      1|    secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
  187|      1|}
secp256k1_context_destroy:
  189|      1|void secp256k1_context_destroy(secp256k1_context* ctx) {
  190|      1|    ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
  ------------------
  |  |   52|      1|#define ARG_CHECK_VOID(cond) do { \
  |  |   53|      1|    if (EXPECT(!(cond), 0)) { \
  |  |  ------------------
  |  |  |  |  146|      2|#define EXPECT(x,c) __builtin_expect((x),(c))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (146:21): [True: 0, False: 1]
  |  |  |  |  |  Branch (146:39): [True: 0, False: 1]
  |  |  |  |  |  Branch (146:39): [True: 1, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |   54|      0|        secp256k1_callback_call(&ctx->illegal_callback, #cond); \
  |  |   55|      0|        return; \
  |  |   56|      0|    } \
  |  |   57|      1|} while(0)
  |  |  ------------------
  |  |  |  Branch (57:9): [Folded, False: 1]
  |  |  ------------------
  ------------------
  191|       |
  192|       |    /* Defined as noop */
  193|      1|    if (ctx == NULL) {
  ------------------
  |  Branch (193:9): [True: 0, False: 1]
  ------------------
  194|      0|        return;
  195|      0|    }
  196|       |
  197|      1|    secp256k1_context_preallocated_destroy(ctx);
  198|      1|    free(ctx);
  199|      1|}
secp256k1.c:secp256k1_context_is_proper:
   83|      2|static int secp256k1_context_is_proper(const secp256k1_context* ctx) {
   84|      2|    return secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx);
   85|      2|}

secp256k1.c:secp256k1_memclear_explicit:
  268|      3|static SECP256K1_INLINE void secp256k1_memclear_explicit(void *ptr, size_t len) {
  269|       |    /* The current implementation zeroes, but callers must not rely on this */
  270|      3|    secp256k1_memzero_explicit(ptr, len);
  271|       |#ifdef VERIFY
  272|       |    SECP256K1_CHECKMEM_UNDEFINE(ptr, len);
  273|       |#endif
  274|      3|}
secp256k1.c:secp256k1_memzero_explicit:
  236|      3|static SECP256K1_INLINE void secp256k1_memzero_explicit(void *ptr, size_t len) {
  237|       |#if defined(_MSC_VER)
  238|       |    /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
  239|       |    SecureZeroMemory(ptr, len);
  240|       |#elif defined(__GNUC__)
  241|       |    /* We use a memory barrier that scares the compiler away from optimizing out the memset.
  242|       |     *
  243|       |     * Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
  244|       |     * in BoringSSL (ISC License):
  245|       |     *    As best as we can tell, this is sufficient to break any optimisations that
  246|       |     *    might try to eliminate "superfluous" memsets.
  247|       |     * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it
  248|       |     * is pretty efficient, because the compiler can still implement the memset() efficiently,
  249|       |     * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
  250|       |     * Yang et al. (USENIX Security 2017) for more background.
  251|       |     */
  252|      3|    memset(ptr, 0, len);
  253|      3|    __asm__ __volatile__("" : : "r"(ptr) : "memory");
  254|       |#else
  255|       |    void *(*volatile const volatile_memset)(void *, int, size_t) = memset;
  256|       |    volatile_memset(ptr, 0, len);
  257|       |#endif
  258|      3|}

random.cpp:_ZN16secure_allocatorIN12_GLOBAL__N_18RNGStateEE10deallocateEPS1_m:
   37|      1|    {
   38|      1|        if (p != nullptr) {
  ------------------
  |  Branch (38:13): [True: 1, False: 0]
  ------------------
   39|      1|            memory_cleanse(p, sizeof(T) * n);
   40|      1|        }
   41|      1|        LockedPoolManager::Instance().free(p);
   42|      1|    }

_Z14memory_cleansePvm:
   15|      9|{
   16|       |#if defined(WIN32)
   17|       |    /* SecureZeroMemory is guaranteed not to be optimized out. */
   18|       |    SecureZeroMemory(ptr, len);
   19|       |#else
   20|      9|    std::memset(ptr, 0, len);
   21|       |
   22|       |    /* Memory barrier that scares the compiler away from optimizing out the memset.
   23|       |     *
   24|       |     * Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
   25|       |     * in BoringSSL (ISC License):
   26|       |     *    As best as we can tell, this is sufficient to break any optimisations that
   27|       |     *    might try to eliminate "superfluous" memsets.
   28|       |     * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it
   29|       |     * is pretty efficient because the compiler can still implement the memset() efficiently,
   30|       |     * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
   31|       |     * Yang et al. (USENIX Security 2017) for more background.
   32|       |     */
   33|      9|    __asm__ __volatile__("" : : "r"(ptr) : "memory");
   34|      9|#endif
   35|      9|}

_ZN5ArenaD2Ev:
   48|      1|Arena::~Arena() = default;
_ZN5Arena4freeEPv:
   87|      1|{
   88|       |    // Freeing the nullptr pointer is OK.
   89|      1|    if (ptr == nullptr) {
  ------------------
  |  Branch (89:9): [True: 0, False: 1]
  ------------------
   90|      0|        return;
   91|      0|    }
   92|       |
   93|       |    // Remove chunk from used map
   94|      1|    auto i = chunks_used.find(ptr);
   95|      1|    if (i == chunks_used.end()) {
  ------------------
  |  Branch (95:9): [True: 0, False: 1]
  ------------------
   96|      0|        throw std::runtime_error("Arena: invalid or double free");
   97|      0|    }
   98|      1|    auto freed = std::make_pair(static_cast<char*>(i->first), i->second);
   99|      1|    chunks_used.erase(i);
  100|       |
  101|       |    // coalesce freed with previous chunk
  102|      1|    auto prev = chunks_free_end.find(freed.first);
  103|      1|    if (prev != chunks_free_end.end()) {
  ------------------
  |  Branch (103:9): [True: 1, False: 0]
  ------------------
  104|      1|        freed.first -= prev->second->first;
  105|      1|        freed.second += prev->second->first;
  106|      1|        size_to_free_chunk.erase(prev->second);
  107|      1|        chunks_free_end.erase(prev);
  108|      1|    }
  109|       |
  110|       |    // coalesce freed with chunk after freed
  111|      1|    auto next = chunks_free.find(freed.first + freed.second);
  112|      1|    if (next != chunks_free.end()) {
  ------------------
  |  Branch (112:9): [True: 0, False: 1]
  ------------------
  113|      0|        freed.second += next->second->first;
  114|      0|        size_to_free_chunk.erase(next->second);
  115|      0|        chunks_free.erase(next);
  116|      0|    }
  117|       |
  118|       |    // Add/set space with coalesced free chunk
  119|      1|    auto it = size_to_free_chunk.emplace(freed.second, freed.first);
  120|      1|    chunks_free[freed.first] = it;
  121|      1|    chunks_free_end[freed.first + freed.second] = it;
  122|      1|}
_ZN24PosixLockedPageAllocator10FreeLockedEPvm:
  254|      1|{
  255|      1|    len = align_up(len, page_size);
  256|      1|    memory_cleanse(addr, len);
  257|      1|    munlock(addr, len);
  258|      1|    munmap(addr, len);
  259|      1|}
_ZN10LockedPoolD2Ev:
  283|      1|LockedPool::~LockedPool() = default;
_ZN10LockedPool4freeEPv:
  308|      1|{
  309|      1|    std::lock_guard<std::mutex> lock(mutex);
  310|       |    // TODO we can do better than this linear search by keeping a map of arena
  311|       |    // extents to arena, and looking up the address.
  312|      1|    for (auto &arena: arenas) {
  ------------------
  |  Branch (312:21): [True: 1, False: 0]
  ------------------
  313|      1|        if (arena.addressInArena(ptr)) {
  ------------------
  |  Branch (313:13): [True: 1, False: 0]
  ------------------
  314|      1|            arena.free(ptr);
  315|      1|            return;
  316|      1|        }
  317|      1|    }
  318|      0|    throw std::runtime_error("LockedPool: invalid address not pointing to any arena");
  319|      1|}
_ZN10LockedPool15LockedPageArenaD2Ev:
  370|      1|{
  371|      1|    allocator->FreeLocked(base, size);
  372|      1|}
_ZN17LockedPoolManager8InstanceEv:
  405|      1|{
  406|      1|    static std::once_flag init_flag;
  407|      1|    std::call_once(init_flag, LockedPoolManager::CreateInstance);
  408|      1|    return *LockedPoolManager::_instance;
  409|      1|}
lockedpool.cpp:_ZL8align_upmm:
   32|      1|{
   33|      1|    return (x + align - 1) & ~(align - 1);
   34|      1|}

_ZNK5Arena14addressInArenaEPv:
   90|      1|    bool addressInArena(void *ptr) const { return ptr >= base && ptr < end; }
  ------------------
  |  Branch (90:51): [True: 1, False: 0]
  |  Branch (90:66): [True: 1, False: 0]
  ------------------
_ZN19LockedPageAllocatorD2Ev:
   22|      1|    virtual ~LockedPageAllocator() = default;

_ZN14AnnotatedMixinINSt3__115recursive_mutexEED2Ev:
   96|      1|    ~AnnotatedMixin() {
   97|      1|        DeleteLock((void*)this);
   98|      1|    }
_ZN14AnnotatedMixinINSt3__15mutexEED2Ev:
   96|     34|    ~AnnotatedMixin() {
   97|     34|        DeleteLock((void*)this);
   98|     34|    }
_Z10DeleteLockPv:
   74|     35|inline void DeleteLock(void* cs) {}
_Z17MaybeCheckNotHeldR14AnnotatedMixinINSt3__15mutexEE:
  258|     17|inline Mutex& MaybeCheckNotHeld(Mutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
_ZN10UniqueLockI14AnnotatedMixinINSt3__15mutexEEEC2ERS3_PKcS7_ib:
  181|     17|    UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
  182|     17|    {
  183|     17|        if (fTry)
  ------------------
  |  Branch (183:13): [True: 0, False: 17]
  ------------------
  184|      0|            TryEnter(pszName, pszFile, nLine);
  185|     17|        else
  186|     17|            Enter(pszName, pszFile, nLine);
  187|     17|    }
_Z13EnterCriticalINSt3__15mutexEEvPKcS3_iPT_b:
   67|     17|inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {}
_Z13LeaveCriticalv:
   68|     17|inline void LeaveCritical() {}
_ZN10UniqueLockI14AnnotatedMixinINSt3__15mutexEEE5EnterEPKcS6_i:
  159|     17|    {
  160|     17|        EnterCritical(pszName, pszFile, nLine, Base::mutex());
  161|       |#ifdef DEBUG_LOCKCONTENTION
  162|       |        if (!Base::try_lock()) {
  163|       |            ContendedLock(pszName, pszFile, nLine, static_cast<Base&>(*this));
  164|       |        }
  165|       |#else
  166|     17|        Base::lock();
  167|     17|#endif
  168|     17|    }
_ZN10UniqueLockI14AnnotatedMixinINSt3__15mutexEEED2Ev:
  201|     17|    {
  202|     17|        if (Base::owns_lock())
  ------------------
  |  Branch (202:13): [True: 17, False: 0]
  ------------------
  203|     17|            LeaveCritical();
  204|     17|    }

_ZN12CheckGlobalsD2Ev:
   60|      1|CheckGlobals::~CheckGlobals() = default;
_ZN16CheckGlobalsImplD2Ev:
   25|      1|    {
   26|      1|        if (g_used_g_prng && !g_seeded_g_prng_zero) {
  ------------------
  |  Branch (26:13): [True: 1, False: 0]
  |  Branch (26:30): [True: 0, False: 1]
  ------------------
   27|      0|            std::cerr << "\n\n"
   28|      0|                         "The current fuzz target used the global random state.\n\n"
   29|       |
   30|      0|                         "This is acceptable, but requires the fuzz target to call \n"
   31|      0|                         "SeedRandomStateForTest(SeedRand::ZEROS) in the first line \n"
   32|      0|                         "of the FUZZ_TARGET function.\n\n"
   33|       |
   34|      0|                         "An alternative solution would be to avoid any use of globals.\n\n"
   35|       |
   36|      0|                         "Without a solution, fuzz instability and non-determinism can lead \n"
   37|      0|                         "to non-reproducible bugs or inefficient fuzzing.\n\n"
   38|      0|                      << std::endl;
   39|      0|            std::abort(); // Abort, because AFL may try to recover from a std::exit
   40|      0|        }
   41|       |
   42|      1|        if (g_used_system_time) {
  ------------------
  |  Branch (42:13): [True: 0, False: 1]
  ------------------
   43|      0|            std::cerr << "\n\n"
   44|      0|                         "The current fuzz target accessed system time.\n\n"
   45|       |
   46|      0|                         "This is acceptable, but requires the fuzz target to use \n"
   47|      0|                         "a FakeNodeClock, FakeSteadyClock or call \n"
   48|      0|                         "SetMockTime() at the \n" "beginning of processing the \n"
   49|      0|                         "fuzz input.\n\n"
   50|       |
   51|      0|                         "Without setting mock time, time-dependent behavior can lead \n"
   52|      0|                         "to non-reproducible bugs or inefficient fuzzing.\n\n"
   53|      0|                      << std::endl;
   54|      0|            std::abort();
   55|      0|        }
   56|      1|    }

__gcov_reset:
   13|      1|extern "C" __attribute__((weak)) void __gcov_reset(void) {}

_ZN17BasicTestingSetupD2Ev:
  252|      1|{
  253|      1|    m_node.ecc_context.reset();
  254|      1|    m_node.kernel.reset();
  255|      1|    if (!EnableFuzzDeterminism()) {
  ------------------
  |  Branch (255:9): [True: 0, False: 1]
  ------------------
  256|      0|        SetMockTime(0s); // Reset mocktime for following tests
  257|      0|    }
  258|      1|    LogInstance().DisconnectTestLogger();
  259|      1|    if (m_has_custom_datadir) {
  ------------------
  |  Branch (259:9): [True: 0, False: 1]
  ------------------
  260|       |        // Only remove the lock file, preserve the data directory.
  261|      0|        UnlockDirectory(m_path_lock, ".lock");
  262|      0|        fs::remove(m_path_lock / ".lock");
  263|      1|    } else {
  264|      1|        fs::remove_all(m_path_root);
  265|      1|    }
  266|       |    // Clear all arguments except for -datadir, which GUI tests currently rely
  267|       |    // on to be set even after the testing setup is destroyed.
  268|      1|    gArgs.ClearArgs();
  269|      1|    gArgs.ForceSetArg("-datadir", fs::PathToString(m_path_root));
  270|      1|}

_ZN9base_blobILj256EE4dataEv:
   99|      1|    constexpr unsigned char* data() { return m_data.data(); }
_ZN9base_blobILj256EE4sizeEv:
  107|      1|    static constexpr unsigned int size() { return WIDTH; }

_ZN8UniValueC2Ev:
   31|      1|    UniValue() { typ = VNULL; }
_ZN8UniValueC2IRKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES7_TnNS1_9enable_ifIXoooooooosr3stdE19is_floating_point_vIT0_Esr3stdE9is_same_vIbSB_Esr3stdE11is_signed_vISB_Esr3stdE13is_unsigned_vISB_Esr3stdE18is_constructible_vIS7_SB_EEbE4typeELb1EEEOT_:
   40|      1|    {
   41|       |        if constexpr (std::is_floating_point_v<T>) {
   42|       |            setFloat(val);
   43|       |        } else if constexpr (std::is_same_v<bool, T>) {
   44|       |            setBool(val);
   45|       |        } else if constexpr (std::is_signed_v<T>) {
   46|       |            setInt(int64_t{val});
   47|       |        } else if constexpr (std::is_unsigned_v<T>) {
   48|       |            setInt(uint64_t{val});
   49|      1|        } else {
   50|      1|            setStr(std::string{std::forward<Ref>(val)});
   51|      1|        }
   52|      1|    }

_ZN8UniValue5clearEv:
   18|      1|{
   19|      1|    typ = VNULL;
   20|      1|    val.clear();
   21|      1|    keys.clear();
   22|      1|    values.clear();
   23|      1|}
_ZN8UniValue6setStrENSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   85|      1|{
   86|      1|    clear();
   87|      1|    typ = VSTR;
   88|      1|    val = std::move(str);
   89|      1|}

_ZN10btcsignals6signalIFvvENS_10null_valueEED2Ev:
  175|      3|    ~signal() = default;
_ZN10btcsignals6signalIFv20SynchronizationStatellbENS_10null_valueEED2Ev:
  175|      1|    ~signal() = default;
_ZN10btcsignals6signalIFv20SynchronizationStateRK11CBlockIndexdENS_10null_valueEED2Ev:
  175|      1|    ~signal() = default;
_ZN10btcsignals6signalIFvRKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEibENS_10null_valueEED2Ev:
  175|      1|    ~signal() = default;
_ZN10btcsignals6signalIFvbENS_10null_valueEED2Ev:
  175|      1|    ~signal() = default;
_ZN10btcsignals6signalIFviENS_10null_valueEED2Ev:
  175|      1|    ~signal() = default;
_ZN10btcsignals6signalIFvRKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEENS_10null_valueEED2Ev:
  175|      1|    ~signal() = default;
_ZN10btcsignals6signalIFbRK13bilingual_strRKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEjENS_6any_ofEED2Ev:
  175|      1|    ~signal() = default;
_ZN10btcsignals6signalIFvRK13bilingual_strjENS_10null_valueEED2Ev:
  175|      1|    ~signal() = default;

_Z21EnableFuzzDeterminismv:
   39|      1|{
   40|      1|    if constexpr (G_FUZZING_BUILD) {
   41|      1|        return true;
   42|       |    } else if constexpr (!G_ABORT_ON_FAILED_ASSUME) {
   43|       |        // Running fuzz tests is always disabled if Assume() doesn't abort
   44|       |        // (ie, non-fuzz non-debug builds), as otherwise tests which
   45|       |        // should fail due to a failing Assume may still pass. As such,
   46|       |        // we also statically disable fuzz determinism in that case.
   47|       |        return false;
   48|       |    } else {
   49|       |        return g_enable_dynamic_fuzz_determinism;
   50|       |    }
   51|      1|}
_Z22inline_assertion_checkILb0EbEOT0_S1_RKNSt3__115source_locationENS2_17basic_string_viewIcNS2_11char_traitsIcEEEE:
   90|      5|{
   91|      5|    if (IS_ASSERT || std::is_constant_evaluated() || G_ABORT_ON_FAILED_ASSUME) {
  ------------------
  |  Branch (91:9): [Folded, False: 0]
  |  Branch (91:22): [Folded, False: 0]
  |  Branch (91:54): [True: 0, Folded]
  ------------------
   92|      5|        if (!val) {
  ------------------
  |  Branch (92:13): [True: 0, False: 5]
  ------------------
   93|      0|            assertion_fail(loc, assertion);
   94|      0|        }
   95|      5|    }
   96|      5|    return std::forward<T>(val);
   97|      5|}

setup_common.cpp:_ZN2fsL12PathToStringERKNS_4pathE:
  163|      1|{
  164|       |    // Implementation note: On Windows, the std::filesystem::path(string)
  165|       |    // constructor and std::filesystem::path::string() method are not safe to
  166|       |    // use here, because these methods encode the path using C++'s narrow
  167|       |    // multibyte encoding, which on Windows corresponds to the current "code
  168|       |    // page", which is unpredictable and typically not able to represent all
  169|       |    // valid paths. So fs::path::utf8string() and
  170|       |    // fs::u8path() functions are used instead on Windows. On
  171|       |    // POSIX, u8string/utf8string/u8path functions are not safe to use because paths are
  172|       |    // not always valid UTF-8, so plain string methods which do not transform
  173|       |    // the path there are used.
  174|       |#ifdef WIN32
  175|       |    return path.utf8string();
  176|       |#else
  177|      1|    static_assert(std::is_same_v<path::string_type, std::string>, "PathToString not implemented on this platform");
  178|      1|    return path.std::filesystem::path::string();
  179|      1|#endif
  180|      1|}

_ZN8StdMutex12CheckNotHeldERS_:
   37|      1|    static inline StdMutex& CheckNotHeld(StdMutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
_ZN8StdMutex5GuardC2ERS_:
   33|      1|        explicit Guard(StdMutex& cs) EXCLUSIVE_LOCK_FUNCTION(cs) : std::lock_guard<StdMutex>(cs) {}

_ZN16CThreadInterruptD2Ev:
   32|      2|    virtual ~CThreadInterrupt() = default;

_ZN10ThreadPoolD2Ev:
   93|      5|    {
   94|      5|        Stop(); // In case it hasn't been stopped.
   95|      5|    }
_ZN10ThreadPool4StopEv:
  129|      5|    {
  130|       |        // Notify workers and join them
  131|      5|        std::vector<std::thread> threads_to_join;
  132|      5|        {
  133|      5|            LOCK(m_mutex);
  ------------------
  |  |  268|      5|#define LOCK(cs) UniqueLock BITCOIN_UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
  |  |  ------------------
  |  |  |  |   11|      5|#define BITCOIN_UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
  |  |  |  |  ------------------
  |  |  |  |  |  |    9|      5|#define PASTE2(x, y) PASTE(x, y)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |    8|      5|#define PASTE(x, y) x ## y
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  134|       |            // Ensure Stop() is not called from a worker thread while workers are still registered,
  135|       |            // otherwise a self-join deadlock would occur.
  136|      5|            auto id = std::this_thread::get_id();
  137|      5|            for (const auto& worker : m_workers) assert(worker.get_id() != id);
  ------------------
  |  Branch (137:37): [True: 0, False: 5]
  |  Branch (137:50): [True: 0, False: 0]
  ------------------
  138|       |            // Early shutdown to return right away on any concurrent Submit() call
  139|      5|            m_interrupt = true;
  140|      5|            threads_to_join.swap(m_workers);
  141|      5|        }
  142|      0|        m_cv.notify_all();
  143|       |        // Help draining queue
  144|      5|        while (ProcessTask()) {}
  ------------------
  |  Branch (144:16): [True: 0, False: 5]
  ------------------
  145|       |        // Free resources
  146|      5|        for (auto& worker : threads_to_join) worker.join();
  ------------------
  |  Branch (146:27): [True: 0, False: 5]
  ------------------
  147|       |
  148|       |        // Since we currently wait for tasks completion, sanity-check empty queue
  149|      5|        LOCK(m_mutex);
  ------------------
  |  |  268|      5|#define LOCK(cs) UniqueLock BITCOIN_UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
  |  |  ------------------
  |  |  |  |   11|      5|#define BITCOIN_UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
  |  |  |  |  ------------------
  |  |  |  |  |  |    9|      5|#define PASTE2(x, y) PASTE(x, y)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |    8|      5|#define PASTE(x, y) x ## y
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  150|      5|        Assume(m_work_queue.empty());
  ------------------
  |  |  128|      5|#define Assume(val) inline_assertion_check<false>(val, std::source_location::current(), #val)
  ------------------
  151|       |        // Re-allow Start() now that all workers have exited
  152|      5|        m_interrupt = false;
  153|      5|    }
_ZN10ThreadPool11ProcessTaskEv:
  244|      5|    {
  245|      5|        std::packaged_task<void()> task;
  246|      5|        {
  247|      5|            LOCK(m_mutex);
  ------------------
  |  |  268|      5|#define LOCK(cs) UniqueLock BITCOIN_UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
  |  |  ------------------
  |  |  |  |   11|      5|#define BITCOIN_UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
  |  |  |  |  ------------------
  |  |  |  |  |  |    9|      5|#define PASTE2(x, y) PASTE(x, y)
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |    8|      5|#define PASTE(x, y) x ## y
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  248|      5|            if (m_work_queue.empty()) return false;
  ------------------
  |  Branch (248:17): [True: 5, False: 0]
  ------------------
  249|       |
  250|       |            // Pop the task
  251|      0|            task = std::move(m_work_queue.front());
  252|      0|            m_work_queue.pop();
  253|      0|        }
  254|      0|        task();
  255|      0|        return true;
  256|      5|    }

_ZN12TokenPipeEndD2Ev:
   37|      2|{
   38|      2|    Close();
   39|      2|}
_ZN12TokenPipeEnd5CloseEv:
   80|      2|{
   81|      2|    if (m_fd != -1) close(m_fd);
  ------------------
  |  Branch (81:9): [True: 2, False: 0]
  ------------------
   82|      2|    m_fd = -1;
   83|      2|}

_ZN19WalletInitInterfaceD2Ev:
   25|      1|    virtual ~WalletInitInterface() = default;

