summaryrefslogtreecommitdiff
path: root/src/mongo/bson/bsonelement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/bson/bsonelement.cpp')
-rw-r--r--src/mongo/bson/bsonelement.cpp77
1 files changed, 43 insertions, 34 deletions
diff --git a/src/mongo/bson/bsonelement.cpp b/src/mongo/bson/bsonelement.cpp
index 707f3042cb4..25ff416444f 100644
--- a/src/mongo/bson/bsonelement.cpp
+++ b/src/mongo/bson/bsonelement.cpp
@@ -739,11 +739,11 @@ MONGO_COMPILER_NOINLINE void msgAssertedBadType [[noreturn]] (const char* data)
}
} // namespace
-int BSONElement::computeSize() const {
+int BSONElement::computeSize(int8_t type, const char* elem, int fieldNameSize) {
enum SizeStyle : uint8_t {
kFixed, // Total size is a fixed amount + key length.
kIntPlusFixed, // Like Fixed, but also add in the int32 immediately following the key.
- kRegEx, // Handled specially.
+ kSpecial, // Handled specially: RegEx, MinKey, MaxKey.
};
struct SizeInfo {
uint8_t style : 2;
@@ -751,8 +751,8 @@ int BSONElement::computeSize() const {
};
MONGO_STATIC_ASSERT(sizeof(SizeInfo) == 1);
- // This table should take 20 bytes. Align to next power of 2 to avoid splitting across cache
- // lines unnecessarily.
+ // This table should take 32 bytes. Align to that size to avoid splitting across cache lines
+ // unnecessarily.
static constexpr SizeInfo kSizeInfoTable alignas(32)[] = {
{SizeStyle::kFixed, 1}, // EOO
{SizeStyle::kFixed, 9}, // NumberDouble
@@ -765,7 +765,7 @@ int BSONElement::computeSize() const {
{SizeStyle::kFixed, 2}, // Bool
{SizeStyle::kFixed, 9}, // Date
{SizeStyle::kFixed, 1}, // Null
- {SizeStyle::kRegEx}, // Regex
+ {SizeStyle::kSpecial}, // Regex
{SizeStyle::kIntPlusFixed, 17}, // DBRef
{SizeStyle::kIntPlusFixed, 5}, // Code
{SizeStyle::kIntPlusFixed, 5}, // Symbol
@@ -774,38 +774,47 @@ int BSONElement::computeSize() const {
{SizeStyle::kFixed, 9}, // Timestamp
{SizeStyle::kFixed, 9}, // Long
{SizeStyle::kFixed, 17}, // Decimal
+ {SizeStyle::kSpecial}, // reserved 20
+ {SizeStyle::kSpecial}, // reserved 21
+ {SizeStyle::kSpecial}, // reserved 22
+ {SizeStyle::kSpecial}, // reserved 23
+ {SizeStyle::kSpecial}, // reserved 24
+ {SizeStyle::kSpecial}, // reserved 25
+ {SizeStyle::kSpecial}, // reserved 26
+ {SizeStyle::kSpecial}, // reserved 27
+ {SizeStyle::kSpecial}, // reserved 28
+ {SizeStyle::kSpecial}, // reserved 29
+ {SizeStyle::kSpecial}, // reserved 30
+ {SizeStyle::kSpecial}, // MinKey, MaxKey
};
- MONGO_STATIC_ASSERT((sizeof(kSizeInfoTable) / sizeof(kSizeInfoTable[0])) == JSTypeMax + 1);
-
- // This is the start of the runtime code for this function. Everything above happens at compile
- // time. This function attempts to push complex handling of unlikely events out-of-line to
- // ensure that the common cases never need to spill any registers (at least on x64 with
- // gcc-5.4), which reduces the function call overhead.
- int8_t type = *data;
- if (MONGO_unlikely(type < 0 || type > JSTypeMax)) {
- if (MONGO_unlikely(type != MinKey && type != MaxKey)) {
- msgAssertedBadType(data);
- }
-
- // MinKey and MaxKey should be treated the same as Null
- type = jstNULL;
+ MONGO_STATIC_ASSERT(sizeof(kSizeInfoTable) == 32);
+
+ // This function attempts to push complex handling of unlikely events out-of-line to ensure that
+ // the common cases never need to spill any registers, which reduces the function call overhead.
+ // Most invalid types have type != sizeInfoIndex and fall through to the cold path, as do RegEx,
+ // MinKey, MaxKey and the remaining invalid types mapping to SizeStyle::kSpecial.
+ int sizeInfoIndex = type % sizeof(kSizeInfoTable);
+ const auto sizeInfo = kSizeInfoTable[sizeInfoIndex];
+ if (MONGO_likely(type == sizeInfoIndex)) {
+ if (sizeInfo.style == SizeStyle::kFixed)
+ return sizeInfo.bytes + fieldNameSize;
+ if (MONGO_likely(sizeInfo.style == SizeStyle::kIntPlusFixed))
+ return sizeInfo.bytes + fieldNameSize +
+ ConstDataView(elem + fieldNameSize + 1).read<LittleEndian<int32_t>>();
}
- const auto sizeInfo = kSizeInfoTable[type];
- if (sizeInfo.style == SizeStyle::kFixed)
- return sizeInfo.bytes + fieldNameSize();
- if (MONGO_likely(sizeInfo.style == SizeStyle::kIntPlusFixed))
- return sizeInfo.bytes + fieldNameSize() + valuestrsize();
-
- return [this, type]() {
- // Regex is two c-strings back-to-back.
- invariant(type == BSONType::RegEx);
- const char* p = value();
- size_t len1 = strlen(p);
- p = p + len1 + 1;
- size_t len2 = strlen(p);
- return (len1 + 1 + len2 + 1) + fieldNameSize() + 1;
- }();
+ // The following code handles all special cases: MinKey, MaxKey, RegEx and invalid types.
+ if (type == MaxKey || type == MinKey)
+ return fieldNameSize + 1;
+ if (type != BSONType::RegEx)
+ msgAssertedBadType(elem);
+
+ // RegEx is two c-strings back-to-back.
+ const char* p = elem + fieldNameSize + 1;
+ size_t len1 = strlen(p);
+ p = p + len1 + 1;
+ size_t len2 = strlen(p);
+ return (len1 + 1 + len2 + 1) + fieldNameSize + 1;
}
std::string BSONElement::toString(bool includeFieldName, bool full) const {