Merge branch 'upstream-pycdc'

This commit is contained in:
2025-07-03 14:02:08 +08:00
13 changed files with 243 additions and 23 deletions

4
.gitignore vendored
View File

@@ -6,8 +6,8 @@
/.kdev4 /.kdev4
__pycache__ __pycache__
tests-out tests-out
.vscode/
build/ build/
.vscode/
pyarmor-1shot pyarmor-1shot
pyarmor-1shot.exe pyarmor-1shot.exe

View File

@@ -1113,7 +1113,10 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
case Pyc::INSTRUMENTED_FOR_ITER_A: case Pyc::INSTRUMENTED_FOR_ITER_A:
{ {
PycRef<ASTNode> iter = stack.top(); // Iterable PycRef<ASTNode> iter = stack.top(); // Iterable
if (mod->verCompare(3, 12) < 0) {
// Do not pop the iterator for py 3.12+
stack.pop(); stack.pop();
}
/* Pop it? Don't pop it? */ /* Pop it? Don't pop it? */
int end; int end;
@@ -1379,6 +1382,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
} }
break; break;
case Pyc::JUMP_ABSOLUTE_A: 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; int offs = operand;
if (mod->verCompare(3, 10) >= 0) if (mod->verCompare(3, 10) >= 0)
@@ -1949,10 +1955,37 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
case Pyc::POP_EXCEPT: case Pyc::POP_EXCEPT:
/* Do nothing. */ /* Do nothing. */
break; break;
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
/* 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<ASTBlock> prev = blocks.top();
blocks.pop();
curblock = blocks.top();
curblock->append(prev.cast<ASTNode>());
}
else {
fprintf(stderr, "Wrong block type %i for END_FOR\n", curblock->blktype());
}
}
break;
case Pyc::POP_TOP: case Pyc::POP_TOP:
{ {
PycRef<ASTNode> value = stack.top(); PycRef<ASTNode> value = stack.top();
stack.pop(); stack.pop();
if (!curblock->inited()) { if (!curblock->inited()) {
if (curblock->blktype() == ASTBlock::BLK_WITH) { if (curblock->blktype() == ASTBlock::BLK_WITH) {
curblock.cast<ASTWithBlock>()->setExpr(value); curblock.cast<ASTWithBlock>()->setExpr(value);
@@ -2756,21 +2789,6 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
break; break;
// BEGIN ONESHOT TEMPORARY PATCH // BEGIN ONESHOT TEMPORARY PATCH
// THESE OPCODES ARE NOT IMPLEMENTED HERE // THESE OPCODES ARE NOT IMPLEMENTED HERE
case Pyc::COPY_A:
{
FastStack tmp_stack(20);
for (int i = 0; i < operand - 1; i++) {
tmp_stack.push(stack.top());
stack.pop();
}
auto value = stack.top();
for (int i = 0; i < operand - 1; i++) {
stack.push(tmp_stack.top());
tmp_stack.pop();
}
stack.push(value);
}
break;
case Pyc::PUSH_EXC_INFO: case Pyc::PUSH_EXC_INFO:
{ {
stack.push(stack.top()); stack.push(stack.top());
@@ -2797,6 +2815,79 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
} }
break; break;
// END ONESHOT PATCH // END ONESHOT PATCH
case Pyc::BINARY_SLICE:
{
PycRef<ASTNode> end = stack.top();
stack.pop();
PycRef<ASTNode> start = stack.top();
stack.pop();
PycRef<ASTNode> dest = stack.top();
stack.pop();
if (start.type() == ASTNode::NODE_OBJECT
&& start.cast<ASTObject>()->object() == Pyc_None) {
start = NULL;
}
if (end.type() == ASTNode::NODE_OBJECT
&& end.cast<ASTObject>()->object() == Pyc_None) {
end = NULL;
}
PycRef<ASTNode> slice;
if (start == NULL && end == NULL) {
slice = new ASTSlice(ASTSlice::SLICE0);
} else if (start == NULL) {
slice = new ASTSlice(ASTSlice::SLICE2, start, end);
} else if (end == NULL) {
slice = new ASTSlice(ASTSlice::SLICE1, start, end);
} else {
slice = new ASTSlice(ASTSlice::SLICE3, start, end);
}
stack.push(new ASTSubscr(dest, slice));
}
break;
case Pyc::STORE_SLICE:
{
PycRef<ASTNode> end = stack.top();
stack.pop();
PycRef<ASTNode> start = stack.top();
stack.pop();
PycRef<ASTNode> dest = stack.top();
stack.pop();
PycRef<ASTNode> values = stack.top();
stack.pop();
if (start.type() == ASTNode::NODE_OBJECT
&& start.cast<ASTObject>()->object() == Pyc_None) {
start = NULL;
}
if (end.type() == ASTNode::NODE_OBJECT
&& end.cast<ASTObject>()->object() == Pyc_None) {
end = NULL;
}
PycRef<ASTNode> slice;
if (start == NULL && end == NULL) {
slice = new ASTSlice(ASTSlice::SLICE0);
} else if (start == NULL) {
slice = new ASTSlice(ASTSlice::SLICE2, start, end);
} else if (end == NULL) {
slice = new ASTSlice(ASTSlice::SLICE1, start, end);
} else {
slice = new ASTSlice(ASTSlice::SLICE3, start, end);
}
curblock->append(new ASTStore(values, new ASTSubscr(dest, slice)));
}
break;
case Pyc::COPY_A:
{
PycRef<ASTNode> value = stack.top(operand);
stack.push(value);
}
break;
default: default:
fprintf(stderr, "Unsupported opcode: %s (%d) at %s\n", fprintf(stderr, "Unsupported opcode: %s (%d) at %s\n",
Pyc::OpcodeName(opcode), Pyc::OpcodeName(opcode),

View File

@@ -30,15 +30,31 @@ public:
{ {
if (m_ptr > -1) if (m_ptr > -1)
m_stack[m_ptr--] = nullptr; m_stack[m_ptr--] = nullptr;
else {
#ifdef BLOCK_DEBUG
fprintf(stderr, "pop from empty stack\n");
#endif
}
} }
PycRef<ASTNode> top() const PycRef<ASTNode> top(int i = 1) const
{ {
if (m_ptr > -1) if (i > 0) {
return m_stack[m_ptr]; int idx = m_ptr + 1 - i;
else if ((m_ptr > -1) && (idx >= 0))
return m_stack[idx];
else {
#ifdef BLOCK_DEBUG
fprintf(stderr, "insufficient values on stack\n");
#endif
return nullptr; return nullptr;
} }
}
else {
fprintf(stderr, "incorrect operand %i\n", i);
return nullptr;
}
}
bool empty() const bool empty() const
{ {

View File

@@ -474,6 +474,10 @@ void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
case Pyc::INSTRUMENTED_POP_JUMP_IF_FALSE_A: case Pyc::INSTRUMENTED_POP_JUMP_IF_FALSE_A:
case Pyc::INSTRUMENTED_POP_JUMP_IF_TRUE_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; int offs = operand;
if (mod->verCompare(3, 10) >= 0) if (mod->verCompare(3, 10) >= 0)
offs *= sizeof(uint16_t); // BPO-27129 offs *= sizeof(uint16_t); // BPO-27129

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,7 @@
l = [1,2,3,4,5,6]
print(l[1:3])
print(l[:2])
print(l[3:])
print(l[-4:])
print(l[:-2])
print(l[:])

View File

@@ -0,0 +1,8 @@
a = [0] * 16
l = [1,2,3]
a[13:] = l
a[5] = 10
a[:2] = [1,2]
a[:] = range(16)
print(a)

View File

@@ -0,0 +1,34 @@
def loop1():
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)

View File

@@ -0,0 +1,7 @@
l = [ 1 , 2 , 3 , 4 , 5 , 6 ] <EOL>
print ( l [ 1 : 3 ] ) <EOL>
print ( l [ : 2 ] ) <EOL>
print ( l [ 3 : ] ) <EOL>
print ( l [ - 4 : ] ) <EOL>
print ( l [ : - 2 ] ) <EOL>
print ( l [ : ] ) <EOL>

View File

@@ -0,0 +1,7 @@
a = [ 0 ] * 16 <EOL>
l = [ 1 , 2 , 3 ] <EOL>
a [ 13 : ] = l <EOL>
a [ 5 ] = 10 <EOL>
a [ : 2 ] = [ 1 , 2 ] <EOL>
a [ : ] = range ( 16 ) <EOL>
print ( a ) <EOL>

View File

@@ -0,0 +1,46 @@
def loop1 ( ) : <EOL>
<INDENT>
iterable = [ 1 , 2 , 3 ] <EOL>
for item in iterable : <EOL>
<INDENT>
pass <EOL>
<OUTDENT>
<OUTDENT>
loop1 ( ) <EOL>
def loop2 ( ) : <EOL>
<INDENT>
for i in range ( 2 ) : <EOL>
<INDENT>
print ( i ) <EOL>
<OUTDENT>
<OUTDENT>
loop2 ( ) <EOL>
def loop3 ( ) : <EOL>
<INDENT>
def loop ( ) : <EOL>
<INDENT>
x = ( 1 , 2 , 3 ) <EOL>
l = [ ] <EOL>
for i in x : <EOL>
<INDENT>
l . append ( i ) <EOL>
<OUTDENT>
return l <EOL>
<OUTDENT>
return loop ( ) <EOL>
<OUTDENT>
loop3 ( ) <EOL>
def loop4 ( ) : <EOL>
<INDENT>
for i in range ( 3 ) : <EOL>
<INDENT>
for j in range ( 2 ) : <EOL>
<INDENT>
print ( i * j ) <EOL>
<OUTDENT>
<OUTDENT>
<OUTDENT>
loop4 ( ) <EOL>
for j in [ 1 , 2 , 3 ] [ : : - 1 ] : <EOL>
<INDENT>
print ( 'hi' , j ) <EOL>