※ 引述《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