• <tr id="yyy80"></tr>
  • <sup id="yyy80"></sup>
  • <tfoot id="yyy80"><noscript id="yyy80"></noscript></tfoot>
  • 99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看 ?

    一種結(jié)構(gòu)信息增強(qiáng)的代碼修改自動轉(zhuǎn)換方法*

    2021-05-23 06:11:56曹英魁孫澤宇鄒艷珍
    軟件學(xué)報(bào) 2021年4期
    關(guān)鍵詞:編碼器示例代碼

    曹英魁 ,孫澤宇 ,鄒艷珍 ,謝 冰

    1(北京大學(xué) 信息科學(xué)技術(shù)學(xué)院,北京 100871)

    2(高可信軟件技術(shù)教育部重點(diǎn)實(shí)驗(yàn)室(北京大學(xué)),北京 100871)

    1 引 言

    在開發(fā)過程中,開發(fā)人員常常面臨著相似的代碼修改任務(wù),而完成這些任務(wù)不僅需要耗費(fèi)開發(fā)人員大量的時間和精力,同時,開發(fā)人員在完成重復(fù)的任務(wù)時又容易引入新的錯誤[1,2].得益于不同形式的版本控制系統(tǒng),軟件項(xiàng)目的演化歷史得以完整地記錄下來.在這些演化歷史中,存在著豐富的代碼修改場景和修改方案[3-6].基于已有的相似代碼修改,研究人員開始關(guān)注于相似代碼自動轉(zhuǎn)換方法的研究,即:給定一組示例代碼修改,通過對修改示例的修改方式進(jìn)行抽取和表示,并基于表示結(jié)果來實(shí)現(xiàn)對相似代碼的自動修改.

    在早期工作中,代碼修改的自動轉(zhuǎn)換多是采用人工特征工程的方式[7-11],即人工地提出規(guī)則對修改示例中的修改方案的適配條件、修改過程和修改結(jié)果進(jìn)行限定和說明.然而,這些規(guī)則的提出往往基于研究人員對特定語言的專家知識,并需要耗費(fèi)大量的時間精力來總結(jié)、提煉.近來,采用基于機(jī)器學(xué)習(xí)的代碼轉(zhuǎn)換方法[12,13]不斷涌現(xiàn)出來.常見的做法是采用端到端的翻譯模式,將待修改的代碼“翻譯”為修改后的代碼.然而,現(xiàn)有的工作尚未對修改示例的結(jié)構(gòu)信息充分加以使用.一方面,一些現(xiàn)有工作利用翻譯模型,直接將修改前的代碼“翻譯”為修改后的代碼.然而,在缺失修改示例信息的條件下,試圖訓(xùn)練一個全局的翻譯模型來處理代碼轉(zhuǎn)換任務(wù),無疑是十分困難的.另一方面,相比于自然語言,代碼內(nèi)的信息存在著更為顯著的長程依賴.如圖1 所示,函數(shù)調(diào)用fis.close()中的變量名fis,與最初聲明的變量名為同一個變量.現(xiàn)有工作在采用時序模型對代碼信息建模時,由于兩處代碼間隔很遠(yuǎn),很難捕獲兩處變量間的依賴關(guān)系.

    Fig.1 Long dependency among variable names圖1 變量名間的長程依賴

    針對上述問題,本文提出了一種利用結(jié)構(gòu)信息增強(qiáng)代碼轉(zhuǎn)換的方法ExpTrans.一方面,給定修改示例,方法將修改前和修改后的代碼解析為抽象語法樹,并尋找其節(jié)點(diǎn)間的對應(yīng)關(guān)系.基于節(jié)點(diǎn)間的對應(yīng)關(guān)系,方法采用圖的形式來表示給定的示例代碼修改,以增強(qiáng)模型對代碼修改中的結(jié)構(gòu)信息的捕獲能力;另一方面,方法通過將圖卷積網(wǎng)絡(luò)和Transformer 架構(gòu)[14]有效地結(jié)合來增強(qiáng)模型對代碼間的依賴信息,尤其是長程依賴關(guān)系的捕獲能力.

    方法整體上遵循encoder-decoder 的架構(gòu)設(shè)計(jì).其中,編碼器分別對待修改代碼、修改示例代碼以及中間信息進(jìn)行建模;解碼器依據(jù)編碼器的編碼結(jié)果,預(yù)測轉(zhuǎn)換后的代碼.為了保證方法產(chǎn)生的代碼的可編譯性,方法在預(yù)測修改后的代碼時,借鑒了Yin 和Sun 等人的工作[15,16],以預(yù)測指令序列的方式來產(chǎn)生代碼.所謂指令,形如α→β1β2…,其所代表的含義是在代碼的抽象語法樹中的類型為α的節(jié)點(diǎn)上,插入子節(jié)點(diǎn),類型分別為β1、β2….具體地,在產(chǎn)生代碼的過程中,方法將維持一棵表示中間結(jié)果的抽象語法樹,并基于預(yù)測的下一條指令,對當(dāng)前最左的待擴(kuò)展的節(jié)點(diǎn)進(jìn)行擴(kuò)充,直至所有的非葉子節(jié)點(diǎn)被擴(kuò)展完畢,所生成的抽象語法樹所對應(yīng)的代碼即為轉(zhuǎn)換后的代碼.

    為了驗(yàn)證方法的有效性,本文在兩個數(shù)據(jù)集上進(jìn)行了對比實(shí)驗(yàn).第1 個數(shù)據(jù)集是Yin 等人對外開放的111 724個C#代碼修改[13].實(shí)驗(yàn)結(jié)果表明,對比Yin 的工作(基于深度學(xué)習(xí))[13],本文方法在準(zhǔn)確率上有11.8%~30.8%的提升.第2 個數(shù)據(jù)集是從GitHub 上收集整理的6 組Java 語言典型的相似代碼修改.在該數(shù)據(jù)集上,分別將本文方法、GenPat 方法[17](基于人工規(guī)則)和ARES 方法[10](基于人工規(guī)則)用于自動修改這些代碼實(shí)例.實(shí)驗(yàn)結(jié)果表明,在每組數(shù)據(jù)中,均有實(shí)例被ExpTrans 正確修改,并且在一組數(shù)據(jù)上的實(shí)例全部被ExpTrans 正確修改.相比于GenPat 和ARES 方法的結(jié)果,ExpTrans 的結(jié)果在準(zhǔn)確率和正確修改的實(shí)例的數(shù)量上,均有大幅度提升.

    本文的貢獻(xiàn)主要表現(xiàn)在:(1) 提出了一種基于圖的代碼修改表示方法.相比采用單詞序列的表示方式,圖結(jié)構(gòu)能夠更加準(zhǔn)確地表示代碼修改過程,增強(qiáng)了方法對代碼修改中結(jié)構(gòu)信息的捕獲能力.(2) 提出了一種基于Transformer 架構(gòu)的結(jié)構(gòu)信息增強(qiáng)的代碼修改自動轉(zhuǎn)換方法.該方法采用特殊的copy 指令顯式地表示代碼間廣泛存在的變量聲明與使用的依賴關(guān)系,增加了模型對代碼中長程依賴信息的捕獲能力.(3) 本文在兩個數(shù)據(jù)集上開展了對比實(shí)驗(yàn)并將數(shù)據(jù)全部公開(https://github.com/caoyingkui/ExpTrans).相比于現(xiàn)有的機(jī)器學(xué)習(xí)方法,本文方法ExpTrans 在準(zhǔn)確率上提升了11.8%~30.8%.對比基于人工規(guī)則的方法,在修改實(shí)例的準(zhǔn)確率和正確修改的實(shí)例數(shù)量上均有顯著提升.

    本文第2 節(jié)介紹已有的相關(guān)工作.第3 節(jié)介紹基于預(yù)測指令序列的代碼產(chǎn)生方式,以及本文方法的整體框架.第4 節(jié)介紹本文方法的具體實(shí)現(xiàn)細(xì)節(jié).第5 節(jié)介紹為了驗(yàn)證方法有效性而開展的實(shí)驗(yàn)以及實(shí)驗(yàn)設(shè)置和實(shí)驗(yàn)結(jié)果.最后,第6 節(jié)對本文工作進(jìn)行總結(jié).

    2 相關(guān)工作

    如前所述,本文的相關(guān)工作分為兩類:一類是基于人工特征的方法,另一類是基于深度學(xué)習(xí)的代碼修改自動轉(zhuǎn)換方法.

    2.1 基于人工特征的方法

    該類工作的主要思路是:基于人工提煉的規(guī)則,從給定的修改示例中,抽取一個代碼轉(zhuǎn)換“腳本”,以對示例中的修改條件、修改模式和修改過程進(jìn)行說明和約束,并可以按照腳本中所約定的方式自動地適配到符合條件的代碼區(qū)域并完成代碼轉(zhuǎn)換.在現(xiàn)有的工作中,這種腳本呈現(xiàn)出代碼編輯序列[7]、模板[8]和特定領(lǐng)域語言(DSL)[11]等多種形式.

    在Meng 等人提出的SYDIT 中,利用一組編輯操作序列來表示代碼轉(zhuǎn)換的過程[7].序列中的編輯操作共包含4 種類型:增加、刪除、修改和移動一個AST 節(jié)點(diǎn),同時利用通配符等方式編輯操作中的類型、位置信息以進(jìn)行泛化.例如,!config.inValid()被表示為!v2.m5().按照順序依次執(zhí)行該序列中的操作,即可將代碼修改為修改后的代碼.LASE 是Meng 等人提出的另外一種代碼轉(zhuǎn)換方法,并依舊利用一組編輯操作序列來表示示例代碼中的代碼轉(zhuǎn)換[9].與SYDIT 不同,LASE 是從多個相似修改示例中抽取代碼轉(zhuǎn)換.

    此外,還有一些現(xiàn)有工作采用模板的形式來表示修改示例中的修改模式.如Andersen 等人提出的方法spdiff[8],該方法從修改示例中抽取一個單詞替換補(bǔ)丁(term replacement patch)用于刻畫示例中的代碼修改方法,并將一組修改示例中最長的公共子補(bǔ)丁作為該組示例代碼修改中的代碼轉(zhuǎn)換.針對LASE 在表示代碼修改模式時,無法準(zhǔn)確地識別代碼語句移動等問題,Dotzler 等人提出方法ARSE.ARSE 同樣是一種基于多示例的代碼轉(zhuǎn)換方法[10].然而,與LASE 不同,ARSE 以模板的方式來表示修改示例中的修改模式.Jiang 等人提出的方法GENPAT 是一種從單一修改示例中抽取代碼轉(zhuǎn)換的方法[17].在該方法中,代碼轉(zhuǎn)換最終以樹形結(jié)構(gòu)的形式加以表示.在該結(jié)構(gòu)中,每一個節(jié)點(diǎn)的信息包括節(jié)點(diǎn)ID 和一組屬性值.同時,GENPAT 的表示結(jié)果中還包含一組操作,其中的每一個操作為一個元組〈id,id'〉,id 和id'分別代表了修改前、后代碼的AST 中的一個節(jié)點(diǎn)并存在對應(yīng)關(guān)系,即節(jié)點(diǎn)id 發(fā)生修改后變?yōu)楣?jié)點(diǎn)id'.

    在Rolim 等人提出的REFAZER 中,定義了一種特殊的DSL(領(lǐng)域特定語言)[11].其主要功能是定義對代碼AST 的操作,以及對符合特定修改的AST 的條件及發(fā)生修改的位置和修改類型進(jìn)行限定.因此,該代碼生成任務(wù)的目標(biāo)為:一段基于該DSL 的代碼.該代碼的輸入為一段修改前的代碼,輸出為修改后的一段代碼.

    2.2 基于深度學(xué)習(xí)的方法

    該類工作的主要思路是:給定待修改的代碼,利用機(jī)器學(xué)習(xí)模型預(yù)測修改后的代碼.Tufano 等人提出了基于翻譯模型完成代碼轉(zhuǎn)化方法[12].具體地,給定一段待修改的代碼作為模型的輸入,并利用翻譯模型直接預(yù)測一個token 序列,作為轉(zhuǎn)換后的代碼.同時,該方法也探索了翻譯模型適合何種類型的代碼轉(zhuǎn)化場景.例如,缺陷修改、代碼重構(gòu).代碼作為一種高度結(jié)構(gòu)化的文本,其功能和可編譯性嚴(yán)格依賴于代碼具體的token 序列和token 間的相互位置關(guān)系.然而,以預(yù)測token 序列方式進(jìn)行工作的翻譯模型,無法從方法層面上保證模型的輸出結(jié)果是可編譯的.為了克服這一問題,在Yin 等人提出的方法中,以預(yù)測指令序列的方式來生成代碼,從而能夠保證模型輸出代碼的語法正確性[15].基于此工作機(jī)制,Yin 等人提出一種基于學(xué)習(xí)的代碼轉(zhuǎn)換模型[13].該模型的輸入,除一段待修改的代碼外,同時輸入一個修改示例的修改前、后的代碼,即通過學(xué)習(xí)修改示例中的代碼轉(zhuǎn)換方式,來指導(dǎo)待修改的代碼轉(zhuǎn)換過程.

    綜上,Yin 等人提出的方法是目前現(xiàn)有工作中與本文最為相關(guān)的方法.在Yin 等人的方法中,利用了LSTM 時序模型用于處理代碼的文本信息.然而,相比于自然語言,代碼存在更為顯著的長程依賴關(guān)系,然而有研究表明,時序模型在處理信息長程依賴時效果并不佳[14].因此,克服代碼的信息長程依賴挑戰(zhàn),是提出本文方法的一個主要的動機(jī).

    3 方法框架

    為了保證方法生成代碼的可編譯性,本文借鑒了Yin 等人的工作[15],采用以預(yù)測指令序列的方式來生成代碼,而非單詞序列.同時,方法在代碼指令集合中,增設(shè)了特殊的copy 指令,以顯式地刻畫代碼中變量間的依賴關(guān)系.在介紹方法框架之前,本節(jié)首先詳細(xì)介紹方法中基于預(yù)測指令序列的代碼產(chǎn)生方式.

    代碼指令.在本文中,所謂指令,指的是形如α→β1β2…的產(chǎn)生式.其中,α為非終結(jié)符,βi為終結(jié)符或非終結(jié)符.在代碼的抽象語法樹上,每個非葉子節(jié)點(diǎn)均對應(yīng)一條指令α→β1β2…,其中,α為該節(jié)點(diǎn)的語法類型,βi為其子節(jié)點(diǎn)的語法類型(或單詞).

    指令集的獲取.給定一棵代碼抽象語法樹,假定其中某個節(jié)點(diǎn)v的語法類型為α,節(jié)點(diǎn)v共有n個子節(jié)點(diǎn),且其語法類型(或單詞)分別為β1,…,βn,則依據(jù)節(jié)點(diǎn)v,可獲取指令r:α→β1…βn.按照由上到下、從左至右的順序依次遍歷抽象語法樹的所有非葉子節(jié)點(diǎn),即可獲取相應(yīng)的代碼指令序列.同時,通過遍歷已有數(shù)據(jù)集中代碼的抽象語法樹,即可獲取指令集{r1,…,rN}.

    在代碼中,由于開發(fā)人員可以采用任何合法的變量名、字符串等,導(dǎo)致代碼中存在比自然語言更為顯著的OOV(out of vocabulary)問題.因此方法對出現(xiàn)在指令中的單詞進(jìn)行限制和預(yù)處理,從而避免所獲取的指令集的規(guī)模過于龐大,不利于方法進(jìn)行建模.具體地,在獲取指令之前,本文統(tǒng)計(jì)了在給定數(shù)據(jù)集中的代碼中出現(xiàn)的所有變量名、字符串、數(shù)字常量、字符常量及其出現(xiàn)的次數(shù),只有當(dāng)出現(xiàn)次數(shù)超過閾值的單詞,才會將其保留.當(dāng)代碼中某個單詞出現(xiàn)次數(shù)低于閾值時,本文方法將采用形如type_id 的形式進(jìn)行替換,其中,type 表示該單詞對應(yīng)的類型,即變量名、字符串、數(shù)字常量或字符常量,id 為其編號.通過這樣的處理,能夠保證所獲取的指令規(guī)模在有限的范圍內(nèi).

    此外,本文在指令集中額外增設(shè)了一類特殊的copy 指令.在代碼中,變量聲明和使用之間隱含著明確的依賴關(guān)系.本文利用增設(shè)的copy 指令,顯示地標(biāo)記變量聲明與使用間的這種依賴關(guān)系.如在圖1 中,語句“fis.close();”中的變量名fis 是由語句“FileInputStream fis=new FileInputStream(new File(dir));”聲明得來.因此,方法在解析fis.close();時,采用copy 指令,以標(biāo)記該變量名fis由復(fù)制之前定義的fis而得來.采用copy 指令主要有兩方面的優(yōu)勢:一方面,顯式地標(biāo)記出變量間依賴關(guān)系的方式,有利于增強(qiáng)后續(xù)模型對變量間的依賴關(guān)系的捕獲能力.另一方面,copy 指令的復(fù)制變量的范圍,是代碼已定義的變量名集合.因此,方法在后續(xù)的預(yù)測過程中,所面臨的預(yù)測空間即為代碼已定義的變量名集合.相比于整個單詞空間,copy 指令縮小了在預(yù)測變量名時的預(yù)測空間,從而能夠提升方法的準(zhǔn)確率.

    預(yù)測指令序列的代碼產(chǎn)生方式.圖2 展示了基于指令序列[r1,…,r7]生成代碼“fis.close();”的過程.給定圖2(a)的指令序列,方法首先初始一個只有根節(jié)點(diǎn)的抽象語法樹,其類型為Statement.基于第1 條指令,即Statement→ExpressionStatement,方法為根節(jié)點(diǎn)插入一個類型為ExpressionStatement 的子節(jié)點(diǎn).如圖2(b)所示,當(dāng)完成前3 條指令后,當(dāng)前的抽象語法樹最下層將含有2 個待擴(kuò)展的節(jié)點(diǎn),分別是Expression 和SimpleName.由于“.”“(”和“)”已經(jīng)是終結(jié)符,因此在后續(xù)過程中,方法將不會對它們進(jìn)行擴(kuò)展.此時,方法將利用下一條指令r4來擴(kuò)展最左邊的待擴(kuò)展的節(jié)點(diǎn)(非終結(jié)符),即左側(cè)的Expression 節(jié)點(diǎn).按照上述方式,最終將產(chǎn)生一棵完整的抽象語法樹.按照從左至右的方式,獲取所有的葉子節(jié)點(diǎn)內(nèi)容,即為所生成的代碼.

    Fig.2 The rule sequences and generation of fis.close();圖2 語句fis.close();對應(yīng)的指令序列和生成過程

    基于上述方式,本文將以預(yù)測指令序列的方式,實(shí)現(xiàn)代碼修改的自動轉(zhuǎn)換.方法的輸入為x和xΔ→yΔ,其中,x為待修改的代碼,xΔ→yΔ表示一個修改示例(xΔ和yΔ分別為修改前、后的代碼).最終的輸出為表示代碼轉(zhuǎn)換后的結(jié)果.在生成代碼的過程中,方法將維持一棵表示中間結(jié)果的抽象語法樹.通過預(yù)測下一條指令,并基于該指令對當(dāng)前的抽象語法樹最左邊待擴(kuò)展的節(jié)點(diǎn)進(jìn)行擴(kuò)展,直至生成最終的代碼.本文將生成代碼的概率形式化地表示為

    其中,r1,…,ri為產(chǎn)生的指令序列.

    圖3 展示了本文方法ExpTrans 的整體框架.

    Fig.3 The neural network of ExpTrans圖3 ExpTrans 的網(wǎng)絡(luò)結(jié)構(gòu)

    方法整體上遵從encoder-decoder 的架構(gòu)模式,主要包含4 個模塊:代碼差異編碼器、代碼編碼器、AST 編碼器和解碼器.這4 個子模塊均采用了Transformer 的多塊(block)架構(gòu)[14],即每一個子模塊均由多個結(jié)構(gòu)相同的塊組成.例如,在代碼差異編碼器中,每一個塊均由相同的網(wǎng)絡(luò)結(jié)構(gòu)組成,包含Graph-conv 層、Self-attention 層、Char-gating 層和Rule-gating 層,并且按照前一塊的輸出為后一塊的輸入的方式進(jìn)行連接.在每一個塊的內(nèi)部結(jié)構(gòu)中,采用殘差連接的方式[18],將相鄰的網(wǎng)絡(luò)層(如Graph-conv 層與Self-attention 層之間)進(jìn)行連接.需要注意的是,圖3 只展示了每個模塊的一個塊.4 個模塊的主要功能如下.

    代碼差異編碼器.方法利用該模塊,對輸入的修改示例xΔ→yΔ的信息進(jìn)行建模.

    代碼編碼器.方法利用該模塊,對輸入的待修改代碼x的信息進(jìn)行建模.

    AST 編碼器.在生成代碼時,方法需要維持一棵表示中間狀態(tài)的抽象語法樹.方法利用該模塊對該抽象語法樹的信息進(jìn)行建模,以期在預(yù)測代碼指令時,能夠提供語法樹的全局信息.

    解碼器.在生成代碼時,解碼器將依據(jù)已生成的抽象語法樹中待擴(kuò)展的節(jié)點(diǎn),預(yù)測一下指令.具體地,方法以待擴(kuò)展的節(jié)點(diǎn)信息作為查詢,輸入解碼器.基于輸入的查詢,解碼器采用注意力機(jī)制來結(jié)合代碼編碼器、代碼差異編碼器和AST 編碼器的建模信息.然后根據(jù)解碼器的輸出,方法結(jié)合softmax 和指針網(wǎng)絡(luò)[19]以預(yù)測下一條指令.

    4 本文方法

    給定待修改代碼x以及修改示例xΔ→yΔ,方法的目標(biāo)是實(shí)現(xiàn)代碼轉(zhuǎn)換其中,為轉(zhuǎn)換后的代碼.本節(jié)將介紹ExpTrans 中不同模塊的具體實(shí)現(xiàn).

    4.1 代碼差異編碼器

    方法利用代碼差異編碼器,對修改示例xΔ→yΔ的修改方式、代碼結(jié)構(gòu)信息進(jìn)行建模.基于xΔ→yΔ,分別將修改前、后代碼xΔ和yΔ表示為抽象語法樹的形式.按照由上到下、從左至右的順序,獲取兩棵語法樹所對應(yīng)的節(jié)點(diǎn)序列然后將兩個序列合并成同一個序列并統(tǒng)一地記為其中,L為方法預(yù)設(shè)的最大長度,前L(ori)個節(jié)點(diǎn)為修改前的節(jié)點(diǎn)序列,隨后L(mod)個節(jié)點(diǎn)為修改后的節(jié)點(diǎn).當(dāng)修改前、后的節(jié)點(diǎn)序列長度小于L時,方法利用特殊的占位符號〈EMPTY〉進(jìn)行擴(kuò)充.代碼差異編碼器將修改示例xΔ→yΔ建模為節(jié)點(diǎn)序列[v1,…,vL],代碼差異編碼器的輸出為其中,為節(jié)點(diǎn)vi的表示向量,H表示空間緯度(在方法中設(shè)定為128).

    4.1.1 代碼差異的圖表示

    修改示例xΔ→yΔ,以修改前、后代碼分離的形式存在,采用單獨(dú)對xΔ和yΔ進(jìn)行建模的方式,將損失修改前、后代碼間的關(guān)聯(lián)關(guān)系及結(jié)構(gòu)信息.為了更加精確地表示xΔ→yΔ中所蘊(yùn)含的代碼修改方式,本文將xΔ→yΔ表示為一個統(tǒng)一的圖G=〈V,E〉,其中,節(jié)點(diǎn)集合V包含xΔ和yΔ所對應(yīng)的抽象語法樹節(jié)點(diǎn)的集合,E為節(jié)點(diǎn)間的連邊集合.

    為了建立xΔ和yΔ節(jié)點(diǎn)間的連邊關(guān)系,本文利用工具GumTree[20]來獲取代碼修改前、后節(jié)點(diǎn)的對應(yīng)關(guān)系.GumTree 是一種基于代碼抽象語法樹的代碼差異抽取工具.在工作時,GumTree 首先獲取修改前、后的代碼xΔ和yΔ所對應(yīng)的抽象語法樹treex和treey.然后按照自底向上的順序,對比treex和treey節(jié)點(diǎn)間的類型信息和文本信息,并據(jù)此計(jì)算節(jié)點(diǎn)的相似度,從而獲取treex和treey節(jié)點(diǎn)間的最佳匹配關(guān)系,并據(jù)此能夠準(zhǔn)確地推導(dǎo)出代碼的修改過程.

    在本文中,當(dāng)節(jié)點(diǎn)vj與節(jié)點(diǎn)vi間存在連邊,且由vj指向vi時,我們稱節(jié)點(diǎn)vj為節(jié)點(diǎn)vi的父節(jié)點(diǎn).進(jìn)一步地,vj的父節(jié)點(diǎn)為vi的祖父節(jié)點(diǎn).結(jié)合工具GumTree 的結(jié)果,當(dāng)節(jié)點(diǎn)vi和vj滿足下列3 種關(guān)系之一時,則建立一條由vj指向vi的連邊,并將該邊加入集合E中.

    (1) 節(jié)點(diǎn)vi和vj均為treex上的節(jié)點(diǎn),且vj為vi的父節(jié)點(diǎn).

    (2) 節(jié)點(diǎn)vi和vj均為treey上的節(jié)點(diǎn),且vj為vi的父節(jié)點(diǎn).

    (3) 節(jié)點(diǎn)vi為treey上的節(jié)點(diǎn),vj為treex上的節(jié)點(diǎn),并且在GumTree 的結(jié)果中,vi和vj存在對應(yīng)關(guān)系.

    基于集合E,可以構(gòu)造節(jié)點(diǎn)間的鄰接矩陣M,當(dāng)vj為vi的父節(jié)點(diǎn)時,M[i][j]=1;否則,M[i][j]=0.例如,現(xiàn)將代碼“fis.close();”修改為“inputFile.close();”,圖4 給出了采用圖結(jié)構(gòu)表示本處代碼修改的過程和結(jié)果.如圖4(a)所示,首先將修改前、后的代碼表示為抽象語法樹的形式(這里,省略了‘.’‘(’等符號以方便展示).基于獲取的抽象語法樹,利用GumTree 來獲取修改前、后代碼抽象語法樹節(jié)點(diǎn)間的對應(yīng)關(guān)系.在圖4(a)中,節(jié)點(diǎn)ni與in'表示兩個節(jié)點(diǎn)存在對應(yīng)關(guān)系.最終,該處代碼修改的圖結(jié)構(gòu)被表示為圖4(b)所示的鄰接矩陣.

    Fig.4 The illustration of construction of code change adjacent matrix圖4 代碼差異鄰接矩陣建立過程示意圖

    4.1.2 編碼信息的抽取

    在計(jì)算Y(diff)之前,方法首先獲取每個節(jié)點(diǎn)不同方面的初始信息.

    節(jié)點(diǎn)的單詞信息.在代碼的抽象語法樹中,每個非葉子節(jié)點(diǎn)均有相應(yīng)的語法類型,每個葉子節(jié)點(diǎn)則對應(yīng)代碼中的一個單詞.基于圖G的節(jié)點(diǎn)序列V,可以得到單詞序列[w1,…,wL].當(dāng)vi為非葉子節(jié)點(diǎn)時,wi為節(jié)點(diǎn)對應(yīng)的語法類型;當(dāng)vi為葉子節(jié)點(diǎn)時,wi為節(jié)點(diǎn)對應(yīng)的單詞.通過embedding 方式,為每個單詞wi初始一個表示向量節(jié)點(diǎn)序列[v1,…,vL]對應(yīng)的單詞信息為

    節(jié)點(diǎn)單詞字符信息.有些語義相似的單詞存在相同的字符序列.例如,同一詞根派生的不同類型的單詞.而上述將單詞作為整體進(jìn)行信息編碼的方式,將丟棄單詞的字符信息.為了在節(jié)點(diǎn)表示向量中引入單詞的字符信息,本文借鑒了Sun 等人對單詞的字符信息進(jìn)行編碼的方法[16].具體地,基于獲取的單詞序列,將每個單詞wi切分為字符序列[ci,1,…,ci,L′],其中,L′為模型預(yù)設(shè)的單詞最大長度.類似地,利用embedding 方式為每個字符ci,j初始一個表示向量并利用全連接層,按照公式(2)的方式,計(jì)算單詞wi的字符表示向量

    節(jié)點(diǎn)指令信息.在抽象語法樹中,每個非葉子節(jié)點(diǎn)vi均對應(yīng)一條指令其中,α(i)為節(jié)點(diǎn)vi對應(yīng)的語法類型,所有β(i)均為節(jié)點(diǎn)vi的子節(jié)點(diǎn)的語法類型或單詞.采用類似公式(2)的方式,方法為每條指令ri:計(jì)算表示向量此外,葉子節(jié)點(diǎn)所對應(yīng)的指令,統(tǒng)一采用特殊指令〈EMPTY_RULE〉進(jìn)行替代.據(jù)此,節(jié)點(diǎn)序列[v1,…,vL]對應(yīng)的節(jié)點(diǎn)指令信息為

    位置信息.在Transformer 的架構(gòu)中,方法將時序數(shù)據(jù)(例如代碼的節(jié)點(diǎn)序列的表示向量)打包成一個向量矩陣,以使得模型能夠并行訓(xùn)練.但這樣的處理方式會丟失數(shù)據(jù)的位置(時序)信息.因此,需要額外添加數(shù)據(jù)的位置信息.在本文中,采用Dehghani 的工作做法[21],利用下列公式人為地構(gòu)造每個節(jié)點(diǎn)的位置信息:

    4.1.3 代碼差異編碼器的網(wǎng)絡(luò)結(jié)構(gòu)

    Graph-conv 層.在將xΔ→yΔ表示為節(jié)點(diǎn)序列后,模型將無法捕獲節(jié)點(diǎn)間的結(jié)構(gòu)信息.因此本文方法利用一層圖卷積層來實(shí)現(xiàn)在每個節(jié)點(diǎn)的表示向量中引入代碼的結(jié)構(gòu)信息.

    基于構(gòu)造的圖G=〈V,E〉和鄰接矩陣M,假定當(dāng)前節(jié)點(diǎn)的表示向量矩陣F=[f1;…;fL],方法將按照公式(5)計(jì)算每個節(jié)點(diǎn)的父節(jié)點(diǎn)的表示向量:

    在卷積時,方法預(yù)設(shè)了卷積窗口K,并按照如下方式進(jìn)行卷積:

    其中,W(conv)為卷積參數(shù),f為Rule 激活函數(shù).

    該層的輸入為節(jié)點(diǎn)的表示向量和節(jié)點(diǎn)的位置信息之和,即I=[xb,1+pb,1;…;xb,L+pb,L],該層的輸出為

    其中,當(dāng)b=1 時(即為第1 個塊),xb,i表示對應(yīng)節(jié)點(diǎn)的單詞信息(即);而對于其他塊,xb,i則為前一塊的輸出.

    Self-attention 層.該層采用了Transformer 中的self-attention 注意力機(jī)制[14],以捕獲代碼間的長程依賴關(guān)系.

    在Transformer 中,注意力機(jī)制被表述為將查詢Q、鍵值對K和V映射到輸出的過程,其中,Q、K和V均為向量矩陣.輸出為對V中分量加權(quán)求和的結(jié)果.而V中每個value 相應(yīng)的權(quán)重將依據(jù)Q與相應(yīng)的關(guān)鍵字K的匹配程度給出,其加權(quán)求和的結(jié)果為

    其中,dk為縮放因子.同時,Transformer 采用multi-head attention 機(jī)制,使得模型能夠從不同的表示空間的角度來注意到不同位置的信息,即:

    特別地,當(dāng)Q、K和V相同時,即形如Multihead(Q,Q,Q)的形式,則被稱為self-attention.該層實(shí)現(xiàn)了selfattention 注意力機(jī)制,該層的輸出為

    Char-gating 層.在該層之前,節(jié)點(diǎn)序列被表示為向量矩陣Y(self),為了在節(jié)點(diǎn)vi的表示向量中引入字符信息方法在該層中采用門機(jī)制,使得節(jié)點(diǎn)的表示向量矩陣更新為Y(self)和Y(char)的加權(quán)和.

    門(gating)機(jī)制的目的在于對不同表示空間的表示結(jié)果進(jìn)行綜合,形成最終的表示向量.給定表示向量f1和f2,門機(jī)制的目標(biāo)是將f1和f2進(jìn)行加權(quán)求和,獲取綜合f1和f2后的表示向量f(gate).其中,f1和f2的權(quán)重按照下列公式進(jìn)行計(jì)算:

    為了保證Y(self)依舊為加權(quán)后的結(jié)果的信息主體,方法首先基于Y(self)通過線性變換的方式獲取控制向量C(self).然后按照下列公式來計(jì)算Y(self)和Y(char)的加權(quán)結(jié)果作為該層的輸出:

    Rule-gating 層.類似地,該層同樣采用門機(jī)制,使得在節(jié)點(diǎn)的表示向量中融合指令字符信息Y(rule),該層的輸出為

    其中,C(char)為通過Y(char-gate)線性變換得來的控制向量.

    最終,代碼差異編碼器的輸出為Y(diff).

    4.2 代碼編碼器

    代碼編碼器的作用是為了實(shí)現(xiàn)對待修改代碼x的信息建模.如圖3 所示,代碼編碼器和差異編碼器的網(wǎng)絡(luò)結(jié)構(gòu)是一致的,只是在獲取該層的輸入方式上有所不同.

    給定待修改代碼x,通過將其解析為抽象語法樹treex,并按照由上到下、從左至右的方式,獲取節(jié)點(diǎn)序列V(x)=基于treex,構(gòu)造圖G(x)=〈V,E〉,其中,V=V(x),E為treex中節(jié)點(diǎn)的連邊集合.此外,方法同樣為G(x)構(gòu)造其節(jié)點(diǎn)間的鄰接矩陣M(x).

    代碼編碼器采用與代碼差異編碼器中相同的數(shù)據(jù)預(yù)處理方式來獲取節(jié)點(diǎn)序列V(x)對應(yīng)的單詞信息、節(jié)點(diǎn)單詞字符信息、節(jié)點(diǎn)指令信息和位置信息.然后,信息依次經(jīng)過Graph-conv 層、Self-attention 層、Char-gating層和Rule-gating 層,并記代碼編碼器的最終輸出為Y(x).

    4.3 AST編碼器

    本文方法在產(chǎn)生代碼的過程中,需要維持一個由已產(chǎn)生指令序列生成的抽象語法樹.方法以當(dāng)前抽象語法樹的最左非葉子節(jié)點(diǎn)(待擴(kuò)展節(jié)點(diǎn))為查詢,預(yù)測下一條指令,并利用預(yù)測的指令對該節(jié)點(diǎn)進(jìn)行擴(kuò)充.因此,需要對產(chǎn)生代碼過程中的抽象語法樹的信息進(jìn)行編碼,以在預(yù)測下一條指令時,能夠?yàn)槟P吞峁┏橄笳Z法樹的全局視圖.在AST 編碼器中,方法利用已產(chǎn)生的指令序列[r1,…,rp]來表示已產(chǎn)生的抽象語法樹.AST 編碼器的目標(biāo)則是:將指令序列最終表示為其中,為指令ri的表示向量,P為方法預(yù)設(shè)的最大指令序列長度.

    4.3.1 編碼信息的提取

    指令的初始向量.利用embedding 方式,為每條指令r初始一條表示向量因此給定指令序列[r1,…,rR],通過查表的方式,獲取指令序列的初始表示向量矩陣

    指令的符號信息.在形如α→β1β2…的指令表示形式中,符號α和βi對于表達(dá)指令的語義信息十分重要.例如,當(dāng)待擴(kuò)展的節(jié)點(diǎn)的類型為Statement 時,則下一條預(yù)測的指令的非終結(jié)符α必須同樣為Statement,以保證代碼的合法性.然而,上述將指令作為整體進(jìn)行編碼的方式,將忽略指令涉及的符號信息.為了在指令的表示向量中引入指令符號序列的信息,本文采用了Sun 的工作方式[16].具體地,給定指令ri:α→β1β2…,α及所有的βj均為標(biāo)準(zhǔn)單詞集中的一個單詞.通過查表的方式,可以獲取每個單詞對應(yīng)的表示向量α(w)或類似公式(2),利用全連接層,以α(w)和所有作為輸入,并將輸出記為最后,再次利用全連接層實(shí)現(xiàn)如下的編碼方式:

    其中,W(rule)為網(wǎng)絡(luò)參數(shù).指令序列[r1,...,rp]對應(yīng)的符號信息為

    位置信息.本文方法同樣利用公式(3)和公式(4)來計(jì)算指令序列的位置信息其中,為第b個塊中的第i條指令的位置信息.

    4.3.2 AST 編碼器的網(wǎng)絡(luò)結(jié)構(gòu)

    Self-attention 層.方法利用一層Self-attention 層來捕獲指令間的依賴關(guān)系.該層結(jié)構(gòu)和代碼差異編碼器中的Self-attention 層的結(jié)構(gòu)是一致的.該層輸入為指令表示向量與位置信息之和,即該層的輸出為

    當(dāng)b=1 時(即為第1 塊),rb,i表示指令ri的初始向量(即);而在其他塊中,rb,i為前一塊的輸出.

    Rule-gating 層.如上文所述,指令的符號信息對于表示指令的語義十分重要,因此,本文方法同樣利用門機(jī)制來實(shí)現(xiàn)對指令符號信息的獲取.與之前的gating 層相似,首先基于R(self)獲取控制變量矩陣C(r-self),然后按照下列公式進(jìn)行計(jì)算:

    Code-attention 層.代碼轉(zhuǎn)換需要依據(jù)待修改代碼x進(jìn)行轉(zhuǎn)換,因此在后續(xù)的代碼指令預(yù)測過程中,模型需要獲取待修改代碼的信息.本文方法利用該層來實(shí)現(xiàn)在指令序列的編碼結(jié)果中,引入待修改代碼x的信息(Y(x)).該層的輸出為

    Diff-attention 層.針對代碼x進(jìn)行修改時,所修改的方式依賴于給定修改示例xΔ→yΔ.因此,在后續(xù)的代碼指令預(yù)測過程中,模型需要修改示例的差異信息.本文方法利用該層來實(shí)現(xiàn)在指令序列的編碼結(jié)果中,引入xΔ→yΔ的信息(Y(diff)).該層的輸出為

    Graph-conv 層.由已生成的代碼指令可以構(gòu)造出局部的抽象語法樹,而預(yù)測的指令均會對應(yīng)特定的節(jié)點(diǎn),因此,指令(節(jié)點(diǎn))間存在有意義的結(jié)構(gòu)關(guān)系.然而,以指令序列的形式表示已生成的抽象語法樹,將會遺失指令間的結(jié)構(gòu)信息.因此,本文方法采用一層圖卷積層,利用代碼的抽象語法樹的結(jié)構(gòu)信息來增強(qiáng)指令的編碼信息.

    依據(jù)指令對應(yīng)節(jié)點(diǎn)的鄰接關(guān)系,可以獲得一個指令間的鄰接矩陣Mp*p.當(dāng)M[i][j]=1 時,表示指令rj(對應(yīng)的節(jié)點(diǎn))為指令ri(對應(yīng)的節(jié)點(diǎn))的父節(jié)點(diǎn).基于此,該層的輸出為

    最終AST 編碼器的輸出為R(ast).

    4.4 解碼器

    解碼器以當(dāng)前待擴(kuò)展的非葉子節(jié)點(diǎn)為輸入,即Q(d)=[q1;…;qR],其中,qi為每個待擴(kuò)展節(jié)點(diǎn)的表示向量.由于解碼器仍然遵循多塊的設(shè)計(jì),因此在第1 塊中,qi為節(jié)點(diǎn)對應(yīng)的語法類型或單詞信息;而在其他塊中,qi則為上一個塊的輸出.解碼器的目標(biāo)是生成查詢矩陣其中,為第i個節(jié)點(diǎn)相應(yīng)的查詢向量,方法將依據(jù)預(yù)測第i條指令.解碼器首先利用Self-attention 層來獲取待擴(kuò)展節(jié)點(diǎn)間的依賴關(guān)系.然后,數(shù)據(jù)流將依次經(jīng)過AST-attention 層、Code-attention 層和Diff-attention 層,分別用于獲取抽象語法樹、待修改代碼和修改示例的信息.具體地:

    Self-attention 層.在上述查詢矩陣中,每個查詢分量qi均代表抽象語法樹中的一個待擴(kuò)展的節(jié)點(diǎn)的信息.在代碼的抽象語法樹中,不同節(jié)點(diǎn)彼此間存在不同程度的依賴關(guān)系,因此,我們利用一層Self-attention 層來捕獲查詢間(即節(jié)點(diǎn)間)的依賴關(guān)系,該層的輸出為

    Ast-attention 層.本文方法利用該層實(shí)現(xiàn)利用已產(chǎn)生的抽象語法樹的信息(即Y(ast))增強(qiáng)查詢信息.在該層中,Q=D(self),K=Y(ast),V=Y(ast),輸出為

    Code-attention 層.本文方法利用該層實(shí)現(xiàn)待修改代碼x的信息(即Y(x))增強(qiáng)查詢信息.在該層中,Q=D(ast),K=Y(x),V=Y(xt).輸出為

    Diff-attention 層.本文方法利用該層實(shí)現(xiàn)利用修改示例xΔ→yΔ的信息(即Y(diff))增強(qiáng)查詢信息.在該層中,Q=D(x),K=Y(diff),V=Y(diff),輸出為

    最終,解碼器的輸出為D(query).

    4.5 指令預(yù)測

    在預(yù)測下一條指令時,模型的預(yù)測范圍將來自于兩種類型的指令.首先,在我們處理數(shù)據(jù)時,獲取了標(biāo)準(zhǔn)數(shù)據(jù)指令集R={r1,r2,…,rN},該指令集能夠滿足正常的代碼生成需要.然而,在代碼中變量名定義和使用存在依賴關(guān)系.為了捕獲這種依賴關(guān)系,方法增設(shè)了指令copy(n),表示復(fù)制已產(chǎn)生指令中第n條指令中的變量名.在預(yù)測第i條指令時,除了計(jì)算指令rj的概率p(rj)以外,方法還將依據(jù)指針網(wǎng)絡(luò)計(jì)算p(copy(t))的概率.因此,最終的第i條指令預(yù)測結(jié)果需要從指令rj和copy(t)中進(jìn)行選擇.本文將采用下列公式所示的門機(jī)制來對兩種類型的指令進(jìn)行篩選:

    其中,g表示當(dāng)前預(yù)測指令屬于R的概率,亦即指令為copy 的概率為1-g.最終預(yù)測的指令為op=argmaxopp(op).

    其中,本文將按照公式(27),計(jì)算下一條指令為rj的概率p(rj):

    在預(yù)測第i條指令時,copy 指令所復(fù)制的變量名來自于前i-1 條指令中聲明的變量,因此,本文方法將按照下列公式來計(jì)算p(copy(t)):

    其中,1≤t≤i–1,為已產(chǎn)生的第t條指令的表示向量,W(query)和W(rule)為網(wǎng)絡(luò)參數(shù).

    5 方法驗(yàn)證

    本文開展了兩個實(shí)驗(yàn),分別將本文方法與現(xiàn)有的基于深度學(xué)習(xí)的方法以及基于人工規(guī)則的方法進(jìn)行對比,以驗(yàn)證方法的有效性.

    5.1 實(shí)驗(yàn)1

    該實(shí)驗(yàn)通過與現(xiàn)有的基于深度學(xué)習(xí)的方法進(jìn)行對比,以驗(yàn)證本文方法的有效性.

    (1) 數(shù)據(jù)集.該實(shí)驗(yàn)在Yin 等人的數(shù)據(jù)集[13]上來驗(yàn)證本文方法的有效性.在Yin 等人的工作中,他們從Github上收集了54 個C#開源項(xiàng)目,然后從這些軟件項(xiàng)目的提交歷史中抽取并篩選出111 724 處C#代碼修改,其中,91372/10176/10176 條數(shù)據(jù)分別用于訓(xùn)練/驗(yàn)證/測試.在該數(shù)據(jù)集中,數(shù)據(jù)示例均可表示為〈xi,yi〉的形式,其中,xi為修改前的代碼,yi為修改后的代碼.依據(jù)實(shí)例〈xi,yi〉,將其轉(zhuǎn)換為數(shù)據(jù)〈xi,xi→yi,yi〉的形式,并按照模型輸入要求進(jìn)行預(yù)處理.具體地,首先將xi和yi解析為抽象語法樹的形式,并按照由上至下、從左到右的順序,獲取節(jié)點(diǎn)序列此外,依據(jù)yi對應(yīng)的抽象語法樹,獲取指令序列[r1,…,rR].其中,修改前的代碼節(jié)點(diǎn)序列作為代碼編碼器的輸入,長度為L(ori);將修改前、后代碼的節(jié)點(diǎn)序列進(jìn)行拼接,作為代碼差異編碼器的輸入,長度為L(ori)+L(mod);指令序列作為模型預(yù)測目標(biāo),長度為P.表1 列出了該數(shù)據(jù)集中數(shù)據(jù)的4 種長度的分布情況.如表中第2 行所示,92.2%的實(shí)例的長度L(ori)小于100,7.7%的實(shí)例的長度L(ori)處于101~200 之間,0.1%的實(shí)例的長度L(ori)處于201~300 之間,最大長度為239.此外,本文對預(yù)處理后的數(shù)據(jù)中所包含的單詞進(jìn)行統(tǒng)計(jì),共發(fā)現(xiàn)2 931 個獨(dú)有單詞,其中最大字符長度為70,且80.3%的單詞的字符長度少于20 個.

    (2) 對比方法.Yin 等人的工作是目前與本文工作最為相關(guān)的最新工作[13].在該工作中,作者通過表示示例代碼中的修改方式,并用于指導(dǎo)代碼轉(zhuǎn)換.在該工作中,作者還嘗試?yán)貌煌姆绞絹肀硎敬a和修改示例,并驗(yàn)證不同模型的組合的方法效果.

    (3) 參數(shù)設(shè)置.為了獲取較優(yōu)的Transformer 架構(gòu)的塊數(shù)設(shè)置,方法分別將塊數(shù)設(shè)為4、6 和8,且實(shí)驗(yàn)結(jié)果表明,當(dāng)塊數(shù)為6 時,模型效果最佳(具體結(jié)果見表3).因此,方法最終將代碼差異編碼器、代碼編碼器、AST 編碼器和解碼器的塊數(shù)(即N1/N2/N3/N4)設(shè)為6.此外,如表1 所示,由于所有的代碼長度都小于300,且超過98%的代碼差異長度小于300,因此代碼差異編碼器和代碼編碼器的最大輸入長度L被設(shè)定為300.同時,所有數(shù)據(jù)實(shí)例的指令長度均小于200,且最大長度為185,因此,模型允許最大的指令長度P被設(shè)定為200.此外,還有超過80%的單詞的字符≤20,且最大長度為70,因此,方法將模型允許單詞的最大長度L'設(shè)定為20,意在保證該值能夠覆蓋到大多數(shù)單詞的同時,避免引入過多的占位符而影響模型效果.

    (4) 實(shí)驗(yàn)過程.在與Yin 等人的方法進(jìn)行對比時,本文沿用了他們的實(shí)驗(yàn)設(shè)置,并利用其數(shù)據(jù)集的訓(xùn)練集和驗(yàn)證集來訓(xùn)練本文方法.然后,利用測試集來測試本文方法,即方法是否能夠?qū)⑿薷那暗拇axi正確地轉(zhuǎn)換為yi.

    (5) 評估標(biāo)準(zhǔn).本文主要采用準(zhǔn)確率來量化方法的效果.給定一條數(shù)據(jù)〈x,xΔ→yΔ,y〉,其中,x為修改前的代碼,xΔ→yΔ為修改示例,y為修改后的代碼.若方法的預(yù)測結(jié)果與y完全相同,則稱x被正確地修改.本文將方法的準(zhǔn)確率定義為

    (6) 實(shí)驗(yàn)結(jié)果.表2 展示了與Yin 等人方法對比后的實(shí)驗(yàn)結(jié)果.從實(shí)驗(yàn)結(jié)果來看,較之Yin 等人提出的不同的模型,本文方法在準(zhǔn)確率上提升了11.8%~30.8%.在Yin 等人的工作方法中,他們采用了兩個不同的子模塊分別用于編碼待修改代碼的信息和修改示例的信息.同時,他們還嘗試了兩種不同思路以對信息進(jìn)行建模,即基于單詞序列的方式和基于圖結(jié)構(gòu)的方式,并探索了信息建模方式的不同組合的實(shí)際效果.僅從Yin 等人的工作結(jié)果來看,基于單詞序列模型(如Seq2Seq-Seq)的結(jié)果要比基于圖結(jié)構(gòu)模型(如Graph2Tree-Graph)的結(jié)果更優(yōu).導(dǎo)致這種結(jié)果的原因在于實(shí)驗(yàn)數(shù)據(jù)的特殊性.由于模型輸入的修改示例包含了待修改代碼的修改結(jié)果信息,反而更有利于基于單詞序列的模型預(yù)測修改結(jié)果.

    反觀本文方法ExpTrans 的結(jié)果,若單獨(dú)與Yin 工作中的基于圖結(jié)構(gòu)的模型進(jìn)行對比,ExpTrans 在準(zhǔn)確率上提升了23.4%,這表明,ExpTrans 采用圖的形式來表示修改示例,并結(jié)合卷積神經(jīng)網(wǎng)絡(luò)的方式,能夠有效增強(qiáng)模型對代碼的結(jié)構(gòu)信息的捕獲能力,從而使得方法的準(zhǔn)確率有了大幅度的提升.與Yin 等人基于單詞序列的方法進(jìn)行對比,ExpTrans 同樣具有至少11.8%的提升.這些實(shí)驗(yàn)結(jié)果表明,本文方法是有效的.

    此外,在模型ExpTrans 中,Transformer 架構(gòu)的塊數(shù)、copy 指令和模型的不同模塊對代碼轉(zhuǎn)換效果均有一定程度的影響.因此,基于ExpTrans,本文通過修改模型的架構(gòu)或參數(shù)設(shè)置,產(chǎn)生了不同的變體,以此探究上述因素在ExpTrans 轉(zhuǎn)換代碼過程中的有效性.表3 列出這些變體的具體設(shè)置及實(shí)驗(yàn)結(jié)果.

    首先,為了尋求模型中Transformer 架構(gòu)層數(shù)較優(yōu)的設(shè)置,本文借鑒了Vaswani 等人的工作[14],先后將模型的層數(shù)設(shè)置為4、6 和8,具體的實(shí)驗(yàn)結(jié)果如表3 中(A)行所示.從結(jié)果可以看出,當(dāng)層數(shù)設(shè)置為4 時,方法的準(zhǔn)確率為67.37%,較之層數(shù)為6 時,下降4.08%.當(dāng)層數(shù)設(shè)置為8 時,準(zhǔn)確率為64.37%.鑒于上述結(jié)果,最終將ExpTrans中Transformer 的層數(shù)設(shè)置為6 層.

    同時,為了驗(yàn)證copy 指令的有效性,本文再次將ExpTrans 應(yīng)用于Yin 等人提供的數(shù)據(jù)集上.所不同的是,在處理該數(shù)據(jù)集時,取消了copy 指令.具體的實(shí)驗(yàn)結(jié)果如表3 中(B)行所示.如結(jié)果顯示,當(dāng)指令集中不含copy 指令時,模型的準(zhǔn)確下降為60.12%,該結(jié)果表明,增設(shè)的copy 指令能夠有效地提升模型對代碼間長程依賴的捕獲能力,并提升方法的準(zhǔn)確性.

    最后,本文通過分別刪除模型中的代碼差異編碼器以及代碼差異編碼器和代碼編碼器中的圖卷積層,來驗(yàn)證它們的必要性.具體結(jié)果如表3 中(C)行所示.當(dāng)刪除代碼差異編碼器時,方法的準(zhǔn)確率驟降為6.36%.該實(shí)驗(yàn)結(jié)果充分說明,在代碼自動轉(zhuǎn)換時,給定一個或一組實(shí)例修改的必要性,同時也說明了ExpTrans 中的代碼差異編碼器的有效性.另外,當(dāng)分別刪除代碼差異編碼器和代碼編碼器中圖卷積層后,模型的準(zhǔn)確率分別下降為68.01%和65.69%.在取消圖卷積層的情況下,模型實(shí)際處理輸入數(shù)據(jù)的效果等同于處理線性的單詞序列,失去了代碼自身的結(jié)構(gòu)信息.這些結(jié)果表明,本文方法采用圖卷積的方式能夠有效地捕獲代碼的結(jié)構(gòu)信息,并增強(qiáng)模型的轉(zhuǎn)換能力,提升模型效果.

    Table 1 Data length distribution in the first experiment表1 實(shí)驗(yàn)1 中數(shù)據(jù)長度分布

    Table 2 The comprative results with the work of Yin,et al表2 與Yin 等人方法的對比實(shí)驗(yàn)結(jié)果

    Table 3 Performances of different variations on ExpTrans表3 ExpTrans 的不同變體及實(shí)驗(yàn)結(jié)果

    5.2 實(shí)驗(yàn)2

    該實(shí)驗(yàn)通過與現(xiàn)有的基于人工規(guī)則的方法進(jìn)行對比,來驗(yàn)證本文方法的有效性.

    1) 數(shù)據(jù)集.由于所對比的基于人工規(guī)則的方法是針對Java 語言的,因此我們又收集了Java 語言的代碼修改數(shù)據(jù)集.在收集該數(shù)據(jù)之前,我們查閱了Java 語言在不同版本上新增的功能,選出其中5 種并總結(jié)了可能導(dǎo)致的修改模式.表4 列出了所選出的Java 功能和相應(yīng)的修改模式.基于每種功能,構(gòu)造相應(yīng)的查詢語句,并在Github上搜索相關(guān)的commit.依據(jù)搜索結(jié)果,人工地為每個查詢篩選出10 個具有相應(yīng)修改模式的代碼修改,即為相似代碼修改.

    2) 對比方法.在本實(shí)驗(yàn)中,對比了兩種基于人工特征的代碼轉(zhuǎn)換方法GenPat 和ARES.

    (1) GenPat[17].該方法是一種基于單示例的代碼轉(zhuǎn)換方法,其通過將給定的單個修改示例解析為抽象語法樹,對抽象語法樹上的特定節(jié)點(diǎn)的屬性進(jìn)行了泛化或限制,并標(biāo)注抽象語法樹的節(jié)點(diǎn)的變化過程.在代碼轉(zhuǎn)換時,GenPat 將根據(jù)抽取的抽象語法樹進(jìn)行代碼匹配,并利用標(biāo)注的節(jié)點(diǎn)的變化過程對代碼進(jìn)行轉(zhuǎn)換.

    (2) ARES[10].該方法是一種基于多示例的代碼轉(zhuǎn)換方法,其利用模板來表示修改示例中的修改模式.在模板中保留了修改示例中的共有部分,而采用通配符的形式對不同的部分進(jìn)行泛化.在代碼轉(zhuǎn)換時,ARES 將依據(jù)抽取的模版對代碼進(jìn)行匹配,并利用模版所刻畫的修改結(jié)果模式,對匹配成功的代碼進(jìn)行修改.

    Table 4 The corresponding query sentences and change patterns of different Java features表4 不同Java 功能對應(yīng)的查詢語句和修改模式

    3) 實(shí)驗(yàn)過程.在該實(shí)驗(yàn)中,本文按照搜集的6 組相似代碼修改分別進(jìn)行實(shí)驗(yàn).具體地,給定一組相似修改集合P={p1,…,p10},其中,代碼修改pi=〈xi,yi〉,xi為修改前的代碼,yi為修改后的代碼.為了訓(xùn)練本文方法,我們基于集合P,進(jìn)行了如下方式的構(gòu)造:

    其中,1≤i,j≤10,pi,j所代表的含義是利用pj的修改模式對代碼xi進(jìn)行修改,并且按照如下方式將P'分為:

    訓(xùn)練集:{pi,j},1≤i≤10,1≤j≤8;

    驗(yàn)證集:{pi,j},1≤i≤10,j=9;

    測試集:{pi,j},1≤i≤10,j=10.

    在實(shí)驗(yàn)時,分別利用3 種方法對測試集中的實(shí)例進(jìn)行修改.由于ARES 是一種基于多示例的代碼轉(zhuǎn)換方法,因此,我們將P作為一組相似代碼變更提供給ARES,以供ARES 抽取所需的代碼修改模式.

    參數(shù)設(shè)置.在該實(shí)驗(yàn)中,本文方法中的模型參數(shù)沿用了實(shí)驗(yàn)1 中的參數(shù)設(shè)置.

    實(shí)驗(yàn)結(jié)果.我們將方法的輸出結(jié)果分為4 種.

    ○ 表示方法無法從給定的修改示例中抽取出統(tǒng)一的修改模式,導(dǎo)致方法無輸出.

    表5 中展示了方法在6 組數(shù)據(jù)上的對比實(shí)驗(yàn)結(jié)果.結(jié)果表明,ExpTrans 要明顯優(yōu)于其他兩種對比方法.ExpTrans 在所有組別上,均有正確的修改示例,尤其是在第2 組數(shù)據(jù)上,ExpTrans 能夠?qū)⑷康拇a實(shí)例修改成功.我們?nèi)斯z查了ExpTrans 修改錯誤的實(shí)例,發(fā)現(xiàn)這些錯誤實(shí)例主要發(fā)生在預(yù)測同一個函數(shù)的多個參數(shù)時.其可能的原因是,ExpTrans 在預(yù)測函數(shù)的參數(shù)時,缺乏參數(shù)的序列位置信息,從而導(dǎo)致錯誤的預(yù)測結(jié)果.例如,一個預(yù)期結(jié)果為byteBufferReadCheck(in,buf,11);,而ExpTrans 的預(yù)測結(jié)果為byteBufferReadCheck(in,11,11);,其中,11為錯誤預(yù)測的參數(shù).

    進(jìn)一步地,我們檢查了GenPat 和ARES 的輸出結(jié)果,以探究導(dǎo)致兩種方法結(jié)果不理想的原因.

    方法GenPat 失效的原因在于:(1) 方法依賴于待修改的代碼與修改示例代碼的結(jié)構(gòu)和語法類型的相似性.例如,“return new Double(0.0);”→“return new Double.valueOf(0.0);”中的修改方式,由于語法類型不同,導(dǎo)致無法用于修改代碼“val=new Double(0.0);”.而在本實(shí)驗(yàn)所獲取的數(shù)據(jù)中,無法保證相似的代碼修改具有相似的結(jié)構(gòu)和語法特征.因此,導(dǎo)致GenPat 從示例中抽取的修改模式無法適配于待修改的代碼(類型).(2) GenPat 需要利用代碼中變量的定義信息.然而,由于獲取代碼修改時,只抽取了發(fā)生修改的代碼片段,因而無法保證抽取的代碼修改中同時包含所有涉及的變量的定義.由于GenPat 無法獲取足夠的信息,因此在將抽取的模式匹配待修改的代碼時,產(chǎn)生錯誤匹配,從而導(dǎo)致錯誤修改(類型?).

    Table 5 The comprative results with GenPat and ARES表5 ExpTrans 方法與GenPat 和ARES 方法的對比實(shí)驗(yàn)結(jié)果

    由于ARES 方法是一種基于多示例的代碼轉(zhuǎn)換方法,因此,當(dāng)給定一組相似代碼修改示例時,ARES 需要對修改示例中的不同部分進(jìn)行泛化,以使其表示的修改模式能夠擬合給定的修改示例.然而,當(dāng)給定的修改示例的修改語義相似但結(jié)構(gòu)不同時,容易導(dǎo)致方法無法抽取出統(tǒng)一的修改模式.例如,在實(shí)驗(yàn)中我們發(fā)現(xiàn),ARES 無法從組別2、4、6 的數(shù)據(jù)中抽取統(tǒng)一的修改模式,因此也無法完成對相應(yīng)代碼的修改(類型○).此外,還有一些錯誤實(shí)例是因?yàn)锳RES 在抽取的模式中,保留了修改示例所特有的變量名.因此,在將抽取的模式適配到待修改的代碼時,所修改的結(jié)果中引入了這些變量名,導(dǎo)致修改失敗(類型?).

    5.3 討 論

    方法適用范圍.在本文方法中,我們針對輸入的待修改代碼x和修改示例xΔ→yΔ,預(yù)設(shè)了最大長度.當(dāng)代碼長度超過預(yù)設(shè)長度時,超過預(yù)設(shè)長度的代碼內(nèi)容將被截取.這在一定程度上影響了方法能夠使用的代碼修改場景.但在一些頻繁發(fā)生的相似修改任務(wù)中,例如API 版本遷移,所修改的代碼往往是局部的、簡短的,因此,方法預(yù)設(shè)最大的長度并不會嚴(yán)重制約本文方法的實(shí)用性.盡管如此,在未來的工作中,我們?nèi)孕鑷L試提出不同的網(wǎng)絡(luò)模型以降低修改代碼長度對方法的影響.

    數(shù)據(jù)規(guī)模.在收集Java 數(shù)據(jù)時,依賴于人工對搜索結(jié)果的篩選,這限制了本文收集數(shù)據(jù)的規(guī)模和效率,也一定程度地制約了挖掘方法更大的潛力.在未來的工作中,我們將嘗試?yán)米詣踊姆绞絹泶笠?guī)模地收集數(shù)據(jù),盡量在降低人力代價(jià)的情況下,提升方法的效果.

    6 總結(jié)

    在本文中,我們提出了一種基于深度學(xué)習(xí)的代碼轉(zhuǎn)換方法.通過采用圖形式來表示修改示例,并結(jié)合卷積網(wǎng)絡(luò)和Transformer架構(gòu),增加了方法捕獲代碼結(jié)構(gòu)信息的能力.實(shí)驗(yàn)結(jié)果表明,我們的方法比現(xiàn)有的基于深度學(xué)習(xí)和基于人工規(guī)則的方法,其效果有著較為明顯的提升.針對可能影響方法有效性的因素,我們將在未來的工作中,通過提出優(yōu)化模型和自動化的數(shù)據(jù)收集方法,來降低這些因素對方法的影響.

    猜你喜歡
    編碼器示例代碼
    大還是小
    2019年高考上海卷作文示例
    常見單位符號大小寫混淆示例
    山東冶金(2019年5期)2019-11-16 09:09:22
    “全等三角形”錯解示例
    創(chuàng)世代碼
    動漫星空(2018年11期)2018-10-26 02:24:02
    創(chuàng)世代碼
    動漫星空(2018年2期)2018-10-26 02:11:00
    創(chuàng)世代碼
    動漫星空(2018年9期)2018-10-26 01:16:48
    創(chuàng)世代碼
    動漫星空(2018年5期)2018-10-26 01:15:02
    基于FPGA的同步機(jī)軸角編碼器
    基于PRBS檢測的8B/IOB編碼器設(shè)計(jì)
    99精国产麻豆久久婷婷| 制服丝袜香蕉在线| av又黄又爽大尺度在线免费看| 久久影院123| 国产男女超爽视频在线观看| 亚洲国产成人一精品久久久| 天堂俺去俺来也www色官网| 热re99久久国产66热| 夫妻午夜视频| 一级毛片 在线播放| 亚洲色图 男人天堂 中文字幕 | 亚洲综合精品二区| 99香蕉大伊视频| 免费女性裸体啪啪无遮挡网站| 亚洲少妇的诱惑av| 丰满饥渴人妻一区二区三| 在线观看美女被高潮喷水网站| 亚洲欧美成人综合另类久久久| 秋霞在线观看毛片| 欧美另类一区| av播播在线观看一区| 亚洲精品美女久久久久99蜜臀 | 大陆偷拍与自拍| 中文乱码字字幕精品一区二区三区| 黄色怎么调成土黄色| 色哟哟·www| 超色免费av| 亚洲一码二码三码区别大吗| 青春草亚洲视频在线观看| 亚洲av.av天堂| 天堂俺去俺来也www色官网| 天堂8中文在线网| 99热国产这里只有精品6| 国产永久视频网站| 考比视频在线观看| 老司机亚洲免费影院| av国产久精品久网站免费入址| 国产一区亚洲一区在线观看| 亚洲精品自拍成人| av.在线天堂| 99精国产麻豆久久婷婷| 99视频精品全部免费 在线| 97在线人人人人妻| 妹子高潮喷水视频| 最近2019中文字幕mv第一页| 亚洲 欧美一区二区三区| 久久久国产一区二区| 一区二区av电影网| 男女无遮挡免费网站观看| 亚洲精品国产av蜜桃| 一二三四在线观看免费中文在 | 午夜福利视频精品| 亚洲欧洲精品一区二区精品久久久 | 香蕉精品网在线| 久久久久网色| 久久99热这里只频精品6学生| 一本—道久久a久久精品蜜桃钙片| 国产永久视频网站| 国产av精品麻豆| 亚洲久久久国产精品| 亚洲三级黄色毛片| 妹子高潮喷水视频| 国产精品99久久99久久久不卡 | 国产一区有黄有色的免费视频| 国产69精品久久久久777片| 综合色丁香网| 免费av中文字幕在线| 成人国产av品久久久| 欧美日韩综合久久久久久| 精品国产一区二区三区四区第35| 国产精品久久久久久精品古装| 亚洲四区av| 日韩欧美精品免费久久| 一本久久精品| 中文字幕精品免费在线观看视频 | 欧美老熟妇乱子伦牲交| 国产精品麻豆人妻色哟哟久久| 免费黄网站久久成人精品| 另类精品久久| 一级黄片播放器| 亚洲欧美一区二区三区国产| 超碰97精品在线观看| 国产精品久久久久成人av| 美女内射精品一级片tv| 免费久久久久久久精品成人欧美视频 | 韩国精品一区二区三区 | kizo精华| 伊人久久国产一区二区| 久久久久久人人人人人| 高清av免费在线| 91久久精品国产一区二区三区| 欧美日韩精品成人综合77777| 91国产中文字幕| 天堂中文最新版在线下载| 99国产综合亚洲精品| 亚洲精品一二三| 亚洲人成网站在线观看播放| 青春草视频在线免费观看| 伊人久久国产一区二区| 极品少妇高潮喷水抽搐| 国产亚洲精品第一综合不卡 | 香蕉丝袜av| 97超碰精品成人国产| 在线观看人妻少妇| 国产精品国产av在线观看| 精品一区二区三卡| 一个人免费看片子| 国产精品三级大全| 中文字幕人妻熟女乱码| 26uuu在线亚洲综合色| av播播在线观看一区| 精品一区二区三区四区五区乱码 | 蜜桃国产av成人99| 亚洲高清免费不卡视频| 天堂8中文在线网| 国产精品免费大片| 日韩中文字幕视频在线看片| 国产一区二区三区av在线| 不卡视频在线观看欧美| 99视频精品全部免费 在线| 日韩,欧美,国产一区二区三区| 色5月婷婷丁香| 又黄又爽又刺激的免费视频.| 91成人精品电影| 如何舔出高潮| 蜜桃国产av成人99| 在线观看www视频免费| 亚洲欧美日韩另类电影网站| 少妇熟女欧美另类| 99久久精品国产国产毛片| 免费不卡的大黄色大毛片视频在线观看| 婷婷色综合大香蕉| 国产精品国产av在线观看| 国产69精品久久久久777片| 国产日韩欧美视频二区| 亚洲精品国产av蜜桃| 成人综合一区亚洲| 十八禁高潮呻吟视频| 久热久热在线精品观看| 中文字幕制服av| 久久久久久久国产电影| 丝袜喷水一区| 国产精品一区二区在线不卡| 少妇人妻久久综合中文| 久久精品国产自在天天线| 满18在线观看网站| 男女下面插进去视频免费观看 | 国国产精品蜜臀av免费| 午夜av观看不卡| 久久这里只有精品19| 亚洲av福利一区| 久久午夜综合久久蜜桃| 欧美国产精品va在线观看不卡| 久久97久久精品| 三级国产精品片| 亚洲av免费高清在线观看| 亚洲 欧美一区二区三区| 王馨瑶露胸无遮挡在线观看| 美国免费a级毛片| 日本欧美国产在线视频| 热re99久久国产66热| 在线免费观看不下载黄p国产| 亚洲色图 男人天堂 中文字幕 | 亚洲国产精品专区欧美| 少妇人妻久久综合中文| 桃花免费在线播放| 99久久中文字幕三级久久日本| 久久这里只有精品19| 精品久久久久久电影网| 国产成人免费观看mmmm| 欧美精品国产亚洲| 少妇被粗大猛烈的视频| 成人黄色视频免费在线看| av福利片在线| 国产欧美另类精品又又久久亚洲欧美| 国产一区二区在线观看av| 一级毛片 在线播放| 欧美精品国产亚洲| 亚洲av成人精品一二三区| 成人免费观看视频高清| 久久精品人人爽人人爽视色| 欧美日韩综合久久久久久| h视频一区二区三区| 国产毛片在线视频| 欧美激情极品国产一区二区三区 | 九色成人免费人妻av| 国产亚洲最大av| 99九九在线精品视频| 亚洲国产色片| 三级国产精品片| 在线亚洲精品国产二区图片欧美| 丝瓜视频免费看黄片| h视频一区二区三区| 免费大片黄手机在线观看| 国产熟女欧美一区二区| 成人毛片60女人毛片免费| 日韩av在线免费看完整版不卡| 香蕉国产在线看| 777米奇影视久久| xxxhd国产人妻xxx| 亚洲av男天堂| 男女边吃奶边做爰视频| 欧美另类一区| 久久国产亚洲av麻豆专区| 国语对白做爰xxxⅹ性视频网站| 午夜激情av网站| 精品99又大又爽又粗少妇毛片| 亚洲婷婷狠狠爱综合网| 9191精品国产免费久久| 观看美女的网站| 免费日韩欧美在线观看| 精品99又大又爽又粗少妇毛片| 日本91视频免费播放| 91精品三级在线观看| 永久免费av网站大全| 日韩制服骚丝袜av| av天堂久久9| 在现免费观看毛片| 另类精品久久| 免费人成在线观看视频色| 欧美激情极品国产一区二区三区 | av在线播放精品| 国产亚洲精品久久久com| 国产精品久久久久久久久免| 国产日韩欧美在线精品| 99国产综合亚洲精品| 日本色播在线视频| 自拍欧美九色日韩亚洲蝌蚪91| av天堂久久9| 一边摸一边做爽爽视频免费| 男人舔女人的私密视频| 日韩制服丝袜自拍偷拍| 赤兔流量卡办理| 亚洲成人av在线免费| 欧美日韩综合久久久久久| 国产精品久久久久久久电影| 亚洲精品,欧美精品| 亚洲av成人精品一二三区| 制服人妻中文乱码| 国产精品熟女久久久久浪| 久久久久久久大尺度免费视频| 午夜视频国产福利| 看十八女毛片水多多多| 日韩一本色道免费dvd| 蜜臀久久99精品久久宅男| 精品国产一区二区久久| 国产激情久久老熟女| 一本久久精品| 青春草国产在线视频| 一本一本久久a久久精品综合妖精 国产伦在线观看视频一区 | 久久青草综合色| 春色校园在线视频观看| 国产老妇伦熟女老妇高清| 亚洲图色成人| 91成人精品电影| 亚洲欧美成人精品一区二区| 男女啪啪激烈高潮av片| 26uuu在线亚洲综合色| 黄片播放在线免费| 亚洲国产精品成人久久小说| 丝袜在线中文字幕| 国产色婷婷99| 深夜精品福利| 成人毛片60女人毛片免费| 日产精品乱码卡一卡2卡三| 亚洲国产av新网站| 国产日韩一区二区三区精品不卡| 久久免费观看电影| 欧美日韩视频精品一区| 久久久国产一区二区| 久久国内精品自在自线图片| 亚洲国产成人一精品久久久| 18+在线观看网站| 肉色欧美久久久久久久蜜桃| 国产精品国产三级国产av玫瑰| 黄色怎么调成土黄色| 性色av一级| 久久久久久久久久成人| 寂寞人妻少妇视频99o| 久久精品国产自在天天线| 丰满迷人的少妇在线观看| 亚洲欧美一区二区三区国产| 午夜影院在线不卡| 99精国产麻豆久久婷婷| 国产麻豆69| 黄色怎么调成土黄色| 亚洲av综合色区一区| 免费少妇av软件| 全区人妻精品视频| 99热国产这里只有精品6| 久久综合国产亚洲精品| 久久精品夜色国产| 97在线人人人人妻| 大陆偷拍与自拍| av片东京热男人的天堂| 青青草视频在线视频观看| 热99国产精品久久久久久7| 极品少妇高潮喷水抽搐| 五月开心婷婷网| 两性夫妻黄色片 | 日本wwww免费看| 男男h啪啪无遮挡| 美女视频免费永久观看网站| 赤兔流量卡办理| 免费女性裸体啪啪无遮挡网站| 亚洲av成人精品一二三区| 9色porny在线观看| 久久精品夜色国产| 久久精品aⅴ一区二区三区四区 | 国产成人午夜福利电影在线观看| 精品熟女少妇av免费看| 26uuu在线亚洲综合色| 天天操日日干夜夜撸| 99热网站在线观看| 啦啦啦中文免费视频观看日本| 麻豆精品久久久久久蜜桃| 99re6热这里在线精品视频| 国产精品无大码| 在线观看三级黄色| 综合色丁香网| 日韩一区二区三区影片| 中文字幕制服av| 成人亚洲精品一区在线观看| 国产精品国产三级国产av玫瑰| 国产免费一区二区三区四区乱码| 乱码一卡2卡4卡精品| 90打野战视频偷拍视频| 看非洲黑人一级黄片| 日日摸夜夜添夜夜爱| 香蕉精品网在线| 久久鲁丝午夜福利片| 久久精品久久久久久噜噜老黄| 亚洲综合色网址| 国产精品久久久久久精品电影小说| 国产又爽黄色视频| 肉色欧美久久久久久久蜜桃| 又粗又硬又长又爽又黄的视频| www.熟女人妻精品国产 | 亚洲美女搞黄在线观看| 看十八女毛片水多多多| 婷婷色麻豆天堂久久| 桃花免费在线播放| 一本大道久久a久久精品| 亚洲国产欧美日韩在线播放| 欧美日本中文国产一区发布| 又大又黄又爽视频免费| 亚洲av福利一区| 美女国产高潮福利片在线看| 亚洲丝袜综合中文字幕| 久久女婷五月综合色啪小说| 草草在线视频免费看| 久久国产亚洲av麻豆专区| 亚洲精品久久午夜乱码| 在线观看人妻少妇| 亚洲精品乱码久久久久久按摩| 午夜激情久久久久久久| 国产老妇伦熟女老妇高清| 午夜免费观看性视频| 亚洲一码二码三码区别大吗| 一本—道久久a久久精品蜜桃钙片| av卡一久久| 妹子高潮喷水视频| 免费在线观看完整版高清| 中文欧美无线码| 青春草亚洲视频在线观看| 曰老女人黄片| av视频免费观看在线观看| 汤姆久久久久久久影院中文字幕| 国产麻豆69| 又黄又粗又硬又大视频| 丝袜喷水一区| 国产av精品麻豆| 免费不卡的大黄色大毛片视频在线观看| xxxhd国产人妻xxx| 中文字幕制服av| 亚洲成色77777| 日韩制服骚丝袜av| av卡一久久| 黑人巨大精品欧美一区二区蜜桃 | 有码 亚洲区| 老司机亚洲免费影院| 夜夜爽夜夜爽视频| 成人毛片a级毛片在线播放| 制服诱惑二区| 日日爽夜夜爽网站| 黑人巨大精品欧美一区二区蜜桃 | 狂野欧美激情性xxxx在线观看| 欧美xxxx性猛交bbbb| 国产精品人妻久久久久久| 久久久久久久久久久久大奶| 国产片内射在线| 亚洲av综合色区一区| 国产一区二区激情短视频 | 18禁在线无遮挡免费观看视频| 久久久久久人人人人人| 国产熟女欧美一区二区| 日韩大片免费观看网站| a级毛片黄视频| 成人午夜精彩视频在线观看| 最新的欧美精品一区二区| 视频中文字幕在线观看| av在线app专区| 免费观看在线日韩| 国产欧美另类精品又又久久亚洲欧美| 国产精品久久久久成人av| 国产无遮挡羞羞视频在线观看| 久久av网站| 26uuu在线亚洲综合色| 一区二区三区乱码不卡18| 夜夜爽夜夜爽视频| 亚洲精品日韩在线中文字幕| 丰满迷人的少妇在线观看| 久久久久久久大尺度免费视频| 免费看光身美女| 精品一区二区免费观看| av电影中文网址| 国产成人精品一,二区| av网站免费在线观看视频| 国产高清国产精品国产三级| 国产精品久久久av美女十八| 久久久久精品久久久久真实原创| 亚洲综合精品二区| 秋霞伦理黄片| 精品国产乱码久久久久久小说| 婷婷色综合www| 国产精品不卡视频一区二区| 日韩不卡一区二区三区视频在线| 久久国内精品自在自线图片| h视频一区二区三区| 少妇被粗大猛烈的视频| 一区二区三区乱码不卡18| 午夜福利,免费看| 国产一区亚洲一区在线观看| 狂野欧美激情性bbbbbb| 国产av精品麻豆| 久久热在线av| 欧美97在线视频| 观看av在线不卡| 国产 精品1| 久久久国产精品麻豆| 久久亚洲国产成人精品v| 大话2 男鬼变身卡| 日本av手机在线免费观看| tube8黄色片| 国产精品成人在线| 亚洲综合精品二区| 国产在线免费精品| 精品一区在线观看国产| 精品亚洲乱码少妇综合久久| 亚洲一区二区三区欧美精品| 久久久久人妻精品一区果冻| 亚洲国产毛片av蜜桃av| 哪个播放器可以免费观看大片| 少妇猛男粗大的猛烈进出视频| 丁香六月天网| 哪个播放器可以免费观看大片| 国语对白做爰xxxⅹ性视频网站| 日韩欧美一区视频在线观看| 中文字幕人妻熟女乱码| 91精品国产国语对白视频| 亚洲第一av免费看| 黄片无遮挡物在线观看| 欧美人与性动交α欧美软件 | 各种免费的搞黄视频| 久久久久久久国产电影| 国产黄频视频在线观看| 午夜福利视频精品| 日韩成人伦理影院| av又黄又爽大尺度在线免费看| 热re99久久精品国产66热6| 中文字幕另类日韩欧美亚洲嫩草| 国产精品一区二区在线不卡| 婷婷成人精品国产| 男女免费视频国产| 免费黄网站久久成人精品| 国产男女超爽视频在线观看| 黑人欧美特级aaaaaa片| 欧美97在线视频| 一本—道久久a久久精品蜜桃钙片| 一二三四在线观看免费中文在 | 你懂的网址亚洲精品在线观看| 国产男人的电影天堂91| 最新中文字幕久久久久| 午夜福利视频精品| 亚洲,欧美精品.| 黑人高潮一二区| 日韩制服丝袜自拍偷拍| 免费播放大片免费观看视频在线观看| 成人漫画全彩无遮挡| 免费黄网站久久成人精品| 国产女主播在线喷水免费视频网站| 日本av手机在线免费观看| 天天影视国产精品| 日韩中字成人| 一本大道久久a久久精品| 精品少妇黑人巨大在线播放| 欧美激情 高清一区二区三区| 久久精品久久久久久噜噜老黄| 日本欧美国产在线视频| 尾随美女入室| 十分钟在线观看高清视频www| 午夜激情av网站| 国产一区二区激情短视频 | 在线观看人妻少妇| 国产一区二区三区av在线| 女性被躁到高潮视频| 精品少妇黑人巨大在线播放| 九色成人免费人妻av| 久久久久久人妻| 两性夫妻黄色片 | 亚洲国产成人一精品久久久| 亚洲一码二码三码区别大吗| 欧美性感艳星| 妹子高潮喷水视频| 大话2 男鬼变身卡| 久久午夜福利片| 高清视频免费观看一区二区| 亚洲内射少妇av| 纯流量卡能插随身wifi吗| 超色免费av| 国语对白做爰xxxⅹ性视频网站| 国产成人午夜福利电影在线观看| 色吧在线观看| 国产爽快片一区二区三区| 亚洲精品久久久久久婷婷小说| 国产在视频线精品| 国产在线视频一区二区| 久久久国产一区二区| 高清在线视频一区二区三区| 大香蕉久久成人网| 国语对白做爰xxxⅹ性视频网站| 久久精品国产亚洲av涩爱| 丰满乱子伦码专区| 伊人久久国产一区二区| 哪个播放器可以免费观看大片| 9热在线视频观看99| 国产在线免费精品| 国产视频首页在线观看| 在线观看免费视频网站a站| 五月玫瑰六月丁香| 丝瓜视频免费看黄片| 高清视频免费观看一区二区| 波多野结衣一区麻豆| 久久国内精品自在自线图片| 精品人妻熟女毛片av久久网站| 男女边吃奶边做爰视频| av黄色大香蕉| 91aial.com中文字幕在线观看| 男人爽女人下面视频在线观看| 波野结衣二区三区在线| 观看美女的网站| 18+在线观看网站| 各种免费的搞黄视频| 男女午夜视频在线观看 | 久久久久视频综合| 久久精品国产亚洲av天美| 成人毛片60女人毛片免费| 亚洲精品国产色婷婷电影| 日韩电影二区| 国产男人的电影天堂91| 欧美成人午夜免费资源| 99热国产这里只有精品6| 超碰97精品在线观看| 这个男人来自地球电影免费观看 | 亚洲国产日韩一区二区| 国产精品女同一区二区软件| 精品一品国产午夜福利视频| 亚洲国产精品专区欧美| 九九爱精品视频在线观看| 国产高清不卡午夜福利| 免费观看性生交大片5| 精品少妇黑人巨大在线播放| 视频中文字幕在线观看| 91精品三级在线观看| 国产精品一区二区在线不卡| 久久久欧美国产精品| 搡女人真爽免费视频火全软件| 亚洲五月色婷婷综合| 亚洲精品乱码久久久久久按摩| 久久午夜福利片| 久久久久久久久久久免费av| 亚洲精品av麻豆狂野| 国产精品.久久久| 男男h啪啪无遮挡| 波野结衣二区三区在线| 卡戴珊不雅视频在线播放| 精品少妇黑人巨大在线播放| 成人漫画全彩无遮挡| 尾随美女入室| 欧美性感艳星| 18+在线观看网站| 夫妻午夜视频| a级片在线免费高清观看视频| 欧美精品国产亚洲| videos熟女内射| 日本wwww免费看| 高清在线视频一区二区三区| 精品一区二区三区四区五区乱码 | 黑人欧美特级aaaaaa片| 午夜福利,免费看| 午夜免费鲁丝| 久久久久精品人妻al黑| av国产精品久久久久影院| 日韩熟女老妇一区二区性免费视频| 久久青草综合色| 成人免费观看视频高清| 国产成人av激情在线播放| 精品少妇黑人巨大在线播放| 观看美女的网站| 黄色一级大片看看| 国产精品女同一区二区软件| 久久国产精品男人的天堂亚洲 | 婷婷成人精品国产| 日韩伦理黄色片| av在线app专区|