久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    Mac OS X 背后的故事(八)三好學(xué)生Chris Lattner的LLVM編譯工具鏈

     方海龍的書館 2014-12-22

    文 / 王越

    2011年12月3日,LLVM 3.0正式版發(fā)布,完整支持所有ISO C 標(biāo)準(zhǔn)和大部分C 0x的新特性, 這對于一個(gè)短短幾年的全新項(xiàng)目來說非常不易。

    開發(fā)者的驚愕

    在2011年WWDC(蘋果全球開發(fā)者大會)的一場與Objective-C相關(guān)的講座上,開發(fā)者的人生觀被顛覆了。

    作為一個(gè)開發(fā)者,管理好自己程序所使用的內(nèi)存是天經(jīng)地義的事,好比人們在溜狗時(shí)必須清理狗的排泄物一樣(美國隨處可見“Clean up after your dogs”的標(biāo)志)。在本科階段上C語言的課程時(shí),教授們會向?qū)W生反復(fù)強(qiáng)調(diào):如果使用malloc函數(shù)申請了一塊內(nèi)存,使用完后必須再使用free函數(shù)把申請的內(nèi)存還給系統(tǒng)——如果不還,會造成“內(nèi)存泄漏”的結(jié)果。這對于Hello World可能還不算嚴(yán)重,但對于龐大的程序或是長時(shí)間運(yùn)行的服務(wù)器程序,泄內(nèi)存是致命的。如果沒記住,自己還清理了兩次,造成的結(jié)果則嚴(yán)重得多——直接導(dǎo)致程序崩潰

    Objective-C有類似malloc/free的對子,叫alloc/dealloc,這種原始的方式如同管理C內(nèi)存一樣困難。所以O(shè)bjective-C中的內(nèi)存管理又增加了“引用計(jì)數(shù)”的方法,也就是如果一個(gè)物件被別的物件引用一次,則引用計(jì)數(shù)加一;如果不再被該物件引用,則引用計(jì)數(shù)減一;當(dāng)引用計(jì)數(shù)減至零時(shí),則系統(tǒng)自動清掉該物件所占的內(nèi)存。具體來說,如果我們有一個(gè)字符串,當(dāng)建立時(shí),需要使用alloc方法來申請內(nèi)存,引用計(jì)數(shù)則變成了一;然后被其他物件引用時(shí),需要用retain方法去增加它的引用計(jì)數(shù),變成二。當(dāng)它和剛才引用的物件脫離關(guān)聯(lián)時(shí),需使release方法減少引用計(jì)數(shù),又變回了一;最后,使用完這個(gè)字符串時(shí),再用release方法減少其引用計(jì)數(shù),這時(shí),運(yùn)行庫發(fā)現(xiàn)其引用計(jì)數(shù)變?yōu)榱懔耍瑒t回收走它的內(nèi)存。這是手動的方式

    這種方式自然很麻煩,所以又設(shè)計(jì)出一種叫做autorelease的機(jī)制(不是類似Java的自動垃圾回收)。在Objective-C中,設(shè)計(jì)了一個(gè)叫做NSAutoReleasePool的池,當(dāng)開發(fā)者需要完成一個(gè)任務(wù)時(shí)(比如每開啟一個(gè)線程,或者開始一個(gè)函數(shù)),可以手動創(chuàng)立一個(gè)這樣的池子, 然后通過顯式申明把物件扔進(jìn)自動回收池中。NSAutoReleasePool內(nèi)有一個(gè)數(shù)組來保存聲明為autorelease的所有對象。如果一個(gè)對象聲明為autorelease,則會自動加到池子里。如果完成了一個(gè)任務(wù)(結(jié)束線程了,或者退出那個(gè)函數(shù)),則開發(fā)者需對這個(gè)池子發(fā)送一個(gè)drain消息。這時(shí),NSAutoReleasePool會對池子中所有的物件發(fā)送release消息,把它們的引用計(jì)數(shù)都減一 ——這就好比游泳池關(guān)門時(shí)通知所有客人都“滾蛋”一樣。所以開發(fā)者無需顯式聲明release,所有的物件也會在池子清空時(shí)自動呼叫release函數(shù),如果引用計(jì)數(shù)變成零了,系統(tǒng)才回收那塊內(nèi)存。所以這是個(gè)半自動、半手動的方式

    Objective-C的這種方式雖然比起C來進(jìn)了一大步,我剛才花了幾分鐘就和讀者講明白了。只要遵守上面這兩個(gè)簡單的規(guī)則,就可以保證不犯任何錯(cuò)誤。但這和后來的Java自動垃圾回收相比則是非常繁瑣的,哪怕是再熟練的開發(fā)者,一不小心就會弄錯(cuò)。而且,哪怕很簡單的代碼,比如物件的getter/setter函數(shù),都需要用戶寫上一堆的代碼來管理接收來的物件的內(nèi)存。

    經(jīng)典教材《Cocoa Programming for Mac OS X》用了整整一章節(jié)的篇幅,來講解Objective-C中內(nèi)存管理相關(guān)的內(nèi)容,但初學(xué)者們看得還是一頭霧水。所以,在2007年10.5發(fā)布時(shí),Objective-C做出了有史以來最大的更新,最大的亮點(diǎn)是它的運(yùn)行庫libobjc 2.0正式支持自動垃圾回收,也就是由運(yùn)行庫在運(yùn)行時(shí)隨時(shí)偵測哪些物件需要被釋放。聽上去很不錯(cuò),可惜使用這個(gè)技術(shù)的項(xiàng)目卻少之又少。原因很簡單,使用這個(gè)特性,會有很大的性能損失,使Objective-C的內(nèi)存管理效率低得和Java一樣,而且一旦有一個(gè)模塊啟用了這個(gè)特性,這個(gè)進(jìn)程中所有的地方都要啟用這個(gè)特性——因此如果你寫了一個(gè)使用垃圾回收的庫,那所有引用你庫的程序就都得被迫使用垃圾回收。所以Apple自己也不使用這項(xiàng)技術(shù),大量的第三方庫也不使用它。

    這個(gè)問題隨Apple在移動市場的一炮走紅而變得更加嚴(yán)峻。不過這次,Apple和與會的開發(fā)者講,他們找到了一個(gè)解決問題的終極方法,這個(gè)方法把從世界各地專程趕來聆聽圣諭的開發(fā)者驚得目瞪口呆——你不用寫任何內(nèi)存管理代碼,也不需要使用自動垃圾回收。因?yàn)槲覀兊木幾g器已經(jīng)學(xué)會了上面所介紹的內(nèi)存管理規(guī)則,會自動在編譯程序時(shí)把這些代碼插進(jìn)去。

    這個(gè)編譯器,一直是Apple公開的秘密——LLVM。說它公開,是因?yàn)樗允贾两K都是一個(gè)開源項(xiàng)目;而秘密,則是因?yàn)樗鼜膩頉]公開在WWDC的Keynote演講上亮相過 。

    一直關(guān)注這系列連載的讀者一定還記得,在第二篇《Linus Torvalds的短視》介紹Apple和GPL社區(qū)的不合時(shí),提到過“自以為是但代碼又寫得差的開源項(xiàng)目,Apple事后也遇到不少,比如GCC編譯器項(xiàng)目組。雖然大把鈔票扔進(jìn)去,在先期能夠解決一些問題,但時(shí)間長了這群人總和Apple過不去,并以自己在開源世界的地位恫嚇之,最終Apple由于受不了這些項(xiàng)目組的態(tài)度、協(xié)議、代碼質(zhì)量,覺得還不如自己造輪子來得方便。”LLVM則是Apple造的這個(gè)輪子,它的目的是完全替代掉GCC那條編譯鏈。它的主要作者,則是現(xiàn)在就職于Apple的Chris Lattner。

    編譯器高材生Chris Lattner

    2000年,本科畢業(yè)的Chris Lattner像中國多數(shù)大學(xué)生一樣,按部就班地考了GRE,最終前往UIUC(伊利諾伊大學(xué)厄巴納香檳分校),開始了艱苦讀計(jì)算機(jī)碩士和博士的生涯。在這階段,他不僅周游美國各大景點(diǎn),更是努力學(xué)習(xí)科學(xué)文化知識,翻爛了“龍書”(《Compilers: Principles, Techniques, and Tools》),成了GPA牛人【注:最終學(xué)分積4.0滿分】,以及不斷地研究探索關(guān)于編譯器的未知領(lǐng)域,發(fā)表了一篇又一篇的論文,是中國傳統(tǒng)觀念里的“三好學(xué)生”。他的碩士畢業(yè)論文提出了一套完整的在編譯時(shí)、鏈接時(shí)、運(yùn)行時(shí)甚至是在閑置時(shí)優(yōu)化程序的編譯思想,直接奠定了LLVM的基礎(chǔ)。
    LLVM在他念博士時(shí)更加成熟,使用GCC作為前端來對用戶程序進(jìn)行語義分析產(chǎn)生IF(Intermidiate Format),然后LLVM使用分析結(jié)果完成代碼優(yōu)化和生成。這項(xiàng)研究讓他在2005年畢業(yè)時(shí),成為小有名氣的編譯器專家,他也因此早早地被Apple相中,成為其編譯器項(xiàng)目的骨干。

    Apple相中Chris Lattner主要是看中LLVM能擺脫GCC束縛。Apple(包括中后期的NeXT) 一直使用GCC作為官方的編譯器。GCC作為開源世界的編譯器標(biāo)準(zhǔn)一直做得不錯(cuò),但Apple對編譯工具會提出更高的要求。

    一方面,是Apple對Objective-C語言(甚至后來對C語言)新增很多特性,但GCC開發(fā)者并不買Apple的帳——不給實(shí)現(xiàn),因此索性后來兩者分成兩條分支分別開發(fā),這也造成Apple的編譯器版本遠(yuǎn)落后于GCC的官方版本。另一方面,GCC的代碼耦合度太高,不好獨(dú)立,而且越是后期的版本,代碼質(zhì)量越差,但Apple想做的很多功能(比如更好的IDE支持)需要模塊化的方式來調(diào)用GCC,但GCC一直不給做。甚至最近,《GCC運(yùn)行環(huán)境豁免條款 (英文版)》從根本上限制了LLVM-GCC的開發(fā)。 所以,這種不和讓Apple一直在尋找一個(gè)高效的、模塊化的、協(xié)議更放松的開源替代品,Chris Lattner的LLVM顯然是一個(gè)很棒的選擇。

    剛進(jìn)入Apple,Chris Lattner就大展身手:首先在OpenGL小組做代碼優(yōu)化,把LLVM運(yùn)行時(shí)的編譯架在OpenGL棧上,這樣OpenGL棧能夠產(chǎn)出更高效率的圖形代碼。如果顯卡足夠高級,這些代碼會直接扔入GPU執(zhí)行。但對于一些不支持全部OpenGL特性的顯卡(比如當(dāng)時(shí)的Intel GMA卡),LLVM則能夠把這些指令優(yōu)化成高效的CPU指令,使程序依然能夠正常運(yùn)行。這個(gè)強(qiáng)大的OpenGL實(shí)現(xiàn)被用在了后來發(fā)布的Mac OS X 10.5上。同時(shí),LLVM的鏈接優(yōu)化被直接加入到Apple的代碼鏈接器上,而LLVM-GCC也被同步到使用GCC4代碼。

    LLVM真正的發(fā)跡,則得等到Mac OS X 10.6 Snow Leopard登上舞臺。可以說, Snow Leopard的新功能,完全得益于LLVM的技術(shù)。而這一個(gè)版本,也是將LLVM推向真正成熟的重大機(jī)遇。

    關(guān)于Snow Leopard的三項(xiàng)主推技術(shù)(64位支持、OpenCL,以及Grand Central Dispatch)的細(xì)節(jié),我們會在下一次有整整一期篇幅仔細(xì)討論,這次只是點(diǎn)到為止——我們告訴讀者,這些技術(shù),不但需要語言層面的支持(比如Grand Centrual Dispatch所用到的“代碼塊”語法, 這被很多人看作是帶lambda的C),也需要底層代碼生成和優(yōu)化(比如OpenCL是在運(yùn)行時(shí)編譯為GPU或CPU代碼并發(fā)執(zhí)行的)。而這些需求得以實(shí)現(xiàn),歸功于LLVM自身的新前端——Clang。

    優(yōu)異的答卷——Clang

    前文提到,Apple吸收Chris Lattner的目的要比改進(jìn)GCC代碼優(yōu)化宏大得多——GCC系統(tǒng)龐大而笨重,而Apple大量使用的Objective-C在GCC中優(yōu)先級很低。此外GCC作為一個(gè)純粹的編譯系統(tǒng),與IDE配合得很差。加之許可證方面的要求,Apple無法使用LLVM 繼續(xù)改進(jìn)GCC的代碼質(zhì)量。于是,Apple決定從零開始寫 C、C 、Objective-C語言的前端 Clang,完全替代掉GCC。

    正像名字所寫的那樣,Clang只支持C,C 和Objective-C三種C家族語言。2007年開始開發(fā),C編譯器最早完成,而由于Objective-C相對簡單,只是C語言的一個(gè)簡單擴(kuò)展,很多情況下甚至可以等價(jià)地改寫為C語言對Objective-C運(yùn)行庫的函數(shù)調(diào)用,因此在2009年時(shí),已經(jīng)完全可以用于生產(chǎn)環(huán)境。C 的支持也熱火朝天地進(jìn)行著。

    Clang的加入代表著LLVM真正走向成熟和全能,Chris Lattner以影響他最大的“龍書”封面【注:見http://en./wiki/Dragon_Book_(computer_science)】為靈感,為項(xiàng)目選定了圖標(biāo)——一條張牙舞爪的飛龍

    Clang一個(gè)重要的特性是編譯快速,占內(nèi)存少,而代碼質(zhì)量還比GCC來得高。測試結(jié)果表明Clang編譯Objective-C代碼時(shí)速度為GCC的3倍【注:http:///pubs/2007-07-25-LLVM-2.0-and-Beyond.pdf】,而語法樹(AST)內(nèi)存占用則為被編譯源碼的1.3倍,而GCC則可以輕易地可以超過10倍。Clang不但編譯代碼快,對于用戶犯下的錯(cuò)誤,也能夠更準(zhǔn)確地給出建議。使用過GCC的讀者應(yīng)該熟悉,GCC給出的錯(cuò)誤提示基本都不是給人看的。

    比如最簡單的:

    struct foo { int x; }
    typedef int bar;

    如果使用GCC編譯,它將告訴你:
    t.c:3: error: two or more data types in declaration specifiers

    但是Clang給出的出錯(cuò)提示則顯得人性化得多:
    t.c:1:22: error: expected “;” after struct

    甚至,Clang可以根據(jù)語境,像拼寫檢查程序一樣地告訴你可能的替代方案。
    比如這個(gè)程序:

    #include <inttypes.h>
    int64 x;

    GCC一樣給出亂碼似的出錯(cuò)提示:

    t.c:2: error: expected “=”, “,”, “;”, “asm” or “__attribute__” before “x”

    而優(yōu)雅的Clang則用彩色的提示告訴你是不是拼錯(cuò)了,并給出可能的變量名:

    t.c:2:1: error: unknown type name “int64″; did you mean “int64_t”?
    int64 x;^~~~~int64_t

    更多的例子可以參考http://blog./2010/04/amazing-feats-of-clang-error-recovery.html。 而同時(shí)又因?yàn)镃lang是高度模塊化的一個(gè)前端,很容易實(shí)現(xiàn)代碼的高度重用。所以比如Xcode 4.0的集成編程環(huán)境就使用Clang的模塊來實(shí)現(xiàn)代碼的自動加亮、代碼出錯(cuò)的提示和自動的代碼補(bǔ)全。開發(fā)者使用Xcode 4.0以后的版本,可以極大地提高編程效率,盡可能地降低編譯錯(cuò)誤的發(fā)生率。

    支持C 也是Clang的一項(xiàng)重要使命。C 是一門非常復(fù)雜的語言,大多編譯器(如GCC、MSVC)用了十多年甚至二十多年來完善對C 的支持,但效果依然不很理想。Clang的C 支持卻一直如火如荼地展開著。2010年2月4日,Clang已經(jīng)成熟到能自舉(即使用Clang編譯Clang,到我發(fā)稿時(shí),LLVM 3.0發(fā)布已完整支持所有ISO C 標(biāo)準(zhǔn),以及大部分C 0x的新特性

    這對于一個(gè)短短幾年的全新項(xiàng)目來說是非常不易的。得益于本身健壯的架構(gòu)和Apple的大力支持,Clang越來越全能,從FreeBSD【注:http://lists./pipermail/freebsd-current/2009-February/003743.html】 到Linux Kernel【注:http://lists.cs./pipermail/cfe-dev/2010-October/011711.html】, 從Boost【注:http://blog./2010/05/clang-builds-boost.html】 到Java虛擬機(jī), Clang支持的項(xiàng)目越來越多。

    Apple的Mac OS X以及iOS也成了Clang和LLVM的主要試驗(yàn)場——10.6時(shí)代,很多需要高效運(yùn)行的程序比如OpenSSL和Hotspot就由LLVM-GCC編譯來加速的。而10.6時(shí)代的Xcode 3.2諸多圖形界面開發(fā)程序如Xcode、Interface Builder等,皆由Clang編譯。到了Mac OS X 10.7,整個(gè)系統(tǒng)的的代碼都由Clang或LLVM-GCC編譯【注:http:///Users.html】。

    LLVM周邊工具

    由于受到Clang項(xiàng)目的威脅,GCC也不得不軟下來,讓自己變得稍微模塊化一些,推出插件的支持,而LLVM項(xiàng)目則順?biāo)浦郏餍詮U掉了出道時(shí)就一直作為看家本領(lǐng)的LLVM-GCC,改為一個(gè)GCC的插件DragonEgg。 Apple也于Xcode 4.2徹底拋棄了GCC工具鏈。

    而Clang的一個(gè)重要衍生項(xiàng)目,則是靜態(tài)分析工具,能夠通過自動分折程序的邏輯,在編譯時(shí)就找出程序可能的bug。在Mac OS X 10.6時(shí),靜態(tài)分析被集成進(jìn)Xcode 3.2,幫助用戶查找自己犯下的錯(cuò)誤。其中一個(gè)功能,就是告訴用戶內(nèi)存管理的Bug,比如alloc了一個(gè)物件卻忘記使用release回收。這已經(jīng)是一項(xiàng)很可怕的技術(shù),而Apple自己一定使用它來發(fā)現(xiàn)并改正Mac OS X整個(gè)系統(tǒng)各層面的問題。但許多開發(fā)者還不滿足——既然你能發(fā)現(xiàn)我漏寫了release,你為什么不能幫我自動加上呢?于是ARC被,發(fā)生了文章開頭開發(fā)者們的驚愕——從來沒有人覺得這件事是可以做成的。

    除LLVM核心和Clang以外,LLVM還包括一些重要的子項(xiàng)目,比如一個(gè)原生支持調(diào)試多線程程序的調(diào)試器LLDB,和一個(gè)C 的標(biāo)準(zhǔn)庫libc ,這些項(xiàng)目由于是從零重寫的,因此要比先前的很多項(xiàng)目站得更高,比如先前GNU、Apache、STLport等C 標(biāo)準(zhǔn)庫在設(shè)計(jì)時(shí),C 0x標(biāo)準(zhǔn)還未公布,所以大多不支持這些新標(biāo)準(zhǔn)或者需要通過一些骯臟的改動才能支持,而libc 則原生支持C 0x。而且在現(xiàn)代架構(gòu)上,這些項(xiàng)目能動用多核把事情處理得更好。

    不單單是Apple,諸多的項(xiàng)目和編程語言都從LLVM里取得了關(guān)鍵性的技術(shù)。Haskell語言編譯器GHC使用LLVM作為后端,實(shí)現(xiàn)了高質(zhì)量的代碼編譯。很多動態(tài)語言實(shí)現(xiàn)也使用LLVM作為運(yùn)行時(shí)的編譯工具,較著名的有Google的Unladen Swallow【注:Python實(shí)現(xiàn),后夭折】、PyPy【注:Python實(shí)現(xiàn)】,以及MacRuby【注:Ruby實(shí)現(xiàn)】。例如 MacRuby 后端改為LLVM后,速度不但有了顯著的提高,更是支持Grand Central Dispatch來實(shí)現(xiàn)高度的并行運(yùn)行。由于LLVM高度的模塊化,很方便重用其中的組件來作為一個(gè)實(shí)現(xiàn)的重要組成部分,因此類似的項(xiàng)目會越來越多。

    LLVM的成熟也給其他痛恨GCC的開發(fā)項(xiàng)目出了一口惡氣。其中最重要的,恐怕是以FreeBSD為代表的BSD社區(qū)。BSD社區(qū)和Apple的聯(lián)系一向很緊密,而且由于代碼相似,很多Apple的技術(shù)如Grand Central Dispatch也是最早移植到FreeBSD上。BSD社區(qū)很早就在找GCC的替代品,無奈大多都很差(如Portable C Compiler產(chǎn)生的代碼質(zhì)量和gcc不能同日而語)。

    一方面是因?yàn)椴粷M意GCC的代碼品質(zhì)【注:BSD代碼整體要比GNU的高一些,GNU代碼永無休止地出現(xiàn)各種嚴(yán)重的安全問題】,更重要的是協(xié)議問題。BSD開發(fā)者有潔癖的居多,大多都不喜歡GPL代碼,尤其是GPL協(xié)議第三版發(fā)布時(shí),和FreeBSD的協(xié)議甚至是沖突的。這也正是為什么FreeBSD中包含的GNU的C 運(yùn)行庫還是2007年以GPLv2發(fā)布的老版本,而不是支持C 0x的但依GPLv3協(xié)議發(fā)布的新版本。 因此歷時(shí)兩年的開發(fā)后,2012年初發(fā)布的FreeBSD 9.0中,Clang被加入到FreeBSD的基礎(chǔ)系統(tǒng)。 但這只是第一步,因?yàn)镕reeBSD中依然使用GNU的C STL 庫、C 運(yùn)行庫、GDB調(diào)試器、libgcc/libgcc_s編譯庫都是和編譯相關(guān)的重要底層技術(shù),先前全被GNU壟斷,而現(xiàn)在LLVM子項(xiàng)目lldb、libc 、compiler-rt等項(xiàng)目的出現(xiàn),使BSD社區(qū)有機(jī)會向GNU說“不”,因此一個(gè)把GNU組件移出FreeBSD的計(jì)劃被構(gòu)想出來,并完成了很大一部分。編寫過《Cocoa Programming Developer”s Handbook》的著名Objective-C牛人David Chisnall也被吸收入FreeBSD開發(fā)組完成這個(gè)計(jì)劃的關(guān)鍵部分。 預(yù)計(jì)在FreeBSD 10發(fā)布時(shí),將不再包含GNU代碼。

    LLVM在短短五年內(nèi)取得的快速發(fā)展充分反映了Apple對于產(chǎn)品技術(shù)的遠(yuǎn)見和處理爭端的決心和手腕,并一躍成為最領(lǐng)先的開源軟件技術(shù)。而Chris Lattner在2010年也贏得了他應(yīng)有的榮譽(yù)——Programming Languages Software Award(程序設(shè)計(jì)語言軟件獎(jiǎng))

    作者王越,美國賓夕法尼亞大學(xué)計(jì)算機(jī)系研究生,中國著名TeX開發(fā)者,非著名OpenFOAM開發(fā)者。

     Mac OS X 背后的故事系列更多精彩內(nèi)容

    本文選自《程序員》雜志2012年01期,更多精彩內(nèi)容敬請關(guān)注01期雜志

    《程序員》2012年雜志訂閱送好禮活動火熱進(jìn)行中

      本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
      轉(zhuǎn)藏 分享 獻(xiàn)花(0

      0條評論

      發(fā)表

      請遵守用戶 評論公約

      類似文章 更多

      主站蜘蛛池模板: 人妻久久久一区二区三区| 国产在线亚州精品内射| 欧美综合婷婷欧美综合五月| 呦交小U女精品视频| 亚洲AV中文无码乱人伦在线视色| 国产精品一区中文字幕| 国产曰批视频免费观看完| 欧美国产日韩A在线观看| 唐人社视频呦一区二区| 国产精品久久久久无码AV| 日本高清一区免费中文视频| 国产成人久久精品一区二区三区| 亚洲精品日韩中文字幕| 久久伊人精品青青草原APP| 日韩精品国产二区三区| 精品日本一区二区三区在线观看 | 欧美激情一区二区三区成人 | 99欧美日本一区二区留学生| 欧美野外伦姧在线观看| 欧洲卡一卡二卡三爱区| 亚洲国产成人资源在线| 国产69精品久久久久999小说| 东京热人妻丝袜无码AV一二三区观| 精品久久人人妻人人做精品| 成 人 在 线 免费观看| 公天天吃我奶躁我的在线观看| 精品国产一区AV天美传媒| 国产精品福利自产拍久久| 欧美午夜片欧美片在线观看| 久久天天躁夜夜躁狠狠| 亚洲人成电影网站 久久影视| 大香区一二三四区2021| 中文字幕乱码一区二区免费| 护士张开腿被奷日出白浆| 人妻影音先锋啪啪AV资源| 亚洲国产日韩一区三区| 日本午夜精品一区二区三区电影 | 久久久噜噜噜久久| 男人狂桶女人高潮嗷嗷| 日韩中文字幕高清有码| 亚洲国产成人无码网站|