天天看點

HDC技術分論壇:ArkCompiler原了解析

ArkCompiler(方舟編譯器)是元件化、可配置的多語言編譯和運作平台,它既能支撐單一語言運作環境,也能支撐多種語言組合的運作環境。它目前主要支援的語言是JavaScript、TypeScript和Java。

HarmonyOS的設計目标,是成為打通手機、PC、平闆、電視、車機和智能穿戴等多種裝置的統一作業系統。

::: hljs-center

HDC技術分論壇:ArkCompiler原了解析

圖1 多裝置互聯

:::

其應用開發有多程式設計語言、多範式的支援需求,其中進階程式設計語言包括JavaScript、TypeScript、Java等,開發範式包括聲明式UI範式、分布式程式設計範式。 我們需要相應的編譯器和運作時來支撐這些進階應用程式設計語言的高效開發、部署和運作。 使應用開發者能使用同一套開發架構實作一次開發多端部署運作。并且讓使用HarmonyOS裝置的使用者,能獲得統一的使用者體驗。于是,ArkCompiler應運而生。

ArkCompiler是為支援多種程式設計語言、多種晶片平台的聯合編譯、運作而設計的統一程式設計平台,其設計目标是提供一個語言可插拔、元件可配置的多語言編譯器運作時。

語言可插拔: 設計架構上支援多種語言接入,ArkCompiler有能力提供具有高效執行性能且具有跨語言優勢的多語言運作時,也可以在小裝置上提供高效輕量的單一語言運作時。

元件可配置: ArkCompiler具有豐富的編譯器運作時元件系統。通過定制化配置編譯運作時的語言群組件,以支援手機、PC、平闆、電視、汽車和智能穿戴等多種裝置上不同的性能和記憶體需求。

如圖2所示,ArkCompiler包含編譯器、工具鍊、運作時等關鍵部件。ArkCompiler工具鍊實作對應語言的前端編譯器,将前端開發架構的進階語言編譯成統一的位元組碼/二進制檔案。根據不同的應用場景,通過ArkCompiler運作時解釋器解釋執行位元組碼檔案或JIT/AOT編譯器編譯執行對應體系架構的優化機器碼,進而提升運作效率和啟動性能。

HDC技術分論壇:ArkCompiler原了解析

圖2 ArkCompiler運作原理

下面,本文将從前端編譯器,運作時展開介紹。

前端編譯器是進階語言通往語言運作時的橋梁,它按照語言規範,将程式設計語言表達的語義翻譯為運作時能夠了解的媒體,在ArkCompiler解決方案裡,這展現為ArkCompiler位元組碼。即圖3中的ArkCompiler Bytecode(簡稱abc)。部分語言,也支援通過ArkCompiler的AOT Compiler元件直接将位元組碼編譯成對應體系架構的優化機器碼。

HDC技術分論壇:ArkCompiler原了解析

圖3 ArkCompiler前端

在需要支援多種語言的ArkCompiler中,前端編譯器的主要作用是在Host側把源碼生成位元組碼檔案,這樣的優點:

利用Host強大的計算能力,能夠在運作前做更多更複雜的算法優化,減少運作時的工作,提高運作效率。

相比常見的JavaScript運作時,可以把端側的編譯解析過程提前到釋出前,提升程式的啟動性能。

HDC技術分論壇:ArkCompiler原了解析

圖4 JavaScript運作流程

ArkCompiler提供對TypeScript(TS)的原生支援。在前端編譯TS源碼時,會利用TS的顯式類型聲明,應用類型推導進行類型優化,并且将推導出的類型資訊通過位元組碼檔案保留至運作時,由此運作時可以直接利用類型資訊執行快速路徑。此外,靜态的類型分析和推導也使得TS AOT (Ahead of Time) Compiler成為可能,靜态分析得到的類型資訊幫助AOT Compiler直接編譯生成高品質的機器碼,使得TS源碼可以直接以機器碼形式運作,進一步提升運作性能。

HDC技術分論壇:ArkCompiler原了解析

圖5 編譯優化

ArkCompiler位元組碼(ArkCompiler Bytecode)是運作時解釋器能夠解析運作的一種硬體和平台無關的中間表現形式,以緊湊、可擴充、多語言支援作為設計目标。屏蔽裝置的差異,支援應用的跨裝置分發、部署和運作。ArkCompiler采用的是基于寄存器的位元組碼格式。每個寄存器的寬度為64位,最多支援65536個寄存器。

ArkCompiler寄存器要求能夠放置對象引用和基本類型,寬度采用64位。寄存器的作用域是以函數棧幀為範圍。在位元組碼指令編碼中,寄存器索引支援4位、8位以及16位的變長編碼,在支援方法内不同數量範圍的寄存器尋址的同時減小位元組碼尺寸。

累加寄存器,俗稱累加器,是一個特殊的寄存器,被指令隐含使用。使用累加器的主要目的是在不損失性能的前提下改善指令編碼密度。在ArkCompiler位元組碼中,上一條指令利用累加器作為結果輸出,下一條指令将此累加器作為輸入,可以有效改善指令密度,減小位元組碼的尺寸。同時,通過在生成位元組碼階段的資料流及控制流分析和優化,前端編譯器可以有效消除備援的累加器load和store操作。

ArkCompiler位元組碼提供對32位(i32)和64位(i64)整型數值的寄存器操作支援,8位和16位數值通過擴充到32位來模拟。支援對IEEE-754雙精度浮點f64值的寄存器的操作,f32資料類型(IEEE-754單精度)也通過轉換為f64值進行模拟。基本資料類型不需要虛拟機進行記錄、跟蹤和推導,而是通過操作不同基本資料類型的專用位元組碼進行表示,包括整數值的符号性。為了更有效地利用位元組碼的指令空間,設計中對高頻使用的資料類型和操作引入更多的專用位元組碼,而對低頻使用的資料類型和操作采用更通用的位元組碼。

ArkCompiler根據其執行的語言支援階層化的類型系統。這樣,建立或者從常量池加載的字元串、數組、異常對象等,都是含有相應層次關系的、和具體語言規範相比對的資料對象。

為支援類似JS/TS的動态類型語言,ArkCompiler通過特殊的标記值("Any")表示動态類型值,其包裝了值本身和相應的類型資訊(包括基本類型和對象引用類型資料)。虛拟寄存器的寬度可以容納“Any”值。同時,在動态類型語言代碼的執行上下文中,也可能使用到包含類型檢查指令在内的靜态确定類型指令序列,以表示動态類型相關語義。

ArkCompiler運作時,如圖6所示,被分為了核心運作時(Core Runtime)和各自語言獨立的運作時插件(Runtime Plugin)。

核心運作時主要由運作時的公共核心元件構成,包含定義位元組碼格式和行為的Public ISA子產品,對接系統調用的ArkCompiler Base Platform子產品, 支援Debugger、Profiler等工具的Common Tool子產品和承載位元組碼檔案處理的ArkCompiler File子產品等。也提供了可選的語言無關的解釋器、記憶體管理、編譯器和并發等基礎設施元件。

各語言運作時插件則包含各語言特有的特性實作以及标準庫來支撐語言的運作行為符合對應的語言規範,由各語言按需定制。

HDC技術分論壇:ArkCompiler原了解析

圖6 運作時架構

ArkCompiler運作時執行引擎有多種元件,包括解釋器、JIT編譯器和AOT編譯器,如圖7所示。

HDC技術分論壇:ArkCompiler原了解析

圖7 執行引擎結構

解釋器可直接運作前端編譯器輸出的位元組碼。

JIT編譯器一般需要運作時執行代碼一段時間,Profiler生成了profiling資料之後,根據profiling資料即時編譯生成高品質的機器碼(上圖Optimized Code II)來運作。(JIT可以根據代碼執行情況實時編譯生成最優機器指令)

AOT編譯器則是在運作前根據靜态資訊直接編譯生成高品質的目标機器碼(上圖Optimized Code I)在裝置上運作,PGO(Profile Guided Optimization)配置檔案可以作為AOT Compiler的輸入之一,給AOT Compiler一些訓示,比如編譯的範圍以及編譯某個方法時使用哪些優化技術。通常這種PGO配置檔案由在同等規格的裝置上經過運作時profiling或者大資料分析生成。

無論是JIT 編譯器生成的優化代碼,還是AOT編譯器生成的優化代碼,通常都是在一定優化假設或者優化推斷的前提下生成的。如果這個前提在運作時不成立,則需要進行Deopt(逆優化),回退到解釋器執行,這種情況一般較少發生。

各個執行引擎的性能如圖8所示:

HDC技術分論壇:ArkCompiler原了解析

圖8 各執行引擎的性能對比

ArkCompiler運作時通過不同執行模式的按需組合,支援多種裝置不同的定制化需求。

在低端IOT裝置上,ArkCompiler執行引擎支援純解釋器的執行模式,以滿足小裝置的記憶體限制條件;

在高端裝置上,ArkCompiler執行引擎支援解釋器配合AOT編譯器以及JIT編譯器的模式運作,對相當部分代碼使用AOT編譯器編譯,使得程式一開始就可以運作在高品質的優化代碼上,獲得最好的執行性能;

在其它裝置上,則根據裝置的硬體條件限制來選擇政策,設定高頻使用需要AOT編譯的代碼範圍,其它代碼則依靠解釋器配合JIT Compiler運作,使得應用執行性能能夠得到最大化。

為了提升解釋執行性能,在特定的體系架構下,解釋器約定了将解釋執行上下文中某些頻繁使用的資料放在對應的實體寄存器中,比如在Arm64架構下,上下文中目前位元組碼指令位址、累加器值、解釋器棧幀、指令映射表、目前線程對象等,直接放在固定的寄存器上,避免了在棧上頻繁的加載和寫入操作。

複雜移動應用的開發和運作對并發有較強的需求。ArkCompiler運作時除了提供标準的“Java多線程程式設計”和“運作支援”之外,也提供響應式的Actor并發程式設計模型支援。此模型下執行體之間不共享任何資料,通過消息機制進行通信。目前,業界的一些Actor并發模型,例如傳統JS引擎的web-worker實作,有啟動速度慢、記憶體占用高等缺陷。

為了利用裝置的多核能力獲得更好的性能提升,在Actor記憶體隔離模型的基礎上,ArkCompiler運作時通過共享Actor執行個體中的不可變或者不易變的對象、内建代碼塊、方法位元組碼等,提升Actor的啟動性能和節省記憶體開銷,達到實作輕量級Actor并發模型的目标。

HDC技術分論壇:ArkCompiler原了解析

圖9 輕量級Actor實作

HarmonyOS應用在某些情況下實際上是由多種語言的代碼組成的。例如對HarmonyOS JS/TS應用,有一些系統庫、架構和應用依賴的部分能力的實作使用了C/C++ 和Java語言。HarmonyOS開發架構也提供了JS/TS與C/C++ 互動的JS NAPI以及JS/TS與Java互動的Channel機制。考慮不同語言之間的互動場景的開發和運作效率需求,ArkCompiler和開發架構聯合設計,提供了對應的優化機制。

在TS 版本的作業系統平台API實作中,通常需要面臨C/C++ 代碼通路和操作TS對象的場景。對這個業務場景,ArkCompiler可以根據TS源碼的class聲明和運作時約定,生成包含TS對象布局描述的C/C++ 頭檔案,以及操作這些TS對象的C/C++ 實作庫。在 C/C++ 代碼中,通過包含TS對象描述頭檔案以及連結對應實作庫,實作直接操作TS對象的效果。需要說明的是,由于TS類型或其内在布局并非總是固定不變的,是以在TS對象操作的代碼實作中,會插入類型檢查,如果對象類型或布局在運作時發生變化,則回退執行通用的慢速路徑。

HDC技術分論壇:ArkCompiler原了解析

圖10 跨語言互動

HarmonyOS中有一些應用所需的能力是通過系統、架構或應用的Java庫提供的。是以在HarmonyOS應用中,也存在較多JS/TS代碼與Java代碼互動的場景。常見的案例中,由于JS/TS代碼和Java代碼有各自獨立的運作環境,互相之間對于對方的資料表示、調用約定都是不可知的,是以JS/TS與Java的資料互動通常需要經過标準的JSON序列化和反序列化流程,以及經由Native層橋接的互相調用。這造成在一些場景中開銷較大,影響使用者體驗。

ArkCompiler利用同時支援多語言的優勢,運作時具備不同語言的資料表示、對象布局、函數調用約定等資訊,這使得跨語言之間的直接資料通路、對象操作和方法調用成為可能,同時Java代碼提供的更多确定的類型資訊也成為JS/TS類型推導的額外輸入,利于對JS/TS的編譯優化。另一方面,這也使我們能為開發者提供一個更簡化的多語言程式設計模型,減少需要額外手工編寫的業務無關的跨語言互動代碼工作量。

HDC技術分論壇:ArkCompiler原了解析

圖11 簡化的多語言程式設計模型

HarmonyOS所支援的IoT時代下,結合應用生态、開發體驗和使用者體驗等方面的需求, ArkCompiler與硬體、作業系統、開發架構、程式設計語言協同設計,在多語言統一編譯運作和多裝置支援的基礎上,實作對HarmonyOS應用在開發和運作效率等方面的提升。

未來,ArkCompiler在持續優化基礎體驗的同時,更會進一步結合HarmonyOS萬物互聯的需求,在跨端遷移、多端協同等創新場景,從編譯器和運作時等方面提供底層的解決方案和優化機制,提升分布式應用的開發和運作體驗。

作者:xianyuqiang 編譯器首席架構師 

想了解更多關于鴻蒙的内容,請通路:

51CTO和華為官方戰略合作共建的鴻蒙技術社群

https://harmonyos.51cto.com/#bkwz

HDC技術分論壇:ArkCompiler原了解析

繼續閱讀