精華區beta Programming 關於我們 聯絡資訊
※ 引述《tinlans.bbs@whshs.cs.nccu.edu.tw (汀)》之銘言: : ※ 引述《freaky.bbs@ptt.cc (jon)》之銘言: : > .net 的 IL 主要是為了各種高階語言間的 interoperability 而設計的。 : 看起來不是很像, : 因為我看過 GCC 自從 4.0 開始, : 為了整合 C、fortran、Ada、Java 等語言, : 而把 front-end 獨立成 generic tree 的表示法, : 比較之下 .NET 的 IL 並沒有這麼高階, : 不然 C# .NET 跟 C++ .NET 還有 VB .NET 使用相似寫法, : 應該要產生「相當程度相似」的 IL 才對; : 然而實際觀察它們產生出來的 IL, : 會很明顯感覺到 high-level language compiler 這部分各自做了不同的事。 因為高階語言的特性不同,對 CLI 的支援度也不一樣,產生出來的 IL 自然不會完全一樣。舉例來說,C# 不支援 exception filter 而 MC++ 和 VB.NET 有這樣的語法可以直接利用 MSIL 的指令。至於你說到不同語言間 使用相似語法得到不同的 IL,就牽涉到 source compiler 最佳化的問題, 這也是我為什麼說要用 C++/CLI 的原因,因為 C++ compiler 可以產生最 佳化程度最高的 MSIL,而且對 CIL 的支援度最高。 : 我寫過 Java assembly code , : 發現 Java bytecode 設計上有很強烈想縮短「bytecode -> native」轉換時間的傾向, : 觀察過 .NET 的 IL 之後也有相似但是比較不那麼強烈的感覺, : 整理一下這樣的感覺大致上可以把時間點區分為這樣: : ============================================================================= : |<-- front-end -->|<-- middle end -->|<- back end ->| : Generic Gimple Tree-SSA RTL : HLL Tree Tree form form ASM : GCC +--------+---------+----------+--------+-------------+ : ============================================================================= : back-end : |<--------------- front-end ---------------->|<------>| : Java : HLL bytecode Native : Java +--------------------------------------------+-------+ : ============================================================================= : back-end : |<------------- front-end ------------->|<---------->| : .NET : HLL IL Native : NET +----------------------------------------+-----------+ : ============================================================================= : Java 跟 .NET 我猜應該也是有所謂的 middle-end 表示法並做一些最佳化, : 可能也是 tree 的形式, : 不過沒有真的下去看所以沒打上去。 : 說的簡單一點, : 就是 .NET IL 雖然沒有 Java bytecode 那麼貼近 native code, : 但是離原始的 high-level language 還是有不可忽視的距離, : 提供 generic form 看起來只是它的非主要意圖。 這方面可以參考 Mono 實作者的意見,能從微軟獲得的資訊太少,而 Rotor 的最佳化程度和 Mono 和 .net 差了一截。 : > .net JIT compiler 和傳統 compiler 做的事幾乎沒什麼差別: : > 1. Importing. : > 2. Morphing. : > 3. Flowgraph analysis. : > 4. Optimization phase. : > 5. Register allocation. : > 6. Code generation. : > 7. Emit. : > 沒有保留足夠的資訊也無法完成這些事情。 : 還是有差別的。 : 最大的差別還是資訊量, : 以 Tree-SSA form 為例, : 它很難有具體的方法被以 metadata 的形式保存至檔案, : 而 .NET 和 Java 從 front-end 到 back-end 之間有一個分離性斷層, : 也就是說 front-end 跟 back-end 是兩個完全不同的 program, : 要讓 back-end 自由的參照 Tree-SSA 裡的 information 是不可能的, : 它只能學早期的傳統 compiler 在 back-end 重新審視 IL 重建 CFG 和 DFG, : 然後進行相當古老的 low-level SSA 最佳化。 : 舉這個例子是因為它特別明顯, : 並不是說只有這樣一個特例而已; : 傳統 compiler 因為從 front-end 到 back-end 都在同一個程式內部, : 不需要考慮該封裝多少 high-level information 到 back-end 去, : 也能讓 back-end 自由參考前端的最佳化結果和資訊。 : 另一個較大的差異就是 4. 的 phases 數量, : 雖然可以使用 NGen 做 offline compile & optimize 提昇數量, : 但是正如你所說其實用 NGen 並不見得能獲得效能改善, : 而選用 JIT 的話跑個 20 到 30 個 phases 效能絕對會很慘, : 即使這個 JIT 行為是一次性的也一樣, : 在這種不定性下真的很難確信是否能夠做到最好。 這點用 64-bit NGen 可以得到不錯的效果,因為它會在背景做大量的最佳化編譯。 32-bit NGen 和 JITter 採用相同的最佳化方式所以沒有這個好處。 : 其實還有三項應該也被列進來討論: : A. instruction selecting : B. instruction scheduling : C. instruction dispatching (VLIW processor only) : 這三件事情常跟 register allocation 有糾纏不清的關係, : 一直以來有很多人在討論誰先做誰後做比較好, : 還是混在一起做比較好, : 而目前普遍採用的方式就是「分開做,反覆做好幾輪」, : 而在 back-end 裡這可以說是最消耗 CPU time 的部分, : 因為通常需要 scan 整個 procedure 的所有 IL, : 執行大量複雜度從 O(nlgn) 到 O(n**2) 的 algorithms, : 這樣的東西在 JIT 做絕對是死路一條, : 非得強迫使用 NGen 才能被 user 接受, : 最後不管怎麼選總是要先折斷一隻手, : 只是選左手和選右手的差別。 這部份也是和 Mono 實作者討論比較有意義,因為我們都只是從理論角度推測。 : > Herb Sutter 最近寫了一篇關於 C++/CLI 的 paper,有興趣的話看看吧: : > http://www.gotw.ca/publications/C++CLIRationale.pdf : 這個我在不久之前才看到過耶, : 感覺上就像是 C++/CLI 跟之前的 managed/unmanaged C++ 異同說明, : 它最引起我注意的地方是在 3.4.1, : 也許是我大量利用 template 改善傳統動態多型的速度缺陷太久了, : 我相當不能接受 runtime template instantiation, : 那一小節也是我對 C++/CLI 徹底失望的主因。 : 雖然說是因為個人 programming 習慣所產生的偏見, : 不過這個作法的確跟 JDK 1.5 的 template 一樣辜負了某一族群的期待。 .net Generics 和 Java 是不能相提並論的。 Java Generics 為了維持 VM 的相容性,compiler 會移除型別參數以 Object 取代,然後插入許多 cast, 自然產生許多 overhead。而且 erasure 法到了runtime 就會出現更大的問題, 因為型別資訊已經沒了,Reflection 無法運作。.net 則是保留型別資訊, 新增處理 Generics 的 CIL 指令;而在 instantiate 的部份,reference types 參數的 instantiations 共用一份 native code,value types 則有個別的 native code。已經 JIT 過的 instantiation 會被 cache 起來,下次用到 不需要再重新 JIT 。如此以最小的 overhead 得到 strongly-typed Generics,相較之下 C++ templates 的型別檢查要到 link-time 才會發生。 : 其餘的部分看起來主要都是和以前的 managed/unmanaged C++ 語言機制相比, : 至於記憶體管理上的好處則大都是 .NET 裡其它語言所共有的, : 加上一些像是為了推銷而故意保留給 C++/CLI 的專屬小創意, : 這只是在 syntax 所能表示的 semantic 範圍上動動手腳而已, : 增加一些 notation 來給 compiler 更多的 hints, : 畢竟新推的語言標準可以玩的地方也大都只有這邊。 -- ※ Origin: 臺大電機 Maxwell 站 ◆ From: 60-248-105-82.HINET-IP.hinet.net