国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

詳解關于Lua源碼分析學習教程

移動開發 iOS
關于Lua源碼分析學習教程是本文要介紹的內容,主要來了解LUA中源碼的使用方法。Lua首先將源程序編譯成為字節碼,然后交由虛擬機解釋執行.對于每一個函數,Lua的編譯器將創建一個原型.

關于Lua源碼分析學習教程是本文要介紹的內容,主要來了解LUA源碼的使用方法。Lua首先將源程序編譯成為字節碼,然后交由虛擬機解釋執行。對于每一個函數,Lua的編譯器將創建一個原型(prototype),它由一組指令及其使用到的常量組成[1]。最初的Lua虛擬機是基于棧的。到1993年,Lua5.0版本,采用了基于寄存器的虛擬機,使得Lua的解釋效率得到提升。

體系結構與指令系統

與虛擬機和指令相關的文件主要有兩個: lopcodes.c 和 lvm.c。從名稱可以看出來,這兩個文件分別用于描述操作碼(指令)和虛擬機。

首先來看指令:

Lua共有38條指令,在下面兩處地方分別描述了這些指令的名稱和模式, 如下:

  1. lopcodes.c:16  
  2. const char *const luaP_opnames[NUM_OPCODES+1] = {  
  3. "MOVE",  
  4. "LOADK",  
  5. "LOADBOOL",  
  6. "LOADNIL",  
  7. "GETUPVAL",  
  8. "GETGLOBAL",  
  9. "GETTABLE",  
  10. "SETGLOBAL",  
  11. "SETUPVAL",  
  12. "SETTABLE",  
  13. "NEWTABLE",  
  14. "SELF",  
  15. "ADD",  
  16. "SUB",  
  17. "MUL",  
  18. "DIV",  
  19. "MOD",  
  20. "POW",  
  21. "UNM",  
  22. "NOT",  
  23. "LEN",  
  24. "CONCAT",  
  25. "JMP",  
  26. "EQ",  
  27. "LT",  
  28. "LE",  
  29. "TEST",  
  30. "TESTSET",  
  31. "CALL",  
  32. "TAILCALL",  
  33. "RETURN",  
  34. "FORLOOP",  
  35. "FORPREP",  
  36. "TFORLOOP",  
  37. "SETLIST",  
  38. "CLOSE",  
  39. "CLOSURE",  
  40. "VARARG",  
  41. NULL  
  42. };  
  43.  
  44. #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))  
  45.  
  46. const lu_byte luaP_opmodes[NUM_OPCODES] = {  
  47. /*       T A    B       C     mode           opcode    */  
  48. opmode(0, 1, OpArgR, OpArgN, iABC)         /* OP_MOVE */  
  49. ,opmode(0, 1, OpArgK, OpArgN, iABx)        /* OP_LOADK */  
  50. ,opmode(0, 1, OpArgU, OpArgU, iABC)        /* OP_LOADBOOL */  
  51. ,opmode(0, 1, OpArgR, OpArgN, iABC)        /* OP_LOADNIL */  
  52. ,opmode(0, 1, OpArgU, OpArgN, iABC)        /* OP_GETUPVAL */  
  53. ,opmode(0, 1, OpArgK, OpArgN, iABx)        /* OP_GETGLOBAL */  
  54. ,opmode(0, 1, OpArgR, OpArgK, iABC)        /* OP_GETTABLE */  
  55. ,opmode(0, 0, OpArgK, OpArgN, iABx)        /* OP_SETGLOBAL */  
  56. ,opmode(0, 0, OpArgU, OpArgN, iABC)        /* OP_SETUPVAL */  
  57. ,opmode(0, 0, OpArgK, OpArgK, iABC)        /* OP_SETTABLE */  
  58. ,opmode(0, 1, OpArgU, OpArgU, iABC)        /* OP_NEWTABLE */  
  59. ,opmode(0, 1, OpArgR, OpArgK, iABC)        /* OP_SELF */  
  60. ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_ADD */  
  61. ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_SUB */  
  62. ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_MUL */  
  63. ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_DIV */  
  64. ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_MOD */  
  65. ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_POW */  
  66. ,opmode(0, 1, OpArgR, OpArgN, iABC)        /* OP_UNM */  
  67. ,opmode(0, 1, OpArgR, OpArgN, iABC)        /* OP_NOT */  
  68. ,opmode(0, 1, OpArgR, OpArgN, iABC)        /* OP_LEN */  
  69. ,opmode(0, 1, OpArgR, OpArgR, iABC)        /* OP_CONCAT */  
  70. ,opmode(0, 0, OpArgR, OpArgN, iAsBx)        /* OP_JMP */  
  71. ,opmode(1, 0, OpArgK, OpArgK, iABC)        /* OP_EQ */  
  72. ,opmode(1, 0, OpArgK, OpArgK, iABC)        /* OP_LT */  
  73. ,opmode(1, 0, OpArgK, OpArgK, iABC)        /* OP_LE */  
  74. ,opmode(1, 1, OpArgR, OpArgU, iABC)        /* OP_TEST */  
  75. ,opmode(1, 1, OpArgR, OpArgU, iABC)        /* OP_TESTSET */  
  76. ,opmode(0, 1, OpArgU, OpArgU, iABC)        /* OP_CALL */  
  77. ,opmode(0, 1, OpArgU, OpArgU, iABC)        /* OP_TAILCALL */  
  78. ,opmode(0, 0, OpArgU, OpArgN, iABC)        /* OP_RETURN */  
  79. ,opmode(0, 1, OpArgR, OpArgN, iAsBx)        /* OP_FORLOOP */  
  80. ,opmode(0, 1, OpArgR, OpArgN, iAsBx)        /* OP_FORPREP */  
  81. ,opmode(1, 0, OpArgN, OpArgU, iABC)        /* OP_TFORLOOP */  
  82. ,opmode(0, 0, OpArgU, OpArgU, iABC)        /* OP_SETLIST */  
  83. ,opmode(0, 0, OpArgN, OpArgN, iABC)        /* OP_CLOSE */  
  84. ,opmode(0, 1, OpArgU, OpArgN, iABx)        /* OP_CLOSURE */  
  85. ,opmode(0, 1, OpArgU, OpArgN, iABC)        /* OP_VARARG */  
  86. }; 

前面一個數組容易理解,表示了每條指令的名稱。后面一個數組表示的是指令的模式。奇怪的符號讓人有些費解。在看模式之前, 首先來看Lua指令的格式,如圖:

詳解關于Lua源碼分析學習教程

如上圖, Lua的指令可以分成三種形式. 即在上面的模式數組中也可以看到的iABC, iABx 和 iAsBx. 對于三種形式的指令來說, 前兩部分都是一樣的, 分別是6位的操作碼和8位A操作數; 區別在于, 后面部是分割成為兩個長度為9位的操作符(B, C),一個無符號的18位操作符Bx還是有符號的18位操作符sBx. 這些定義的代碼如下:

  1. lopcodes.c : 34  
  2. /*  
  3. ** size and position of opcode arguments.  
  4. */  
  5. #define SIZE_C        9  
  6. #define SIZE_B        9  
  7. #define SIZE_Bx        (SIZE_C + SIZE_B)  
  8. #define SIZE_A        8  
  9.  
  10. #define SIZE_OP        6  
  11.  
  12. #define POS_OP        0  
  13. #define POS_A        (POS_OP + SIZE_OP)  
  14. #define POS_C        (POS_A + SIZE_A)  
  15. #define POS_B        (POS_C + SIZE_C)  
  16. #define POS_Bx        POS_C 

再來看指令的操作模式, Lua使用一個字節來表示指令的操作模式. 具體的含義如下:

1、使用最高位來表示是否是一條測試指令. 之所以將這一類型的指令特別地標識出來, 是因為Lua的指令長度是32位,對于分支指令來說, 要想在這32位中既表示兩個操作數來做比較, 同時還要表示一個跳轉的地址, 是很困難的. 因此將這種指令分成兩條, 第一條是測試指令, 緊接著一條無條件跳轉. 如果判斷條件成立則將PC(Program Counter, 指示下一條要執行的指令)加一, 跳過下一條無條件跳轉指令, 繼續執行; 否則跳轉.

2、第二位用于表示A操作數是否被設置

3、接下來的二位用于表示操作數B的格式,OpArgN表示操作數未被使用, OpArgU表示操作數被使用(立即數?), OpArgR表示表示操作數是寄存器或者跳轉的偏移量, OpArgK表示操作數是寄存器或者常量.

最后, 給出Lua虛擬機的體系結構圖(根據源代碼分析得出):

詳解關于Lua源碼分析學習教程

首先, 我們注意到, Lua的解釋器還是一個以棧為中心的結構. 在lua_State這個結構中,有許多個字段用于描述這個結構.stack用于指向絕對棧底, 而base指向了當前正在執行的函數的第一個參數, 而top指向棧頂的第一個空元素.

我們可以看到,這個體系結構中并沒有獨立出來的寄存器. 從以下代碼來看:

  1. lvm.c:343  
  2. #define RA(i)    (base+GETARG_A(i))  
  3. /* to be used after possible stack reallocation */  
  4. #define RB(i)    check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))  
  5. #define RC(i)    check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))  
  6. #define RKB(i)    check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \  
  7.     ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))  
  8. #define RKC(i)    check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \  
  9.     ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))  
  10. #define KBx(i)    check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) 

當指令操作數的類型是寄存器時,它的內容是以base為基址在棧上的索引值.如圖所示.寄存器實際是base之上棧元素的別名;當指令操作數的類型的常數時, 它首先判斷B操作數的最位是否為零.如果是零,則按照和寄存器的處理方法一樣做,如果不是零,則在常數表中找相應的值.

我們知道Lua中函數的執行過程是這樣的. 首先將函數壓棧,然后依次將參數壓棧,形成圖中所示的棧的內容. 因此R[0]到R[n]也分別表示了Arg[1]到Arg[N+1].在第一個參數之下,就是當前正在執行的函數,對于Lua的函數(相對C函數)來說,它是指向類型為 Prototype的TValue, 在Prototype中字段code指向了一個數組用來表示組成這個函數的所有指令,字段k指向一個數組來表示這個函數使用到的所有常量.最后,Lua在解釋執行過程中有專門的變量pc來指向下一條要執行的指令.

指令解釋器

有了前面對指令格式和體系結構的介紹,現在我們可以進入正題, 來看看Lua的指令是如何執行的了.主函數如下:

  1. lvm.c:373  
  2. void luaV_execute (lua_State *L, int nexeccalls) {  
  3. LClosure *cl;  
  4. StkId base;  
  5. TValue *k;  
  6. const Instruction *pc;  
  7. reentry: /* entry point */  
  8. lua_assert(isLua(L->ci));  
  9. pc = L->savedpc;  
  10. cl = &clvalue(L->ci->func)->l;  
  11. base = L->base;  
  12. k = cl->p->k; 

這是最開始的初始化過程.其中, pc被初始化成為了L->savedpc,base被初始化成為了L->base, 即程序從L->savedpc開始執行 (在下一篇專題中,將會介紹到 L->savedpc在函數調用的預處理過程中指向了當前函數的code),而L->base指向棧中當前函數的下一個位置.cl表示當前正在執行閉包(當前可以理解成為函數),k指向當前閉包的常量表.

接下來(注意,為了專注主要邏輯, 我將其中用于Debugger支持,斷言等代碼省略了):

  1. /* main loop of interpreter */  
  2. for (;;) {  
  3.     const Instruction i = *pc++;  
  4.     StkId ra;  
  5.     /* 省略Debugger支持和Coroutine支持*/  
  6.     /* warning!! several calls may realloc the stack and invalidate `ra' */  
  7.     ra = RA(i);  
  8.     /* 省略斷言 */  
  9.     switch (GET_OPCODE(i)) { 

進入到解釋器的主循環,處理很簡單,取得當前指令,pc遞增,初始化ra,然后根據指令的操作碼進行選擇. 接下來的代碼是什么樣的, 估計大家都能想到,一大串的case來指示每條指令的執行.具體的實現可以參考源碼, 在這里不對每一條指令展開, 只是對其中有主要的幾類指令進行說明:

傳值類的指令,與MOVE為代表:

  1. lvm.c:403  
  2.       case OP_MOVE: {  
  3.         setobjs2s(L, ra, RB(i));  
  4.         continue;  
  5.       }  
  6. lopcodes:154  
  7. OP_MOVE,/*    A B    R(A) :R(B)                    */  
  8. lobject.h:161  
  9. #define setobj(L,obj1,obj2) \  
  10. { const TValue *o2=(obj2); TValue *o1=(obj1); \  
  11.     o1->value = o2->value; o1->tt=o2->tt; \  
  12.     checkliveness(G(L),o1); }  
  13.  
  14. /*  
  15. ** different types of sets, according to destination  
  16. */  
  17. /* from stack to (same) stack */  
  18. #define setobjs2s    setobj 

從注釋來看, 這條指令是將操作數A,B都做為寄存器,然后將B的值給A. 而實現也是簡單明了,只使用了一句. 宏展開以后, 可以看到, R[A],R[B]的類型是TValue, 只是將這兩域的值傳過來即可. 對于可回收對象來說,真實值不會保存在棧上,所以只是改了指針,而對于非可回收對象來說,則是直接將值從R[B]賦到R[A].

數值運算類指令,與ADD為代表:

  1. lvm.c:470  
  2.       case OP_ADD: {  
  3.         arith_op(luai_numadd, TM_ADD);  
  4.         continue;  
  5.       }  
  6. lvm.c:360  
  7. #define arith_op(op,tm) { \  
  8.         TValue *rb = RKB(i); \  
  9.         TValue *rc = RKC(i); \  
  10.         if (ttisnumber(rb) && ttisnumber(rc)) { \  
  11.           lua_Number nb = nvalue(rb), nc = nvalue(rc); \  
  12.           setnvalue(ra, op(nb, nc)); \  
  13.         } \  
  14.         else \  
  15.           Protect(Arith(L, ra, rb, rc, tm)); \  
  16.       }  
  17. lopcodes.c:171  
  18. OP_ADD,/*    A B C    R(A) :RK(B) + RK(C)                */ 

如果兩個操作數都是數值的話,關鍵的一行是:

  1. setnvalue(ra,op(nb,nc)); 

即兩個操作數相加以后,把值賦給R[A].值得注意的是,操作數B,C都是RK, 即可能是寄存器也可能是常量,這最決于最B和C的最高位是否為1,如果是1,則是常量,反之則是寄存器.具體可以參考宏ISK的實現.

如果兩個操作數不是數值,即調用了Arith函數,它嘗試將兩個操作轉換成數值進行計算,如果無法轉換,則使用元表機制.該函數的實現如下:

  1. lvm.c:313  
  2. static void Arith (lua_State *L, StkId ra, const TValue *rb,  
  3.                    const TValue *rc, TMS op) {  
  4. TValue tempb, tempc;  
  5. const TValue *b, *c;  
  6. if ((b = luaV_tonumber(rb, &tempb)) != NULL &&  
  7.       (c = luaV_tonumber(rc, &tempc)) != NULL) {  
  8.     lua_Number nb = nvalue(b), nc = nvalue(c);  
  9.     switch (op) {  
  10.       case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;  
  11.       case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;  
  12.       case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;  
  13.       case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break;  
  14.       case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break;  
  15.       case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;  
  16.       case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;  
  17.       default: lua_assert(0); break;  
  18.     }  
  19. }  
  20. else if (!call_binTM(L, rb, rc, ra, op))  
  21.     luaG_aritherror(L, rb, rc);  

在上面call_binTM用于調用到元表中的元方法,因為在Lua以前的版本中元方法也被叫做tag method, 所以函數最后是以TM結尾的.

  1. lvm:163  
  2. static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2,  
  3.                        StkId res, TMS event) {  
  4. const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */  
  5. if (ttisnil(tm))  
  6.     tm = luaT_gettmbyobj(L, p2, event); /* try second operand */  
  7. if (!ttisfunction(tm)) return 0;  
  8. callTMres(L, res, tm, p1, p2);  
  9. return 1;  

在 這個函數中,試著從二個操作數中找到其中一個操作數的元方法(第一個操作數優先), 這里event表示具體哪一個元方法,找到了之后,再使用函數callTMres()去調用相應的元方法. callTMres()的實現很簡單,只是將元方法,第一,第二操作數先后壓棧,再調用并取因返回值.具體如下:

  1. lvm.c:82  
  2. static void callTMres (lua_State *L, StkId res, const TValue *f,  
  3.                         const TValue *p1, const TValue *p2) {  
  4. ptrdiff_t result = savestack(L, res);  
  5. setobj2s(L, L->top, f); /* push function */  
  6. setobj2s(L, L->top+1, p1); /* 1st argument */  
  7. setobj2s(L, L->top+2, p2); /* 2nd argument */  
  8. luaD_checkstack(L, 3);  
  9. L->top += 3;  
  10. luaD_call(L, L->top - 3, 1);  
  11. res = restorestack(L, result);  
  12. L->top--;  
  13. setobjs2s(L, res, L->top);  

邏輯運算類指令,與EQ為代表:

  1. lvm.c:541  
  2.       case OP_EQ: {  
  3.         TValue *rb = RKB(i);  
  4.         TValue *rc = RKC(i);  
  5.         Protect(  
  6.           if (equalobj(L, rb, rc) == GETARG_A(i))  
  7.             dojump(L, pc, GETARG_sBx(*pc));  
  8.         )  
  9.         pc++;  
  10.         continue;  
  11.       }  
  12. lopcodes.c:185  
  13. OP_EQ,/*    A B C    if ((RK(B) == RK(C)) ~= A) then pc++        */ 

在這條指令實現的過程中,equalobj與之前的算術運算類似,讀者可以自行分析.關鍵看它是如果實現中跳轉的,如果RK[B]==RK[C]并且A為1 的情況下(即條件為真),則會使用pc取出下一條指令,調用dojump進行跳轉,否則pc++,掛空緊接著的無條件跳轉指令. dojump的實現如下:

  1. lvm.c:354  
  2. #define dojump(L,pc,i)    {(pc) += (i); luai_threadyield(L);} 

luai_threadyield只是順序地調用lua_unlock和lua_lock,這里為釋放一次鎖,使得別的線程可以得到調度.

函數調用類指令,與CALL為代表:

  1. lvm.c:582  
  2.       case OP_CALL: {  
  3.         int b = GETARG_B(i);  
  4.         int nresults = GETARG_C(i) - 1;  
  5.         if (b != 0) L->top = ra+b; /* else previous instruction set top */  
  6.         L->savedpc = pc;  
  7.         switch (luaD_precall(L, ra, nresults)) {  
  8.           case PCRLUA: {  
  9.             nexeccalls++;  
  10.             goto reentry; /* restart luaV_execute over new Lua function */  
  11.           }  
  12.           case PCRC: {  
  13.             /* it was a C function (`precall' called it); adjust results */  
  14.             if (nresults >= 0) L->top = L->ci->top;  
  15.             base = L->base;  
  16.             continue;  
  17.           }  
  18.           default: {  
  19.             return; /* yield */  
  20.           }  
  21.         }  
  22.       }  
  23. lopcodes.c:192  
  24.  
  25. OP_CALL,/*    A B C    R(A), ... ,R(A+C-2) :R(A)(R(A+1), ... ,R(A+B-1)) */ 

這一條指令將在下一個介紹Lua函數調用規范的專題中詳細介紹. 在這里只是簡單地說明CALL指令的R[A]表示的是即將要調用的函數,而B和C則分別表示參數個數加1,和返回值個數加1. 之所以這里需要加1,其原因是:B和C使用零來表示變長的參數和變長的返回值,而實際參數個數就向后推了一個.

指令的介紹就先到此為止了, 其它的指令的實現也比較類似.仔細閱讀源碼就可很容易地分析出它的意義來. 下一篇將是一個專題, 詳細地介紹Lua中函數的調用是如何實現的.

小結:詳解關于Lua源碼分析學習教程的內容介紹完了,希望通過本文的學習能對你有所幫助!

責任編輯:zhaolei 來源: 互聯網
相關推薦

2011-08-24 15:42:38

LUA源代碼

2011-08-25 16:20:33

Lua腳本變量

2011-08-23 17:06:03

2011-08-23 15:34:56

Lua模式 匹配

2011-08-24 14:14:13

LUA環境 配置

2011-08-24 11:03:33

LUA環境 安裝

2011-08-23 16:37:05

Lua數學庫

2011-08-24 15:34:44

MinGWLua環境配置

2011-09-02 13:51:00

PhoneGap框架HTML5

2011-08-24 17:09:35

LUA閉包函數

2011-08-24 11:08:09

Lua

2011-08-25 10:07:24

Lua 5.0函數編譯器

2011-08-24 13:27:07

Lua 游戲C接口腳本

2011-08-31 10:20:26

MTK驅動開發

2011-08-24 16:59:59

LuaModule

2011-08-23 16:48:41

Lua 5.1API 函數

2011-08-23 13:54:10

LUA全局變量

2011-08-25 17:25:55

LUADelphi

2011-08-25 14:03:32

UbuntuLUA安裝

2011-08-24 14:33:14

LUA開發環境Decoda
點贊
收藏

51CTO技術棧公眾號

在线黄色.com| 91网页版在线登录入口| jizz欧美| 亚洲一二三四区| 欧美日韩综合久久| 久久青草视频| 欧美三级蜜桃2在线观看| 免费看又黄又无码的网站| 奇米影视亚洲| 精品国产一区二区三区久久久| 日韩在线免费播放| 91在线视频观看| 精品乱子伦一区二区三区| а√中文在线天堂精品| 亚洲第一av在线| 一级毛片在线播放| 国产欧美日本一区二区三区| 狼狼综合久久久久综合网| 欧美不卡在线观看| 亚洲成在人线av| 天堂91在线| 久久综合久久综合久久综合| 免费精品视频一区| 欧美日韩在线二区| 欧美大成色www永久网站婷| 蜜桃视频在线观看www社区| 最新中文字幕一区二区三区| 97超碰免费观看| 成人h在线播放| 青青草视频在线观看| 国产香蕉在线| 亚洲精品福利在线观看| 欧洲熟妇精品视频| 亚洲视频香蕉人妖| 精品这里只有精品| 亚洲一区二区视频在线| 日本肉肉一区| 9999在线观看| 高清久久久久久| 国产精品yjizz| 亚洲伦理一区二区| 91精品在线看| 久久精品亚洲| 免费观看黄色的网站| 欧美一区二区| 亚洲91av视频| 色综合久久天天| 国内精品免费在线观看| 成人网18免费网站在线| 亚洲国产cao| 国模私拍国内精品国内av| 久久久极品av| vam成人资源在线观看| 国产精品美女xx| 资源视频在线播放免费| 欧美亚洲在线| 久久日韩精品| 极品裸体白嫩激情啪啪国产精品| 午夜精品在线观看| 国产成人视屏| 欧美国产一区二区三区| 美女久久精品| 亚洲国产人成综合网站| 九九综合在线| 十八禁视频网站在线观看| 久久久不卡网国产精品二区| 色悠悠久久综合网| 亚洲精品亚洲人成人网在线播放| 国产69精品久久久久99| 丁香婷婷深情五月亚洲| 精精国产xxxx视频在线中文版| 一区二区三区日韩欧美精品 | xxxcom在线观看| 精品国产一区av| 亚洲国产婷婷| 视频一区视频二区欧美| 国语对白做受xxxxx在线中国| 国产亚洲精品91在线| 精品网站aaa| 粗大黑人巨茎大战欧美成人| 精品国产一区二区三区四区vr| 2021中文字幕在线| 欧美亚洲大陆| 91精品国产综合久久久久久久久| 久久中文视频| 日本午夜精品一区二区| 九色综合国产一区二区三区| 玩弄中年熟妇正在播放| 国产色产综合色产在线视频 | 日本免费在线一区| 色综合久综合久久综合久鬼88 | 水蜜桃久久夜色精品一区| 国产一区香蕉久久| 亚洲精品在线观看91| 久久国产精品免费一区| 成人免费高清视频在线观看| 日日干夜夜操s8| 欧美亚洲日本一区| 影音先锋男人资源在线| 久久99精品久久久久久青青91| 国产美女视频一区| 尤物99国产成人精品视频| 日本在线中文字幕一区| 成人一区二区电影| 久久国产欧美| 国产视频一视频二| 亚洲在线视频一区| a免费在线观看| 九九热精品视频| 欧美 日韩 国产一区二区在线视频 | 日韩欧美中文字幕公布| 自拍视频在线网| 一区二区三区视频观看| 日韩三级av| 青青草国产精品| 久久久精品免费免费| 欧洲天堂在线观看| 亚洲性无码av在线| 日韩高清三区| www国产无套内射com| 亚洲综合色视频| 国产免费拔擦拔擦8x高清在线人| 国产精品国产亚洲伊人久久 | 国产911在线观看| 久久综合色之久久综合| 在线手机福利影院| 国产亚洲福利一区| 欧美日本亚洲韩国国产| 邪恶网站在线观看| 精品国产3级a| 欧美一区不卡| 日韩在线第三页| 日韩精品在线看| 91亚洲成人| 国产精品黄页网站在线播放免费 | 中文字幕精品影院| 91香蕉在线观看| 在线日本中文字幕| 欧美一级精品在线| 日韩精品免费一区二区三区竹菊| 日韩精品久久久免费观看| 久久精品国产99精品国产亚洲性色| 水蜜桃久久夜色精品一区| 国产肉体ⅹxxx137大胆| www国产精品| 99久久亚洲国产日韩美女| 久久久这里只有精品视频| 成人免费a**址| 亚洲精品久久久中文字幕| 亚洲高清久久久久久| 国产日韩综合| 国产精品一久久香蕉国产线看观看| 国产日韩欧美视频在线| 在线看片成人| 国产精品乱码一区二区三区| 一区二区三区在线不卡| 欧美成a人片免费观看久久五月天| 国产精品午夜一区二区欲梦| 久久久精品黄色| 日韩电影精品| 中文字幕一区二区三区四区五区六区 | 91福利视频在线| 国产精品成人自拍| 五月天色婷婷综合| 欧美美女直播网站| 91精品一区二区三区久久久久久| 撸视在线观看免费视频| 国产日韩欧美在线| 亚洲欧美区自拍先锋| 国产精品777| 成人欧美一区二区| 久久久久久com| 久久精品2019中文字幕| 一本色道久久综合精品竹菊| 97精品久久久久中文字幕| 美女尤物久久精品| 成人另类视频| 国产91沈先生在线播放| 亚洲天堂免费观看| 羞羞的视频在线观看| 99欧美精品| 国产精品天堂| 少妇**av毛片在线看| 亚洲一区三区视频在线观看| 亚洲一区二区av电影| 天天揉久久久久亚洲精品| 一本色道久久加勒比88综合| 性欧美xxxx视频在线观看| 亚洲精品欧美在线| 欧美私模裸体表演在线观看| 1区2区3区在线| 亚洲国产精品久久久久久女王| 欧美日韩国产中文| 麻豆精品国产91久久久久久| 免费在线看污片| 国产 日韩 亚洲 欧美| 欧美久久久久久久久久| 无吗不卡中文字幕| 日韩欧美资源站| 亚洲午夜国产成人av电影男同|