Python虚拟机是一种抽象层次更高的虚拟机
PyCodeObject对象pyc文件
对于Python编译器来说,PyCodeObject对象是真正的编译结果,pyc文件只是这个对象在硬盘上的表现形式
Python源码中的PyCodeObject
[code.h]
typedef struct {
PyObject_HEAD
int co_argcount; /* #arguments, except *args */
int co_nlocals; /* #local variables */
int co_stacksize; /* #entries needed for evaluation stack */
int co_flags;
PyObject* co_code; /* instruction opcodes */
PyObject* co_consts; /* list (constants used) */
PyObject* co_names; /* list of strings (names used) */
PyObject* co_varnames; /* tuple of strings (local variable names) */
PyObject* co_freevars; /* tuple of strings (free variable names) */
PyObject* co_cellvars; /* tuple of strings (cell variable names) */
/* The rest doesn't count for hash/cmp */
PyObject* co_filename; /* string (where it was loaded from) */
PyObject* co_name; /* string (name, for reference) */
int co_firstlineno; /* first source line number */
PyObject* co_lnotab; /* string (encoding add<->lineno mapping) */
void* co_zombieframe; /* for optimization only */
} PyCodeObject;
当进入一个新的名字空间或者作用域时,就进入一个新的Code Block
名字空间链
pyc文件
import imp
import sys
def generate_pyc(name):
fp,pathname,description = imp.find_module(name)
try:
imp.load_module(name,fp,pathname,description)
finally:
if fp:
fp.close()
if __name__ == '__main__':
generate_pyc(sys.argv[1])
在Python中访问PyCodeObject对象
source = open('demo.py').read()
co = compile(source,'demo.py','exec')
type(co)
创建pyc文件的具体过程
[import.c]
static void write_compiled_module(PyCodeObject* co, char* cpathname, long mtime){
FILE* fp;
//排他性打开文件
fp = open_exclusive(cpathname);
//写入python的magic number,用来解决因为python字节码不兼容的问题
PyMarshal_WriteLongToFile(pyc_magic,fp,Py_MARSHAL_VERSION);
//写入时间
PyMarshal_WriteLongToFile(mtime,fp,Py_MARSHAL_VERSION);
//写入PyCodeObject对象
PyMarshal_WriteObjectToFile((PyObject *)co,fp,Py_MARSHAL_VERSION);
}
/* python2.5 pyc_number 的定义 */
[import.c]
#define MAGIC (62131 | ((long)'\r' << 16) | ((long)'\n' << 24))
static long pyc_magic = MAGIC
[marshal.c]
typedef struct {
FILE *p;
int depth;
PyObject* strings; /* dict on marshal, list on unmarshal 写入时指向PyDictObject对象,读出时指向PyListObject对象*/
} WFILE;
#define w_byte(c,p) putc((c),(p)->fp)
static void w_long(long x, WFILE* p){
w_byte((char)(x & 0xff),p);
w_byte((char)((x>>8) & 0xff), p);
w_byte((char)((x>>16) & 0xff), p);
w_byte((char)((x>>24) & 0xff),p);
}
static void w_string(char* s,int n, WFILE* p){
fwrite(s,1,n,p->fp);
}
static void w_object(PyObject* v, WFILE* p){
...
/*面对PyCodeObject*/
else if(PyCode_Check(v)){
PyCodeObject* co = (PyCodeObject *)v;
w_byte(TYPE_CODE,p);
w_long(co->co_argcount,p);
.....
w_object(co->co_code,p);
w_object(co->co_consts,p);
w_object(co->co_names,p);
.....
w_object(co->co_lnotab,p);
}
....
/*面对PyListObject*/
else if(PyList_Check(v)){
w_byte(TYPE_LIST,p);
n = PyList_GET_SIZE(v);
w_long((long)n,p);
for(i = 0;i < n; i++){
w_object(PyList_GET_ITEM(v,i),p);
}
}
..../*面对PyIntObkect*/
else if(PyInt_Check(v)){
w_byte(TYPE_INT,p);
w_long(x,p);
}
}
向pyc文件写入字符串
[marshal.c]
/*写入用PyDictObject*/
void PyMarshal_WriteObjectToFile(PyObject* x, FILE* fp, int version){
WFILE wf;
wf.fp = fp;
wf.strings = (version > 0) ? PyDict_New() : NULL;
w_object(x,&wf);
}
/* 在w_object的字符串处理部分 */
...
else if(PyString_Check(v)){
if(p->strings && PyString_CHECK_INTERNED(v)){
//获得PyStringObject对象在strings符号
PyObject* o = PyDict_GetItem(p->strings,v);
//intern 字符串的非首次写入
if(o){
long w = PyInt_AsLong(o);
w_byte(TYPE_STRINGREF,p);
w_long(w,p);
goto exit;
}
//intern字符串男的首次写入
else{
o = PyInt_FromLong(PyDict_Size(p->strings));
PyDict_SetItem(p->strings,v,o);
Py_DECREF(o);
w_byte(TYPE_INTERNED,p);
}
//写入普通string
else{
//写入字符串的类型TYPE_STRING
w_byte(TYPE_STRING,p);
}
//写入字符串的长度
n = PyString_GET_SIZE(v);
w_long((long)n,p);
//写入字符串
w_string(PyString_AS_STRING(v),n,p);
}
}
/*由于PyDictObject没有访问索引的能力,所以读出时使用PyListObject*/
[marshal.c]
PyObject* PyMarshal_ReadObjectFromFile(FILE* fp){
RFILE rf;
PyObject* result;
rf.fp = fp;
rf.strings = PyList_New(0);
result = r_object(&rf);
return result;
}
一个PyCodeObject,多个PyCodeObject
一共定义了104条字节码指令
[opcode.h]
#define STOP_CODE 0
#define POP_TOP 1
#define ROT_TWO 2
....
#define CALL_FUNCTION_KW 141
#define CALL_FUNCTION_VAR_KW 142
#define EXTENDED_ARG 143