• lua源码学习篇四:字节码指令


    在llimits.h文件中定义了指令的类型。其实就是32个字节。

    typedef lu_int32 Instruction;
    

    上节说到变量最终会存入proto的数组k中,返回的索引放在expdesc *var->u.s.info。那么这个索引就是用来生成中间码的指令。如下。

    int e = luaK_exp2anyreg(fs, ex);//返回寄存器索引
    luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);//生成指令

    首先讲一下lua指令的构造,如图。简单来说就是把32位字节分割一下,低位的6个字节表示的是哪一种操作指令, 即opcode; 后面的分为2个参数和三个参数的情况。参数代表的计算在寄存器中的索引,寄存器可以想象成一个数组。

    例如,如果指令的三段分别代表,“add  0   1”.表示的意思是对两个数求和,两个数分别在寄存器中,索引为0 和 1 的地方。

    lopcodes.h定义了相关方法。其实就是些二进制的操作,可以获取指定范围内的比特值。不熟悉的同学可以先学习C语言的二进制运算。

    #define GET_OPCODE(i)    (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
    #define SET_OPCODE(i,o)    ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
            ((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))

    lopcodes.c中定义了相关参数的比特长度:

    enum OpMode {iABC, iABx, iAsBx};  /* basic instruction format */
    /*
    ** size and position of opcode arguments.
    */
    #define SIZE_C        9
    #define SIZE_B        9
    #define SIZE_Bx        (SIZE_C + SIZE_B)
    #define SIZE_A        8
    #define SIZE_OP        6
    #define POS_OP        0
    #define POS_A        (POS_OP + SIZE_OP)
    #define POS_C        (POS_A + SIZE_A)
    #define POS_B        (POS_C + SIZE_C)
    #define POS_Bx        POS_C

    生成指令时,主要依据以下的格式:

    #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
    
    const lu_byte luaP_opmodes[NUM_OPCODES] = {
    /*       T  A    B       C     mode           opcode    */
      opmode(0, 1, OpArgR, OpArgN, iABC)         /* OP_MOVE */
     ,opmode(0, 1, OpArgK, OpArgN, iABx)        /* OP_LOADK */
     ,opmode(0, 1, OpArgU, OpArgU, iABC)        /* OP_LOADBOOL */
     ,opmode(0, 1, OpArgR, OpArgN, iABC)        /* OP_LOADNIL */
     ,opmode(0, 1, OpArgU, OpArgN, iABC)        /* OP_GETUPVAL */
     ,opmode(0, 1, OpArgK, OpArgN, iABx)        /* OP_GETGLOBAL */
     ,opmode(0, 1, OpArgR, OpArgK, iABC)        /* OP_GETTABLE */
     ,opmode(0, 0, OpArgK, OpArgN, iABx)        /* OP_SETGLOBAL */
    ......
    }

    #define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3))
    #define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
    #define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))
    #define testAMode(m) (luaP_opmodes[m] & (1 << 6))
    #define testTMode(m) (luaP_opmodes[m] & (1 << 7))

     

    生成指令后,那么寄存器的地址和函数类型proto是如何对应的呢,如下图

    至此,生成中间码指令的过程就分析完了。下一步重点关注lua本身的数据结构。

    done。

  • 相关阅读:
    html5shiv.js-让IE浏览器支持HTML5标准
    CSS2系列:外边距合并问题(margincollapse)
    HTML5:离线存储(缓存机制)-IndexDB
    CSS3系列:流式(弹性)布局(flex布局)
    Sublime Text 3 常用插件以及安装方法(转)
    后台配置参数写在文件上
    20160414
    2016413
    20160412
    网页设计素材网站
  • 原文地址:https://www.cnblogs.com/nazhizq/p/6525263.html
Copyright © 2020-2023  润新知