summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorParker Felix <parker.felix@mongodb.com>2022-06-22 14:47:56 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-06-22 15:47:46 +0000
commitaf7d7199295acdd5001ff25e197fe74d93cfef66 (patch)
treef8b632c717d79f059122a55d00df658d2c4cd327
parente5ba004eba04ee99263f252b584d982d457e912e (diff)
downloadmongo-af7d7199295acdd5001ff25e197fe74d93cfef66.tar.gz
SERVER-66842 Fix pcPointer for instructions that take arguments in CodeFragment::toString()
-rw-r--r--src/mongo/db/exec/sbe/SConscript1
-rw-r--r--src/mongo/db/exec/sbe/sbe_test.cpp80
-rw-r--r--src/mongo/db/exec/sbe/vm/vm.cpp30
-rw-r--r--src/mongo/db/exec/sbe/vm/vm.h19
4 files changed, 120 insertions, 10 deletions
diff --git a/src/mongo/db/exec/sbe/SConscript b/src/mongo/db/exec/sbe/SConscript
index 6a2503d7f26..6ee97450f2b 100644
--- a/src/mongo/db/exec/sbe/SConscript
+++ b/src/mongo/db/exec/sbe/SConscript
@@ -223,6 +223,7 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/db/query/collation/collator_interface_mock',
'$BUILD_DIR/mongo/db/service_context_d_test_fixture',
'$BUILD_DIR/mongo/db/service_context_test_fixture',
+ '$BUILD_DIR/mongo/util/pcre_wrapper',
'sbe_plan_stage_test',
],
)
diff --git a/src/mongo/db/exec/sbe/sbe_test.cpp b/src/mongo/db/exec/sbe/sbe_test.cpp
index 323368a5334..5a577f02462 100644
--- a/src/mongo/db/exec/sbe/sbe_test.cpp
+++ b/src/mongo/db/exec/sbe/sbe_test.cpp
@@ -31,6 +31,7 @@
#include "mongo/db/exec/sbe/values/value.h"
#include "mongo/db/exec/sbe/vm/vm.h"
#include "mongo/unittest/unittest.h"
+#include "mongo/util/pcre.h"
namespace mongo::sbe {
@@ -421,6 +422,85 @@ TEST(SBEVM, ConvertBinDataToBsonObj) {
namespace {
+// The hex representation of memory addresses in the output of CodeFragment::toString() differs on
+// Linux and Windows machines so 'addrPattern' is used to cover both cases.
+static const std::string kLinuxAddrPattern{"(0x[a-f0-9]+)"};
+static const std::string kWindowsAddrPattern{"([A-F0-9]+)"};
+static const std::string kAddrPattern{"(" + kLinuxAddrPattern + "|" + kWindowsAddrPattern + ")"};
+
+// The beginning of the output from CodeFragment::toString() gives a range of the addresses that
+// 'pcPointer' will traverse.
+static const std::string kPcPointerRangePattern{"(\\[" + kAddrPattern + ")-(" + kAddrPattern +
+ ")\\])"};
+
+/**
+ * Creates a pcre pattern to match the instructions in the output of CodeFragment::toString(). Any
+ * arguments must be passed in a single comma separated string, and no arguments can be represented
+ * using an empty string.
+ */
+std::string instrPattern(std::string op, std::string args) {
+ return "(" + kAddrPattern + ": " + op + "\\(" + args + "\\); )";
+}
+} // namespace
+
+TEST(SBEVM, CodeFragmentToString) {
+ {
+ vm::CodeFragment code;
+ std::string toStringPattern{kPcPointerRangePattern + "( )"};
+
+ code.appendDiv();
+ toStringPattern += instrPattern("div", "");
+ code.appendMul();
+ toStringPattern += instrPattern("mul", "");
+ code.appendAdd();
+ toStringPattern += instrPattern("add", "");
+
+ std::string instrs = code.toString();
+
+ static const pcre::Regex validToStringOutput{toStringPattern};
+
+ ASSERT_TRUE(!!validToStringOutput.matchView(instrs));
+ }
+}
+
+TEST(SBEVM, CodeFragmentToStringArgs) {
+ {
+ vm::CodeFragment code;
+ std::string toStringPattern{kAddrPattern};
+
+ code.appendFillEmpty(vm::Instruction::True);
+ toStringPattern += instrPattern("fillEmptyConst", "k: True");
+ code.appendFillEmpty(vm::Instruction::Null);
+ toStringPattern += instrPattern("fillEmptyConst", "k: Null");
+ code.appendFillEmpty(vm::Instruction::False);
+ toStringPattern += instrPattern("fillEmptyConst", "k: False");
+
+ code.appendTraverseP(0xAA);
+ auto offsetP = 0xAA - code.instrs().size();
+ toStringPattern += instrPattern("traversePConst", "offset: " + std::to_string(offsetP));
+ code.appendTraverseF(0xBB, vm::Instruction::True);
+ auto offsetF = 0xBB - code.instrs().size();
+ toStringPattern +=
+ instrPattern("traverseFConst", "k: True, offset: " + std::to_string(offsetF));
+
+ auto [tag, val] = value::makeNewString("Hello world!");
+ value::ValueGuard guard{tag, val};
+ code.appendGetField(tag, val);
+ toStringPattern += instrPattern("getFieldConst", "value: \"Hello world!\"");
+
+ code.appendAdd();
+ toStringPattern += instrPattern("add", "");
+
+ std::string instrs = code.toString();
+
+ static const pcre::Regex validToStringOutput{toStringPattern};
+
+ ASSERT_TRUE(!!validToStringOutput.matchView(instrs));
+ }
+}
+
+namespace {
+
/**
* Fills bytes after the null terminator in the string with 'pattern'.
*
diff --git a/src/mongo/db/exec/sbe/vm/vm.cpp b/src/mongo/db/exec/sbe/vm/vm.cpp
index 3aae133219f..4f9329e7ed6 100644
--- a/src/mongo/db/exec/sbe/vm/vm.cpp
+++ b/src/mongo/db/exec/sbe/vm/vm.cpp
@@ -27,7 +27,6 @@
* it in the license file.
*/
-
#include "mongo/platform/basic.h"
#include "mongo/db/exec/sbe/expressions/expression.h"
@@ -213,17 +212,13 @@ std::string CodeFragment::toString() const {
case Instruction::cmp3w:
case Instruction::collCmp3w:
case Instruction::fillEmpty:
- case Instruction::fillEmptyConst:
case Instruction::getField:
- case Instruction::getFieldConst:
case Instruction::getElement:
case Instruction::getArraySize:
case Instruction::collComparisonKey:
case Instruction::getFieldOrElement:
case Instruction::traverseP:
- case Instruction::traversePConst:
case Instruction::traverseF:
- case Instruction::traverseFConst:
case Instruction::setField:
case Instruction::aggSum:
case Instruction::aggMin:
@@ -251,9 +246,15 @@ std::string CodeFragment::toString() const {
break;
}
// Instructions with a single integer argument.
+ case Instruction::pushLocalLambda:
+ case Instruction::traversePConst: {
+ auto offset = readFromMemory<int>(pcPointer);
+ pcPointer += sizeof(offset);
+ ss << "offset: " << offset;
+ break;
+ }
case Instruction::pushLocalVal:
- case Instruction::pushMoveLocalVal:
- case Instruction::pushLocalLambda: {
+ case Instruction::pushMoveLocalVal: {
auto arg = readFromMemory<int>(pcPointer);
pcPointer += sizeof(arg);
ss << "arg: " << arg;
@@ -268,6 +269,21 @@ std::string CodeFragment::toString() const {
break;
}
// Instructions with other kinds of arguments.
+ case Instruction::traverseFConst: {
+ auto k = readFromMemory<Instruction::Constants>(pcPointer);
+ pcPointer += sizeof(k);
+ auto offset = readFromMemory<int>(pcPointer);
+ pcPointer += sizeof(offset);
+ ss << "k: " << Instruction::toStringConstants(k) << ", offset: " << offset;
+ break;
+ }
+ case Instruction::fillEmptyConst: {
+ auto k = readFromMemory<Instruction::Constants>(pcPointer);
+ pcPointer += sizeof(k);
+ ss << "k: " << Instruction::toStringConstants(k);
+ break;
+ }
+ case Instruction::getFieldConst:
case Instruction::pushConstVal: {
auto tag = readFromMemory<value::TypeTags>(pcPointer);
pcPointer += sizeof(tag);
diff --git a/src/mongo/db/exec/sbe/vm/vm.h b/src/mongo/db/exec/sbe/vm/vm.h
index 801a139e5b8..2fec8265bfd 100644
--- a/src/mongo/db/exec/sbe/vm/vm.h
+++ b/src/mongo/db/exec/sbe/vm/vm.h
@@ -332,6 +332,19 @@ struct Instruction {
False,
};
+ static const char* toStringConstants(Constants k) {
+ switch (k) {
+ case Null:
+ return "Null";
+ case True:
+ return "True";
+ case False:
+ return "False";
+ default:
+ return "unknown";
+ }
+ }
+
// Make sure that values in this arrays are always in-sync with the enum.
static int stackOffset[];
@@ -777,6 +790,9 @@ public:
void fixup(int offset);
+ // For printing from an interactive debugger.
+ std::string toString() const;
+
private:
void appendSimpleInstruction(Instruction::Tags tag);
auto allocateSpace(size_t size) {
@@ -789,9 +805,6 @@ private:
void copyCodeAndFixup(CodeFragment&& from);
private:
- // For printing from an interactive debugger.
- std::string toString() const;
-
absl::InlinedVector<uint8_t, 16> _instrs;
/**