test.py的指令序列

func函数的指令序列

第一列表示以下几个指令在py文件中的行号;

第二列是该指令在指令序列co_code里的偏移量;

第三列是指令opcode的名称,分为有操作数和无操作数两种,opcode在指令序列中是一个字节的整数;

第四列是操作数oparg,在指令序列中占两个字节,基本都是co_consts或者co_names的下标;

第五列带括号的是操作数说明。

7. 执行字节码

Python虚拟机的原理就是模拟可执行程序再X86机器上的运行,X86的运行时栈帧如下图:

假如test.py用C语言来实现,会是下面这个样子:

  1. const char *s = “hello”; 
  2.  
  3. void func() { 
  4.     printf(“%s\n”, s); 
  5.  
  6. int main() { 
  7.     func(); 
  8.     return 0; 

Python虚拟机的原理就是模拟上述行为。当发生函数调用时,创建新的栈帧,对应Python的实现就是PyFrameObject对象。

7.1 PyFrameObject

  1. typedef struct _frame { 
  2.     PyObject_VAR_HEAD 
  3.     struct _frame *f_back;    /* 调用者的帧 */ 
  4.     PyCodeObject *f_code;     /* 帧对应的字节码对象 */ 
  5.     PyObject *f_builtins;     /* 内置名字空间 */ 
  6.     PyObject *f_globals;      /* 全局名字空间 */ 
  7.     PyObject *f_locals;       /* 本地名字空间 */ 
  8.     PyObject **f_valuestack;  /* 运行时栈底 */ 
  9.     PyObject **f_stacktop;    /* 运行时栈顶 */ 
  10.     ……. 

那么对应Python的运行时栈就是这样子:

7.2 执行指令

执行test.py的字节码时,会先创建一个栈帧,以下用f表示当前栈帧,执行过程注释如下:

test.py的符号名集合和常量集合

  1. co.co_names   (‘s’, ’func’) 
  2. co.co_consts  (‘hello’, <code object func at 0x2aaeeec57110, file ”test.py”, line 3>, None) 

test.py的指令序列

上面的CALL_FUNCTION指令执行时,会创建新的栈帧,并执行func的字节码指令,以下用f表示当前栈帧,func的字节码执行过程如下:

func函数的符号名集合和常量集合

  1. func.co_names       (‘s’,) 
  2. func.co_consts      (None,) 


评论关闭