diff --git a/ConflictSet.cpp b/ConflictSet.cpp index f2b2b9b..6f989d5 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -269,14 +269,22 @@ struct TaggedNodePointer { TaggedNodePointer(const TaggedNodePointer &) = default; TaggedNodePointer &operator=(const TaggedNodePointer &) = default; + /*implicit*/ TaggedNodePointer(Node *n); + // Leaf constructor + TaggedNodePointer(InternalVersionT rangeVersion, struct Node *parent); + void prefetch() { // __builtin_prefetch is ok even if argument isn't addressable __builtin_prefetch((void *)withoutType()); } - bool isLeaf() { return getType() > Type_Node256; } + bool isLeaf() { return (p & uintptr_t(15)) > Type_Node256; } + InternalVersionT rangeVersion() { + assert(isLeaf()); + return InternalVersionT(p >> 32); + } private: TaggedNodePointer(struct Node *p, Type t) : p((uintptr_t)p) { @@ -323,6 +331,12 @@ private: TaggedNodePointer::TaggedNodePointer(Node *n) : TaggedNodePointer(n, n->getType()) {} +TaggedNodePointer::TaggedNodePointer(InternalVersionT rangeVersion, Node *n) { + p = rangeVersion.toInt64(); + p <<= 32; + p |= n->getType(); +} + Type TaggedNodePointer::getType() { assert(p != 0); prefetch(); @@ -6096,18 +6110,27 @@ void checkVersionsGeqOldestExtant(Node *n, [[maybe_unused]] auto *self = static_cast(n); for (int i = 0; i < 3; ++i) { assert(self->childMaxVersion[i] >= oldestExtantVersion); + if (i < self->numChildren && self->children[i].isLeaf()) { + assert(self->children[i].rangeVersion() >= oldestExtantVersion); + } } } break; case Type_Node16: { [[maybe_unused]] auto *self = static_cast(n); for (int i = 0; i < 16; ++i) { assert(self->childMaxVersion[i] >= oldestExtantVersion); + if (i < self->numChildren && self->children[i].isLeaf()) { + assert(self->children[i].rangeVersion() >= oldestExtantVersion); + } } } break; case Type_Node48: { auto *self = static_cast(n); for (int i = 0; i < 48; ++i) { assert(self->childMaxVersion[i] >= oldestExtantVersion); + if (i < self->numChildren && self->children[i].isLeaf()) { + assert(self->children[i].rangeVersion() >= oldestExtantVersion); + } } for ([[maybe_unused]] auto m : self->maxOfMax) { assert(m >= oldestExtantVersion); @@ -6117,11 +6140,18 @@ void checkVersionsGeqOldestExtant(Node *n, auto *self = static_cast(n); for (int i = 0; i < 256; ++i) { assert(self->childMaxVersion[i] >= oldestExtantVersion); + if (self->children[i].isLeaf()) { + assert(self->children[i].rangeVersion() >= oldestExtantVersion); + } } for ([[maybe_unused]] auto m : self->maxOfMax) { assert(m >= oldestExtantVersion); } } break; + case Type_Leaf3: + case Type_Leaf16: + case Type_Leaf48: + case Type_Leaf256: default: abort(); } @@ -6180,9 +6210,10 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion, return total; } -[[maybe_unused]] void checkMemoryBoundInvariants(Node *node, bool &success) { +[[maybe_unused]] void checkMemoryBoundInvariants(TaggedNodePointer node, + bool &success) { int minNumChildren; - switch (node->getType()) { + switch (node.getType()) { case Type_Node0: minNumChildren = kMinChildrenNode0; break; @@ -6198,6 +6229,11 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion, case Type_Node256: minNumChildren = kMinChildrenNode256; break; + case Type_Leaf3: + case Type_Leaf16: + case Type_Leaf48: + case Type_Leaf256: + return; default: abort(); } @@ -6219,8 +6255,9 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion, success = false; } - for (auto child = getChildGeq(node, 0); child != nullptr; - child = getChildGeq(node, child->parentsIndex + 1)) { + // Safety: if node were a leaf we would have returned by now + for (auto child = getChildGeq(node.asNodeUnsafe(), 0); child != nullptr; + child = getChildGeq(node.asNodeUnsafe(), child->parentsIndex + 1)) { checkMemoryBoundInvariants(child, success); } }