久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術文章
文章詳情頁

PHP內核探索 —— 理解Zend里的哈希表

瀏覽:5日期:2022-09-16 14:06:18

在PHP的Zend引擎中,有一個數據結構非常重要,它無處不在,是PHP數據存儲的核心,各種常量、變量、函數、類、對象等都用它來組織,這個數據結構就是HashTable。

HashTable在通常的數據結構教材中也稱作散列表,哈希表。其基本原理比較簡單(如果你對其不熟悉,請查閱隨便一本數據結構教材或在網上搜索),但PHP的實現有其獨特的地方。理解了HashTable的數據存儲結構,對我們分析PHP的源代碼,特別是Zend Engine中的虛擬機的實現時,有很重要的幫助。它可以幫助我們在大腦中模擬一個完整的虛擬機的形象。它也是PHP中其它一些數據結構如數組實現的基礎。

Zend HashTable的實現結合了雙向鏈表和向量(數組)兩種數據結構的優點,為PHP提供了非常高效的數據存儲和查詢機制。

HashTable的數據結構

在Zend Engine中的HashTable的實現代碼主要包括zend_hash.h, zend_hash.c這兩個文件中。Zend HashTable包括兩個主要的數據結構,其一是Bucket(桶)結構,另一個是HashTable結構。Bucket結構是用于保存數據的容器,而 HashTable結構則提供了對所有這些Bucket(或桶列)進行管理的機制。

typedef struct bucket { ulong h; /* Used for numeric indexing */ uint nKeyLength; /* key 長度 */ void *pData; /* 指向Bucket中保存的數據的指針 */ void *pDataPtr; /* 指針數據 */ struct bucket *pListNext; /* 指向HashTable桶列中下一個元素 */ struct bucket *pListLast; /* 指向HashTable桶列中前一個元素 */ struct bucket *pNext; /* 指向具有同一個hash值的桶列的后一個元素 */ struct bucket *pLast; /* 指向具有同一個hash值的桶列的前一個元素 */ char arKey[1]; /* 必須是最后一個成員,key名稱*/} Bucket;

在Zend HashTable中,每個數據元素(Bucket)有一個鍵名(key),它在整個HashTable中是唯一的,不能重復。根據鍵名可以唯一確定 HashTable中的數據元素。鍵名有兩種表示方式。第一種方式使用字符串arKey作為鍵名,該字符串的長度為nKeyLength。注意到在上面的數據結構中arKey雖然只是一個長度為1的字符數組,但它并不意味著key只能是一個字符。實際上Bucket是一個可變長的結構體,由于arKey是 Bucket的最后一個成員變量,通過arKey與nKeyLength結合可確定一個長度為nKeyLength的key。這是C語言編程中的一個比較 常用的技巧。另一種鍵名的表示方式是索引方式,這時nKeyLength總是0,長整型字段h就表示該數據元素的鍵名。簡單的來說,即如果 nKeyLength=0,則鍵名為h;否則鍵名為arKey, 鍵名的長度為nKeyLength。

當nKeyLength > 0時,并不表示這時的h值就沒有意義。事實上,此時它保存的是arKey對應的hash值。不管hash函數怎么設計,沖突都是不可避免的,也就是說不同 的arKey可能有相同的hash值。具有相同hash值的Bucket保存在HashTable的arBuckets數組(參考下面的解釋)的同一個索 引對應的桶列中。這個桶列是一個雙向鏈表,其前向元素,后向元素分別用pLast, pNext來表示。新插入的Bucket放在該桶列的最前面。

在Bucket中,實際的數據是保存在pData指針指向的內存塊中,通常這個內存塊是系統另外分配的。但有一種情況例外,就是當Bucket保存的數據是一個指針時,HashTable將不會另外請求系統分配空間來保存這個指針,而是直接將該指針保存到pDataPtr中,然后再將pData指向 本結構成員的地址。這樣可以提高效率,減少內存碎片。由此我們可以看到PHP HashTable設計的精妙之處。如果Bucket中的數據不是一個指針,pDataPtr為NULL。

HashTable中所有的Bucket通過pListNext, pListLast構成了一個雙向鏈表。最新插入的Bucket放在這個雙向鏈表的最后。

注意在一般情況下,Bucket并不能提供它所存儲的數據大小的信息。所以在PHP的實現中,Bucket中保存的數據必須具有管理自身大小的能力。

typedef struct _hashtable { uint nTableSize; uint nTableMask; uint nNumOfElements; ulong nNextFreeElement; Bucket *pInternalPointer; Bucket *pListHead; Bucket *pListTail; Bucket **arBuckets; dtor_func_t pDestructor; zend_bool persistent; unsigned char nApplyCount; zend_bool bApplyProtection; #if ZEND_DEBUG int inconsistent; #endif} HashTable;

在HashTable結構中,nTableSize指定了HashTable的大小,同時它限定了HashTable中能保存Bucket的最大數量,此 數越大,系統為HashTable分配的內存就越多。為了提高計算效率,系統自動會將nTableSize調整到最小一個不小于nTableSize的2 的整數次方。也就是說,如果在初始化HashTable時指定一個nTableSize不是2的整數次方,系統將會自動調整nTableSize的值。即

nTableSize = 2ceil(log(nTableSize, 2)) 或 nTableSize = pow(ceil(log(nTableSize,2)))

例如,如果在初始化HashTable的時候指定nTableSize = 11,HashTable初始化程序會自動將nTableSize增大到16。

arBuckets是HashTable的關鍵,HashTable初始化程序會自動申請一塊內存,并將其地址賦值給arBuckets,該內存大 小正好能容納nTableSize個指針。我們可以將arBuckets看作一個大小為nTableSize的數組,每個數組元素都是一個指針,用于指向 實際存放數據的Bucket。當然剛開始時每個指針均為NULL。

nTableMask的值永遠是nTableSize – 1,引入這個字段的主要目的是為了提高計算效率,是為了快速計算Bucket鍵名在arBuckets數組中的索引。

nNumberOfElements記錄了HashTable當前保存的數據元素的個數。當nNumberOfElement大于nTableSize時,HashTable將自動擴展為原來的兩倍大小。

nNextFreeElement記錄HashTable中下一個可用于插入數據元素的arBuckets的索引。

pListHead, pListTail則分別表示Bucket雙向鏈表的第一個和最后一個元素,這些數據元素通常是根據插入的順序排列的。也可以通過各種排序函數對其進行重 新排列。pInternalPointer則用于在遍歷HashTable時記錄當前遍歷的位置,它是一個指針,指向當前遍歷到的Bucket,初始值是 pListHead。

pDestructor是一個函數指針,在HashTable的增加、修改、刪除Bucket時自動調用,用于處理相關數據的清理工作。

persistent標志位指出了Bucket內存分配的方式。如果persisient為TRUE,則使用操作系統本身的內存分配函數為Bucket分配內存,否則使用PHP的內存分配函數。具體請參考PHP的內存管理。

nApplyCount與bApplyProtection結合提供了一個防止在遍歷HashTable時進入遞歸循環時的一種機制。

inconsistent成員用于調試目的,只在PHP編譯成調試版本時有效。表示HashTable的狀態,狀態有四種:

狀態值的含義:

HT_IS_DESTROYING 正在刪除所有的內容,包括arBuckets本身HT_IS_DESTROYED 已刪除,包括arBuckets本身HT_CLEANING 正在清除所有的arBuckets指向的內容,但不包括arBuckets本身HT_OK 正常狀態,各種數據完全一致

typedef struct _zend_hash_key { char *arKey; /* hash元素key名稱 */ uint nKeyLength; /* hash 元素key長度 */ ulong h; /* key計算出的hash值或直接指定的數值下標 */} zend_hash_key;

現在來看zend_hash_key結構就比較容易理解了。它通過arKey, nKeyLength, h三個字段唯一確定了HashTable中的一個元素。

根據上面對HashTable相關數據結構的解釋,我們可以畫出HashTable的內存結構圖:

PHP內核探索 —— 理解Zend里的哈希表

Zend HashTable的實現

本節具體介紹一下PHP中HashTable的實現。以下函數均取自于zend_hash.c。只要充分理解了上述數據結構,HashTable實現的代碼并不難理解。

1. HashTable初始化

HashTable提供了一個zend_hash_init宏來完成HashTable的初始化操作。實際上它是通過下面的內部函數來實現的:

ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC){ uint i = 3; Bucket **tmp; SET_INCONSISTENT(HT_OK); if (nSize >= 0×80000000) {/* prevent overflow */ht->nTableSize = 0×80000000; } else {while ((1U << i) < nSize) { /* 自動調整nTableSize至2的n次方 */ i++; } ht->nTableSize = 1 << i; /* i的最小值為3,因此HashTable大小最小為8 */ } ht->nTableMask = ht->nTableSize - 1; ht->pDestructor = pDestructor; ht->arBuckets = NULL; ht->pListHead = NULL; ht->pListTail = NULL; ht->nNumOfElements = 0; ht->nNextFreeElement = 0; ht->pInternalPointer = NULL; ht->persistent = persistent; ht->nApplyCount = 0; ht->bApplyProtection = 1; /* 根據persistent使用不同方式分配arBuckets內存,并將其所有指針初始化為NULL*/ /* Uses ecalloc() so that Bucket* == NULL */ if (persistent) {tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *));if (!tmp) { return FAILURE;}ht->arBuckets = tmp; } else {tmp = (Bucket **) ecalloc_rel(ht->nTableSize, sizeof(Bucket *));if (tmp) { ht->arBuckets = tmp;} } return SUCCESS;}

在以前的版本中,可以使用pHashFunction來指定hash函數。但現PHP已強制使用DJBX33A算法,因此實際上pHashFunction這個參數并不會用到,保留在這里只是為了與以前的代碼兼容。

2. 增加、插入和修改元素

向HashTable中添加一個新的元素最關鍵的就是要確定將這個元素插入到arBuckets數組中的哪個位置。根據上面對Bucket結構鍵名 的解釋,我們可以知道有兩種方式向HashTable添加一個新的元素。第一種方法是使用字符串作為鍵名來插入Bucket;第二種方法是使用索引作為鍵 名來插入Bucket。第二種方法具體又可以分為兩種情況:指定索引或不指定索引,指定索引指的是強制將Bucket插入到指定的索引位置中;不指定索引 則將Bucket插入到nNextFreeElement對應的索引位置中。這幾種插入數據的方法實現比較類似,不同的只是定位Bucket的方法。

修改HashTable中的數據的方法與增加數據的方法也很類似。

我們先看第一種使用字符串作為鍵名增加或修改Bucket的方法:

ZEND_API int _zend_hash_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC){ ulong h; uint nIndex; Bucket *p; IS_CONSISTENT(ht); // 調試信息輸出 if (nKeyLength <= 0) {#if ZEND_DEBUG ZEND_PUTS(”zend_hash_update: Can’t put in empty keyn”); #endif return FAILURE; } /* 使用hash函數計算arKey的hash值 */ h = zend_inline_hash_func(arKey, nKeyLength); /* 將hash值和nTableMask按位與后生成該元素在arBuckets中的索引。讓它和 * nTableMask按位與是保證不會產生一個使得arBuckets越界的數組下標。 */ nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; /* 取得相應索引對應的Bucket的指針 */ /* 檢查對應的桶列中是否包含有數據元素(key, hash) */ while (p != NULL) {if ((p->h == h) && (p->nKeyLength == nKeyLength)) { if (!memcmp(p->arKey, arKey, nKeyLength)) { if (flag & HASH_ADD) { return FAILURE; // 對應的數據元素已存在,不能進行插入操作 } HANDLE_BLOCK_INTERRUPTIONS(); #if ZEND_DEBUG if (p->pData == pData) { ZEND_PUTS(”Fatal error in zend_hash_update: p->pData == pDatan”); HANDLE_UNBLOCK_INTERRUPTIONS(); return FAILURE; } #endif if (ht->pDestructor) { /* 如果數據元素存在,對原來的數據進行析構操作 */ ht->pDestructor(p->pData); } /* 用新的數據來更新原來的數據 */ UPDATE_DATA(ht, p, pData, nDataSize); if (pDest) { *pDest = p->pData; } HANDLE_UNBLOCK_INTERRUPTIONS(); return SUCCESS; }}p = p->pNext; } /* HashTable中沒有key對應的數據,新增一個Bucket */ p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent); if (!p) {return FAILURE; } memcpy(p->arKey, arKey, nKeyLength); p->nKeyLength = nKeyLength; INIT_DATA(ht, p, pData, nDataSize); p->h = h; // 將Bucket加入到相應的桶列中 CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]); if (pDest) {*pDest = p->pData; } HANDLE_BLOCK_INTERRUPTIONS(); // 將Bucket 加入到HashTable的雙向鏈表中 CONNECT_TO_GLOBAL_DLLIST(p, ht); ht->arBuckets[nIndex] = p; HANDLE_UNBLOCK_INTERRUPTIONS(); ht->nNumOfElements++; // 如果HashTable已滿,重新調整HashTable的大小。 ZEND_HASH_IF_FULL_DO_RESIZE(ht); /* If the Hash table is full, resize it */ return SUCCESS;}

因為這個函數是使用字符串作為鍵名來插入數據的,因此它首先檢查nKeyLength的值是否大于0,如果不是的話就直接退出。然后計算arKey對應的 hash值h,將其與nTableMask按位與后得到一個無符號整數nIndex。這個nIndex就是將要插入的Bucket在arBuckets數 組中的索引位置。

現在已經有了arBuckets數組的一個索引,我們知道它包括的數據是一個指向Bucket的雙向鏈表的指針。如果這個雙向鏈表不為空的話我們首先檢查 這個雙向鏈表中是否已經包含了用字符串arKey指定的鍵名的Bucket,這樣的Bucket如果存在,并且我們要做的操作是插入新Bucket(通過 flag標識),這時就應該報錯 – 因為在HashTable中鍵名不可以重復。如果存在,并且是修改操作,則使用在HashTable中指定了析構函數pDestructor對原來的 pData指向的數據進行析構操作;然后將用新的數據替換原來的數據即可成功返回修改操作。

如果在HashTable中沒有找到鍵名指定的數據,就將該數據封裝到Bucket中,然后插入HashTable。這里要注意的是如下的兩個宏:

CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex])CONNECT_TO_GLOBAL_DLLIST(p, ht)

前者是將該Bucket插入到指定索引的Bucket雙向鏈表中,后者是插入到整個HashTable的Bucket雙向鏈表中。兩者的插入方式也不同,前者是將該Bucket插入到雙向鏈表的最前面,后者是插入到雙向鏈表的最末端。

下面是第二種插入或修改Bucket的方法,即使用索引的方法:

ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC){uint nIndex;Bucket *p;IS_CONSISTENT(ht);if (flag & HASH_NEXT_INSERT) {h = ht->nNextFreeElement;}nIndex = h & ht->nTableMask;p = ht->arBuckets[nIndex];// 檢查是否含有相應的數據while (p != NULL) {if ((p->nKeyLength == 0) && (p->h == h)) {if (flag & HASH_NEXT_INSERT || flag & HASH_ADD) {return FAILURE;}//// …… 修改Bucket數據,略//if ((long)h >= (long)ht->nNextFreeElement) {ht->nNextFreeElement = h + 1;}if (pDest) {*pDest = p->pData;}return SUCCESS;}p = p->pNext;}p = (Bucket *) pemalloc_rel(sizeof(Bucket) - 1, ht->persistent);if (!p) {return FAILURE;}p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */p->h = h;INIT_DATA(ht, p, pData, nDataSize);if (pDest) {*pDest = p->pData;}CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);HANDLE_BLOCK_INTERRUPTIONS();ht->arBuckets[nIndex] = p;CONNECT_TO_GLOBAL_DLLIST(p, ht);HANDLE_UNBLOCK_INTERRUPTIONS();if ((long)h >= (long)ht->nNextFreeElement) {ht->nNextFreeElement = h + 1;}ht->nNumOfElements++;ZEND_HASH_IF_FULL_DO_RESIZE(ht);return SUCCESS;}

flag標志指明當前操作是HASH_NEXT_INSERT(不指定索引插入或修改), HASH_ADD(指定索引插入)還是HASH_UPDATE(指定索引修改)。由于這些操作的實現代碼基本相同,因此統一合并成了一個函數,再用flag加以區分。

本函數基本與前一個相同,不同的是如果確定插入到arBuckets數組中的索引的方法。如果操作是HASH_NEXT_INSERT,則直接使用nNextFreeElement作為插入的索引。注意nNextFreeElement的值是如何使用和更新的。

3. 訪問元素

同樣,HashTable用兩種方式來訪問元素,一種是使用字符串arKey的zend_hash_find();另一種是使用索引的訪問方式zend_hash_index_find()。由于其實現的代碼很簡單,分析工作就留給讀者自已完成。

4. 刪除元素

HashTable刪除數據均使用zend_hash_del_key_or_index()函數來完成,其代碼也較為簡單,這里也不再詳細分析。需要的是注意如何根據arKey或h來計算出相應的下標,以及兩個雙向鏈表的指針的處理。

5. 遍歷元素

/* This is used to recurse elements and selectively delete certain entries* from a hashtable. apply_func() receives the data and decides if the entry* should be deleted or recursion should be stopped. The following three* return codes are possible:* ZEND_HASH_APPLY_KEEP - continue* ZEND_HASH_APPLY_STOP - stop iteration* ZEND_HASH_APPLY_REMOVE - delete the element, combineable with the former*/ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC){Bucket *p;IS_CONSISTENT(ht);HASH_PROTECT_RECURSION(ht);p = ht->pListHead;while (p != NULL) {int result = apply_func(p->pData TSRMLS_CC);if (result & ZEND_HASH_APPLY_REMOVE) {p = zend_hash_apply_deleter(ht, p);} else {p = p->pListNext;}if (result & ZEND_HASH_APPLY_STOP) {break;}}HASH_UNPROTECT_RECURSION(ht);}

因為HashTable中所有Bucket都可以通過pListHead指向的雙向鏈表來訪問,因此遍歷HashTable的實現也比較簡單。這里值得一 提的是對當前遍歷到的Bucket的處理使用了一個apply_func_t類型的回調函數。根據實際需要,該回調函數返回下面值之一:

ZEND_HASH_APPLY_KEEPZEND_HASH_APPLY_STOPZEND_HASH_APPLY_REMOVE

它們分別表示繼續遍歷,停止遍歷或刪除相應元素后繼續遍歷。

還有一個要注意的問題就是遍歷時的防止遞歸的問題,也就是防止對同一個HashTable同時進行多次遍歷。這是用下面兩個宏來實現的:

HASH_PROTECT_RECURSION(ht)HASH_UNPROTECT_RECURSION(ht)

其主要原理是如果遍歷保護標志bApplyProtection為真,則每次進入遍歷函數時將nApplyCount值加1,退出遍歷函數時將nApplyCount值減1。開始遍歷之前如果發現nApplyCount > 3就直接報告錯誤信息并退出遍歷。

上面的apply_func_t不帶參數。HashTable還提供帶一個參數或可變參數的回調方式,對應的遍歷函數分別為:

typedef int (*apply_func_arg_t)(void *pDest,void *argument TSRMLS_DC);void zend_hash_apply_with_argument(HashTable *ht,apply_func_arg_t apply_func, void *data TSRMLS_DC);typedef int (*apply_func_args_t)(void *pDest,int num_args, va_list args, zend_hash_key *hash_key);void zend_hash_apply_with_arguments(HashTable *ht,apply_func_args_t apply_func, int numargs, …);

除了上面提供的幾種提供外,還有許多其它操作HashTable的API。如排序、HashTable的拷貝與合并等等。只要充分理解了上述HashTable的數據結構,理解這些代碼并不困難。

標簽: PHP
相關文章:
主站蜘蛛池模板: 黄色国产一级视频 | 蜜桃精品久久久久久久免费影院 | 国产精品久久久爽爽爽麻豆色哟哟 | 精品免费久久久久 | 日韩欧美精品一区二区三区 | 一区二区av| 一区二区三区在线视频播放 | 一级片av | 青青久久 | 久久亚洲一区二区三区四区五区高 | 一区二区免费在线观看 | 日韩国产在线播放 | 成人免费一区二区三区视频软件 | 国产精品美女久久久久久久久久久 | 久久国产精品久久精品 | 精品久久久久一区二区国产 | 成人免费在线电影 | 欧美激情一区二区 | 欧美一区二区激情三区 | 亚洲无吗天堂 | 在线观看av网站永久 | 久久高清精品 | 欧美成人h版在线观看 | 一本久久a久久精品亚洲 | 国产高清第一页 | 日韩中文字幕一区二区 | 亚洲一区国产视频 | 亚洲精品午夜国产va久久成人 | 亚洲免费视频在线 | 国产精品亚洲视频 | 欧美日韩中文在线 | 午夜久久久 | 国产精品18久久久久久首页狼 | 欧美日韩在线一区二区 | 精品视频久久 | 一区二区三区久久 | 狠狠亚洲 | 日本三级视频 | 久久精品视频在线播放 | 日产精品久久 | 久久精品国产免费 | 中文字幕国产一区 | 亚洲一区二区在线播放 | 99视频网站 | 国产成人99久久亚洲综合精品 | 性做久久久 | 久久亚洲一区二区 | 91高清在线 | 欧美日一区二区 | 欧美视频三区 | 亚洲日本欧美日韩高观看 | 成人精品一区二区三区中文字幕 | 免费看国产一级片 | 日韩精品免费 | 日本一区二区精品 | 久久精品99国产精品日本 | 精品国产精品国产偷麻豆 | 欧美日韩中文字幕在线 | hitomi一区二区三区精品 | 视频一区在线播放 | 中文字幕在线一区 | 亚洲精品午夜国产va久久成人 | 91午夜在线 | 国产精品一区在线观看 | 亚州中文字幕 | 成人福利影院 | 亚洲综合色视频在线观看 | 另类五月 | 毛片网在线观看 | 亚洲风情在线观看 | 日韩精品一区二区三区在线观看 | 亚洲一区二区三区免费在线观看 | 韩日av在线| 日韩成人免费 | 亚洲欧美另类在线观看 | 精品久久久久久久久久久久 | h片在线看 | 亚州精品国产 | 国产激情一区二区三区 | 日韩性猛交 | 国产精品99久久久久久大便 | 99re在线播放视频 | 亚洲精品影院 | 欧美视频区 | 蜜臀久久99精品久久久无需会员 | 热re99久久精品国99热线看 | 欧美精品一区二区三区在线 | 在线播放亚洲 | 九九热在线观看 | 天天澡天天狠天天天做 | 国产视频一区二区 | 欧洲妇女成人淫片aaa视频 | 久久久久久久久99精品 | 国产精品久久久久久久久免费桃花 | 嫩草懂你| 亚洲处破女 | 久久久中文字幕 | 国产综合精品一区二区三区 | av网站观看 | www.视频在线观看 | 亚洲成人一区二区三区 | 天天操夜夜操av | 日韩中文字幕欧美 | 成人看片免费 | 伊人电影综合 | 超碰人操 | 五月激情综合网 | 亚洲中午字幕在线观看 | 中文字幕在线观看 | 久久亚洲精品国产一区 | 久久久一区二区 | 久久精品久久久久电影 | 成人免费视频网站在线看 | 国产日韩欧美三级 | 亚洲福利片 | 岛国av在线 | 亚洲欧美激情精品一区二区 | 视频精品一区 | 国产精品二区三区 | 91免费国产 | 午夜日韩| 久久大陆| 亚洲久草 | 日韩喷潮 | 欧美日韩在线播放 | 亚洲视频一区在线 | 欧美亚洲日本 | h视频在线免费观看 | 日韩免费av一区二区 | 欧美日韩一 | 成人影院av | 欧美激情一区二区三区四区 | 亚洲专区在线播放 | 国产精品综合 | 羞羞网页 | 久久视频一区 | 日韩精品一区二区三区视频播放 | 国产精品资源在线 | 91麻豆精品国产91久久久更新资源速度超快 | 亚洲高清av | 亚洲福利视频在线 | 狠狠中文字幕 | 一区视频在线 | 亚洲午夜激情网 | 91麻豆精品国产91久久久久久久久 | 99精品国产一区二区三区 | 亚洲第一精品在线 | 亚洲精品中文字幕在线观看 | 国产日韩精品一区二区在线观看播放 | 日韩精品一区二区三区在线观看 | 日一区二区 | 一级黄色大片免费 | 一区二区三区日韩 | 琪琪午夜伦伦电影福利片 | 国产精品综合久久 | 久久久久亚洲精品 | 青青草精品 | 欧美日韩成人在线观看 | 中文字幕视频一区 | 一区二区三区四区在线 | 日本免费一区二区三区 | 欧美中文一区 | 在线国产一区 | 日韩av网站在线 | 国产女人高潮视频在线观看 | 亚洲精品久久久一区二区三区 | 99热最新网站 | 久久亚洲精品视频 | 日韩av成人 | 国产日韩欧美视频 | 国产一区二区三区四 | 成人在线一区二区 | 欧美簧片在线 | 亚洲精品视频在线播放 | 欧美激情a∨在线视频播放 成人免费共享视频 | m豆传媒在线链接观看 | 欧美久久视频 | 欧美在线二区 | 国产成人影院在线观看 | 欧美第一区 | 日韩精品小视频 | 香蕉国产精品 | 国产美女高潮一区二区三区 | 亚洲欧美日本在线 | 欧美日韩国产精品一区二区 | 国产剧情一区二区三区 | 日日干天天干 | 久久99这里只有精品 | 亚洲精品一区二区三区 | 91丝袜| 久久久久91| 一区二区在线播放视频 | 午夜老湿影院 | 毛片91| 亚洲精品视频免费看 | 欧美一区二区三区男人的天堂 | 国产福利精品一区 | 国产一区二区三区在线 | 国产精品久久久久9999 | 亚洲国产高清高潮精品美女 | 99精品欧美一区二区三区 | 亚洲精品影院 | 国产免费无遮挡 | 在线成人www免费观看视频 | 国产午夜精品久久久久久久 | 欧美视频网站 | a久久| 亚洲精品一区二区在线观看 | 羞羞视频在线网站观看 | 国产精品国产三级国产aⅴ无密码 | 99久久国产 | 亚洲福利片 | 波多野结衣在线网址 | 一级毛片免费看 | 中文字幕亚洲精品 | 国产精品成人3p一区二区三区 | 亚洲欧美在线观看 | 日韩一区二区久久 | 91亚洲日本aⅴ精品一区二区 | 久久久精 | 一级欧美 | 欧美日本韩国一区二区 | 天堂综合网久久 | av在线免费看片 | 国产视频2021 | 伊人网站 | 黄网站涩免费蜜桃网站 | 在线国产视频 | 99久久久无码国产精品 | 国产传媒一区 | 欧美精品网站 | 免费一区二区三区 | 欧美日韩国产一区二区三区不卡 | 国产一区二区av | 亚洲精品在线视频观看 | 荷兰欧美一级毛片 | 国语av在线| 黄色影片免费在线观看 | 精品国产99 | 欧美人人| 亚洲精品国产高清 | 夜夜操天天操 | 欧美日韩中文字幕在线 | 欧美精产国品一二三区 | 精品国产一区二区三区久久影院 | 精品一区二区三区免费毛片爱 | 午夜伦理影院 | www.色在线| 无毒黄网| 超级碰在线视频 | 久久久中文字幕 | 高清国产午夜精品久久久久久 | 国产在线一区二区三区 | 日韩精品 | 国产成人精品免费 | 久久99国产精品 | 97久久香蕉国产线看观看 | 国产成人精品久久二区二区 | 精品伦理一区二区三区 | 国产成人精品一区二区三区网站观看 | 午夜精品一区二区三区在线视频 | a在线观看| 亚洲免费小视频 | 精品国产精品三级精品av网址 | 日韩成人一区二区 | 国产精品污www在线观看 | 亚洲一区二区三区爽爽爽爽爽 | 国产精品久久777777 | www狠狠操| 成人午夜电影在线观看 | 国产午夜精品久久久久久久 | 国产三级在线免费观看 | 91电影院 | 久久免费99精品久久久久久 | 色香蕉久久 | 成人精品久久 | 久综合网 | 欧美一性一交 | 亚洲日日操| 午夜精品久久久久久久男人的天堂 | 正在播放国产精品 | 91人人澡人人爽 | 午夜欧美| 久久精品 | 成人免费福利视频 | 国产精品毛片久久久久久久 | 99热国产在线观看 | 美女久久久久久久久久久 | 亚洲性视频网站 | 精品国产91乱码一区二区三区 | 欧美一级黄色大片 | 欧美日韩国产一区二区三区 | 日韩久久久久久 | 国产福利一区二区 | 91视频免费在线 | 精品自拍视频 | 男人的天堂中文字幕 | 久久精品视频网站 | 在线成人av观看 | 国产一区二区视频在线观看 | 蜜臀网| 久久99精品视频 | 一区二区在线视频 | 91精品国产综合久久久久久漫画 | 99re视频在线播放 | 欧美久久久久久久久久 | 成人男女激情免费视频 | 在线观看黄色大片 | 免费看一区二区三区 | 国产精品久久久久久久久免费 | 日韩在线视频一区 | 亚洲一区二区免费看 | 国产96在线视频 | 国产亚洲成av人片在线观看桃 | 国产精品日韩欧美一区二区 | 天天干天天看天天操 | 国产成人久久精品麻豆二区 | 日本a v在线播放 | 奇米二区| 中文字幕精品一区二区三区精品 | 狠狠的干 | 7777视频| 一区二区三区在线观看国产 | 国产欧美精品一区二区 | 日韩亚洲视频在线观看 | 亚洲小视频 | 中国国产一级毛片 | 美女h视频 | 青青草久久爱 | 综合五月激情 | 色婷婷国产精品免费网站 | 久久999 | 日韩精品一区二区三区在线观看 | 色视频网站在线观看 | 狠狠干美女 | 一区二区日本 | 视频一区 日韩 | 97视频精品| 免费在线黄色av | 久草电影网 | 午夜精品一区二区三区在线视频 | 欧美一级在线免费观看 | 日本一区二区电影 | 亚洲乱码国产乱码精品精的特点 | 2019天天干夜夜操 | 午夜寂寞福利视频 | 国产福利在线视频 | 国产美女在线播放 | 欧美日韩国产一区二区 | 国产91看片 | 成人国产在线观看 | 国产精品a久久久久 | 在线视频 亚洲 | 国产高清视频在线 | 成人在线精品视频 | 日韩免费视频中文字幕 | 国产精品视频免费 | 久久噜噜噜精品国产亚洲综合 | 国内精品在线视频 | 久久精品综合 | 91 在线观看 | 国产综合精品 | 天天干天天添 | 中文视频在线 | 日韩精品一区二区三区在线观看 | 欧美中文字幕在线 | 国产精品视频播放 | 亚洲精品视频区 | 成人免费视频网站 | 黄色资源在线观看 | 色必久久| 日日干夜夜操 | 亚洲激情av | 国产福利在线观看 | 91精品国产综合久久久久久丝袜 | 国产乱码精品一区二区三 | 情一色一乱一欲一区二区 | 午夜欧美精品久久久久 | 综合久久久久 | 国产三区在线成人av | 久久爱电影 | 亚洲综合国产 | 亚洲网站免费看 | 在线观看免费av网 | 亚洲欧洲视频 | 午夜精品在线 | 国产一区二区免费 | 久久a视频| 男女免费在线观看视频 | 韩日中文字幕 | 亚洲精品乱码久久久久久 | 精品成人免费一区二区在线播放 | 亚洲成人精品一区二区三区 | 免费毛片在线播放 | 黄a在线观看 | 亚洲精品乱码久久久久久久久 | 日日爱夜夜爱 | 亚洲第一性理论片 | 亚洲第一成人在线视频 | 玖玖成人 | 欧美日韩视频网站 | 91精品中文字幕一区二区三区 | 国产大奶视频 | 国产一区二区成人 | 成人a在线视频免费观看 | 欧美一区二区三区aa大片漫 | 精品一二区 | 国产一级黄色av | 91电影在线观看 | 午夜天堂精品久久久久 | 国产乱码精品一区二区三区忘忧草 | 久久久999国产 | 日本免费在线视频 | 中文字幕视频在线观看 | 久久九 | 国产在线一二三区 | 综合av第一页 | 91人人| 免费一区二区三区视频在线 | 黄色毛片在线观看 | 欧美一级特黄aaaaaaa色戒 | 国产在线欧美 | 亚洲骚片 | 成人精品免费视频 | 操操网| 久草精品在线观看 | 国产浪潮av色综合久久超碰 | 成人午夜看片 | 91av国产精品 | 免费国产一区 | 欧美日韩午夜 | 国产免费视频在线 | 97视频精品 | 亚洲一区二区在线 | 午夜影院普通用户体验区 | 欧美在线观看一区 | 久久久久久久久久久久网站 | 欧美日韩国产精品 | 一区二区亚洲 | 日本一区二区三区免费观看 | 日本高清中文字幕 | 毛片激情永久免费 | 亚洲国产精品一区 | 亚洲日本欧美日韩高观看 | 欧美国产日韩一区 | 日本一区二区不卡视频 | av大片 | 伊人色综合网 | 日本久久网站 | 91高清视频 | 理论片免费在线观看 | 日日爽天天操 | 午夜激情免费看 | 久久这里只有国产精品 | 在线观看毛片视频 | 久久99er6热线精品首页蜜臀 | 久久99精品久久久久蜜臀 | 99国产精品一区 | 久久综合久久综合久久综合 | 日韩视频中文 | 国产高清在线精品一区二区三区 | 一区二区av| 精品久久一区二区 | 国产一区 日韩 | 天堂一区二区三区四区 | 一级视频毛片 | 美国一级黄色片 | 亚洲免费视频一区二区 | 97夜夜操| 91传媒在线播放 | 91高清视频 | 亚洲福利视频在线 | 国产福利在线观看 | 亚洲视频一区二区三区 | 中文字幕一区二区三区精彩视频 | 国产一区二区精品在线 | 欧美一区2区三区3区公司 | 中文字幕在线看片 | 亚洲精品在线播放 | 国产精品女教师av久久 | 欧美日韩免费一区二区三区 | 亚洲成人中文字幕 | 国产精品一区二区在线观看 | 国产精品日日做人人爱 | 一区二区三区在线免费观看 | 成人在线不卡 | 99这里只有精品视频 | 五月激情综合网 | 天堂一区二区三区 | 嫩草研究院在线观看入口 | 国产视频一区二区三区四区 | 国产福利精品一区 | 国产精品久久国产愉拍 | 91超碰在线观看 | 天天插天天操天天干 | 国产看片网站 | 中文字幕亚洲区 | 国户精品久久久久久久久久久不卡 | 日韩成人在线观看 | 久久国产区 | 伊人青青操 | 91精品久久久久久久久久入口 | 高清久久 | 国产成人精品一区二区在线 | 在线成人av | 理论片一区 | 天天操天天干天天 | 久久精品国产99精品国产亚洲性色 | 91精品国产高清一区二区三区 | 视频一区二区国产 | 久色视频在线观看 | 高清免费av| 蜜桃αv| 国产一区二区自拍视频 | www天天干| 99久久久国产精品 | 亚洲一级毛片 | 日韩一级 | 成人黄色片网站 | 欧美不卡 | 中文字幕一区在线观看视频 | 亚洲高清资源 | 亚洲一区二区三区爽爽爽爽爽 | 99爱在线观看 | 影音先锋中文字幕在线 | 中国一级大黄大黄大色毛片 | 亚洲精品中文视频 | 尹人成人| 黄视频入口 | 天天天干夜夜夜操 | 日本精品视频在线观看 | a视频在线 | 国产午夜精品一区二区 | 操操网 | 精品国产一区二区三区在线观看 | 亚洲免费在线视频 | 成人国产精品久久久 | 国产91亚洲精品 | 亚洲免费在线看 | 在线成人免费视频 | 国产欧美一区二区三区在线看 | av三级| 图片区 国产 欧美 另类 在线 | 欧美精品在欧美一区二区少妇 | 亚洲精品一区在线观看 | 九九在线视频 | 国产美女www | 少妇精品久久久久久久久久 | 国产黄色免费网站 | 免费午夜剧场 | 国产高清精品一区二区三区 | 黄色国产一级视频 | 欧州一区二区三区 | 在线观看v片 | 99热精品在线 | 久久久久久毛片免费播放 | 国产成人免费视频网站视频社区 | 成人做爰69片免费 | 日韩一区不卡 | 亚洲精品二三区 | 欧美日本免费一区二区三区 | 99热在线免费观看 | 国产一级淫免费播放m | 午夜影院免费看 | 黄色大片在线播放 | 亚洲综合在线一区二区 | 91精品国产91久久综合桃花 | 亚洲午夜精品一区二区三区 | 爱爱网址| 亚洲精品视频免费观看 | 第一色视频 | 999视频 | 精品免费国产一区二区三区 | 亚洲精品影院 | 国产成人精品免高潮在线观看 | 永久看片 | 免费黄色片一区二区 | 91精品一区二区三区久久久久久 | 国产午夜精品久久久久久久 | 久久久久亚洲一区二区三区 | 犬夜叉在线观看 | 成年人网站国产 | 性视频黄色 | 91亚洲精品视频 | 日日操操 | 一级片免费视频 | 日韩国产在线观看 | 国产精品免费一区二区三区四区 | 日韩色综合 | www操com | 99成人 | 免费特级黄毛片 | 午夜寂寞少妇aaa片毛片 | 国产综合久久久久久鬼色 | 国产精品夜夜爽 | 国产在线一区二区三区 | 久久久久久久精 | 国产精品一区av | 国产精品视频免费观看 | av一区二区在线观看 | 青娱乐网 | 亚洲伦理 | 欧美一级日韩 | 国产精品久久 | 午夜视频免费 | 成人一区二区在线 | 成人免费淫片aa视频免费 | 久久久精品网站 | 欧美影院| 欧美日韩国产精品一区二区亚洲 | 欧美日韩国产精品 | 草久在线视频 | 欧美二区三区 | 欧美日韩精品在线观看 | 一区二区中文字幕 |