From a4a6a24f3e5e3a2b408319e9c8fbcf4ca6d1a073 Mon Sep 17 00:00:00 2001 From: Sahil Jain Date: Mon, 30 Jun 2025 21:35:59 +0530 Subject: [PATCH 1/6] Support END_FOR opcode --- .gitignore | 2 ++ ASTree.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 7cfe02d..3b39e81 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ /.kdev4 __pycache__ tests-out +build/ +.vscode/ diff --git a/ASTree.cpp b/ASTree.cpp index 1f419d0..10f507e 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -1679,6 +1679,7 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) /* Do nothing. */ break; case Pyc::POP_TOP: + case Pyc::END_FOR: { PycRef value = stack.top(); stack.pop(); @@ -2473,6 +2474,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack.push(next_tup); } break; + case Pyc::COPY_A: + break; default: fprintf(stderr, "Unsupported opcode: %s (%d)\n", Pyc::OpcodeName(opcode), opcode); cleanBuild = false; From a93fd14672eccfe9741082ec475a02da04fe3dc3 Mon Sep 17 00:00:00 2001 From: Sahil Jain Date: Mon, 30 Jun 2025 20:57:21 +0530 Subject: [PATCH 2/6] Add new loop tests --- ASTree.cpp | 28 +++++++++++++++-- FastStack.h | 11 ++++++- tests/compiled/test_loops3.3.12.pyc | Bin 0 -> 1249 bytes tests/input/test_loops3.py | 34 ++++++++++++++++++++ tests/tokenized/test_loops3.txt | 46 ++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 tests/compiled/test_loops3.3.12.pyc create mode 100644 tests/input/test_loops3.py create mode 100644 tests/tokenized/test_loops3.txt diff --git a/ASTree.cpp b/ASTree.cpp index 10f507e..ebd8e81 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -897,7 +897,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) case Pyc::INSTRUMENTED_FOR_ITER_A: { PycRef iter = stack.top(); // Iterable - stack.pop(); + if (mod->verCompare(3,12) < 0) + stack.pop(); /* Pop it? Don't pop it? */ int end; @@ -1678,11 +1679,34 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) case Pyc::POP_EXCEPT: /* Do nothing. */ break; - case Pyc::POP_TOP: case Pyc::END_FOR: + { + stack.pop(); + + if ((opcode == Pyc::END_FOR) && (mod->majorVer() == 3) && (mod->minorVer() == 12)) { + // one additional pop for python 3.12 + stack.pop(); + } + + // end for loop here + if (curblock->blktype() == ASTBlock::BLK_FOR) { + PycRef prev = blocks.top(); + blocks.pop(); + + curblock = blocks.top(); + curblock->append(prev.cast()); + } + else { + fprintf(stderr, "Wrong block type %i for END_FOR\n", curblock->blktype()); + break; + } + } + break; + case Pyc::POP_TOP: { PycRef value = stack.top(); stack.pop(); + if (!curblock->inited()) { if (curblock->blktype() == ASTBlock::BLK_WITH) { curblock.cast()->setExpr(value); diff --git a/FastStack.h b/FastStack.h index 45f8ed5..3f9c2c8 100644 --- a/FastStack.h +++ b/FastStack.h @@ -30,14 +30,23 @@ public: { if (m_ptr > -1) m_stack[m_ptr--] = nullptr; + else { + #ifdef BLOCK_DEBUG + fprintf(stderr, "pop from empty stack\n"); + #endif + } } PycRef top() const { if (m_ptr > -1) return m_stack[m_ptr]; - else + else { + #ifdef BLOCK_DEBUG + fprintf(stderr, "top on empty stack\n"); + #endif return nullptr; + } } bool empty() const diff --git a/tests/compiled/test_loops3.3.12.pyc b/tests/compiled/test_loops3.3.12.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efb575c88ee84c87b005b3b5e2e6b21bec868f31 GIT binary patch literal 1249 zcmZ`&OHUJV5TDscS+Lu;ydp_`#AGiefbn1mNfQr5W250>NQ@S?fs)eJ|CU5ZoAdz5 z8jF^T+_^RQ9sB@(fx2)odg4au&5O?byVMfmG&`N0_xxt|n`w>!k^5z3{VM|e;+IR( zeWANc!XenO3(KHD4vu{Tf{mm@(&2zkA)P`xWk9ErP9>fCPqzlPc7(Q0zrdb4K{+48 zs~Z5z8u{t=P)<8mdW8@grUu)(Wvu#@Lsz~{Dp;Rh6bE)#S zr?WUCg5=COodmHuc;WH-;z?xO)!Ig|qe66|OM1A{uSN>l?;{cpp~B&kY&`a5>fEHx zp~8NWs&Hu|6v8}@rDQ~aY%RspMYgz>^YpUF7b_Nen0Gi)QV@*L>vUGcNjB(l#)#G7 z)QmM}KE8DE)G*!bzCq1~Mg>*9+H4=(QL@nTY0))WKD9&dOiSFzwfVSMcYzp()MzI) zl=~okO{wBWe`Ze6qpC76;Y|&yxCDadr-1_5ayeJDE!D$!9u`E5)DGK{Nq*N_kh z2FgOg*LV%eIl+e(VpD`z9WE4Ik9I;3jC^=le|8;1-V!(4eM9WO3s1_0_kpqdaL_SO zof-}vLlt-Evm5{{ra|M5JPS1=hNzCb4Z*`(ip0yq4ga(U&f + +iterable = [ 1 , 2 , 3 ] +for item in iterable : + +pass + + +loop1 ( ) +def loop2 ( ) : + +for i in range ( 2 ) : + +print ( i ) + + +loop2 ( ) +def loop3 ( ) : + +def loop ( ) : + +x = ( 1 , 2 , 3 ) +l = [ ] +for i in x : + +l . append ( i ) + +return l + +return loop ( ) + +loop3 ( ) +def loop4 ( ) : + +for i in range ( 3 ) : + +for j in range ( 2 ) : + +print ( i * j ) + + + +loop4 ( ) +for j in [ 1 , 2 , 3 ] [ : : - 1 ] : + +print ( 'hi' , j ) From 040732920b1bcc9005345a4518955c904c50caa9 Mon Sep 17 00:00:00 2001 From: Sahil Jain Date: Mon, 30 Jun 2025 21:29:53 +0530 Subject: [PATCH 3/6] Add comment --- ASTree.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ASTree.cpp b/ASTree.cpp index ebd8e81..b5b42f7 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -1689,6 +1689,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) } // end for loop here + // TODO : Ensure that FOR loop ends here. + // Due to CACHE instructions at play, this can change. if (curblock->blktype() == ASTBlock::BLK_FOR) { PycRef prev = blocks.top(); blocks.pop(); From 6dae4e801f18e99b77c0679cb4ddab0a2e8217ca Mon Sep 17 00:00:00 2001 From: Sahil Jain Date: Mon, 30 Jun 2025 22:24:01 +0530 Subject: [PATCH 4/6] Remove COPY opcode --- ASTree.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/ASTree.cpp b/ASTree.cpp index b5b42f7..5f5603a 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -2500,8 +2500,6 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack.push(next_tup); } break; - case Pyc::COPY_A: - break; default: fprintf(stderr, "Unsupported opcode: %s (%d)\n", Pyc::OpcodeName(opcode), opcode); cleanBuild = false; From 97ec04789d795ed589a324aaf7dd9eb79ec4f7d9 Mon Sep 17 00:00:00 2001 From: Sahil Jain Date: Mon, 30 Jun 2025 22:57:49 +0530 Subject: [PATCH 5/6] Add JUMP_BACKWARD + CACHE comments --- ASTree.cpp | 11 ++++++++--- bytecode.cpp | 4 ++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ASTree.cpp b/ASTree.cpp index 5f5603a..99f95cb 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -1164,10 +1164,13 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) } break; case Pyc::JUMP_ABSOLUTE_A: + // bpo-47120: Replaced JUMP_ABSOLUTE by the relative jump JUMP_BACKWARD. + case Pyc::JUMP_BACKWARD_A: + case Pyc::JUMP_BACKWARD_NO_INTERRUPT_A: { int offs = operand; if (mod->verCompare(3, 10) >= 0) - offs *= sizeof(uint16_t); // // BPO-27129 + offs *= sizeof(uint16_t); // // BPO-27129 if (offs < pos) { if (curblock->blktype() == ASTBlock::BLK_FOR) { @@ -1689,8 +1692,10 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) } // end for loop here - // TODO : Ensure that FOR loop ends here. - // Due to CACHE instructions at play, this can change. + /* TODO : Ensure that FOR loop ends here. + Due to CACHE instructions at play, the end indicated in + the for loop by pycdas is not correct, it is off by + some small amount. */ if (curblock->blktype() == ASTBlock::BLK_FOR) { PycRef prev = blocks.top(); blocks.pop(); diff --git a/bytecode.cpp b/bytecode.cpp index 7821459..c6b7cba 100644 --- a/bytecode.cpp +++ b/bytecode.cpp @@ -472,6 +472,10 @@ void bc_disasm(std::ostream& pyc_output, PycRef code, PycModule* mod, case Pyc::INSTRUMENTED_POP_JUMP_IF_FALSE_A: case Pyc::INSTRUMENTED_POP_JUMP_IF_TRUE_A: { + /* TODO: Fix offset based on CACHE instructions. + Offset is relative to next non-CACHE instruction + and thus will be printed lower than actual value. + See TODO @ END_FOR ASTree.cpp */ int offs = operand; if (mod->verCompare(3, 10) >= 0) offs *= sizeof(uint16_t); // BPO-27129 From 6e0089e01c5f45b956d655a0c69a41e5ccc382bf Mon Sep 17 00:00:00 2001 From: Sahil Jain Date: Tue, 1 Jul 2025 22:52:59 +0530 Subject: [PATCH 6/6] Update --- ASTree.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ASTree.cpp b/ASTree.cpp index 99f95cb..6e010e0 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -897,8 +897,10 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) case Pyc::INSTRUMENTED_FOR_ITER_A: { PycRef iter = stack.top(); // Iterable - if (mod->verCompare(3,12) < 0) + if (mod->verCompare(3, 12) < 0) { + // Do not pop the iterator for py 3.12+ stack.pop(); + } /* Pop it? Don't pop it? */ int end; @@ -1705,7 +1707,6 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) } else { fprintf(stderr, "Wrong block type %i for END_FOR\n", curblock->blktype()); - break; } } break;