diff options
author | Parker Felix <parker.felix@mongodb.com> | 2022-06-22 14:47:56 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-06-22 15:47:46 +0000 |
commit | af7d7199295acdd5001ff25e197fe74d93cfef66 (patch) | |
tree | f8b632c717d79f059122a55d00df658d2c4cd327 | |
parent | e5ba004eba04ee99263f252b584d982d457e912e (diff) | |
download | mongo-af7d7199295acdd5001ff25e197fe74d93cfef66.tar.gz |
SERVER-66842 Fix pcPointer for instructions that take arguments in CodeFragment::toString()
-rw-r--r-- | src/mongo/db/exec/sbe/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/sbe_test.cpp | 80 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/vm/vm.cpp | 30 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/vm/vm.h | 19 |
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; /** |