Lua1.1 虛擬機指令分析(二)

(接上篇)
> EQOP
c++

   case EQOP:
   {
    Object *l = top-2;
    Object *r = top-1;
    --top;
    if (tag(l) != tag(r))
     tag(top-1) = T_NIL;
    else
    {
     switch (tag(l))
     {
      case T_NIL: tag(top-1) = T_NUMBER; break;
      case T_NUMBER: tag(top-1) = (nvalue(l) == nvalue(r)) ? T_NUMBER : T_NIL; break;
      case T_ARRAY: tag(top-1) = (avalue(l) == avalue(r)) ? T_NUMBER : T_NIL; break;
      case T_FUNCTION: tag(top-1) = (bvalue(l) == bvalue(r)) ? T_NUMBER : T_NIL; break;
      case T_CFUNCTION: tag(top-1) = (fvalue(l) == fvalue(r)) ? T_NUMBER : T_NIL; break;
      case T_USERDATA: tag(top-1) = (uvalue(l) == uvalue(r)) ? T_NUMBER : T_NIL; break;
      case T_STRING: tag(top-1) = (strcmp (svalue(l), svalue(r)) == 0) ? T_NUMBER : T_NIL; break;
      case T_MARK: return 1;
     }
    }
    nvalue(top-1) = 1;
   }
   break;

  判斷棧頂的兩個 Object 是否相等。
  先判斷是不是相同類型,若是不是,則不等。
  不然,判斷值是否相等。數值和字符串類型是判斷是否值相等,而數組、函數這種則是判斷其指針是否相等。
  若是相等,把棧頂 Object 設置爲 T_NUMBER 類型,值設置爲 1。
  若是不等,設置棧頂 Object 爲 T_NIL(空類型足以識別它本身,此時能夠認爲設置什麼值都無心義)。

> LTOP
express

   case LTOP:
   {
    Object *l = top-2;
    Object *r = top-1;
    --top;
    if (tag(l) == T_NUMBER && tag(r) == T_NUMBER)
     tag(top-1) = (nvalue(l) < nvalue(r)) ? T_NUMBER : T_NIL;
    else
    {
     if (tostring(l) || tostring(r))
      return 1;
     tag(top-1) = (strcmp (svalue(l), svalue(r)) < 0) ? T_NUMBER : T_NIL;
    }
    nvalue(top-1) = 1;
   }
   break;

  判斷 top-2 是否小於 top-1。只在兩個 Object 均爲數值型,或者可轉化爲字符串型時有意義。
  若是判斷結果爲真,設置棧頂元素類型爲 T_NUMBER,值爲 1。
  若是判斷結果爲假,設置棧頂元素類型爲 T_NIL。

> LEOP
數組

   case LEOP:
   {
    Object *l = top-2;
    Object *r = top-1;
    --top;
    if (tag(l) == T_NUMBER && tag(r) == T_NUMBER)
     tag(top-1) = (nvalue(l) <= nvalue(r)) ? T_NUMBER : T_NIL;
    else
    {
     if (tostring(l) || tostring(r))
      return 1;
     tag(top-1) = (strcmp (svalue(l), svalue(r)) <= 0) ? T_NUMBER : T_NIL;
    }
    nvalue(top-1) = 1;
   }
   break;

  判斷 top-2 是否小於等於 top-1。只在兩個 Object 均爲數值型,或者可轉化爲字符串型時有意義。
  若是判斷結果爲真,設置棧頂元素類型爲 T_NUMBER,值爲 1。
  若是判斷結果爲假,設置棧頂元素類型爲 T_NIL。

> ADDOP
函數

   case ADDOP:
   {
    Object *l = top-2;
    Object *r = top-1;
    if (tonumber(r) || tonumber(l))
     return 1;
    nvalue(l) += nvalue(r);
    --top;
   }
   break;

  棧頂兩元素 top-2 和 top-1 相加,top-1 出棧,結果保存在新的棧頂。
  只在兩個 Object 都可轉化爲數值型時該運算有效。

> SUBOP,
lua

   case SUBOP:
   {
    Object *l = top-2;
    Object *r = top-1;
    if (tonumber(r) || tonumber(l))
     return 1;
    nvalue(l) -= nvalue(r);
    --top;
   }
   break;

  棧頂兩元素 top-2 和 top-1 相減,top-1 出棧,結果保存在新的棧頂。
  只在兩個 Object 都可轉化爲數值型時該運算有效。

> MULTOP,
debug

   case MULTOP:
   {
    Object *l = top-2;
    Object *r = top-1;
    if (tonumber(r) || tonumber(l))
     return 1;
    nvalue(l) *= nvalue(r);
    --top;
   }
   break;

  棧頂兩元素 top-2 和 top-1 相乘,top-1 出棧,結果保存在新的棧頂。
  只在兩個 Object 都可轉化爲數值型時該運算有效。

> DIVOP,
指針

   case DIVOP:
   {
    Object *l = top-2;
    Object *r = top-1;
    if (tonumber(r) || tonumber(l))
     return 1;
    nvalue(l) /= nvalue(r);
    --top;
   }
   break;

  棧頂兩元素 top-2 和 top-1 相除,top-1 出棧,結果保存在新的棧頂。
  只在兩個 Object 都可轉化爲數值型時該運算有效。

> CONCOP,
code

   case CONCOP:
   {
    Object *l = top-2;
    Object *r = top-1;
    if (tostring(r) || tostring(l))
     return 1;
    svalue(l) = lua_createstring (lua_strconc(svalue(l),svalue(r)));
    if (svalue(l) == NULL)
     return 1;
    --top;
   }
   break;

  棧頂兩元素 top-2 和 top-1 字符串鏈接,top-1 出棧,結果保存在新的棧頂。
  只在兩個 Object 都可轉化爲字符串型時該運算有效。
  鏈接結果是新生成的字符串,原來的兩個字符串保持不變。

> MINUSOP
字符串

   case MINUSOP:
    if (tonumber(top-1))
     return 1;
    nvalue(top-1) = - nvalue(top-1);
   break;

  棧頂元素數值取反,只在其可轉化爲數值型時有效。

> NOTOP
get

   case NOTOP:
    tag(top-1) = tag(top-1) == T_NIL ? T_NUMBER : T_NIL;
   break;

  棧頂元素邏輯取反。
  當棧頂元素爲假(T_NIL)時設置其爲真(T_NUMBER)。
  當棧頂元素爲真(非 T_NIL 型)時設置其爲假(T_NIL)。

> ONTJMP

   case ONTJMP:
   {
    CodeWord code;
    get_word(code,pc);
    if (tag(top-1) != T_NIL) pc += code.w;
   }
   break;

  真跳轉,若是判斷棧頂元素爲真則跳轉,指令偏移量從字節碼中取得。

> ONFJMP

   case ONFJMP:
   {
    CodeWord code;
    get_word(code,pc);
    if (tag(top-1) == T_NIL) pc += code.w;
   }
   break;

  假跳轉,若是判斷棧頂元素爲假則跳轉,指令偏移量從字節碼中取得。

> JMP

   case JMP:
   {
    CodeWord code;
    get_word(code,pc);
    pc += code.w;
   }
   break;

  無條件跳轉,指令偏移量從字節碼中取得。

> UPJMP

   case UPJMP:
   {
    CodeWord code;
    get_word(code,pc);
    pc -= code.w;
   }
   break;

  向上無條件跳轉,指令偏移量從字節碼中取得。


> IFFJMP

   case IFFJMP:
   {
    CodeWord code;
    get_word(code,pc);
    top--;
    if (tag(top) == T_NIL) pc += code.w;
   }
   break;

  假跳轉,若是判斷棧頂元素爲假則跳轉,指令偏移量從字節碼中取得。
  判斷條件出棧。

> IFFUPJMP

   case IFFUPJMP:
   {
    CodeWord code;
    get_word(code,pc);
    top--;
    if (tag(top) == T_NIL) pc -= code.w;
   }
   break;

  假跳轉,若是判斷棧頂元素爲假則向上跳轉,指令偏移量從字節碼中取得。
  判斷條件出棧。

> POP

   case POP: --top; break;

  出棧。

> CALLFUNC

   case CALLFUNC:
   {
    Byte *newpc;
    Object *b = top-1;
    while (tag(b) != T_MARK) b--;
    if (tag(b-1) == T_FUNCTION)
    {
     lua_debugline = 0;     /* always reset debug flag */
     newpc = bvalue(b-1);
     bvalue(b-1) = pc;     /* store return code */
     nvalue(b) = (base-stack);     /* store base value */
     base = b+1;
     pc = newpc;
     if (MAXSTACK-(base-stack) < STACKGAP)
     {
      lua_error ("stack overflow");
      return 1;
     }
    }
    else if (tag(b-1) == T_CFUNCTION)
    {
     int nparam;
     lua_debugline = 0;     /* always reset debug flag */
     nvalue(b) = (base-stack);     /* store base value */
     base = b+1;
     nparam = top-base;     /* number of parameters */
     (fvalue(b-1))();     /* call C function */
     
     /* shift returned values */
     {
      int i;
      int nretval = top - base - nparam;
      top = base - 2;
      base = stack + (int) nvalue(base-1);
      for (i=0; i<nretval; i++)
      {
       *top = *(top+nparam+2);
       ++top;
      }
     }
    }
    else
    {
     lua_reportbug ("call expression not a function");
     return 1;
    }
   }
   break;

  函數調用,從棧頂到棧中類型爲 T_MARK 的 Object 均爲函數參數。
  類型爲 T_MARK 的 Object 的下一個 Object 爲函數名。
  函數調用有兩種:
  一種爲 Lua 腳本中定義的函數的調用,相應的 Object 類型爲 T_FUNCTION。
  另外一種爲 Lua 腳本中調用 C 寫的函數,相應的 Object 類型爲 T_CFUNCTION。
  T_FUNCTION 調用前保存當前執行字節碼 pc 和棧的 base 以作調用結束後的恢復,設置 pc 爲調用函數的字節碼地址便可。
  T_CFUNCTION 調用前保存棧的 base 以作調用結束後的恢復,取得函數參數個數。
  函數調用結束後,調整返回值的位置,恢復 top 和 base 的值。把返回值調整得和 Lua 函數返回的同樣。
  也就是原來函數 Object 和 T_MARK 的地方被返回值替掉。
  能夠看出來,這裏的函數調用和彙編或者 C 語言裏的函數調用的棧楨是長得很像的(除了沒有寄存器)。

> RETCODE

   case RETCODE:
   {
    int i;
    int shift = *pc++;
    int nretval = top - base - shift;
    top = base - 2;
    pc = bvalue(base-2);
    base = stack + (int) nvalue(base-1);
    for (i=0; i<nretval; i++)
    {
     *top = *(top+shift+2);
     ++top;
    }
   }
   break;

  拷貝返回值到函數調用前的位置,就是棧裏 T_MARK 前面的那個函數類型的 Object 處。
  當前的字節碼保存的偏移量,經過計算 top, base, shift 之差獲得返回值個數。 shift 是指函數有幾個參數。
  重置 top, pc, base。
  把函數的返回值拷貝到棧上原來的函數 Object 處。

> HALT

   case HALT:
    base = oldbase;
   return 0;     /* success */

  正常中止,重置棧。

> SETFUNCTION

   case SETFUNCTION:
   {
    CodeWord file, func;
    get_word(file,pc);
    get_word(func,pc);
    if (lua_pushfunction (file.w, func.w))
     return 1;
   }
   break;

  設置函數,函數的文件名和函數地址從字節碼裏取得。

> SETLINE

   case SETLINE:
   {
    CodeWord code;
    get_word(code,pc);
    lua_debugline = code.w;
   }
   break;

  設置 debug 行號。

> RESET

   case RESET:
    lua_popfunction ();
   break;

  彈出函數

相關文章
相關標籤/搜索