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

動手實現objc_msgSend

移動開發
objc_msgSend 函數支撐了我們使用 Objective-C 實現的一切。Gwynne Raskind,Friday Q&A 的讀者,建議我談談 objc_msgSend 的內部實現。要理解某件事還有比自己動手實現一次更好的方法嗎?咱們來自己動手實現一個 objc_msgSend。

[[146754]]

objc_msgSend 函數支撐了我們使用 Objective-C 實現的一切。Gwynne Raskind,Friday Q&A 的讀者,建議我談談 objc_msgSend 的內部實現。要理解某件事還有比自己動手實現一次更好的方法嗎?咱們來自己動手實現一個 objc_msgSend。

Tramapoline! Trampopoline! (蹦床)

當你寫了一個發送 Objective-C 消息的方法:

  1. [obj message] 

編譯器會生成一個 objc_msgSend 調用:

  1. objc_msgSend(obj, @selector(message)); 

之后 objc_msgSend 會負責轉發這個消息。

它都做了什么?它會查找合適的函數指針或者 IMP,然后調用,***跳轉。任何傳給 objc_msgSend 的參數,最終都會成為 IMP 的參數。 IMP 的返回值成為了最開始被調用的方法的返回值。

因為 objcmsgSend 只是負責接收參數,找到合適的函數指針,然后跳轉,有時管這種叫做 trampoline(譯注:[蹦床](https://en.wikipedia.org/wiki/Trampoline(computing)). 更通用的來說,任何一段負責把一段代碼轉發到另一處的代碼,都可以被叫做 trampoline。

這種轉發的行為使 objc_msgSend 變得特殊起來。因為它只是簡單的查找合適的代碼,然后直接跳轉過去,這相當的通用。傳入任何參數組合都可以,因為它只是把這些參數留給 IMP 去讀取。返回值有些棘手,但最終都可以看成 objc_msgSend 的不同變種。

不幸的是,這些轉發行為都不能用純 C 實現。因為沒有方法可以將傳入 C 函數的泛參(generic parameters)傳給另一個函數。 你可以使用變參,但是變參和普通參數的傳遞方法不同,而且慢,所以這不適合普通的 C 參數。

如果要用 C 來實現 objc_msgSend,基本樣子應該像這樣:

  1. id objc_msgSend(id self, SEL _cmd, ...) 
  2.     Class c = object_getClass(self); 
  3.     IMP imp = class_getMethodImplementation(c, _cmd); 
  4.     return imp(self, _cmd, ...); 

這有點過于簡單。事實上會有一個方法緩存來提升查找速度,像這樣:

  1. id objc_msgSend(id self, SEL _cmd, ...) 
  2.     Class c = object_getClass(self); 
  3.     IMP imp = cache_lookup(c, _cmd); 
  4.     if(!imp) 
  5.         imp = class_getMethodImplementation(c, _cmd); 
  6.     return imp(self, _cmd, ...); 

通常為了速度,cache_lookup 使用 inline 函數實現。

匯編

在 Apple 版的 runtime 中,為了***化速度,整個函數是使用匯編實現的。在 Objective-C 中每次發送消息都會調用 objc_msgSend,在一個應用中最簡單的動作都會有成千或者上百萬的消息。

為了讓事情更簡單,我自己的實現中會盡可能少的使用匯編,使用獨立的 C 函數抽象復雜度。匯編代碼會實現下面的功能:

  1. id objc_msgSend(id self, SEL _cmd, ...) 
  2.     IMP imp = GetImplementation(self, _cmd); 
  3.     imp(self, _cmd, ...); 

GetImplementation 可以用更可讀的方式工作。

匯編代碼需要:

1. 把所有潛在的參數存儲在安全的地方,確保 GetImplementation 不會覆蓋它們。
2. 調用 GetImplementation。
3. 把返回值保存在某處。
4. 恢復所有的參數值。
5. 跳轉到 GetImplementation 返回的 IMP。

讓我們開始吧!

這里我會嘗試使用 x86-64 匯編,這樣可以很方便的在 Mac 上工作。這些概念也可以應用于 i386 或者 ARM。

這個函數會保存在獨立的文件中,叫做 msgsend-asm.s。這個文件可以像源文件那樣傳遞給編譯器,然后會被編譯并鏈接到程序中。

***件事要做的是聲明全局的符號(global symbol)。因為一些無聊的歷史原因,C 函數的 global symbol 會在名字前有個下劃線:

  1. .globl _objc_msgSend 
  2. _objc_msgSend: 

編譯器會很高興的鏈接最近可使用的(nearest available) objc_msgSend。簡單的鏈接這個到一個測試 app 已經可以讓 [obj message] 表達式使用我們自己的代碼而不是蘋果的 runtime,這樣可以相當方便的測試我們的代碼確保它可以工作。

整型數和指針參數會被傳入寄存器 %rsi, %rdi, %rdx, %rcx, %r8 和 %r9。其他類型的參數會被傳進棧(stack)中。這個函數***做的事情是把這六個寄存器中的值保存在棧中,這樣它們可以在之后被恢復:

  1. pushq %rsi 
  2. pushq %rdi 
  3. pushq %rdx 
  4. pushq %rcx 
  5. pushq %r8 
  6. pushq %r9 

除了這些寄存器,寄存器 %rax 扮演了一個隱藏的參數。它用于變參的調用,并保存傳入的向量寄存器(vector registers)的數量,用于被調用的函數可以正確的準備變參列表。以防目標函數是個變參的方法,我同樣也保存了這個寄存器中的值:

  1. pushq %rax 

為了完整性,用于傳入浮點類型參數的寄存器 %xmm 也應該被保存。但是,要是我能確保 GetImplementation 不會傳入任何的浮點數,我就可以忽略掉它們,這樣我就可以讓代碼更簡潔。

接著,對齊棧。 Mac OS X 要求一個函數調用棧需要對齊 16 字節邊界。上面的代碼已經是棧對齊的,但是還是需要顯式手動處理下,這樣可以確保所有都是對齊的,就不用擔心動態調用函數時會崩潰。要對齊棧,在保存 %r12 的原始值到棧中后,我把當前的棧指針保存到了 %r12 中。%r12 是隨便選的,任何保存的調用者寄存器(caller-saved register)都可以。重要的是在調用完 GetImplementation 后這些值仍然存在。然后我把棧指針按位與(and)上 -0x10,這樣可以清除棧底的四位:

  1. pushq %r12 
  2. mov %rsp, %r12 
  3. andq $-0x10, %rsp 

現在棧指針是對齊的了。這樣可以安全的避開上面(above)保存的寄存器,因為棧是向下增長的,這種對齊的方法會讓它更向下(move it further down)。

是時候該調用 GetImplementation 了。它接收兩個參數,self 和 _cmd。 調用習慣是把這兩個參數分別保存到 %rsi 和 %rdi 中。然而傳入 objc_msgSend 中時就是那樣了,它們沒有被移動過,所以不需要改變它們。所有要做的事情實際上是調用 GetImplementation,方法名前面也要有一個下劃線:

  1. callq _GetImplementation 

整型數和指針類型的返回值保存在 %rax 中,這就是找到返回的 IMP 的地方。因為 %rax 需要被恢復到初始的狀態,返回的 IMP 需要被移動到別的地方。我隨便選了個 %r11。

  1. mov %rax, %r11 

現在是時候該恢復原樣了。首先要恢復之前保存在 %r12 中的棧指針,然后恢復舊的 %r12 的值:

  1. mov %r12, %rsp 
  2. popq %r12 

然后按壓入棧的相反順序恢復寄存器的值:

  1. popq %rax 
  2. popq %r9 
  3. popq %r8 
  4. popq %rcx 
  5. popq %rdx 
  6. popq %rdi 
  7. popq %rsi 

現在一切都已經準備好了。參數寄存器(argument registers)都恢復到了之前的樣子。目標函數需要的參數都在合適的位置了。 IMP 在寄存器 %r11 中,現在要做的是跳轉到那里:

  1. jmp *%r11 

就這樣!不需要其他的匯編代碼了。jump 把控制權交給了方法實現。從代碼的角度看,就好像發送消息者直接調用的這個方法。之前的那些迂回的調用方法都消失了。當方法返回,它會直接放回到 objc_msgSend 的調用處,不需要其他的操作。這個方法的返回值可以在合適的地方找到。

非常規的返回值有一些細節需要注意。比如大的結構體(不能用一個寄存器大小保存的返回值)。在 x86-64,大的結構體使用隱藏的***個參數返回。當你像這樣調用:

  1. NSRect r = SomeFunc(a, b, c); 

這個調用會被翻譯成這樣:

  1. NSRect r; 
  2. SomeFunc(&r, a, b, c); 

用于返回值的內存地址被傳入到 %rdi 中。因為 objc_msgSend 期望 %rdi 和 %rsi 中包含 self 和 _cmd,當一個消息返回大的結構體時不會起作用的。同樣的問題存在于多個不同平臺上。runtime 提供了 objc_msgSend_stret 用于返回結構體,工作原理和 objc_msgSend 類似,只是知道在 %rsi 中尋找 self 和在 %rdx 中尋找 _cmd。

相似的問題發生在一些平臺上發送消息(messages)返回浮點類型值。在這些平臺上,runtime 提供了 objc_msgSend_fpret(在 x86-64,objc_msgSend_fpret2 用于特別極端的情況)。

方法查找

讓我們繼續實現 GetImplementation。上面的匯編蹦床意味著這些代碼可以用 C 實現。記得嗎,在真正的 runtime 中,這些代碼都是直接用匯編寫的,是為了盡可能的保證最快的速度。這樣不僅可以更好的控制代碼,也可以避免重復像上面那樣保存并恢復寄存器的代碼。

GetImplementation 可以簡單的調用 class_getMethodImplementation 實現,混入 Objective-C runtime 的實現。這有點無聊。真正的 objc_msgSend 為了***化速度首先會查找類的方法緩存。因為 GetImplementation 想模仿 objc_msgSend,所以它也會這么做。要是緩存中不包含給定的 selector 入口點(entry),它會繼續查找 runtime(it fall back to querying the runtime)。

我們現在需要的是一些結構體定義。方法緩存是類(class)結構體中的私有結構體,為了得到它我們需要定義自己的版本。盡管是私有的,這些結構體的定義還是可以通過蘋果的 Objective-C runtime 開源實現獲得(譯注:http://opensource.apple.com/tarballs/objc4/)。

首先需要定義一個 cache entry:

  1. typedef struct { 
  2.     SEL name; 
  3.     void *unused; 
  4.     IMP imp; 
  5. } cache_entry; 

相當簡單。別問我 unused 字段是干什么的,我也不知道它為什么在那。這是 cache 的全部定義:

  1. struct objc_cache { 
  2.     uintptr_t mask; 
  3.     uintptr_t occupied; 
  4.     cache_entry *buckets[1]; 
  5. }; 

緩存使用 hash table(哈希表)實現。實現這個表是為了速度的考慮,其他無關的都簡化了,所以它有點不一樣。表的大小永遠都是 2 的冪。表格使用 selector 做索引,bucket 是直接使用 selector 的值做索引,可能會通過移位去除不相關的低位(low bits),并與 mask 執行一個邏輯與(logical and)。下面是一些宏,用于給定 selector 和 mask 時計算 bucket 的索引:

  1. #ifndef __LP64__ 
  2. # define CACHE_HASH(sel, mask) (((uintptr_t)(sel)>>2) & (mask)) 
  3. #else 
  4. # define CACHE_HASH(sel, mask) (((unsigned int)((uintptr_t)(sel)>>0)) & (mask)) 
  5. #endif 

***是類的結構體。 這是 Class 指向的類型:

  1. struct class_t { 
  2.     struct class_t *isa; 
  3.     struct class_t *superclass; 
  4.     struct objc_cache *cache; 
  5.     IMP *vtable; 
  6. }; 

需要的結構體都已經有了,現在開始實現 GetImplementation 吧:

  1. IMP GetImplementation(id self, SEL _cmd) 

首先要做的是獲取對象的類。真正的 objc_msgSend 通過類似 self->isa 的方式獲取,但是它會使用官方的 API 實現:

  1. Class c = object_getClass(self); 

因為我想訪問最原始的形式,我會為指向 class_t 結構體的指針執行類型轉換:

  1. struct class_t *classInternals = (struct class_t *)c; 

現在該查找 IMP 了。首先我們把它初始為 NULL。如果我們在緩存中找到,我們會賦值為它。如果查找緩存后仍為 NULL,我們會回退到速度較慢的方法:

  1. IMP imp = NULL; 

接著,獲取指向 cache 的指針:

  1. struct objc_cache *cache = classInternals->cache; 

計算 bucket 的索引,獲取指向 buckets 數組的指針:

  1. uintptr_t index = CACHE_HASH(_cmd, cache->mask); 
  2. cache_entry **buckets = cache->buckets; 

然后,我們使用要找的 selector 查找緩存。runtime 使用的是線性鏈(linear chaining),之后只是遍歷 buckets 子集直到找到需要的 entry 或者 NULL entry:

  1. for(; buckets[index] != NULL; index = (index + 1) & cache->mask) 
  2.     if(buckets[index]->name == _cmd) 
  3.     { 
  4.         imp = buckets[index]->imp; 
  5.         break
  6.     } 

如果沒有找到 entry,我們會調用 runtime 使用一種較慢的方法。在真正的 objc_msgSend 中,上面的所有代碼都是使用匯編實現的,這時候就該離開匯編代碼調用 runtime 自己的方法了。一旦查找緩存后沒有找到需要的 entry,期望快速發送消息的希望就要落空了。這時候獲取更快的速度就沒那么重要了,因為已經注定會變慢,在一定程度上也極少的需要這么調用。因為這點,放棄匯編代碼轉而使用更可維護的 C 也是可以接受的:

  1. if(imp == NULL) 
  2.     imp = class_getMethodImplementation(c, _cmd); 

不管怎樣,IMP 現在已經獲取到了。如果它在緩存中,就會在那里找到它,否則它會通過 runtime 查找到。class_getMethodImplementation 調用同樣會使用緩存,所以下次調用會更快。剩下的就是返回 IMP:

  1. return imp; 

測試

為了確保它能工作,我寫了一個快速的測試程序:

  1. @interface Test : NSObject 
  2. - (void)none; 
  3. - (void)param: (int)x; 
  4. - (void)params: (int)a : (int)b : (int)c : (int)d : (int)e : (int)f : (int)g; 
  5. - (int)retval; 
  6. @end 
  7.  
  8. @implementation Test 
  9.  
  10. - (id)init 
  11.     fprintf(stderr, "in init method, self is %p\n", self); 
  12.     return self; 
  13.  
  14. - (void)none 
  15.     fprintf(stderr, "in none method\n"); 
  16.  
  17. - (void)param: (int)x 
  18.     fprintf(stderr, "got parameter %d\n", x); 
  19.  
  20. - (void)params: (int)a : (int)b : (int)c : (int)d : (int)e : (int)f : (int)g 
  21.     fprintf(stderr, "got params %d %d %d %d %d %d %d\n", a, b, c, d, e, f, g); 
  22.  
  23. - (int)retval 
  24.     fprintf(stderr, "in retval method\n"); 
  25.     return 42
  26.  
  27. @end 
  28.  
  29.  
  30. int main(int argc, char **argv) 
  31.     for(int i = 0; i < 20; i++) 
  32.     { 
  33.         Test *t = [[Test alloc] init]; 
  34.         [t none]; 
  35.         [t param: 9999]; 
  36.         [t params: 1 : 2 : 3 : 4 : 5 : 6 : 7]; 
  37.         fprintf(stderr, "retval gave us %d\n", [t retval]); 
  38.  
  39.         NSMutableArray *a = [[NSMutableArray alloc] init]; 
  40.         [a addObject: @1]; 
  41.         [a addObject: @{ @"foo" : @"bar" }]; 
  42.         [a addObject: @("blah")]; 
  43.         a[0] = @2
  44.         NSLog(@"%@", a); 
  45.     } 

以防因為一些意外調用的是 runtime 的實現。我在 GetImplementation 中加了一些調試的日志確保它被調用了。一切都正常,即使是 literals and subscripting 也都調用的是替換的實現。

結論

objc_msgSend 的核心部分相當的簡單。但它的實現需要一些匯編代碼,這讓它比它應該的樣子更難理解。但是為了性能的優化還是得使用一些匯編代碼。但是通過構建了一個簡單的匯編蹦床,然后使用 C 實現了它的邏輯,我們可以看到它是如何工作的,它真的沒有什么高深的。

很顯然,你不應該在自己的 app 中使用替換的 objc_msgSend 實現。你會后悔這么做的。這么做只為了學習目的。

責任編輯:倪明 來源: Cocoabit
相關推薦

2015-08-13 10:28:07

Cobjc_msgSen匯編

2019-03-26 08:15:45

iOS尾調用Objective-C

2021-07-09 19:04:55

Cache查找消息

2010-09-01 11:31:52

vSphere服務器虛擬化VMware

2022-01-04 11:08:02

實現Localcache存儲

2014-06-20 09:18:54

Dustjs中間件

2015-03-16 10:17:48

objc照片框架

2015-04-17 16:30:46

swiftOC

2024-12-06 09:58:09

2009-10-26 14:25:09

VB.NET控件數組

2009-06-01 10:23:31

asp.net mvcasp.net mvc.net mvc框架

2010-09-01 10:24:53

vSphere服務器虛擬化VMware

2010-09-01 10:27:43

vSphere服務器虛擬化VMware

2010-08-31 11:37:26

vSphere服務器虛擬化VMwar

2021-12-08 07:31:40

設計Localcache緩存

2010-08-31 11:30:26

vSphere服務器虛擬化VMware

2024-11-08 09:06:16

agentJava探針

2023-06-15 07:53:07

NeRF深度學習

2010-09-01 10:37:04

vSphere服務器虛擬化VMware

2010-09-01 10:57:18

vSphere服務器虛擬化VMware
點贊
收藏

51CTO技術棧公眾號

久久午夜夜伦鲁鲁片| 在线观看av的网址| 成年人视频免费| 欧美激情777| 欧美成人在线直播| 久久精品香蕉视频| 18+激情视频在线| 9i在线看片成人免费| 国产精品天天狠天天看| 欧美毛片在线观看| 国产最新精品| 日韩午夜激情电影| 国产精品无码一本二本三本色| www国产在线观看| 久久九九全国免费| 国产精品乱子乱xxxx| 亚洲一线在线观看| 久久国产欧美| 久久久久久久久久久久久久久久久久av | 久久婷婷av| 欧美成人四级hd版| 无码人妻丰满熟妇啪啪欧美| 动漫视频在线一区| 在线91免费看| 中文字幕一区二区三区四区在线视频| 欧美videossex另类| 国产精品乱码妇女bbbb| 乱色588欧美| 蜜臀av在线观看| 国产一区二区三区日韩| 国产精品青草久久久久福利99| 精品少妇久久久久久888优播| 久久国产成人精品| 亚洲情综合五月天| 国产精品久久不卡| 红杏成人性视频免费看| 日韩欧美一级精品久久| 第一区免费在线观看| 日本另类视频| 色8久久精品久久久久久蜜| av无码久久久久久不卡网站| 午夜成年人在线免费视频| 国产精品久久久久久亚洲毛片| 狼狼综合久久久久综合网| 人妻无码中文字幕| 国产.欧美.日韩| 91精品久久香蕉国产线看观看| 艳妇乳肉豪妇荡乳av| 天堂蜜桃一区二区三区| 日韩av不卡在线| 美日韩一二三区 | 国产91对白刺激露脸在线观看| 中文字幕在线观看播放| 亚洲精品中文在线| 加勒比海盗1在线观看免费国语版| 九七电影韩国女主播在线观看| 国产精品久久久久影院| 丰满女人性猛交| 好吊日视频在线观看| 中文字幕一区二区三区蜜月| 亚洲综合视频一区| 国产精品一区二区三区视频网站| 亚洲视频图片小说| 一本大道东京热无码aⅴ| 亚洲小说区图片| 亚洲五码中文字幕| 人妻久久久一区二区三区| 国产传媒在线观看| 日韩欧美在线视频日韩欧美在线视频| 人妻有码中文字幕| 日本欧美一区| 欧美久久久久久久久| 91香蕉国产线在线观看| 91大神精品| 日韩精品中文字幕有码专区| 久久亚洲AV无码专区成人国产| 成人av动漫在线观看| 久久精品国产亚洲精品2020| 国产女人被狂躁到高潮小说| 亚洲高清二区| 国产激情999| 国产女人18毛片水18精| 成人av在线一区二区三区| 欧美欧美一区二区| 日日夜夜精品一区| 亚洲午夜视频在线观看| jizz欧美激情18| 国产一区二区三区黄网站| 亚洲精品国产成人| 1024手机在线观看你懂的| **女人18毛片一区二区| 午夜精品美女自拍福到在线| а中文在线天堂| 国产成人在线视频播放| 欧美裸体网站| 欧美黑人xx片| 欧美视频一区二区在线观看| ass极品水嫩小美女ass| 九九热精品视频在线观看| 久久精品亚洲国产| www.毛片.com| 国产在线国偷精品产拍免费yy| 韩国一区二区三区美女美女秀 | 欧美wwwsss9999| 色伦专区97中文字幕| 日韩av一二三区| 麻豆成人av在线| 久久66热这里只有精品| 国产福利视频在线观看| 日本韩国一区二区三区| youjizz.com日本| 日本欧美国产| 青草青草久热精品视频在线网站| 国产美女永久免费| 国产三级精品三级| 欧美成人高潮一二区在线看| 高清一区二区三区av| 日韩精品在线看| 欧美成人国产精品高潮| 久久国产免费看| 欧美一区2区三区4区公司二百| 男女免费观看在线爽爽爽视频| 欧美中文字幕一二三区视频| 中文字幕在线播放一区| 欧美二区视频| 91精品视频免费看| 91精彩在线视频| 在线观看一区二区视频| 搡老熟女老女人一区二区| 国产精品第十页| 91在线网站视频| 日韩大片在线永久免费观看网站| 色综合咪咪久久| 800av在线播放| 亚洲视频综合| 国产91免费视频| 伊人福利在线| 日韩午夜小视频| 欧美日韩精品一区二区三区视频播放| 麻豆国产欧美日韩综合精品二区| 欧美一进一出视频| 日韩不卡在线| 日日摸夜夜添一区| 中文字幕视频二区| 中文av一区二区| jizz18女人| 色呦哟—国产精品| 国产精品主播视频| 欧美性天天影视| 欧美精品v日韩精品v韩国精品v| 激情五月深爱五月| 国精产品一区一区三区mba视频| 一区二区视频在线播放| 青娱乐极品盛宴一区二区| 中文字幕精品网| 一区二区视频网站| 亚洲欧美日韩国产一区二区三区| 亚洲精品中文字幕乱码无线| 亚洲有吗中文字幕| 成人永久免费| 免费看男女www网站入口在线| 日韩久久午夜影院| 国产精品自拍第一页| 国产精品午夜久久| 亚洲av无日韩毛片久久| 国一区二区在线观看| 国产亚洲福利社区| 成人av免费电影网站| 一区二区三欧美| 国产一区二区自拍视频| 亚洲精品成人悠悠色影视| 中文字幕永久免费| 一本久久知道综合久久| 欧美在线视频二区| 99久久这里有精品| 久久男人的天堂| 看电影就来5566av视频在线播放| 欧美日韩国产美女| 精品97人妻无码中文永久在线| 99久久精品免费看国产| 免费观看成人网| 91精品蜜臀一区二区三区在线| 国产精品一级久久久| 电影亚洲精品噜噜在线观看| 日韩在线高清视频| 刘亦菲毛片一区二区三区| 色天使色偷偷av一区二区| 日本午夜在线观看| 久久伊99综合婷婷久久伊| 日韩爱爱小视频| 国产一区二区三区四区老人| 青娱乐国产91| 2023国产精华国产精品| 国产精品久久久久久久久久小说| 中文字幕中文字幕在线十八区| 精品无人区乱码1区2区3区在线| 中文字幕永久免费视频| 亚洲成a人片综合在线| 日本理论中文字幕| 成人黄页毛片网站| av亚洲天堂网| 亚洲一区二区三区高清不卡| 可以在线看黄的网站| 亚洲精品亚洲人成在线| 亚洲自拍av在线| 日韩av超清在线观看| 欧美激情高清视频| 2021av在线| 国产视频精品va久久久久久| 草草视频在线播放| 欧美日韩一卡二卡三卡| 日韩精品在线免费看| 亚洲欧洲av色图| 少妇久久久久久久久久| 成人免费精品视频| 亚洲高清视频免费| 日韩av在线发布| 精品久久久久久久久久中文字幕| 亚洲成av人电影| 丝袜足脚交91精品| 亚洲裸色大胆大尺寸艺术写真| 99久久精品免费看国产一区二区三区| 欧美成人福利| 国产成人极品视频| 欧亚av在线| 久久久视频在线| 欧美一卡二卡| 久久久精品电影| 777电影在线观看| 伊人激情综合网| 久久电影视频| 亚洲免费福利视频| 亚洲av激情无码专区在线播放| 精品伦理精品一区| 亚洲福利在线观看视频| 9191精品国产综合久久久久久| 伊人22222| 欧美日韩中文字幕精品| 国产精品传媒在线观看| 亚洲成av人在线观看| 欧美精品久久久久性色| 亚洲精品综合在线| 免费在线观看黄色av| 亚洲乱码国产乱码精品精可以看 | 色视频免费在线观看| 亚洲加勒比久久88色综合| 日本精品久久久久久| 欧美精品一区二区在线观看| 亚洲第一色视频| 亚洲电影免费观看高清完整版在线观看 | 欧美电影免费提供在线观看| 99久久精品无免国产免费| 欧美一区二区三区免费视频 | 日韩精品久久久久久久酒店| 亚洲一区二区在线免费看| 久久久久久国产精品视频| 亚洲超碰精品一区二区| 少妇一级淫片免费放中国| 欧美日韩免费看| 波多野结衣高清视频| 欧美午夜理伦三级在线观看| 中文天堂在线播放| 91麻豆精品国产| 老牛影视av牛牛影视av| 亚洲精品午夜精品| 午夜在线观看视频| 欧美成人在线网站| 捆绑调教日本一区二区三区| 国产99久久精品一区二区 夜夜躁日日躁 | 欧美日韩国产中文| 国产人妻精品一区二区三| 日韩视频一区在线观看| 天天干天天干天天干| 亚洲欧洲国产精品| 日本亚洲精品| 欧美激情综合色| 免费观看一级欧美片| 国产精品一区久久久| 视频二区欧美| 美女亚洲精品| 婷婷亚洲综合| 777av视频| 日本成人在线视频网站| 亚洲综合20p| 91亚洲男人天堂| 手机免费观看av| 天天综合色天天综合| 中文字幕视频一区二区| 欧美精品一区二区三区在线| 国产在线视频网站| 欧美放荡办公室videos4k| 东京一区二区| 91国产在线免费观看| 国产欧美一区二区精品久久久| 今天免费高清在线观看国语| 亚洲免费一区二区| 日韩av影视大全| 国产偷国产偷亚洲高清人白洁| 国产性xxxx| 在线观看日产精品| 丰满人妻一区二区| 色偷偷av一区二区三区| 午夜激情电影在线播放| 91视频网页| 日韩欧美三级| 日日碰狠狠躁久久躁婷婷| 国产91露脸合集magnet| 欧美精品日韩在线| 精品久久久久久久久久久久久| 97在线播放免费观看| 国产亚洲精品一区二区| xxxx另类黑人| 91亚洲精品在线观看| 国产精品免费99久久久| 一卡二卡三卡视频| 国产精品一二三| 欧美xxxooo| 在线免费观看日本欧美| 天天爱天天干天天操| 欧美精品在线第一页| 国产精品伦一区二区| 欧美大香线蕉线伊人久久| 欧美午夜一区| 亚洲欧美一区二区三区不卡| 中文字幕日韩一区二区| 在线观看免费中文字幕| 一本色道久久88亚洲综合88| 欧美91看片特黄aaaa| 精选一区二区三区四区五区| 在线看片一区| 少妇搡bbbb搡bbb搡打电话| 亚洲婷婷在线视频| 在线免费看av的网站| 国产一区二区黄| 99欧美精品| 日韩久久久久久久| 爽爽淫人综合网网站| 欧美熟妇一区二区| 日韩欧美在线观看| 蜜桃免费在线| 国产精品9999| 欧美伦理在线视频| 日日噜噜夜夜狠狠| 中文av一区特黄| 中文字幕有码视频| 日韩一区视频在线| 亚洲狼人在线| 欧美少妇一区二区三区| 国产精品一品二品| 久久久久久久久精| 精品成人一区二区三区| av日韩中文| 欧美日韩成人一区二区三区| 久久久亚洲一区| 快灬快灬一下爽蜜桃在线观看| 在线免费视频一区二区| 91在线品视觉盛宴免费| 成人免费午夜电影| 欧美午夜a级限制福利片| 熟妇高潮一区二区| 精品美女永久免费视频| 欧美色图另类| 国产精品爱久久久久久久| 日韩一区电影| 久久久国产精品久久久| 午夜精品福利一区二区蜜股av| 色天堂在线视频| 国产精品香蕉在线观看| 欧美高清一区| 黄色国产在线观看| 欧美在线视频日韩| 黄色在线播放网站| 成人自拍性视频| 亚洲v在线看| japanese在线观看| 日本乱人伦aⅴ精品| 免费日本一区二区三区视频| 91在线精品视频| 亚洲免费影视| 亚洲熟女毛茸茸| 欧美videofree性高清杂交| 中文字幕在线直播| 自拍偷拍一区二区三区| 粉嫩高潮美女一区二区三区| 日本黄色中文字幕| 精品少妇一区二区30p| 秋霞在线一区| 久久久精品高清| 欧美日韩国产综合新一区| 欧美三级黄网| 久久草.com| 韩国精品免费视频| 特黄视频免费看| 久久亚洲精品一区二区| 先锋影音国产精品| 在线观看国产一级片| 欧美日韩国产中文字幕| 成人短视频在线观看| 欧美一区二区三区精美影视| 国产aⅴ综合色|