• python虚拟机


    翻译自《Python Virtual Machine》

    Python 虚拟机
     
    每个函数对象都和以下的三个结构:
    1。包含参数的局部变量名称(in .__code__.varnames)
    2。全局变量名称(in .__code__.co_names)
    3。常数(in .__code__.co_consts)
     
    在python定义函数的时候创建这些结构,它们被定义在函数对应的__code__对象。
     
    如果我们定义如下:
    Def minimum(alist):
        m=None if let(alist) ==0 else Alist[0]
        for v in alist[1:]:
            if vim:
                m = v
        return m
     
    我们得到
    minimum.__code__.co_varnames is ('alist','m','v')
    minimum.__code__.co_names is ('len','None')
    minimum.__code__.co_consts is (None,0,1)
     
    用于索引的数字+load 运算符(LOAD_FAST、LOAD_GLOBAL、LOAD_CONST都会在之后讨论)。
     
    在PVM中主要的数据结构式“regular”栈(由一连串的push、pop组成)。对栈的主要操作就是load/push和store/pop。我们在栈顶load/push一个值,栈向上扩展,伴随着栈指针上移指向栈顶。同样,store/pop一个栈顶值时,栈指针下移。
     
    还有一个次要的block栈用于从循环嵌套、try和指令中取出值。比如,一个断点指令在block栈中被编码,用于判断哪个循环块被n断下(并如何继续执行循环外的指令)。当循环,try/except和指令开始执行时,他们的信息被push到block栈上;当它们结束时从堆栈上弹出。这种块block stack对于现在来说太过麻烦,不必要去理解:所以当我们遇到有关block stack 的指令时,会指出将其忽略的原因。
     
    这儿有个有关栈操作的简单例子,计算 d=a+b*c。假设a、b、c、d都是一个函数中的局部变量:co_varnames =('a','b','c','d')且这些符号对应的实际值被存放在并行元组中:(1,2,3,none)。符号在元组中的位置与其值在元组的位置是一一对应的。
     
    LOAD_FAST N
    load/push 将co_varnames[N]对应的值压入栈,stackp+=1,stack[stackp] = co_varnames[N]
     
    STORE_FAST N
    store/pop 将栈顶的值放入co_varnames[N], co_varnames[N] = stack[stackp], stackp-=1
     
    BINARY_MULTIPLY
    将‘*’的两个运算数压入栈,stack[stackp-1]=stack[stackp-1]*stack[stack];stackp-=1(将栈顶的两个值转化为它们的乘积)
     
    BINARY_ADD
    将‘+’的两个运算数压入栈,stack[stackp-1]=stack[stackp-1]+stack[stack];stackp-=1(将栈顶的两个值转化为它们的和)
     
    d = a+b*c  的PVM code:
    LOAD_FAST 0
    LOAD_FAST 1
    LOAD_FAST 2
    BINARY_MULTIPLY
    BINARY_ADD
    STORE_FAST 3
     
     
    初始状态:
    co_varnames =('a','b','c','d')
    values=(1,2,3,none)
         +--------------------+
    3    |                    |
         +--------------------+
    2    |                    | 
         +--------------------+
    1    |                    | 
         +--------------------+
    0    |                    |
         +--------------------+
    stack (with stackp=-1,it is an empty stack)
     
    LOAD_FAST 0:
         +--------------------+
    3    |                    |
         +--------------------+
    2    |                    | 
         +--------------------+
    1    |                    | 
         +--------------------+
    0    |     1: value of a  |
         +--------------------+
    stack(with stackp=0)
     
    LOAD_FAST 1:
         +--------------------+
    3    |                    |
         +--------------------+
    2    |                    | 
         +--------------------+
    1    |    2: value of b  | 
         +--------------------+
    0    |    1: value of a  |
         +--------------------+
    stack (with stackp=1)
     
    LOAD_FAST 2:
         +--------------------+
    3    |                    |
         +--------------------+
    2    |   3: value of c   | 
         +--------------------+
    1    |    2: value of b  | 
         +--------------------+
    0    |    1: value of a  |
         +--------------------+
    stack (with stackp=2)
     
    BINARY_MULTIPLY:
         +--------------------+
    3    |                    |
         +--------------------+
    2    |                    | 
         +--------------------+
    1    |   6: value of b*c | 
         +--------------------+
    0    |   1: value of a   |
         +--------------------+
    stack (with stackp=1)
     
    BINARY_ADD:
         +--------------------+
    3    |                    |
         +--------------------+
    2    |                    | 
         +--------------------+
    1    |                    | 
         +--------------------+
    0    | 7: value of a+b*c |
         +--------------------+
    stack (with stackp=0)
     
    STORE_FAST 3:
         +--------------------+
    3    |                    |
         +--------------------+
    2    |                    | 
         +--------------------+
    1    |                    | 
         +--------------------+
    0    |                    |
         +--------------------+
    stack (with stackp=-1)
    co_varnames =('a','b','c','d')
    values=(1,2,3,7)
     
     
    PVM的控制流
     
    在PVM的每个指令都包含了1~3字节的信息。第一个字节是操作标识或字节码,后面的两字节是字节码的操作数(但并不是所有的字节码都需要操作数:BINARY_ADD就不需要)。两字节能够表示0~65536:所以python的函数中不能有超过65536个不同的局部变量。
     
    指令被储存在内存中:把内存也看作一种储存有次序的数据的列表结构。
    Memory          Instruction
    Location  
    0               LOAD_FAST 0
    3               LOAD_FAST 1
    6               LOAD_FAST 2
    9               BINARY_MULTIPLY
    10              BINARY_ADD
    11              STORE_FAST 3
    把内存列表命名为m
    第一条指令被存储在m[0],后一指令存储在高3或高1的位置处(占3字节:有些指令有明确操作数的:load/store。有些指令有隐含的操作数:stack 、pc。占1字节:没有操作数的指令:binary运算)
     
    一旦这些指令被加载进内存后,PVM按照一个简单的规则执行他们。执行周期赋予了计算机生命,这是计算机科学的基础。
    (1)从m [pc]开始获取操作及其操作数(如果存在)
    (2)pc + = 3(如果操作数存在)或pc + = 1(如果没有操作数存在)
    (3)执行操作码(可能更改其操作数,堆栈,堆栈或pc)
    (4)转到步骤1
     
    一些运算会操作stack/stackp和存变量值的元组,一些会改变pc(比如jump指令)。
    所以pc初始时0,PVM执行上述代码以以下流程:
      1.获取操作m [0],操作数m [1]和m [2]
      2.将pc递增至3
      3.操纵堆栈(见上文)
      4.回到步骤1
     
      1.取m [3]的操作,m [4]和m [5]
      2.将pc增加到6
      3.操纵堆栈(见上文)
      4.回到步骤1
     
      1.取m [6]和m [7]和m [8]的操作数,
      2.将pc增加到9
      3.操纵堆栈(见上文)
      4.回到步骤1
     
      1.获取操作a m [9]:它没有操作数
      2.将pc增加到10
      3.操纵堆栈(见上文)
      4.回到步骤1
     
      1.获取操作m [10]:它没有操作数
      2.将pc增加到11
      3.操纵堆栈(见上文)
      4.回到步骤1
     
    内存中指向此处时,没有代码可以执行。在下一个例子中我们可以看到PVM如何执行一个更复杂的代码。
     
    如简要介绍的那样,我们可以用dis.py模块中使用dis函数打印任何Python函数(和模块/类也可以)的注释描述;这里我们打印函数。 
     
    def addup(alist):
         sum=0
         for v in alist:
              sum = sum + v
         return sum
    

      

     
    这个例子用来显示一般函数对象的有用的信息(它的名称,它的三个元组,和反编译信息)
     
    def func_obj(fo):
         print(fo.__name__)
         print('  co_varnames:',fo.__code__.co_varnames)
         print('  co_names   :',fo.__code__.co_names)
         print('  co_consts  :',fo.__code__.co_consts,'
    ')
         print('Source Line m operation/byte-code   operand (useful name/number)
    '+69*'-')
         dis.dis(fo)
     
    calling func_obj(addup) prints
     
    addup
    co_varnames: ('alist', 'sum', 'v')
    co_names : ()
    co_consts : (None, 0)
    Source Line m      op/byte-code  operand (useful name/number)
    ---------------------------------------------------------------------
    2           0      LOAD_CONST    1 (0)
                3      STORE_FAST    1 (sum)
     
    3           6      SETUP_LOOP    24 (to 33)
                9      LOAD_FAST     0 (alist)
                12     GET_ITER
             >> 13     FOR_ITER      16 (to 32)
                16     STORE_FAST    2 (v)
     
    4           19     LOAD_FAST     1 (sum)
                22     LOAD_FAST     2 (v)
                25     BINARY_ADD
                26     STORE_FAST    1 (sum)
                29     JUMP_ABSOLUTE 13
             >> 32     POP_BLOCK
     
    5        >> 33     LOAD_FAST     1 (sum)
                36     RETURN_VALUE
     
    

      

     
    有>>标识的行说明有其他指令会jump到此行。
     
    更详细的描述:
    第2行:
     m [0]:在堆栈上加载值0(co_consts [1])
     m [3]:将值0存入sum(co_varnames [1])
     
    第3行:
     m [6]:通过将循环块的大小压入栈来设置循环
     m [9]:从栈中加载alist(co_varnames [0])的值
     m [12]:通过迭代器替换堆栈上的值(通过弹出和推送)
     m [13]:在堆栈中加载下一个迭代器值,如果StopIteration引起,则跳转到m [32]
               (m [29]中的代码跳回此位置进行循环)
     m [16]:将下一个值存储到v(co_varnames [2])中,将其从堆栈中弹出
     
    第4行:
     m [19]:在栈中加载sum(co_varnames [1])的值
     m [22]:将v(co_varnames [2])的值加载到栈上
     m [25]:将栈顶的两个值进行相加操作后,将结果加载到栈上
     m [26]:栈顶弹出值,存储在sum(co_varnames [1])中
     m [29]:将pc设置为13,因此在m [13]中执行的下一条指令
                 (跳回到前一个位置使循环循环)
     m [32]:弹出m[6]对循环块的设置而压入栈的值
                 (m [13]中的代码在这里跳转到StopIteration,终止循环)
     
    第5行:
     m [33]:将sum(co_varnames [1])的值压入栈,用于返回
     m [36]:从函数返回结果在堆栈顶部
  • 相关阅读:
    mysql高级查询(转的)
    PHP Content-type 的说明
    在textFieldShouldEndEditing 方法中调用[self.tableView reloadData] 失效问题
    关于navigationcontroller 隐藏navigationBar问题
    iOS证书、签名、安装描述文件
    swift 项目搭建
    定义私有cocoapods 源
    Git 服务器搭建
    UITabelView 介绍
    swift aes 加密
  • 原文地址:https://www.cnblogs.com/fancystar/p/6614007.html
Copyright © 2020-2023  润新知