• <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ì)
    91午夜精品亚洲一区二区三区| 国产片特级美女逼逼视频| 国产精品秋霞免费鲁丝片| av在线观看视频网站免费| 如日韩欧美国产精品一区二区三区 | 最近手机中文字幕大全| 丰满少妇做爰视频| av国产精品久久久久影院| 国产免费视频播放在线视频| 国产精品久久久久久精品电影小说| 亚洲精品日本国产第一区| 性色av一级| 高清在线视频一区二区三区| 久久毛片免费看一区二区三区| 国产精品人妻久久久久久| 97超碰精品成人国产| 午夜福利,免费看| 波野结衣二区三区在线| 大话2 男鬼变身卡| 如日韩欧美国产精品一区二区三区 | 全区人妻精品视频| 免费观看av网站的网址| 亚洲天堂av无毛| 色婷婷av一区二区三区视频| 观看美女的网站| 2021少妇久久久久久久久久久| 久久精品国产亚洲网站| 久久精品久久久久久久性| 国产一级毛片在线| 亚洲精品456在线播放app| 国产黄片视频在线免费观看| 亚洲,一卡二卡三卡| 老司机影院成人| 最近的中文字幕免费完整| 性色av一级| 精品亚洲成a人片在线观看| 国产av一区二区精品久久| 亚洲丝袜综合中文字幕| 日本黄色日本黄色录像| 久久国产精品大桥未久av| 两个人免费观看高清视频| 国产欧美日韩一区二区三区在线 | 国产亚洲av片在线观看秒播厂| 91aial.com中文字幕在线观看| 国产av码专区亚洲av| 成年女人在线观看亚洲视频| 国产深夜福利视频在线观看| 国产极品粉嫩免费观看在线 | 最黄视频免费看| 亚洲欧美精品自产自拍| 新久久久久国产一级毛片| 成人午夜精彩视频在线观看| 99视频精品全部免费 在线| 26uuu在线亚洲综合色| 国产亚洲午夜精品一区二区久久| 啦啦啦中文免费视频观看日本| 精品人妻熟女av久视频| 99热这里只有是精品在线观看| 日韩视频在线欧美| 一个人看视频在线观看www免费| 久久人妻熟女aⅴ| 日韩精品有码人妻一区| 一级毛片电影观看| 久久 成人 亚洲| 毛片一级片免费看久久久久| 99九九在线精品视频| 日本欧美国产在线视频| 麻豆乱淫一区二区| 老女人水多毛片| 国产一区有黄有色的免费视频| 久久 成人 亚洲| 午夜91福利影院| 精品人妻熟女av久视频| 美女国产高潮福利片在线看| 亚洲国产精品国产精品| 日本黄色日本黄色录像| 边亲边吃奶的免费视频| 99久久中文字幕三级久久日本| 精品一区在线观看国产| 免费观看性生交大片5| 色视频在线一区二区三区| 嫩草影院入口| 熟女人妻精品中文字幕| 亚洲国产欧美日韩在线播放| 亚洲精品一二三| 高清黄色对白视频在线免费看| 久久久久久久久大av| 欧美日韩视频高清一区二区三区二| 午夜91福利影院| 国产精品熟女久久久久浪| 超碰97精品在线观看| 日本欧美视频一区| 亚洲经典国产精华液单| 久久久午夜欧美精品| 一边亲一边摸免费视频| 亚洲色图综合在线观看| 欧美日韩av久久| 欧美精品亚洲一区二区| 久久精品国产a三级三级三级| 狂野欧美激情性bbbbbb| 80岁老熟妇乱子伦牲交| 国产精品国产av在线观看| av.在线天堂| 欧美日韩精品成人综合77777| 中文精品一卡2卡3卡4更新| 高清不卡的av网站| 久久久精品区二区三区| 婷婷色av中文字幕| 免费黄网站久久成人精品| 亚洲欧美成人精品一区二区| 人妻夜夜爽99麻豆av| 欧美bdsm另类| 国产日韩一区二区三区精品不卡 | av国产精品久久久久影院| 国产精品熟女久久久久浪| 免费观看无遮挡的男女| 免费高清在线观看日韩| 欧美日韩一区二区视频在线观看视频在线| 麻豆成人av视频| 亚洲在久久综合| 99国产精品免费福利视频| 黄色配什么色好看| 国产女主播在线喷水免费视频网站| 日韩伦理黄色片| 26uuu在线亚洲综合色| 草草在线视频免费看| 在线观看美女被高潮喷水网站| 最近2019中文字幕mv第一页| 欧美97在线视频| 亚洲av欧美aⅴ国产| 亚州av有码| 卡戴珊不雅视频在线播放| 亚洲av不卡在线观看| 免费大片黄手机在线观看| 午夜日本视频在线| 一级a做视频免费观看| 亚洲综合精品二区| 夜夜骑夜夜射夜夜干| 极品少妇高潮喷水抽搐| 国产精品.久久久| 亚洲伊人久久精品综合| 久久97久久精品| 五月天丁香电影| 少妇 在线观看| 精品人妻一区二区三区麻豆| kizo精华| 国产男女超爽视频在线观看| 亚洲精品,欧美精品| 久久久久人妻精品一区果冻| 99久国产av精品国产电影| 性色av一级| 80岁老熟妇乱子伦牲交| 中文天堂在线官网| 精品午夜福利在线看| 91精品伊人久久大香线蕉| 水蜜桃什么品种好| 久热这里只有精品99| 夜夜看夜夜爽夜夜摸| 桃花免费在线播放| 性色avwww在线观看| 狠狠精品人妻久久久久久综合| 丁香六月天网| 国产毛片在线视频| 久久精品国产亚洲av涩爱| 亚洲人与动物交配视频| 十八禁高潮呻吟视频| 亚洲国产日韩一区二区| 亚洲国产精品一区二区三区在线| 色吧在线观看| 亚洲国产色片| 一级爰片在线观看| 国产成人精品久久久久久| 免费不卡的大黄色大毛片视频在线观看| 亚洲成人手机| 亚洲人成网站在线播| 国产高清不卡午夜福利| 桃花免费在线播放| 老司机亚洲免费影院| 亚洲少妇的诱惑av| 国产伦理片在线播放av一区| 最新的欧美精品一区二区| 久久午夜综合久久蜜桃| 丝袜在线中文字幕| 国产精品.久久久| 亚洲美女视频黄频| 美女福利国产在线| 美女国产高潮福利片在线看| 丁香六月天网| 99国产精品免费福利视频| 精品国产露脸久久av麻豆| 一级爰片在线观看| 老司机影院毛片| 国产精品国产三级专区第一集| 精品国产一区二区久久| 精品一区在线观看国产| 亚洲人与动物交配视频| 精品亚洲成国产av| 久久精品熟女亚洲av麻豆精品| 国产在线视频一区二区| 大话2 男鬼变身卡| 色吧在线观看| 久久精品国产自在天天线| 美女脱内裤让男人舔精品视频| 在线观看免费日韩欧美大片 | av女优亚洲男人天堂| 亚洲不卡免费看| 亚洲精品国产av蜜桃| 免费观看性生交大片5| 久久久久精品性色| 极品少妇高潮喷水抽搐| 亚洲在久久综合| 这个男人来自地球电影免费观看 | 久久精品人人爽人人爽视色| 欧美日韩亚洲高清精品| 午夜福利视频在线观看免费| 国产熟女欧美一区二区| 大码成人一级视频| 美女cb高潮喷水在线观看| 999精品在线视频| 欧美激情国产日韩精品一区| 又大又黄又爽视频免费| 午夜福利视频精品| 狂野欧美激情性bbbbbb| 亚洲国产精品国产精品| 久久国产精品大桥未久av| 日本wwww免费看| 91久久精品国产一区二区成人| 青春草国产在线视频| 一级毛片aaaaaa免费看小| 一级毛片电影观看| 久久热精品热| 国产成人免费观看mmmm| 一本—道久久a久久精品蜜桃钙片| 欧美性感艳星| 人人澡人人妻人| 亚洲av免费高清在线观看| 蜜桃久久精品国产亚洲av| 国产午夜精品一二区理论片| 亚洲第一区二区三区不卡| 午夜激情久久久久久久| 久久人人爽人人片av| 一本一本久久a久久精品综合妖精 国产伦在线观看视频一区 | 欧美少妇被猛烈插入视频| 97精品久久久久久久久久精品| 在线观看免费视频网站a站| 欧美精品一区二区大全| 亚洲av福利一区| 国产片特级美女逼逼视频| 欧美一级a爱片免费观看看| 黑人猛操日本美女一级片| 好男人视频免费观看在线| av在线老鸭窝| 国产成人精品久久久久久| 亚洲内射少妇av| 久久久久精品性色| 亚洲第一av免费看| 熟女电影av网| 亚洲av.av天堂| 色哟哟·www| 免费观看在线日韩| 亚洲欧美成人综合另类久久久| 国产成人a∨麻豆精品| 99久久人妻综合| .国产精品久久| 99久久中文字幕三级久久日本| 中文字幕精品免费在线观看视频 | 春色校园在线视频观看| 99久久精品国产国产毛片| 我的女老师完整版在线观看| 国产综合精华液| 热re99久久精品国产66热6| 国产午夜精品一二区理论片| 一区二区三区精品91| 亚洲av电影在线观看一区二区三区| av女优亚洲男人天堂| 丝袜喷水一区| 中国国产av一级| 大香蕉97超碰在线| 高清在线视频一区二区三区| 色94色欧美一区二区| 一级毛片 在线播放| 国产精品久久久久成人av| 亚洲图色成人| 久久国产精品大桥未久av| 18禁裸乳无遮挡动漫免费视频| 国产片特级美女逼逼视频| 国产淫语在线视频| 欧美xxⅹ黑人| 中文精品一卡2卡3卡4更新| 中文乱码字字幕精品一区二区三区| av专区在线播放| 在线观看免费日韩欧美大片 | 亚洲五月色婷婷综合| 蜜桃在线观看..| av福利片在线| 男男h啪啪无遮挡| 极品少妇高潮喷水抽搐| 免费观看av网站的网址| 午夜久久久在线观看| a级毛色黄片| 十八禁网站网址无遮挡| 纵有疾风起免费观看全集完整版| av视频免费观看在线观看| freevideosex欧美| av国产精品久久久久影院| 免费黄频网站在线观看国产| av网站免费在线观看视频| 一二三四中文在线观看免费高清| 精品亚洲成国产av| 午夜福利网站1000一区二区三区| 国产精品欧美亚洲77777| 欧美日韩视频高清一区二区三区二| 精品久久蜜臀av无| 91在线精品国自产拍蜜月| 97在线人人人人妻| 欧美xxⅹ黑人| 啦啦啦视频在线资源免费观看| 男女无遮挡免费网站观看| 在线观看免费日韩欧美大片 | 99热这里只有精品一区| 大陆偷拍与自拍| 各种免费的搞黄视频| 在线免费观看不下载黄p国产| 国产白丝娇喘喷水9色精品| 亚洲欧洲日产国产| 丝袜在线中文字幕| 国产熟女欧美一区二区| 又粗又硬又长又爽又黄的视频| 久久99热6这里只有精品| 亚洲经典国产精华液单| 国产亚洲欧美精品永久| 国产日韩欧美视频二区| 国产av精品麻豆| 在线观看美女被高潮喷水网站| 日日啪夜夜爽| 国产精品国产三级专区第一集| 久久国产亚洲av麻豆专区| 乱码一卡2卡4卡精品| 婷婷色麻豆天堂久久| 日韩成人av中文字幕在线观看| 中文字幕制服av| 欧美日本中文国产一区发布| 黄色视频在线播放观看不卡| 久久国产精品男人的天堂亚洲 | 国产女主播在线喷水免费视频网站| 91久久精品国产一区二区三区| 免费黄网站久久成人精品| 免费观看av网站的网址| 免费av中文字幕在线| 免费日韩欧美在线观看| 观看美女的网站| 美女cb高潮喷水在线观看| 亚洲五月色婷婷综合| 成人综合一区亚洲| 91久久精品电影网| 色视频在线一区二区三区| 如何舔出高潮| 波野结衣二区三区在线| 男女国产视频网站| 国产精品久久久久久av不卡| 欧美成人精品欧美一级黄| videosex国产| 18禁裸乳无遮挡动漫免费视频| 最近2019中文字幕mv第一页| 91精品三级在线观看| 日本猛色少妇xxxxx猛交久久| 免费黄网站久久成人精品| 国产黄频视频在线观看| 国内精品宾馆在线| 91精品三级在线观看| 最近最新中文字幕免费大全7| 成年人午夜在线观看视频| 欧美+日韩+精品| 精品一区二区免费观看| 91精品国产九色| 22中文网久久字幕| 丰满少妇做爰视频| 欧美人与善性xxx| 多毛熟女@视频| 日本91视频免费播放| 日本色播在线视频| av卡一久久| 91精品国产九色| 精品亚洲乱码少妇综合久久| 午夜福利在线观看免费完整高清在| 在线观看美女被高潮喷水网站| 伊人久久国产一区二区| 亚洲精品aⅴ在线观看| 男女边吃奶边做爰视频| 少妇熟女欧美另类| 赤兔流量卡办理| 中文字幕久久专区| 亚洲精品久久久久久婷婷小说| 亚洲精品久久午夜乱码| 精品久久久噜噜| 国产av精品麻豆| tube8黄色片| 国产成人精品无人区| 免费大片18禁| 特大巨黑吊av在线直播| 黄色配什么色好看| 最黄视频免费看| 国语对白做爰xxxⅹ性视频网站| 十分钟在线观看高清视频www| 亚洲情色 制服丝袜| 蜜桃国产av成人99| 在线天堂最新版资源| 视频中文字幕在线观看| 国产成人精品一,二区| av福利片在线| 一本一本综合久久| 欧美最新免费一区二区三区| 久久99热这里只频精品6学生| 亚洲三级黄色毛片| 美女国产视频在线观看| 婷婷色av中文字幕| a级毛片在线看网站| 我要看黄色一级片免费的| 人妻 亚洲 视频| 色婷婷av一区二区三区视频| 国内精品宾馆在线| 国国产精品蜜臀av免费| videossex国产| 久久综合国产亚洲精品| 日韩 亚洲 欧美在线| 99热这里只有是精品在线观看| 亚洲成人av在线免费| 精品久久国产蜜桃| 亚洲国产精品国产精品| 在线观看免费日韩欧美大片 | 纯流量卡能插随身wifi吗| 日韩熟女老妇一区二区性免费视频| 国产极品天堂在线| 久久久欧美国产精品| 国产精品一国产av| 简卡轻食公司| 久久女婷五月综合色啪小说| 天美传媒精品一区二区| 亚洲第一av免费看| 蜜臀久久99精品久久宅男| 亚洲国产色片| 久久久久国产网址| 欧美另类一区| 国产色爽女视频免费观看| 欧美精品一区二区免费开放| 亚洲精品av麻豆狂野| 桃花免费在线播放| 亚洲五月色婷婷综合| 在线天堂最新版资源| 一级二级三级毛片免费看| 久久国产精品男人的天堂亚洲 | 久久人妻熟女aⅴ| 国产免费一区二区三区四区乱码| 国产成人午夜福利电影在线观看| 桃花免费在线播放| 成人二区视频| 国产精品久久久久成人av| 美女主播在线视频| 日韩欧美精品免费久久| 亚洲图色成人| 国产免费一级a男人的天堂| 亚洲欧洲精品一区二区精品久久久 | 男女国产视频网站| 婷婷色av中文字幕| 亚洲人成77777在线视频| 国产成人91sexporn| 日韩免费高清中文字幕av| 国产亚洲精品第一综合不卡 | 国产精品蜜桃在线观看| 亚洲中文av在线| 亚洲怡红院男人天堂| 色婷婷久久久亚洲欧美| 日韩一区二区视频免费看| 亚洲精品亚洲一区二区| 男女国产视频网站| 国产黄色视频一区二区在线观看| 免费人成在线观看视频色| 这个男人来自地球电影免费观看 | 天天操日日干夜夜撸| 国产精品一区二区在线不卡| 亚洲国产欧美日韩在线播放| 亚洲一区二区三区欧美精品| 久久久久网色| 国产精品一区二区在线观看99| 高清不卡的av网站| 九草在线视频观看| 啦啦啦中文免费视频观看日本| 十八禁网站网址无遮挡| 最近中文字幕高清免费大全6| 久久久久久久久久成人| 国产视频首页在线观看| 国产精品不卡视频一区二区| 人成视频在线观看免费观看| 久久久久网色| 亚洲成色77777| 9色porny在线观看| 国产午夜精品一二区理论片| 一级片'在线观看视频| 成年av动漫网址| 汤姆久久久久久久影院中文字幕| 国产精品三级大全| 国产男女内射视频| 亚洲av综合色区一区| 国产黄色免费在线视频| 亚洲欧美中文字幕日韩二区| 欧美三级亚洲精品| 美女内射精品一级片tv| 99re6热这里在线精品视频| 丰满迷人的少妇在线观看| 亚洲丝袜综合中文字幕| 日韩制服骚丝袜av| 18禁观看日本| 久久99蜜桃精品久久| 色哟哟·www| 一级a做视频免费观看| 国产亚洲精品第一综合不卡 | 97超碰精品成人国产| 七月丁香在线播放| 一边摸一边做爽爽视频免费| 永久免费av网站大全| 日韩欧美精品免费久久| 国产伦理片在线播放av一区| 日韩不卡一区二区三区视频在线| 国产精品国产三级专区第一集| 毛片一级片免费看久久久久| 亚洲在久久综合| 国产高清国产精品国产三级| 蜜桃在线观看..| 久久久国产一区二区| 在线亚洲精品国产二区图片欧美 | 一区二区三区四区激情视频| 国产精品人妻久久久久久| 美女国产视频在线观看| 国产精品久久久久久精品古装| 女的被弄到高潮叫床怎么办| 黑丝袜美女国产一区| 伦理电影免费视频| 精品国产国语对白av| 欧美日本中文国产一区发布| 黄片播放在线免费| 伊人久久精品亚洲午夜| 久久国产亚洲av麻豆专区| 国产男女超爽视频在线观看| av卡一久久| 中文字幕人妻丝袜制服| 我要看黄色一级片免费的| 在线天堂最新版资源| 亚洲色图综合在线观看| 成年人免费黄色播放视频| 日韩成人av中文字幕在线观看| 久久av网站| 日韩av在线免费看完整版不卡| 啦啦啦在线观看免费高清www| 十八禁高潮呻吟视频| 少妇丰满av| 亚洲国产成人一精品久久久| 美女主播在线视频| 亚洲国产成人一精品久久久| 亚洲熟女精品中文字幕| 久久久久久久久大av| 一本—道久久a久久精品蜜桃钙片| 999精品在线视频| 婷婷色麻豆天堂久久| 久久人人爽人人片av| 国产精品99久久久久久久久| 69精品国产乱码久久久| 中文字幕免费在线视频6| 日韩制服骚丝袜av| 久久久久久久久久久丰满| 插逼视频在线观看| 高清欧美精品videossex| 欧美精品人与动牲交sv欧美| 亚洲精品成人av观看孕妇| 日本色播在线视频| 黑人巨大精品欧美一区二区蜜桃 | 欧美三级亚洲精品| 国产精品熟女久久久久浪| 久久影院123| 超碰97精品在线观看| 日韩伦理黄色片| 亚洲精品一区蜜桃| 五月玫瑰六月丁香| 成年女人在线观看亚洲视频| 精品久久国产蜜桃| 亚洲精华国产精华液的使用体验| 91久久精品国产一区二区三区| 亚洲无线观看免费| 男男h啪啪无遮挡| 永久网站在线| 黄色视频在线播放观看不卡| a级毛片在线看网站| 熟女人妻精品中文字幕| 国产成人精品久久久久久| 国产精品久久久久久精品电影小说| 国产一区有黄有色的免费视频| 日韩,欧美,国产一区二区三区| 黄色怎么调成土黄色| 成人免费观看视频高清| 午夜福利影视在线免费观看| 亚洲国产精品一区二区三区在线| 水蜜桃什么品种好| 日本av免费视频播放| 狠狠精品人妻久久久久久综合| 欧美日韩精品成人综合77777| videos熟女内射| 欧美另类一区| 少妇高潮的动态图| 国产精品嫩草影院av在线观看| 91午夜精品亚洲一区二区三区| 蜜桃国产av成人99| 亚洲伊人久久精品综合| 午夜影院在线不卡| 不卡视频在线观看欧美| 日韩大片免费观看网站| 日韩电影二区|