通过CPython执行跟踪Python字节码

时间:2015-11-11 02:46:15

标签: python c bytecode cpython

我试图通过跟踪不同的字节码/操作码来加深对CPython解释器的理解,因为它们通过ceval.c中的解释器循环来完成一个简单的Python程序。我使用bytecodeopcode来表示同样的事情。

我的python程序是这样的:

#filename: test.py

x = 2
y = 3

if x < y:
    z = x
elif True:
    z = y
else:
    z = 100

我正在使用Python 2.7.8,并使用如下调试标志构建它:

wget https://www.python.org/ftp/python/2.7.8/Python-2.7.8.tgz   # download
tar xvf Python-2.7.8.tgz                                        # extract
cd Python2.7.8 
./configure --with-pydebug                                      # build with debug flag
make -j                                                         # parallel make

我有兴趣跟踪解释器循环for(;;)中不同switch的{​​{1}}语句的opcode循环,从第964行开始。

我在ceval.c循环开始后立即添加了这些行,以检查解释器是否正在运行我的文件,如果是,则打印出for

opcode

我得到的输出是(手动添加注释以显示来自964 for (;;) { 965 if (strcmp(filename, "../test.py") == 0) { 966 printf("%d\n", opcode); 967 } 的{​​{1}} opcode):

DEFINE

我期望12个不同的操作码而不是7个,因为当我得到相同文件的字节码反汇编时,有12个字节码命令。

opcode.h

我对CPython插件工作原理的心理模型和/或我记录不同操作码的方法不正确,或两者兼而有之。你能解释为什么我从 $ ./python.exe ../test.py | cat -n 1 0 // STOP_CODE 2 90 // HAVE_ARGUMENT 3 90 // HAVE_ARGUMENT 4 101 // LOAD_NAME 5 101 // LOAD_NAME 6 101 // LOAD_NAME 7 90 // STORE_NAME 文件的输出和使用$ ./python.exe -m dis ../pytests/test.py | sed "/^$/d" | cat -n 1 1 0 LOAD_CONST 0 (2) 2 3 STORE_NAME 0 (x) 3 2 6 LOAD_CONST 1 (3) 4 9 STORE_NAME 1 (y) 5 4 12 LOAD_NAME 0 (x) 6 15 LOAD_NAME 1 (y) 7 18 COMPARE_OP 0 (<) 8 21 POP_JUMP_IF_FALSE 33 9 5 24 LOAD_NAME 0 (x) 10 27 STORE_NAME 2 (z) 11 30 JUMP_FORWARD 21 (to 54) 12 6 >> 33 LOAD_NAME 包中看到不同的操作码吗?

1 个答案:

答案 0 :(得分:0)

您的跟踪显示有问题,因为在正常情况下您不执行STOP_CODE(值0)将停止执行。此外,HAVE_ARGUMENT不是操作码。对于Python 2.7,操作码是STORE_NAME

对于值的差异,可以在任何非直线(基本块)代码的代码中预期。而你的不是直线代码。有COMPARE <后跟POP_JUMP_IF_FALSE跳转。