0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

介紹WebAssembly現(xiàn)存的一些風(fēng)險(xiǎn)和他們的應(yīng)對方法

工程師鄧生 ? 來源:覺學(xué)社 ? 作者:張漢東 ? 2022-09-21 09:30 ? 次閱讀

標(biāo)準(zhǔn)化進(jìn)展非常緩慢。為此 Fermyon 加入了 字節(jié)碼聯(lián)盟 親自推動標(biāo)準(zhǔn)化進(jìn)程,并通過構(gòu)建 Spin 代碼實(shí)現(xiàn)來充分利用標(biāo)準(zhǔn)

語言支持不夠。Fermyon 認(rèn)為前 20 種語言中至少有 15 種必須完全支持 WebAssembly 以及 WASI 和組件,才能正確地認(rèn)為 WebAssembly 被很好地采用。Fermyon 采取的立場是將注意力集中在最受歡迎的語言上,這就是為什么使用 Rust 而不是 C 或Zig。

這方面也有一些好消息:

語言支持正在迅速增長,今年C#、Python和Ruby都增加了支持

wasi 支持現(xiàn)在是進(jìn)入 wasm 游戲領(lǐng)域的籌碼

在主流實(shí)現(xiàn)語言未能發(fā)揮作用的地方,該語言的替代實(shí)現(xiàn)正在加緊發(fā)展,比如 tinygo 對于 wasm 的支持就超越了 go

生態(tài)系統(tǒng)不是可選的。WebAssembly 有望成為下一波計(jì)算浪潮,但除非 Fermyon 能圍繞它建立生態(tài)系統(tǒng),所以 Fermyon 正在努力聯(lián)合相關(guān)其他企業(yè)合作共建社區(qū)。

社區(qū)實(shí)現(xiàn)碎片化。(比如 deno 和其他非標(biāo)準(zhǔn)化實(shí)現(xiàn),文章沒有明說)。可悲的是,有時(shí)這僅僅是由于無知和不參與:“我們不知道有一個標(biāo)準(zhǔn)為此而出現(xiàn)”。所以目前發(fā)布的組件規(guī)范(正在進(jìn)行中,但正在迅速成熟)旨在解決這類問題,這個標(biāo)準(zhǔn)使得在不同的主機(jī)實(shí)現(xiàn)之間共享 WebAssembly 二進(jìn)制文件成為可能。

還有一個不幸的趨勢,即一些開發(fā)人員選擇與組件模型相反的工作,創(chuàng)建與他們自己的主機(jī)運(yùn)行時(shí)的強(qiáng)鏈接。走這條路一方面會導(dǎo)致平臺鎖定,另一方面會毫無意義地重新編寫相同的代碼(針對略有不同的主機(jī)進(jìn)行工具化)。幸運(yùn)的是,那些準(zhǔn)備最好的人(Fastly、Mozilla、Microsoft)反而選擇推動互操作性標(biāo)準(zhǔn)以造福所有人。這是正確的第一步。

為了阻止破壞性的碎片化“手榴彈”,我們必須增加社會壓力,不要我行我素,而要堅(jiān)持互操作性標(biāo)準(zhǔn)。做到這一點(diǎn)的一個關(guān)鍵方法是彼此公開合作(通過字節(jié)碼聯(lián)盟、W3 和 CNCF 等組織),不僅要創(chuàng)建和實(shí)施標(biāo)準(zhǔn),還要創(chuàng)建對話論壇。

Fermyon 的愿景是,在五年內(nèi),WebAssembly 將成為常態(tài),而不是小眾市場。新一波應(yīng)用程序?qū)⒛軌蚶?WebAssembly 的速度、安全性和組件模型。為了實(shí)現(xiàn)這一目標(biāo),我們每個人都可以發(fā)揮作用。

Wasmtime 1.0 性能概覽

近日字節(jié)碼聯(lián)盟發(fā)布了 wasmtime 1.0 性能概覽[2] 的一篇文章,為將在 9.20號發(fā)布的 wasmtime 1.0 穩(wěn)定版做前期鋪墊,介紹了 wasmtime 團(tuán)隊(duì)近期在編譯器和運(yùn)行時(shí)中所做的工作。這里只做重點(diǎn)摘要,并非全文翻譯,對細(xì)節(jié)感興趣的可進(jìn)一步參閱原文。

什么是性能

讓 Wasmtime 和 Cranelift 變得更快意味著什么?所謂的“快”是什么意思?

Cranelift 也被用于 Rust Debug 模式編譯后端

當(dāng) Wasmtime 執(zhí)行 Wasm 程序時(shí),CPU既執(zhí)行從Wasm字節(jié)碼編譯的本地指令,也執(zhí)行 "Wasmtime Runtime "的一部分,Wasmtime Runtime 用于維護(hù)數(shù)據(jù)結(jié)構(gòu)以幫助實(shí)現(xiàn)Wasm語義。這兩部分的執(zhí)行有兩個階段:啟動初始化(Wasm代碼的編譯,和運(yùn)行時(shí)的初始化)和 穩(wěn)態(tài)(steady-state)執(zhí)行。這兩個層面的四個組合都對性能有一定的影響,可以分別進(jìn)行優(yōu)化。

Compiler (Cranelift) Runtime (Wasmtime)
啟動階段 代碼編譯時(shí)間 Wasm 模塊實(shí)例化時(shí)間
穩(wěn)態(tài)階段 生成代碼的速度 運(yùn)行時(shí)的基本速度

wasmtime 對于改善這四個象限中的每一項(xiàng)都做了大量工作。

Wasm 模塊實(shí)例化

WebAssembly 之所以安全是因?yàn)閣asm 模塊每個實(shí)例與生俱來的隔離性。為了有效地利用這種隔離性,Wasm的一些應(yīng)用將每一個工作單元實(shí)例化為一個新的實(shí)例,例如服務(wù)器上每個傳入的請求。因此,極快的模塊實(shí)例化是像Wasmtime這樣的Wasm VM的一個關(guān)鍵要求。

現(xiàn)在 wasmtime 的模塊實(shí)例化速度已經(jīng)被優(yōu)化到了微秒級別。這是如何做到的呢?

虛擬內(nèi)存技術(shù)

在過去,wasmtime 是通過為 wasm 應(yīng)用初始化一大塊內(nèi)存(通過malloc或mmap或一些其他分配器),然后將數(shù)據(jù)復(fù)制到正確的位置。

現(xiàn)在,是從現(xiàn)代計(jì)算機(jī)使用的虛擬內(nèi)存技術(shù)獲得靈感,實(shí)現(xiàn)了一個 實(shí)例分配器[3]使用了mmap 、madvise 和寫時(shí)復(fù)制(copy-on-write)的技術(shù)將實(shí)例化的成本大大的降低了。

延遲初始化

Wasmtime運(yùn)行時(shí)在開始執(zhí)行已編譯的Wasm代碼之前,要花費(fèi)大量時(shí)間來初始化數(shù)據(jù)結(jié)構(gòu)。所以,團(tuán)隊(duì)為函數(shù)引用表和它們所指向的函數(shù)閉包對象實(shí)現(xiàn)了延遲初始化[4]。

優(yōu)化結(jié)果

SpiderMonkey.wasm 的實(shí)例化時(shí)間從大約2毫秒到5微秒,快了400倍。

運(yùn)行時(shí)性能

Wasm 執(zhí)行過程中的大部分 CPU 時(shí)間通常花在Wasm程序本身,或它調(diào)用的 "hostcalls"(這是Wasmtime用戶插入Wasmtime的代碼,無法直接控制),除此之外,Wasmtime本身有一些部分在某些情況下必須運(yùn)行,這部分代碼就是 Wasmtime Runtime 的性能優(yōu)化之處。

加速棧走查(Stack-Walking)

之前,為了讓W(xué)asmtime列舉所有的棧幀(stackframes),Cranelift編譯器產(chǎn)生了所謂的 "unwind info"。這是一種元數(shù)據(jù),描述了編譯后的代碼將在任意給定點(diǎn)上把值放在棧中。利用這些元數(shù)據(jù),Wasmtime的 "unwinder"能夠逆向程序狀態(tài):它理解一個活動函數(shù)每次調(diào)用的棧幀,最終找出誰調(diào)用了它,并在棧上迭代,直到它到達(dá)Wasm的初始入口。整個過程非常慢。

團(tuán)隊(duì)對此進(jìn)行了改進(jìn),確保始終保持一個幀指針的鏈表,從而達(dá)到棧走查像遍歷鏈表那么簡單。這種性能改進(jìn)是一個巨大的質(zhì)量改進(jìn):它允許啟用棧跟蹤,并大幅提高Wasmtime的健壯性。

加速多任務(wù)協(xié)作 與 代際(Epoch) 中斷

Wasmtime的一個常見用例是同時(shí)并發(fā)運(yùn)行許多不同的 WebAssembly guests,并在它們之間設(shè)置時(shí)間片。Wasmtime內(nèi)置支持在一個異步事件循環(huán)上運(yùn)行對Wasm的調(diào)用。

Wasmtime 用戶在這種情況下可能遇到的一個問題是如何限制 Wasm 程序的執(zhí)行時(shí)間。通常,當(dāng)與事件循環(huán)異步運(yùn)行時(shí),計(jì)算密集型任務(wù)應(yīng)拆分為多個段,以便事件循環(huán)不會停止超過最大“時(shí)間片”。

通過將 Wasm 字節(jié)碼標(biāo)準(zhǔn)編譯為本地機(jī)器代碼,Wasm 中的循環(huán)成為編譯代碼中的循環(huán),并運(yùn)行盡可能多的迭代,沒有限制。如果用戶從事件循環(huán)中調(diào)用此函數(shù),則該事件循環(huán)可能會無限期停止。

因此,特別是在運(yùn)行不受信任的代碼時(shí),Wasmtime 用戶必須建立一種在一定時(shí)間限制后重新獲得控制權(quán)的方法。所以 Wasmtime 必須提供一種在某個時(shí)間點(diǎn)中斷 Wasm 執(zhí)行的方法。

之前,實(shí)現(xiàn)這一行為的主要方式是通過“燃料(fuel)”。這是一種機(jī)制,通過該機(jī)制,已編譯的 Wasm 代碼增加了對“操作”進(jìn)行計(jì)數(shù)的代碼,根據(jù)限制檢查當(dāng)前計(jì)數(shù),如果超出限制,則返回給調(diào)用者或事件循環(huán)。“燃料(fuel)”是一種有效的機(jī)制,但它成本很高:它需要用“計(jì)數(shù)”來擴(kuò)充每一段代碼,并經(jīng)常將該計(jì)數(shù)存儲到內(nèi)存中并檢查它。

團(tuán)隊(duì)使用了基于代際的中斷[5]取代了 “燃料(fuel)”機(jī)制,性能提升了兩倍。

使用 “燃料”機(jī)制還是代際中斷,是一種權(quán)衡?!叭剂稀睓C(jī)制更加精準(zhǔn),而代際中斷性能更好。

Cranelift 編譯代碼的質(zhì)量

Cranelift 用于將Wasm字節(jié)碼編譯成計(jì)算機(jī)可以直接執(zhí)行的本地機(jī)器代碼。

寄存器分配器改造:regalloc2

在過去的一年里,wasmtime引入了新的寄存器分配器 regalloc2[6]。寄存器分配器是編譯器的一個部分,它為程序中的值分配存儲位置。在真正的CPU中,指令對寄存器中的數(shù)據(jù)進(jìn)行操作,寄存器是一些小的存儲位置,每個位置可以容納一個值(例如,一個64位的數(shù)字)。寄存器分配器決定在什么時(shí)候?qū)⒛男┲当4嬖谀男┘拇嫫髦?。做好這一點(diǎn)可以大大改善程序的性能,因?yàn)樗馕吨俚臄?shù)值移動。WebAssembly,作為一個抽象的、與硬件無關(guān)的虛擬機(jī),沒有大多數(shù)指令的輸入和輸出位置的概念。

regalloc2的設(shè)計(jì)是為了支持更高級的算法,以決定如何向寄存器分配數(shù)值。當(dāng)引入時(shí),它將SpiderMonkey.wasm的運(yùn)行時(shí)性能提高了約5%,將另一個CPU密集型基準(zhǔn)測試bz2的性能提高了4%。

更好的模式管理:新的后端、ISLE和持續(xù)的調(diào)整

指令選擇問題是指選擇最佳的CPU指令來實(shí)現(xiàn)一個給定的程序行為。因?yàn)槊總€CPU都有自己獨(dú)特的指令集,而且這些指令可以以許多不同的方式組合,這是一個非常難解決的組合難題。Cranelift最初采用了一種新的編譯器后端設(shè)計(jì),可以實(shí)現(xiàn)更高級的模式匹配,目前采取的方法是用模式匹配DSL(特定領(lǐng)域語言)來表達(dá)底層的指令,這樣我們就可以更容易地調(diào)整這些模式。

未來:中端優(yōu)化

在未來,我們計(jì)劃為Cranelift引入更先進(jìn)的中端優(yōu)化。中端優(yōu)化器 "是編譯器的一部分,在程序被 "降級"為機(jī)器特定的形式之前(也就是在指令選擇之前),以各種方式對程序進(jìn)行轉(zhuǎn)換,使其更快。有一套經(jīng)典的優(yōu)化方法,幾乎所有的編譯器都會執(zhí)行,包括簡化常數(shù)表達(dá)式(1+1變成2)等基本規(guī)則。但也有許多更復(fù)雜和微妙的轉(zhuǎn)換。

Cranelift: 編譯時(shí)優(yōu)化

除了優(yōu)化Cranelift生成的代碼,編譯過程本身如果太慢,那么Wasmtime可能需要很長的時(shí)間來啟動新的代碼,將會阻礙生產(chǎn)力(對于Wasm開發(fā)人員)和響應(yīng)能力(對于訪問新應(yīng)用程序的最終用戶)。因此,編譯器的速度是一個重要的指標(biāo)。

廣義上講,我們可以通過在后端關(guān)鍵部分選擇更好的算法來提高編譯時(shí)間,如寄存器分配器或優(yōu)化通道,或通過做一般的程序優(yōu)化,如減少內(nèi)存使用。

regalloc2

切換到 regalloc2 顯著改善了編譯時(shí)間,因?yàn)榧拇嫫鞣峙湔季幾g時(shí)間的很大一部分:測量單線程時(shí)間(不是并行編譯),SpiderMonkey.wasm 的構(gòu)建速度提高了 6%,bz2 的構(gòu)建速度提高了 10%。

中端優(yōu)化器:將多個passes合并為一

算法重新設(shè)計(jì)也可以大大縮短編譯時(shí)間。在我們的中端優(yōu)化器原型中,我們對編譯器設(shè)計(jì)的相關(guān)部分采取了一種新的方法:幾個不同的 "程序",或以某種方式改造程序的特定算法,被合并成一個統(tǒng)一的框架,只對程序進(jìn)行一次處理。

標(biāo)準(zhǔn)程序優(yōu)化

一種特別有效的提高速度的改變是減少內(nèi)存的分配和使用。程序分配的內(nèi)存越少,它的運(yùn)行速度就越快,至少有兩個原因:內(nèi)存分配器本身可能很慢,而且使用更多的內(nèi)存也會導(dǎo)致更多的緩沖區(qū)未命中和內(nèi)存流量。由于其多線程編譯模式,Cranelift也傾向于對分配器施加特別大的壓力。

總結(jié)

高性能是任何希望成為構(gòu)建高效、持久系統(tǒng)的基礎(chǔ)的軟件的一個關(guān)鍵方面。如果 WebAssembly 想要成功,它的運(yùn)行速度必須能達(dá)到與本地代碼競爭的水平。這也是 wasmtime 性能優(yōu)化的終極目標(biāo)。

通過該篇文章我們簡單了解了 Wasmtime 和 Cranelift 性能優(yōu)化的相關(guān)工作,以及當(dāng)前 wasmtime 1.0 的性能狀態(tài)(詳細(xì)數(shù)據(jù)見原文)。后續(xù)的文章將介紹該團(tuán)隊(duì)如何確保 Wasmtime 安全以及編譯器生成正確的代碼。



審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10780

    瀏覽量

    210493
  • 中斷
    +關(guān)注

    關(guān)注

    5

    文章

    894

    瀏覽量

    41327
  • python
    +關(guān)注

    關(guān)注

    54

    文章

    4759

    瀏覽量

    84297
  • 虛擬內(nèi)存
    +關(guān)注

    關(guān)注

    0

    文章

    70

    瀏覽量

    8046

原文標(biāo)題:WebAssembly 動態(tài) | WebAssembly 的發(fā)展風(fēng)險(xiǎn)及Wasmtime 1.0 性能概覽

文章出處:【微信號:Rust語言中文社區(qū),微信公眾號:Rust語言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    LED驅(qū)動器應(yīng)用的一些指南和技巧

    電子發(fā)燒友網(wǎng)站提供《LED驅(qū)動器應(yīng)用的一些指南和技巧.pdf》資料免費(fèi)下載
    發(fā)表于 09-25 11:35 ?0次下載
    LED驅(qū)動器應(yīng)用的<b class='flag-5'>一些</b>指南和技巧

    使用三階低通濾波器對方波經(jīng)行濾波,想使得方波變得平滑一些,可是濾出來結(jié)果不滿意怎么解決?

    使用三階低通濾波器對方波經(jīng)行濾波,想使得方波變得平滑一些,可是濾出來結(jié)果不滿意。總是在高電平到低電平很陡峭,二低電平到高電平卻平滑?;蚴钦f二階或是三階低通濾波器濾出來以后只能是這種效果。求高手指點(diǎn)一二
    發(fā)表于 09-19 06:22

    電源芯片短路恢復(fù)過沖的風(fēng)險(xiǎn)應(yīng)對措施

    可能導(dǎo)致設(shè)備無法正常使用。為了保護(hù)設(shè)備和提高電源芯片的可靠性,我們需要采取相應(yīng)的應(yīng)對措施。 首先,讓我們先了解下電源芯片短路和過沖的風(fēng)險(xiǎn)。短路是指電路中的兩個節(jié)點(diǎn)之間出現(xiàn)低阻抗路徑,導(dǎo)致電流異常增大。而過沖
    的頭像 發(fā)表于 02-06 09:46 ?1403次閱讀

    PID自動控制回路的振蕩問題與應(yīng)對方法

    在工業(yè)自動化控制領(lǐng)域,PID自動控制回路的應(yīng)用非常廣泛。然而,在使用過程中,我們常常會遇到各種振蕩問題,如同相位振蕩、異相位振蕩和非平滑振蕩等。這些問題不僅會導(dǎo)致裝置的不穩(wěn)定,還可能影響整個生產(chǎn)過程的安全和效率。本文將分享這三種振蕩的特征及相應(yīng)的應(yīng)對方法,以供參考。
    的頭像 發(fā)表于 12-28 09:10 ?1.3w次閱讀
    PID自動控制回路的振蕩問題與<b class='flag-5'>應(yīng)對方法</b>

    電源電壓變化對晶振性能的影響以及應(yīng)對方法

    電源電壓變化對晶振性能的影響以及應(yīng)對方法? 電源電壓的變化是指電源輸入電壓的波動或變化,它可能產(chǎn)生系列的問題,對晶振的性能和工作穩(wěn)定性產(chǎn)生影響。本文將詳細(xì)討論電源電壓變化對晶振的影響,并提供應(yīng)對方法
    的頭像 發(fā)表于 12-18 14:09 ?1084次閱讀

    云服務(wù)器被攻擊應(yīng)對方法

    當(dāng)云服務(wù)器受到攻擊時(shí),采取適當(dāng)?shù)?b class='flag-5'>應(yīng)對策略是關(guān)鍵,以確保系統(tǒng)的安全和可用性。下面,小編給大家簡單總結(jié)下云服務(wù)器被攻擊應(yīng)對方法: 1、監(jiān)控和檢測:部署實(shí)時(shí)監(jiān)控系統(tǒng),定期審查日志,以便及時(shí)發(fā)現(xiàn)異?;顒?/div>
    的頭像 發(fā)表于 12-06 17:44 ?733次閱讀

    提高嵌入式代碼質(zhì)量的一些方法

    的事情搞復(fù)雜,我希望這些文字能給迷惑中的人們指出一些正確的方向,讓他們少走一些彎路,基本做到一分耕耘一分收獲。
    的頭像 發(fā)表于 11-30 09:15 ?395次閱讀

    減少靜電產(chǎn)生和降低擊穿風(fēng)險(xiǎn)方法和材料

    介紹一些常見的方法和材料,以幫助我們更好地了解如何減少靜電產(chǎn)生并降低擊穿風(fēng)險(xiǎn)。 、減少靜電產(chǎn)生的方法
    的頭像 發(fā)表于 11-29 16:30 ?1043次閱讀

    我們?yōu)槭裁葱枰私?b class='flag-5'>一些先進(jìn)封裝?

    我們?yōu)槭裁葱枰私?b class='flag-5'>一些先進(jìn)封裝?
    的頭像 發(fā)表于 11-23 16:32 ?517次閱讀
    我們?yōu)槭裁葱枰私?b class='flag-5'>一些</b>先進(jìn)封裝?

    ECG子系統(tǒng)設(shè)計(jì)主要挑戰(zhàn)及應(yīng)對方

    電子發(fā)燒友網(wǎng)站提供《ECG子系統(tǒng)設(shè)計(jì)主要挑戰(zhàn)及應(yīng)對方案.pdf》資料免費(fèi)下載
    發(fā)表于 11-23 10:43 ?0次下載
    ECG子系統(tǒng)設(shè)計(jì)主要挑戰(zhàn)及<b class='flag-5'>應(yīng)對方</b>案

    分享一些SystemVerilog的coding guideline

    本文分享一些SystemVerilog的coding guideline。
    的頭像 發(fā)表于 11-22 09:17 ?642次閱讀
    分享<b class='flag-5'>一些</b>SystemVerilog的coding  guideline

    PCB抄板的一些方法

    拆掉所有器多層板抄板件,并且將PAD孔里的錫去掉。用酒精將PCB清洗干凈,然后放入掃描儀內(nèi),掃描儀掃描的時(shí)候需要稍調(diào)高一些掃描的像素, 以便得到較清晰的圖像。
    的頭像 發(fā)表于 11-15 17:04 ?834次閱讀
    PCB抄板的<b class='flag-5'>一些</b><b class='flag-5'>方法</b>

    使用軟件如何去除一些內(nèi)部噪聲,降低對ADC結(jié)果的影響?

    使用軟件如何去除一些內(nèi)部噪聲,降低對ADC結(jié)果的影響? 標(biāo)題:使用軟件去除內(nèi)部噪聲,降低對ADC結(jié)果的影響 引言: 在數(shù)字信號處理中,噪聲是個普遍存在的問題。當(dāng)我們使用模擬到數(shù)字轉(zhuǎn)換器(ADC)來
    的頭像 發(fā)表于 11-09 15:38 ?684次閱讀

    一些封裝中沒有串口,或者串口已經(jīng)被用作其他用途,要如何輸出log?

    是非常不便的,但是有一些替代方法可以幫助我們達(dá)到類似的效果。在本文中,我們將探討一些常見的方法,以幫助開發(fā)者在沒有串口輸出的情況下調(diào)試和輸出log。 1. 使用LED燈 在
    的頭像 發(fā)表于 10-31 14:37 ?457次閱讀

    針對RF PCBA設(shè)計(jì)的一些建議

    射頻(RF)PCBA設(shè)計(jì)涉及系列復(fù)雜的考慮因素,包括天線設(shè)計(jì)、濾波器設(shè)計(jì)以及傳輸線(RF Trace)的優(yōu)化。這些因素對于無線通信和射頻應(yīng)用的性能至關(guān)重要。以下是針對RF PCBA設(shè)計(jì)的一些建議。
    的頭像 發(fā)表于 10-30 10:19 ?414次閱讀