Update some of the invariant checks to account for leaves
This commit is contained in:
@@ -269,14 +269,22 @@ struct TaggedNodePointer {
|
|||||||
|
|
||||||
TaggedNodePointer(const TaggedNodePointer &) = default;
|
TaggedNodePointer(const TaggedNodePointer &) = default;
|
||||||
TaggedNodePointer &operator=(const TaggedNodePointer &) = default;
|
TaggedNodePointer &operator=(const TaggedNodePointer &) = default;
|
||||||
|
|
||||||
/*implicit*/ TaggedNodePointer(Node *n);
|
/*implicit*/ TaggedNodePointer(Node *n);
|
||||||
|
|
||||||
|
// Leaf constructor
|
||||||
|
TaggedNodePointer(InternalVersionT rangeVersion, struct Node *parent);
|
||||||
|
|
||||||
void prefetch() {
|
void prefetch() {
|
||||||
// __builtin_prefetch is ok even if argument isn't addressable
|
// __builtin_prefetch is ok even if argument isn't addressable
|
||||||
__builtin_prefetch((void *)withoutType());
|
__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:
|
private:
|
||||||
TaggedNodePointer(struct Node *p, Type t) : p((uintptr_t)p) {
|
TaggedNodePointer(struct Node *p, Type t) : p((uintptr_t)p) {
|
||||||
@@ -323,6 +331,12 @@ private:
|
|||||||
TaggedNodePointer::TaggedNodePointer(Node *n)
|
TaggedNodePointer::TaggedNodePointer(Node *n)
|
||||||
: TaggedNodePointer(n, n->getType()) {}
|
: TaggedNodePointer(n, n->getType()) {}
|
||||||
|
|
||||||
|
TaggedNodePointer::TaggedNodePointer(InternalVersionT rangeVersion, Node *n) {
|
||||||
|
p = rangeVersion.toInt64();
|
||||||
|
p <<= 32;
|
||||||
|
p |= n->getType();
|
||||||
|
}
|
||||||
|
|
||||||
Type TaggedNodePointer::getType() {
|
Type TaggedNodePointer::getType() {
|
||||||
assert(p != 0);
|
assert(p != 0);
|
||||||
prefetch();
|
prefetch();
|
||||||
@@ -6096,18 +6110,27 @@ void checkVersionsGeqOldestExtant(Node *n,
|
|||||||
[[maybe_unused]] auto *self = static_cast<Node3 *>(n);
|
[[maybe_unused]] auto *self = static_cast<Node3 *>(n);
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
assert(self->childMaxVersion[i] >= oldestExtantVersion);
|
assert(self->childMaxVersion[i] >= oldestExtantVersion);
|
||||||
|
if (i < self->numChildren && self->children[i].isLeaf()) {
|
||||||
|
assert(self->children[i].rangeVersion() >= oldestExtantVersion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case Type_Node16: {
|
case Type_Node16: {
|
||||||
[[maybe_unused]] auto *self = static_cast<Node16 *>(n);
|
[[maybe_unused]] auto *self = static_cast<Node16 *>(n);
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
assert(self->childMaxVersion[i] >= oldestExtantVersion);
|
assert(self->childMaxVersion[i] >= oldestExtantVersion);
|
||||||
|
if (i < self->numChildren && self->children[i].isLeaf()) {
|
||||||
|
assert(self->children[i].rangeVersion() >= oldestExtantVersion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case Type_Node48: {
|
case Type_Node48: {
|
||||||
auto *self = static_cast<Node48 *>(n);
|
auto *self = static_cast<Node48 *>(n);
|
||||||
for (int i = 0; i < 48; ++i) {
|
for (int i = 0; i < 48; ++i) {
|
||||||
assert(self->childMaxVersion[i] >= oldestExtantVersion);
|
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) {
|
for ([[maybe_unused]] auto m : self->maxOfMax) {
|
||||||
assert(m >= oldestExtantVersion);
|
assert(m >= oldestExtantVersion);
|
||||||
@@ -6117,11 +6140,18 @@ void checkVersionsGeqOldestExtant(Node *n,
|
|||||||
auto *self = static_cast<Node256 *>(n);
|
auto *self = static_cast<Node256 *>(n);
|
||||||
for (int i = 0; i < 256; ++i) {
|
for (int i = 0; i < 256; ++i) {
|
||||||
assert(self->childMaxVersion[i] >= oldestExtantVersion);
|
assert(self->childMaxVersion[i] >= oldestExtantVersion);
|
||||||
|
if (self->children[i].isLeaf()) {
|
||||||
|
assert(self->children[i].rangeVersion() >= oldestExtantVersion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for ([[maybe_unused]] auto m : self->maxOfMax) {
|
for ([[maybe_unused]] auto m : self->maxOfMax) {
|
||||||
assert(m >= oldestExtantVersion);
|
assert(m >= oldestExtantVersion);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case Type_Leaf3:
|
||||||
|
case Type_Leaf16:
|
||||||
|
case Type_Leaf48:
|
||||||
|
case Type_Leaf256:
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@@ -6180,9 +6210,10 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion,
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] void checkMemoryBoundInvariants(Node *node, bool &success) {
|
[[maybe_unused]] void checkMemoryBoundInvariants(TaggedNodePointer node,
|
||||||
|
bool &success) {
|
||||||
int minNumChildren;
|
int minNumChildren;
|
||||||
switch (node->getType()) {
|
switch (node.getType()) {
|
||||||
case Type_Node0:
|
case Type_Node0:
|
||||||
minNumChildren = kMinChildrenNode0;
|
minNumChildren = kMinChildrenNode0;
|
||||||
break;
|
break;
|
||||||
@@ -6198,6 +6229,11 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion,
|
|||||||
case Type_Node256:
|
case Type_Node256:
|
||||||
minNumChildren = kMinChildrenNode256;
|
minNumChildren = kMinChildrenNode256;
|
||||||
break;
|
break;
|
||||||
|
case Type_Leaf3:
|
||||||
|
case Type_Leaf16:
|
||||||
|
case Type_Leaf48:
|
||||||
|
case Type_Leaf256:
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@@ -6219,8 +6255,9 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion,
|
|||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto child = getChildGeq(node, 0); child != nullptr;
|
// Safety: if node were a leaf we would have returned by now
|
||||||
child = getChildGeq(node, child->parentsIndex + 1)) {
|
for (auto child = getChildGeq(node.asNodeUnsafe(), 0); child != nullptr;
|
||||||
|
child = getChildGeq(node.asNodeUnsafe(), child->parentsIndex + 1)) {
|
||||||
checkMemoryBoundInvariants(child, success);
|
checkMemoryBoundInvariants(child, success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user