From da859f5a2bc7636ca5bd8aa29707a619149b620a Mon Sep 17 00:00:00 2001 From: MrDakik <68035827+TiZCrocodile@users.noreply.github.com> Date: Tue, 18 Jul 2023 18:33:03 +0300 Subject: [PATCH] Added support for opcodes: (in DESC) `KW_NAMES` `POP_JUMP_FORWARD_IF_FALSE` `POP_JUMP_FORWARD_IF_TRUE` `LOAD_GLOBAL` --- ASTNode.h | 18 +++++ ASTree.cpp | 76 +++++++++++++++--- bytecode.cpp | 3 +- tests/compiled/test_kwnames.3.11.pyc | Bin 0 -> 321 bytes .../test_pop_jump_forward_if_false.3.11.pyc | Bin 0 -> 281 bytes .../test_pop_jump_forward_if_true.3.11.pyc | Bin 0 -> 286 bytes tests/input/test_kwnames.py | 3 + tests/input/test_pop_jump_forward_if_false.py | 3 + tests/input/test_pop_jump_forward_if_true.py | 3 + tests/tokenized/test_kwnames.txt | 5 ++ .../test_pop_jump_forward_if_false.txt | 5 ++ .../test_pop_jump_forward_if_true.txt | 5 ++ 12 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 tests/compiled/test_kwnames.3.11.pyc create mode 100644 tests/compiled/test_pop_jump_forward_if_false.3.11.pyc create mode 100644 tests/compiled/test_pop_jump_forward_if_true.3.11.pyc create mode 100644 tests/input/test_kwnames.py create mode 100644 tests/input/test_pop_jump_forward_if_false.py create mode 100644 tests/input/test_pop_jump_forward_if_true.py create mode 100644 tests/tokenized/test_kwnames.txt create mode 100644 tests/tokenized/test_pop_jump_forward_if_false.txt create mode 100644 tests/tokenized/test_pop_jump_forward_if_true.txt diff --git a/ASTNode.h b/ASTNode.h index 9a621b0..22b90e1 100644 --- a/ASTNode.h +++ b/ASTNode.h @@ -18,6 +18,7 @@ public: NODE_COMPREHENSION, NODE_LOADBUILDCLASS, NODE_AWAITABLE, NODE_FORMATTEDVALUE, NODE_JOINEDSTR, NODE_CONST_MAP, NODE_ANNOTATED_VAR, NODE_CHAINSTORE, NODE_TERNARY, + NODE_KW_NAMES_MAP, // Empty node types NODE_LOCALS, @@ -394,6 +395,23 @@ private: map_t m_values; }; +class ASTKwNamesMap : public ASTNode { +public: + typedef std::list, PycRef>> map_t; + + ASTKwNamesMap() : ASTNode(NODE_KW_NAMES_MAP) { } + + void add(PycRef key, PycRef value) + { + m_values.emplace_back(std::move(key), std::move(value)); + } + + const map_t& values() const { return m_values; } + +private: + map_t m_values; +}; + class ASTConstMap : public ASTNode { public: typedef std::vector> values_t; diff --git a/ASTree.cpp b/ASTree.cpp index 4245a69..63a894e 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -123,9 +123,11 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) && opcode != Pyc::JUMP_IF_FALSE_A && opcode != Pyc::JUMP_IF_FALSE_OR_POP_A && opcode != Pyc::POP_JUMP_IF_FALSE_A + && opcode != Pyc::POP_JUMP_FORWARD_IF_FALSE_A && opcode != Pyc::JUMP_IF_TRUE_A && opcode != Pyc::JUMP_IF_TRUE_OR_POP_A && opcode != Pyc::POP_JUMP_IF_TRUE_A + && opcode != Pyc::POP_JUMP_FORWARD_IF_TRUE_A && opcode != Pyc::POP_BLOCK) { else_pop = false; @@ -401,6 +403,19 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack.push(new ASTTuple(values)); } break; + case Pyc::KW_NAMES_A: + { + + int kwparams = code->getConst(operand).cast()->size(); + ASTKwNamesMap kwparamList; + std::vector> keys = code->getConst(operand).cast()->values(); + for (int i = 0; i < kwparams; i++) { + kwparamList.add(new ASTObject(keys[kwparams - i - 1]), stack.top()); + stack.pop(); + } + stack.push(new ASTKwNamesMap(kwparamList)); + } + break; case Pyc::CALL_A: case Pyc::CALL_FUNCTION_A: { @@ -445,12 +460,31 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack_hist.pop(); } - for (int i=0; i val = stack.top(); - stack.pop(); - PycRef key = stack.top(); - stack.pop(); - kwparamList.push_front(std::make_pair(key, val)); + /* + KW_NAMES(i) + Stores a reference to co_consts[consti] into an internal variable for use by CALL. + co_consts[consti] must be a tuple of strings. + New in version 3.11. + */ + if (mod->verCompare(3, 11) >= 0) { + PycRef object_or_map = stack.top(); + if (object_or_map.type() == ASTNode::NODE_KW_NAMES_MAP) { + stack.pop(); + PycRef kwparams_map = object_or_map.cast(); + for (ASTKwNamesMap::map_t::const_iterator it = kwparams_map->values().begin(); it != kwparams_map->values().end(); it++) { + kwparamList.push_front(std::make_pair(it->first, it->second)); + pparams -= 1; + } + } + } + else { + for (int i = 0; i < kwparams; i++) { + PycRef val = stack.top(); + stack.pop(); + PycRef key = stack.top(); + stack.pop(); + kwparamList.push_front(std::make_pair(key, val)); + } } for (int i=0; i param = stack.top(); @@ -1004,13 +1038,17 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) case Pyc::JUMP_IF_TRUE_OR_POP_A: case Pyc::POP_JUMP_IF_FALSE_A: case Pyc::POP_JUMP_IF_TRUE_A: + case Pyc::POP_JUMP_FORWARD_IF_FALSE_A: + case Pyc::POP_JUMP_FORWARD_IF_TRUE_A: { PycRef cond = stack.top(); PycRef ifblk; int popped = ASTCondBlock::UNINITED; if (opcode == Pyc::POP_JUMP_IF_FALSE_A - || opcode == Pyc::POP_JUMP_IF_TRUE_A) { + || opcode == Pyc::POP_JUMP_IF_TRUE_A + || opcode == Pyc::POP_JUMP_FORWARD_IF_FALSE_A + || opcode == Pyc::POP_JUMP_FORWARD_IF_TRUE_A) { /* Pop condition before the jump */ stack.pop(); popped = ASTCondBlock::PRE_POPPED; @@ -1029,15 +1067,18 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) /* "Jump if true" means "Jump if not false" */ bool neg = opcode == Pyc::JUMP_IF_TRUE_A || opcode == Pyc::JUMP_IF_TRUE_OR_POP_A - || opcode == Pyc::POP_JUMP_IF_TRUE_A; + || opcode == Pyc::POP_JUMP_IF_TRUE_A + || opcode == Pyc::POP_JUMP_FORWARD_IF_TRUE_A; int offs = operand; if (mod->verCompare(3, 10) >= 0) offs *= sizeof(uint16_t); // // BPO-27129 if (opcode == Pyc::JUMP_IF_FALSE_A - || opcode == Pyc::JUMP_IF_TRUE_A) { + || opcode == Pyc::JUMP_IF_TRUE_A + || opcode == Pyc::POP_JUMP_FORWARD_IF_TRUE_A + || opcode == Pyc::POP_JUMP_FORWARD_IF_FALSE_A) { /* Offset is relative in these cases */ - offs = pos + operand; + offs += pos; } if (cond.type() == ASTNode::NODE_COMPARE @@ -1455,6 +1496,21 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack.push(new ASTName(code->getLocal(operand))); break; case Pyc::LOAD_GLOBAL_A: + if (mod->verCompare(3, 11) >= 0) { + if (operand & 1) { + /* Changed in version 3.11: + If the low bit of "NAMEI" (operand) is set, + then a NULL is pushed to the stack before the global variable. */ + stack.push(nullptr); + /* + and thats because for some reason for example 3 global functions: input, int, print. + it tries to load: 1, 3, 5 + all though we have only 3 names, so thats should be: (1-1)/2 = 0, (3-1)/2 = 1, (5-1)/2 = 2 + i dont know why, maybe because of the null push, but thats a FIX for now. + */ + operand = (int)((operand - 1) / 2); + } + } stack.push(new ASTName(code->getName(operand))); break; case Pyc::LOAD_LOCALS: diff --git a/bytecode.cpp b/bytecode.cpp index cad4ab0..229648e 100644 --- a/bytecode.cpp +++ b/bytecode.cpp @@ -152,7 +152,8 @@ bool Pyc::IsJumpOffsetArg(int opcode) return (opcode == Pyc::JUMP_FORWARD_A) || (opcode == Pyc::JUMP_IF_FALSE_A) || (opcode == Pyc::JUMP_IF_TRUE_A) || (opcode == Pyc::SETUP_LOOP_A) || (opcode == Pyc::SETUP_FINALLY_A) || (opcode == Pyc::SETUP_EXCEPT_A) || - (opcode == Pyc::FOR_LOOP_A) || (opcode == Pyc::FOR_ITER_A); + (opcode == Pyc::FOR_LOOP_A) || (opcode == Pyc::FOR_ITER_A) || + (opcode == Pyc::POP_JUMP_FORWARD_IF_FALSE_A) || (opcode == Pyc::POP_JUMP_FORWARD_IF_TRUE_A); } bool Pyc::IsCompareArg(int opcode) diff --git a/tests/compiled/test_kwnames.3.11.pyc b/tests/compiled/test_kwnames.3.11.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59d70bb4c44a444583f13ae33bfc9e6f8705b9d5 GIT binary patch literal 321 zcmZ3^%ge<81Yv8orN{&6#~=<2Fhd!iRe+4?3@HpP3{ebB45=Rx%WEfW+8<#4iq;-29Z%oK(9aZXg$ImO7B}ftit!@dFbhBi9E881aCCxq-PM Qv4NwJqlKdZ48aBg0QZJDW&i*H literal 0 HcmV?d00001 diff --git a/tests/compiled/test_pop_jump_forward_if_false.3.11.pyc b/tests/compiled/test_pop_jump_forward_if_false.3.11.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38b534a439557c1a8ea279a9aea1be42a500b168 GIT binary patch literal 281 zcmZ3^%ge<81i@>zrPu-K#~=<2Fhd!iK{C@BQW#Pgvzb6*MchmbsSGJh%NQ9LRs%5v zFfxEenbAd4Sb`ZeSzm(Gy#%Se#ZppKnp!25mY7qVs-RJvuaH%mTacNTu8@{rRGwIr zqUoo}c#E~5C^N5QCBtWsmS2h`sl_Gn1^ET>Ahq#Oh4Gnb@nBQ*3Mzkb*yQG?l;)(` z6>$P}fNU!^0umpX85tRGFtcl1kiEgc+Q52&P3aev0`o}hE#?Wre%x_46A_{ z0vH*Ry6WR&nIzmnf7Jm8Monf=C68;(Udy(%gc~ymW=M{G#&2 zq7+R(O~zZS1x1;8B`X;|gLM5;C`m0Yi7&`6hzF^ShboNEOp6B@qE}G)i^C>2KczG$ z)vkyGr~zbOu_=)Fz|6?Vc!Qmz!?CHXq3i}DTZ3pr)kQ|3D~v)H7=>;yur{z>U{k!v Qpmc>n=>iNDu>o}g0Qi + +print ( x ) + +foo ( x = 1 ) diff --git a/tests/tokenized/test_pop_jump_forward_if_false.txt b/tests/tokenized/test_pop_jump_forward_if_false.txt new file mode 100644 index 0000000..02ce800 --- /dev/null +++ b/tests/tokenized/test_pop_jump_forward_if_false.txt @@ -0,0 +1,5 @@ +if 1 == 0 : + +print ( 'true' ) + +print ( 'false (so jumping forward)' ) diff --git a/tests/tokenized/test_pop_jump_forward_if_true.txt b/tests/tokenized/test_pop_jump_forward_if_true.txt new file mode 100644 index 0000000..6de06be --- /dev/null +++ b/tests/tokenized/test_pop_jump_forward_if_true.txt @@ -0,0 +1,5 @@ +if not 1 == 0 : + +print ( 'not true' ) + +print ( 'true (so jumping forward)' )