Python_virtual_machine

  • reference: Python 源码剖析
  • Python_virtual_machine
    • Python虚拟机的执行环境
    • 名字、作用域和名字空间
    • Python虚拟机的运行框架
    • Python运行时环境初探

1.Python虚拟机框架

a.Python虚拟机的执行环境

  • x86 运行可执行文件的过程

x86_stack

PyCodeObject对象没有包含也不可能包含程序运行的动态信息–执行环境

  • Python源码中的PyFrameObject
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[frameobject.h]
typedef struct _frame{
PyObject_VAR_HEAD //说明PyFrameObject是变长对象,因为不同的Code Block在执行时所需的空间的大小是不同的
struct _frame* f_back; /* 执行环境链上的前一个frame */
PyCodeObject* f_code; /* PyCodeObject对象 */
PyObject* f_builtins; /* builtin名字空间 */
PyObject* f_globals; /* global名字空间 */
PyObject* f_locals; /* local名字空间 */
PyObject** f_valuestack; /* 运行时栈的栈底位置 */
PyObject** f_stacktop; /* 运行时栈的栈顶位置 */
....
int f_lasti; //上一条字节码指令在f_code中的偏移位置
int f_lineno; //当前字节码对应的源代码行

....

//动态内存,维护(局部变量 + cell对象集合 + free对象集合 + 运行时栈)所需要的空间
PyObject* f_localsplus[1];
} PyFrameObject;

python运行时栈指运算时所需要的内存空间

Python_runtime

  • PyFrameObject中的动态内存空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[frameobject.c]
PyFrameObject* PyFrame_New(PyThreadState* tstate, PyCodeObject* code, PyObject* globals, PyObject* locals){
PyFrameObject* f;
Py_ssize_t extras,ncells,nfrees,i;
ncells = PyTuple_GET_SIZE(code->co_cellvars);
nfrees = PyTuple_GET_SIZE(code->co_freevars);
//四部分构成了PyFrameObject维护的动态内存区,其大小由extras确定
extras = code->co_stacksize + code->co_nlocals + ncells + nfrees;
f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type,extras);
//计算初始化时运行时栈的栈顶
extras = code->co_nlocals + ncells + nfrees;
//f_valuestack维护运行时栈的栈底,f_stacktop维护运行时栈的栈顶
f->f_valuestack = f->f_localsplus + extras;
f->f_stacktop = f->f_valuestack;
return f;
}

pyframeobject

  • Python中访问PyFrameObject对象
1
sys._getframe();

b.名字、作用域和名字空间

  • Python程序的基础结构–module

module:1.代码复用 2.划分名字空间

module加载方法:1.import动态加载 2.主module加载

  • 约束与名字空间

(name,obj)关联关系称为约束, 约束的容身之处就是名字空间

属性引用是另一个名字空间中的名字,是一个访问对象属性的动作

  • 作用域与名字空间

Python具有静态作用域,因为约束在文本中的位置不是在运行时动态决定的

Python支持嵌套作用域

  • LGB规则

名字引用动作沿着local作用域、global作用域、builtin作用域的顺序查找名字对应的约束

lgb

  • LEGB规则(E : enclosing)
1
2
3
4
5
6
7
8
9
10
a = 1
def f():
a = 2
def g():
print a
return g

func = f(
func()
)

enclosing

  • global 表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//错误案例

a = 1

def g():
print a

def f():
print a
a = 2
print a

g()
f()

>> "local variable 'a' referenced before assignment"
  • 属性引用与名字引用

c.Python虚拟机的运行框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*Python虚拟机执行字节码指令的整体架构*/
[ceval.c]
/* Interpreter main loop */
PyObject* PyEval_EvalFrameEx(PyFrameObject* f,int throwflag){
...
why = WHY_NOT;
...
for(;;){
....
fast_next_opcode:
f->f_lasti = INSTR_OFFSET();
//获得字节码指令
opcode = NEXTOP();
oparg = 0;
//如果指令需要参数,获得指令参数
if(HAS_ARG(opcode))
oparg = NEXTARG();
dispatch_opcode:
switch (opcode) {
case NOP:
goto fast_next_opcode;
case LOAD_FAST:
...
}
}
}

/* status code for main loop (reason) for stack unwind */
enum why_code{
WHY_NOT = 0x0001, /* No error */
WHY_EXCEPTION = 0x0002 /* Exception occurred */
WHY_RERAISE = 0x0004 /* Exception re-raised by 'finally' */
WHY_RETURN = 0x0008 /* 'return' statement */
WHY_BREAK = 0x0010 /* 'break' statement */
WHY_CONTINUE = 0x0020 /* 'continue' statement */
WHY_YIELD = 0x0040 /* yield operator */
};

d.Python运行时环境初探

PyThreadState实现线程,PyInterpreterState实现进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[pystate.h]
typedef struct _is{
struct _is* next;
struct _ts* tstate_head; //模拟进程环境中的线程集合

PyObject* modules;
PyObject* sysdict;
PyObject* builtins;
...
} PyInterpreterState;

typedef struct _ts{
struct _ts* next;
PyInterpreterState* iterp;
struct _frame* frame; //模拟线程中的函数调用堆栈
int recursion_depth;
...
PyObject* dict;
...
long thread_id;
} PyThreadState;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//当Python虚拟机开始执行时,会将当前线程状态对象中的frame设置为当前的执行环境
[ceval.c]
PyObject* PyEval_EvalFrameEx(PyFrameObject* f, int throwflag){
...
//通过PyThreadState_GET获得当前活动线程对应的线程状态对象
PyThreadState* tstate = PyThreadState_GET();
...
//设置线程状态对象中的frame
tstate->frame = f;
co = f->f_code;
name = co->co_names;
consts = co->co_consts;
...

//虚拟机主循环
for(;;){
...
}
}

//建立新的PyFrameObject对象时,则从当前线程的状态对象中取出旧的frame,建立PyFrameObject链表
PyFrameObject* PyFrame_New(PyThreadState* tstate, PyCodeObject* code, PyObject* globals, PyObject* locals){
//从PyThreadState中获得当前线程的当前执行环境
PyFrameObject* back = tstate->frame;
PyFrameObject* f;
....
//创建新的执行环境
f = PyObject_GC_Resize(PyFrameObject,f,extras);
....
//链接当前执行环境
f->f_back = back;
f->f_tstate = tstate;
...
return f;
}

runtime

Share