精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

PHP內核分析:Zend虛擬機

開發 后端
PHP 是一門解釋型的語言。諸如 Java、Python、Ruby、Javascript 等解釋型語言,我們編寫的代碼不會被編譯成機器碼運行,而是會被編譯中間碼運行在虛擬機(VM)上。運行 PHP 的虛擬機,稱之為 Zend 虛擬機,今天我們將深入內核,探究 Zend 虛擬機運行的原理。

PHP 是一門解釋型的語言。諸如 Java、Python、Ruby、Javascript 等解釋型語言,我們編寫的代碼不會被編譯成機器碼運行,而是會被編譯中間碼運行在虛擬機(VM)上。運行 PHP 的虛擬機,稱之為 Zend 虛擬機,今天我們將深入內核,探究 Zend 虛擬機運行的原理。

OPCODE

什么是 OPCODE?它是一種虛擬機能夠識別并處理的指令。Zend 虛擬機包含了一系列的 OPCODE,通過 OPCODE 虛擬機能夠做很多事情,列舉幾個 OPCODE 的例子:

  • ZEND_ADD 將兩個操作數相加。
  • ZEND_NEW 創建一個 PHP 對象。
  • ZEND_ECHO 將內容輸出到標準輸出中。
  • ZEND_EXIT 退出 PHP。

諸如此類的操作,PHP 定義了186個(隨著 PHP 的更新,肯定會支持更多種類的 OPCODE),所有的 OPCODE 的定義和實現都可以在源碼的 zend/zend_vm_def.h 文件(這個文件的內容并不是原生的 C 代碼,而是一個模板,后面會說明原因)中查閱到。

我們來看下 PHP 是如何設計 OPCODE 數據結構:

struct _zend_op {
	const void *handler;
	znode_op op1;
	znode_op op2;
	znode_op result;
	uint32_t extended_value;
	uint32_t lineno;
	zend_uchar opcode;
	zend_uchar op1_type;
	zend_uchar op2_type;
	zend_uchar result_type;
};

仔細觀察 OPCODE 的數據結構,是不是能找到匯編語言的感覺。每一個 OPCODE 都包含兩個操作數,op1和 op2handler 指針則指向了執行該 OPCODE 操作的函數,函數處理后的結果,會被保存在 result 中。

我們舉一個簡單的例子:

<?php
$b = 1;
$a = $b + 2;

我們通過 vld 擴展看到,經過編譯的后,上面的代碼生成了 ZEND_ADD 指令的 OPCODE。

compiled vars:  !0 = $b, !1 = $a
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   ASSIGN                                                   !0, 1
   3     1        ADD                                              ~3      !0, 2
         2        ASSIGN                                                   !1, ~3
   8     3      > RETURN                                                   1

其中,第二行是 ZEND_ADD 指令的 OPCODE。我們看到,它接收2個操作數,op1 是變量 $bop2 是數字常量1,返回的結果存入了臨時變量中。在 zend/zend_vm_def.h 文件中,我們可以找到 ZEND_ADD 指令對應的函數實現:

ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
{
	USE_OPLINE
	zend_free_op free_op1, free_op2;
	zval *op1, *op2, *result;

	op1 = GE***_ZVAL_PTR_UNDEF(BP_VAR_R);
	op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
	if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) {
		if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
			result = EX_VAR(opline->result.var);
			fast_long_add_function(result, op1, op2);
			ZEND_VM_NEXT_OPCODE();
		} else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
			result = EX_VAR(opline->result.var);
			ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
			ZEND_VM_NEXT_OPCODE();
		}
	} else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) {

	...
}

上面的代碼并不是原生的 C 代碼,而是一種模板。

為什么這樣做?因為 PHP 是弱類型語言,而其實現的 C 則是強類型語言。弱類型語言支持自動類型匹配,而自動類型匹配的實現方式,就像上述代碼一樣,通過判斷來處理不同類型的參數。試想一下,如果每一個 OPCODE 處理的時候都需要判斷傳入的參數類型,那么性能勢必成為極大的問題(一次請求需要處理的 OPCODE 可能能達到成千上萬個)。

哪有什么辦法嗎?我們發現在編譯的時候,已經能夠確定每個操作數的類型(可能是常量還是變量)。所以,PHP 真正執行時的 C 代碼,不同類型操作數將分成不同的函數,供虛擬機直接調用。這部分代碼放在了 zend/zend_vm_execute.h 中,展開后的文件相當大,而且我們注意到還有這樣的代碼:

if (IS_CONST == IS_CV) {

完全沒有什么意義是吧?不過沒有關系,C 的編譯器會自動優化這樣判斷。大多數情況,我們希望了解某個 OPCODE 處理的邏輯,還是通過閱讀模板文件 zend/zend_vm_def.h 比較容易。順便說一下,根據模板生成 C 代碼的程序就是用 PHP 實現的。

執行過程

準確的來說,PHP 的執行分成了兩大部分:編譯和執行。這里我將不會詳細展開編譯的部分,而是把焦點放在執行的過程。

通過語法、詞法分析等一系列的編譯過程后,我們得到了一個名為 OPArray 的數據,其結構如下:

struct _zend_op_array {
	/* Common elements */
	zend_uchar type;
	zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
	uint32_t fn_flags;
	zend_string *function_name;
	zend_class_entry *scope;
	zend_function *prototype;
	uint32_t num_args;
	uint32_t required_num_args;
	zend_arg_info *arg_info;
	/* END of common elements */

	uint32_t *refcount;

	uint32_t last;
	zend_op *opcodes;

	int last_var;
	uint32_t T;
	zend_string **vars;

	int last_live_range;
	int last_try_catch;
	zend_live_range *live_range;
	zend_try_catch_element *try_catch_array;

	/* static variables support */
	HashTable *static_variables;

	zend_string *filename;
	uint32_t line_start;
	uint32_t line_end;
	zend_string *doc_comment;
	uint32_t early_binding; /* the linked list of delayed declarations */

	int last_literal;
	zval *literals;

	int  cache_size;
	void **run_time_cache;

	void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};

內容超多對吧?簡單的理解,其本質就是一個 OPCODE 數組外加執行過程中所需要的環境數據的集合。介紹幾個相對來說比較重要的字段:

  • opcodes 存放 OPCODE 的數組。
  • filename 當前執行的腳本的文件名。
  • function_name 當前執行的方法名稱。
  • static_variables 靜態變量列表。
  • last_try_catch try_catch_array 當前上下文中,如果出現異常 try-catch-finally 跳轉所需的信息。
  • literals 所有諸如字符串 foo 或者數字23,這樣的常量字面量集合。

為什么需要生成這樣龐大的數據?因為編譯時期生成的信息越多,執行時期所需要的時間就越少。

接下來,我們看下 PHP 是如何執行 OPCODE。OPCODE 的執行被放在一個大循環中,這個循環位于 zend/zend_vm_execute.h 中的 execute_ex 函數:

ZEND_API void execute_ex(zend_execute_data *ex) {
	DCL_OPLINE

	zend_execute_data *execute_data = ex;

	LOAD_OPLINE();
	ZEND_VM_LOOP_INTERRUPT_CHECK();

	while (1) {
		if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0)) {
			if (EXPECTED(ret > 0)) {
				execute_data = EG(current_execute_data);
				ZEND_VM_LOOP_INTERRUPT_CHECK();
			} else {
				return;
			}
		}
	}

	zend_error_noreturn(E_CORE_ERROR, "Arrived at end of main loop which shouldn't happen");
}

這里,我去掉了一些環境變量判斷分支,保留了運行的主流程。可以看到,在一個***循環中,虛擬機會不斷調用 OPCODE 指定的 handler 函數處理指令集,直到某次指令處理的結果 ret 小于0。注意到,在主流程中并沒有移動 OPCODE 數組的當前指針,而是把這個過程放到指令執行的具體函數的結尾。所以,我們在大多數 OPCODE 的實現函數的末尾,都能看到調用這個宏:

ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();

在之前那個簡單例子中,我們看到 vld 打印出的執行 OPCODE 數組中,***有一項指令為 ZEND_RETURN 的 OPCODE。但我們編寫的 PHP 代碼中并沒有這樣的語句。在編譯時期,虛擬機會自動將這個指令加到 OPCODE 數組的結尾。ZEND_RETURN 指令對應的函數會返回 -1,判斷執行的結果小于0時,就會退出循環,從而結束程序的運行。

方法調用

如果我們調用一個自定義的函數,虛擬機會如何處理呢?

<?php
function foo() {
    echo 'test';
}

foo();

我們通過 vld 查看生成的 OPCODE。出現了兩個 OPCODE 指令執行棧,是因為我們自定義了一個 PHP 函數。在***個執行棧上,調用自定義函數會執行兩個 OPCODE 指令:INIT_FCALL 和 DO_FCALL

compiled vars:  none
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   NOP
   6     1        INIT_FCALL                                               'foo'
         2        DO_FCALL                                      0
         3      > RETURN                                                   1

compiled vars:  none
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   3     0  E >   ECHO                                                     'test'
   4     1      > RETURN                                                   null

其中,INIT_FCALL 準備了執行函數時所需要的上下文數據。DO_FCALL 負責執行函數。DO_FCALL 的處理函數根據不同的調用情況處理了大量邏輯,我摘取了其中執行用戶定義的函數的邏輯部分:

ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
{
    USE_OPLINE
    zend_execute_data *call = EX(call);
    zend_function *fbc = call->func;
    zend_object *object;
    zval *ret;

    ...

    if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
        ret = NULL;
        if (RETURN_VALUE_USED(opline)) {
            ret = EX_VAR(opline->result.var);
            ZVAL_NULL(ret);
        }

        call->prev_execute_data = execute_data;
        i_init_func_execute_data(call, &fbc->op_array, ret);

        if (EXPECTED(zend_execute_ex == execute_ex)) {
            ZEND_VM_ENTER();
        } else {
            ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
            zend_execute_ex(call);
        }
    }

    ...

    ZEND_VM_SET_OPCODE(opline + 1);
    ZEND_VM_CONTINUE();
}

可以看到,DO_FCALL 首先將調用函數前的上下文數據保存到 call->prev_execute_data,然后調用 i_init_func_execute_data 函數,將自定義函數對象中的 op_array(每個自定義函數會在編譯的時候生成對應的數據,其數據結構中包含了函數的 OPCODE 數組) 賦值給新的執行上下文對象。

然后,調用 zend_execute_ex 函數,開始執行自定義的函數。zend_execute_ex 實際上就是前面提到的 execute_ex 函數(默認是這樣,但擴展可能重寫 zend_execute_ex 指針,這個 API 讓 PHP 擴展開發者可以通過覆寫函數達到擴展功能的目的,不是本篇的主題,不準備深入探討),只是上下文數據被替換成當前函數所在的上下文數據。

我們可以這樣理解,最外層的代碼就是一個默認存在的函數(類似 C 語言中的 main()函數),和用戶自定義的函數本質上是沒有區別的。

邏輯跳轉

我們知道指令都是順序執行的,而我們的程序,一般都包含不少的邏輯判斷和循環,這部分又是如何通過 OPCODE 實現的呢?

<?php
$a = 10;
if ($a == 10) {
    echo 'success';
} else {
    echo 'failure';
}

我們還是通過 vld 查看 OPCODE(不得不說 vld 擴展是分析 PHP 的神器)。

compiled vars:  !0 = $a
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   ASSIGN                                                   !0, 10
   3     1        IS_EQUAL                                         ~2      !0, 10
         2      > JMPZ                                                     ~2, ->5
   4     3    >   ECHO                                                     'success'
         4      > JMP                                                      ->6
   6     5    >   ECHO                                                     'failure'
   7     6    > > RETURN                                                   1

我們看到,JMPZ 和 JMP 控制了執行流程。JMP 的邏輯非常簡單,將當前的 OPCODE 指針指向需要跳轉的 OPCODE。

ZEND_VM_HANDLER(42, ZEND_JMP, JMP_ADDR, ANY)
{
	USE_OPLINE  	ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op1));
	ZEND_VM_CONTINUE();
}

JMPZ 僅僅是多了一次判斷,根據結果選擇是否跳轉,這里就不再重復列舉了。而處理循環的方式與判斷基本上是類似的。

<?php
$a = [1, 2, 3];
foreach ($a as $n) {
    echo $n;
}
compiled vars:  !0 = $a, !1 = $n
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   ASSIGN                                                   !0, <array>
   3     1      > FE_RESET_R                                       $3      !0, ->5
         2    > > FE_FETCH_R                                               $3, !1, ->5
   4     3    >   ECHO                                                     !1
         4      > JMP                                                      ->2
         5    >   FE_FREE                                                  $3
   5     6      > RETURN                                                   1

循環只需要 JMP 指令即可完成,通過 FE_FETCH_R 指令判斷是否已經到達數組的結尾,如果到達則退出循環。

結語

通過了解 Zend 虛擬機,相信你對 PHP 是如何運行的,會有更深刻的理解。想到我們寫的一行行代碼,***機器執行的時候會變成數不勝數的指令,每個指令又建立在復雜的處理邏輯之上。那些從前隨意寫下的代碼,現在會不會在腦海里不自覺的轉換成 OPCODE 再品味一番呢?

責任編輯:張燕妮 來源: Joshua Nie
相關推薦

2009-12-24 15:09:16

Linux內核版本

2009-06-12 16:15:42

死鎖Java虛擬機

2012-05-18 10:22:23

2012-08-16 09:07:57

Erlang

2010-07-26 09:02:38

2013-07-17 09:32:58

2009-11-24 09:15:54

Linux內核虛擬機KVM架構

2017-09-14 10:11:24

OpenStack虛擬機過程分析

2021-01-26 09:30:32

加密虛擬機攻擊

2009-08-18 21:57:59

2012-06-14 10:17:12

虛擬機

2014-02-21 11:20:34

KVMXen虛擬機

2020-01-17 10:52:37

無服務器容器技術

2012-04-10 10:29:29

2023-09-03 17:05:20

虛擬機

2015-05-15 10:36:13

2010-12-23 14:05:12

虛擬機

2022-09-05 21:46:36

VirtualBox虛擬機開源

2009-12-09 13:41:50

PHP Zend框架

2010-02-04 10:10:34

Dalvik虛擬機
點贊
收藏

51CTO技術棧公眾號

啊v视频在线一区二区三区| 色播五月激情综合网| 97超碰最新| 国产精品久久久免费视频| 综合色就爱涩涩涩综合婷婷| 欧美色偷偷大香| 国产又粗又长又爽视频| 五月天激情开心网| 麻豆精品在线观看| 97精品视频在线观看| 亚洲ⅴ国产v天堂a无码二区| 中文无码日韩欧| 色偷偷一区二区三区| 日本黄色播放器| 天天干天天爽天天操| 蜜臂av日日欢夜夜爽一区| 久久免费精品视频| 国产欧美小视频| 偷拍自拍亚洲色图| 日韩欧美一卡二卡| 我看黄色一级片| a级片免费在线观看| 中文字幕日本不卡| 欧美一区二区三区四区五区六区| www.好吊色| 久久国产日韩欧美精品| 日韩av片电影专区| 国产精品.www| 欧美一区高清| 最新69国产成人精品视频免费| 色婷婷免费视频| 久久的色偷偷| 欧美日韩国产高清一区二区三区| 成人在线看视频| 91在线超碰| 亚洲综合免费观看高清完整版在线 | 精品久久一二三区| 亚洲视频一二三四| 久久久成人av毛片免费观看| 精品国产成人av| 人人妻人人澡人人爽欧美一区双 | 国内精品久久久久| 日本在线一级片| 日韩欧美一区二区三区免费看| 亚洲精品视频免费在线观看| 污污内射在线观看一区二区少妇| 日韩中文字幕一区二区高清99| 欧美日本韩国一区二区三区视频| 污污视频网站免费观看| 在线观看欧美日韩电影| 欧美日韩免费网站| 日韩免费视频播放| 草草在线观看| 精品久久久中文| 午夜精品久久久久久久无码| 麻豆免费在线| 精品久久久久久国产91| 欧美色图另类小说| 中文字幕乱码中文乱码51精品| 欧美日韩午夜剧场| 农村妇女精品一二区| 亚洲国产成人二区| 欧美丝袜丝交足nylons| 日本高清久久久| japansex久久高清精品| 欧美一级黄色录像| 一级全黄裸体片| 久久精品福利| 亚洲社区在线观看| 午夜激情福利电影| 亚洲一级淫片| 国语自产精品视频在线看一大j8| wwwxxx亚洲| 水野朝阳av一区二区三区| 国产精品无码专区在线观看| 国产强伦人妻毛片| 成人天堂资源www在线| 久久精品一区二区三区不卡免费视频 | 欧美成人a交片免费看| 在线观看日韩av先锋影音电影院| 国产色视频在线播放| 欧美专区视频| 亚洲精品中文字幕av| 超碰97av在线| 亚洲网站在线| 国产成人在线播放| 国产日本精品视频| 99精品欧美一区二区三区综合在线| 欧美日韩精品免费观看视一区二区| 国产资源在线播放| 亚洲女与黑人做爰| 欧美日韩在线中文| 婷婷激情成人| 日韩精品一区二区三区第95| 国产精品18在线| 在线不卡视频| 国产精品自产拍在线观| 欧美 日韩 国产 精品| 国产午夜精品久久久久久久 | 夜夜爽av福利精品导航| 国产精品久久久久久久久久ktv| 国产人妻精品一区二区三| 久久这里只有精品6| 久久av秘一区二区三区| 一区二区三区短视频| 制服丝袜中文字幕亚洲| 无码h肉动漫在线观看| 亚洲综合专区| 国产成人免费av电影| 亚洲欧美高清视频| 综合分类小说区另类春色亚洲小说欧美 | 国产一区二区色| 日本黄色不卡视频| 亚洲天堂免费在线观看视频| 欧美视频免费看欧美视频| 久久久久久一区二区三区四区别墅| 欧美精品一区二区久久婷婷| 91无套直看片红桃在线观看| 在线亚洲激情| 国产91精品入口17c| 日本蜜桃在线观看| 一本到不卡精品视频在线观看| 深夜视频在线观看| 亚洲澳门在线| 国产美女久久精品香蕉69| 欧美日韩视频精品二区| 亚洲国产一区在线观看| 中文字幕丰满乱码| 日韩国产一区二区三区| 国产97免费视| 欧美美女色图| 精品国产老师黑色丝袜高跟鞋| 亚洲午夜久久久久久久久| 国产二区精品| 成人免费午夜电影| 国产三区在线观看| 欧美区视频在线观看| 欧美激情 一区| 日本aⅴ亚洲精品中文乱码| 久久精品日韩| 深夜av在线| 日韩精品在线观看一区二区| 久久99精品波多结衣一区| 成人午夜大片免费观看| 91九色丨porny丨国产jk| 99这里只有精品视频| 欧美裸体男粗大视频在线观看| 一级特黄aaa| 国产精品国产三级国产aⅴ中文 | 国产成人免费视频网站高清观看视频| 亚洲永久一区二区三区在线| 成人日韩av| 色偷偷888欧美精品久久久| 亚洲手机在线观看| 中文字幕中文乱码欧美一区二区 | 久久麻豆视频| 久久精品99久久香蕉国产色戒| 一本色道久久综合熟妇| 国产精品久久综合| 可以看污的网站| 在线电影一区二区| 99久久99久久精品国产片| www在线看| 亚洲精品在线91| 91丨九色丨海角社区| 欧美高清一级片在线观看| 我要看一级黄色大片| 国产韩日影视精品| 懂色一区二区三区av片| 日本在线播放一二三区| 亚洲视频网站在线观看| 亚洲字幕av一区二区三区四区| 亚洲欧美在线高清| 在线中文字日产幕| 国产九九精品| 亚洲一区综合| 国产成人在线中文字幕| 日本国产高清不卡| 日本亚洲精品| 亚洲国产欧美日韩精品| 欧美亚洲另类小说| 亚洲欧美一区二区不卡| 少妇激情一区二区三区视频| 三级在线观看一区二区| 好色先生视频污| 思热99re视热频这里只精品 | 亚洲无码精品国产| 亚洲免费av高清| 极品白嫩丰满美女无套| 日韩av一二三| 日韩欧美猛交xxxxx无码| 国产一区二区三区四区五区| 亚洲综合中文字幕在线| 妞干网免费在线视频| 日韩在线视频中文字幕| 日韩一区二区三区在线观看视频| 欧美体内she精视频| 日韩手机在线观看| 亚洲欧洲美洲综合色网| 蜜臀av一区二区三区有限公司| 国产在线播放一区二区三区| 99热在线这里只有精品| 中文字幕一区二区av | 国产美女久久精品| 欧美gv在线观看| 久久精品免费电影| 欧美女同网站| 欧美精品一区视频| 一起草av在线| 日本高清不卡视频| 国产午夜小视频| 亚洲特级片在线| 免费网站在线高清观看| 成人免费观看男女羞羞视频| 中文字幕第17页| 丝袜亚洲精品中文字幕一区| www精品久久| 欧美~级网站不卡| 亚洲国产精品www| 国产99久久精品一区二区300| 99超碰麻豆| www999久久| 国产精品亚洲网站| 日韩影片中文字幕| 97色在线视频| 好久没做在线观看| 欧美大尺度在线观看| 男人天堂久久久| 中文字幕亚洲天堂| 国产女主播在线写真| 日韩精品中文字幕视频在线| 男人天堂综合网| 欧美成人三级电影在线| 国产黄a三级三级三级| 欧美美女bb生活片| 一卡二卡三卡在线| 欧美日韩的一区二区| 中文字幕91爱爱| 欧美性猛片xxxx免费看久爱| 欧美brazzers| 一本久道中文字幕精品亚洲嫩| 国产午夜免费福利| 色综合网站在线| 日本中文字幕第一页| 欧美午夜xxx| 国产免费一级视频| 欧美亚洲自拍偷拍| 中文字幕人成人乱码亚洲电影| 欧美视频一区二区在线观看| 最近中文字幕av| 欧美日韩久久一区| 国产理论视频在线观看| 日韩一区二区在线播放| 草逼视频免费看| 精品日韩在线一区| 天堂在线观看免费视频| 日韩电影大全免费观看2023年上| 午夜视频福利在线| 亚洲网站视频福利| 幼a在线观看| 久久久精品一区二区| 青春草免费在线视频| 欧美极品少妇xxxxx| 国产自产自拍视频在线观看| 欧洲中文字幕国产精品| 91亚洲视频| 成人激情视频在线观看| 欧美影院精品| 免费看国产精品一二区视频| 日韩激情在线| 九一免费在线观看| 激情视频一区| 凹凸日日摸日日碰夜夜爽1| 精品在线免费观看| 好吊操视频这里只有精品| 91欧美激情一区二区三区成人| 久久久久无码精品国产sm果冻| 日韩美女久久久| 日韩精品视频播放| 色偷偷久久人人79超碰人人澡| 最近中文字幕在线观看视频| 欧美一级免费大片| 你懂的在线观看视频网站| 色偷偷噜噜噜亚洲男人的天堂| 成人在线直播| 日本一本a高清免费不卡| 亚洲成人高清| 久久九九视频| 欧美一区影院| 成人久久久久久久久| 国产主播一区二区三区| 国产美女视频免费观看下载软件| 中文字幕第一区二区| 久久国产精品波多野结衣| 一本到三区不卡视频| www日本视频| 亚洲色图五月天| 国产99re66在线视频| 国产精品网站视频| 天堂成人娱乐在线视频免费播放网站 | 日批免费在线观看| 中文字幕不卡在线视频极品| 黑人精品视频| 亚洲aa中文字幕| 美女亚洲一区| 国产精品无码免费专区午夜| 999精品视频在线观看播放| 国产美女主播在线观看| 欧美日韩亚洲综合在线| 丰满人妻熟女aⅴ一区| 亚洲天堂第二页| 日本高清在线观看视频| 国产精品一区av| 美女少妇全过程你懂的久久| 日本福利视频一区| 精品一区二区三区的国产在线播放 | 少妇特黄a一区二区三区| 欧美一区视频| 亚洲精品在线视频播放| 久久九九国产精品| 日本熟妇成熟毛茸茸| 日韩一区二区三区三四区视频在线观看 | 国产福利91精品一区| 美国黄色特级片| 在线观看成人免费视频| 青青免费在线视频| 午夜精品久久久久久99热软件| 欧美电影在线观看一区| 一区二区成人国产精品 | 免费观看污网站| 综合av第一页| 在线观看国产精品入口男同| 亚洲男人天堂2019| 色吧亚洲日本| 久久96国产精品久久99软件| 亚洲国产免费| 亚洲香蕉中文网| 午夜精品久久久久影视| 亚洲精品国产suv一区| 欧美美女操人视频| 无码国模国产在线观看| 免费极品av一视觉盛宴| 国产精品白丝jk白祙喷水网站 | 综合久久综合| 国产精品久久久久久久99| 日韩码欧中文字| 97人妻精品一区二区三区软件| 色青青草原桃花久久综合| 韩国女主播一区二区| 亚洲欧洲日本国产| 久久97超碰国产精品超碰| 三级黄色片在线观看| 欧美精品久久久久久久久老牛影院 | 在线视频亚洲欧美中文| 日韩av新片网| 91视频免费观看| 波多野结衣视频免费观看| 亚洲天堂第一页| 老司机精品视频网| av中文字幕av| 成人免费av在线| 天天干天天干天天| 夜夜嗨av一区二区三区四区| 亚洲欧洲一二区| 日韩一级特黄毛片| 成人永久看片免费视频天堂| 日韩精品1区2区| 在线观看国产精品淫| 精品一区二区三区中文字幕在线| 国产女教师bbwbbwbbw| 91丝袜美腿高跟国产极品老师 | 青娱乐在线视频免费观看| 欧美精品一区二区三区久久久| 欧美最新精品| 五月天男人天堂| 成人av在线影院| 青青草视频在线观看免费| 久久精品亚洲精品| julia中文字幕一区二区99在线| 各处沟厕大尺度偷拍女厕嘘嘘| 国产精品嫩草99a| 国产成人手机在线| 国产精品96久久久久久又黄又硬| 亚洲九九在线| 丰满少妇在线观看资源站| 3d成人h动漫网站入口| 成人免费观看在线观看| 正在播放一区| 91在线观看地址| 国产精品女人久久久| 国语自产精品视频在免费| 日韩国产一区| 色呦呦一区二区| 欧美一区二区三区精品| 在线成人av观看| 久久艹国产精品| 国产精品久久久久久久久快鸭| 色综合视频在线| 91最新国产视频| 日韩极品在线观看|