- Khi đưa các ngôn ngữ GC như Java, Kotlin, Dart, Python, C# sang WebAssembly, WasmGC không tái biên dịch VM hiện có mà tận dụng trực tiếp các cấu trúc GC, mảng và hệ thống kiểu của chính Wasm
- Cách port WasmMVP truyền thống giúp dễ tái sử dụng VM và các tối ưu hóa hiện có, nhưng phải gánh chi phí mang theo GC hoặc
malloc/freetrong bộ nhớ tuyến tính, đồng thời bị ràng buộc bởi tham chiếu trên stack, tham chiếu vòng và phân mảnh - Với WasmGC, VM trực tiếp quản lý đối tượng và bộ nhớ nên có thể giảm kích thước nhị phân; trong benchmark
fannkuch, kích thước là 2.3K, nhỏ hơn 6.1~9.6K của C/Rust - WasmGC là biểu diễn trung gian ở mức cao hơn nên các tối ưu hóa của Binaryen
wasm-optvà runtime V8 rất quan trọng; có trường hợp cải thiện trung bình 1.9× trên benchmark Java và khoảng 30% với Google Sheets Calc Engine - Chuẩn hóa và hỗ trợ trình duyệt đã tiến triển, nhưng vì không phải cách biên dịch nguyên trạng VM cũ nên vẫn cần công việc toolchain mới để hạ cấu trúc ngôn ngữ xuống các nguyên thủy WasmGC
Hai cách đưa ngôn ngữ GC sang Wasm
- Việc port ngôn ngữ GC sang WebAssembly được chia lớn thành hai hướng
- Port truyền thống: biên dịch VM ngôn ngữ hiện có sang WasmMVP, tức WebAssembly Minimum Viable Product ra mắt năm 2017
- Port bằng WasmGC: biên dịch ngôn ngữ sang các cấu trúc GC của Wasm được định nghĩa trong đề xuất GC
- Port truyền thống gần với mô hình khi đưa ngôn ngữ sang một kiến trúc CPU mới: dùng lại parser, hỗ trợ thư viện, GC và trình tối ưu của VM, rồi chỉ thêm backend mới
- Port bằng WasmGC lại gần với cách đưa ngôn ngữ sang một VM mới hơn là sang kiến trúc mới
- Giống J2CL biên dịch Java sang JavaScript, đối tượng của ngôn ngữ được biểu diễn thành đối tượng của VM đích và do GC của VM đích quản lý
- WasmGC hướng tới mức thấp hơn JavaScript VM, JVM hay CLR, nhưng vẫn ở mức cao hơn WasmMVP vì cung cấp struct, mảng và quan hệ kiểu do VM quản lý
Ưu điểm và giới hạn của cách port WasmMVP truyền thống
- Ưu điểm lớn nhất của port truyền thống là có thể tái sử dụng gần như nguyên vẹn mã VM hiện có, cách hiện thực ngôn ngữ và các tối ưu hóa
- Kết quả của WasmMVP dùng các cấu trúc cơ bản của WasmMVP như bộ nhớ tuyến tính, bảng và hàm
- Wasm thường chạy bên trong các VM đã có GC như trình duyệt, Node.js, workerd, Deno, Bun
- Trong môi trường này, việc nhúng thêm hiện thực GC vào nhị phân Wasm gây tăng kích thước không cần thiết
- Ngay cả các ngôn ngữ dùng bộ nhớ tuyến tính như C, C++, Rust cũng phải mang theo mã
malloc/freenếu có cấp phát đáng kể dlmalloclà 6K, cònemmalloctối ưu cho kích thước cũng vượt 1K
- Với WasmGC, VM tự động quản lý bộ nhớ nên không cần nhúng GC hay
malloc/freevào Wasm- Trong benchmark
fannkuchtừ bài viết WasmGC trước đó, WasmGC có kích thước 2.3K, còn C/Rust là 6.1~9.6K
- Trong benchmark
Thu gom vòng tham chiếu, tham chiếu trên stack và phân mảnh
- Trong trình duyệt, Wasm thường tương tác với JavaScript và Web API, nhưng chỉ với WasmMVP và reference types thì rất khó thực hiện thu gom vòng tham chiếu tinh vi giữa Wasm và JS
- Liên kết tới đối tượng JS chỉ có thể đặt trong bảng Wasm
- Liên kết từ JS quay lại Wasm có thể tham chiếu toàn bộ instance Wasm như một đối tượng lớn duy nhất
- WasmGC định nghĩa các đối tượng Wasm mà VM hiểu được, nên có thể tạo các tham chiếu phù hợp giữa Wasm và JavaScript
- Ngôn ngữ GC cũng cần nhận biết cả tham chiếu trên stack như biến cục bộ trong scope lời gọi
- Với cách port truyền thống, chương trình không thể tự quét stack của chính nó vì sandboxing của Wasm
- Giải pháp thay thế là dùng shadow stack hoặc chỉ chạy GC khi không còn tham chiếu trên stack, chẳng hạn giữa các turn của event loop JavaScript
- Việc Wasm hỗ trợ stack scanning trong tương lai có thể giúp ích cho cách port truyền thống
- Hiện nay, cách duy nhất xử lý tự động tham chiếu trên stack mà không thêm overhead là WasmGC
malloc/freetrên bộ nhớ tuyến tính của WasmMVP có thể gây phân mảnh bộ nhớ trong các chương trình chạy dài hạn- Dù tổng bộ nhớ trống vẫn đủ, việc thiếu một khối liên tiếp đủ lớn vẫn có thể làm cấp phát lớn thất bại
- Phân mảnh có thể khiến module Wasm phải mở rộng bộ nhớ thường xuyên hơn, dẫn tới overhead và lỗi out-of-memory
- WasmGC tránh được điều này vì VM có thể di chuyển đối tượng để nén heap GC
Công cụ cho nhà phát triển và ngữ nghĩa ngôn ngữ
- Trong cách port WasmMVP truyền thống, đối tượng chỉ là các byte trong bộ nhớ tuyến tính nên công cụ dành cho nhà phát triển khó nhìn thấy thông tin kiểu ở mức cao
- Với WasmGC, VM quản lý các đối tượng GC nên việc tích hợp công cụ trở nên dễ hơn
- Có thể xem heap snapshot của chương trình WasmGC trong tab Memory của Chrome DevTools
- Ở ví dụ danh sách liên kết, tên kiểu
$Nodevà trường$nexttham chiếu đối tượng kế tiếp được hiển thị - Các thông tin heap snapshot thông thường như số lượng đối tượng, shallow size, retained size cũng được cung cấp
- Trình debugger của Chrome DevTools cũng hoạt động với đối tượng WasmGC
- Port truyền thống biên dịch lại VM hiện có nên dễ giữ nguyên ngữ nghĩa ngôn ngữ như mong đợi
- Port bằng WasmGC phải biểu diễn cấu trúc ngôn ngữ bằng struct và array GC mới, nên đôi khi cần thỏa hiệp ngữ nghĩa để đạt hiệu quả
- Trường của struct trong WasmGC có chỉ số và kiểu cố định, nên các ngôn ngữ muốn truy cập trường linh hoạt hơn có thể gặp khó khăn
- Hiện tại WasmGC chưa có interior pointer, dù các hạn chế như vậy được kỳ vọng sẽ cải thiện theo thời gian
- Các trường hợp biên dịch sang VM đích khác cũng có những lựa chọn ngữ nghĩa tương tự
- Hành vi số của dart2js khác với Dart VM
- Chuỗi trong IronPython hoạt động giống chuỗi C#
- Ngược lại, dart2wasm có thể hoạt động mà không phải thỏa hiệp ngữ nghĩa số vì Wasm biểu diễn hiệu quả các kiểu số mà Dart cần
Công việc toolchain cần thiết cho việc port bằng WasmGC
- Port bằng WasmGC không phải là chuyện chỉ đơn giản tái biên dịch VM hiện có
- Một số mã không gắn trực tiếp với runtime GC như logic parser hay tối ưu hóa AOT vẫn có thể tái sử dụng
- Nhưng nhìn chung vẫn cần rất nhiều mã mới để hạ cấu trúc ngôn ngữ xuống struct và array của WasmGC
- Một VM viết bằng C như Lua có thể được biên dịch sang Wasm chỉ trong vài phút, nhưng port Lua sang WasmGC lại đòi hỏi phải quyết định và hiện thực cách biểu diễn cấu trúc Lua trong ràng buộc của hệ thống kiểu WasmGC
- Nhược điểm lớn của port WasmGC là nỗ lực dành cho toolchain
- Trạng thái lý tưởng là hệ thống kiểu của WasmGC hỗ trợ hiệu quả cho mọi ngôn ngữ và mỗi ngôn ngữ tự hiện thực cổng WasmGC của mình
- Các tính năng bổ sung trong tương lai của hệ thống kiểu WasmGC có thể giúp phần đầu
- Chia sẻ công việc toolchain dùng chung có thể giảm gánh nặng của phần sau
Vì sao WasmGC có thể được tối ưu tốt hơn
- WasmGC là biểu diễn trung gian ở mức cao hơn WasmMVP nên có nhiều dư địa tối ưu hơn
- Trong một hàm ví dụ, đoạn mã cấp phát hai đối tượng GC, ghi
10vào trường rồi trả về, về mặt logic có thể rút gọn thànhreturn 10- Với WasmMVP, cấp phát trở thành lời gọi
malloc, màmalloclà hàm phức tạp có side effect trên bộ nhớ tuyến tính nên trình tối ưu khó chắc chắn rằng lần cấp phát thứ hai không thay đổi trường của đối tượng đầu tiên - Với WasmGC, cấp phát được biểu diễn bằng lệnh
struct.new, có thể được suy luận như một thao tác của VM nên có thể theo dõi tham chiếu và giá trị trường
- Với WasmMVP, cấp phát trở thành lời gọi
- WasmGC cũng cung cấp con trỏ hàm tường minh
ref.func, lời gọi thông qua nó làcall_ref, cùng kiểu cho các trường struct và array - Lý do WasmMVP thường đạt tốc độ gần native là vì hầu hết tối ưu hóa đã được thực hiện trước khi tạo Wasm nhờ các compiler tối ưu mạnh như LLVM
- LLVM không hỗ trợ WasmGC, và nhiều ngôn ngữ GC cũng không dùng LLVM, nên WasmGC cần một mô hình tối ưu khác
Tối ưu hóa Binaryen và wasm-opt
- WasmGC cho phép thực hiện tối ưu hóa mục đích chung sau khi đã hạ xuống Wasm, nhờ đó nhiều toolchain ngôn ngữ có thể chia sẻ cùng một trình tối ưu Wasm-to-Wasm
- Đội ngũ V8 đã đầu tư vào hỗ trợ WasmGC cho Binaryen, dự án tối ưu hóa toolchain WebAssembly
- Mỗi toolchain có thể dùng Binaryen qua công cụ dòng lệnh
wasm-opt
- Mỗi toolchain có thể dùng Binaryen qua công cụ dòng lệnh
- Binaryen vốn đã có các tối ưu như inline, constant propagation, dead code elimination cho WasmMVP, và phần lớn trong số đó cũng áp dụng được cho WasmGC
- Các tối ưu quan trọng được bổ sung cho WasmGC gồm:
- Escape analysis: chuyển cấp phát heap thành local
- Devirtualization: chuyển lời gọi gián tiếp thành lời gọi trực tiếp
- Loại bỏ dead code toàn cục mạnh hơn
- Whole-program type-aware content flow analysis, GUFA
- Cast optimizations: loại bỏ cast dư thừa và di chuyển vị trí cast
- Type pruning
- Type merging
- Tinh chỉnh kiểu cho local, global, field và signature
- Các tối ưu GC mới và cách dùng trong Binaryen được tổng hợp trong Binaryen docs
- Khi đo hiệu năng Java trên đầu ra của J2Wasm,
wasm-optđã tăng tốc mọi benchmark và trung bình nhanh hơn 1.9×
Tối ưu hóa WasmGC trong V8
- Ngôn ngữ GC có mô hình hiệu năng khác với các ngôn ngữ như C, C++, Rust vốn phụ thuộc mạnh vào inlining tại thời điểm biên dịch
- Các ngôn ngữ GC như Java hay Dart thường để VM thực hiện inlining và tối ưu hóa ở runtime
- Trong Java, mọi lời gọi ban đầu đều là lời gọi gián tiếp
- Lớp con có thể override hàm của lớp cha, và điều này vẫn đúng cả khi gọi đối tượng con thông qua tham chiếu kiểu cha
- Toolchain có lợi nếu biến lời gọi gián tiếp thành trực tiếp, nhưng trong mã Java thực tế có nhiều đường đi khó suy luận tĩnh là lời gọi trực tiếp
- V8 đã hiện thực speculative inlining cho WasmGC
- Quan sát các lời gọi gián tiếp ở runtime
- Nếu một call site cho thấy hành vi đơn giản, chẳng hạn chỉ có ít đích gọi, thì sẽ inline kèm guard check
- Google Sheets Calc Engine là codebase Java dùng để tính toán công thức bảng tính và trước đây được biên dịch sang JavaScript bằng J2CL
- Đội ngũ V8 đã hợp tác với Sheets và J2CL để port mã này sang WasmGC
- Trên code này, speculative inlining là tối ưu đơn lẻ có tác động lớn nhất mà V8 hiện thực cho WasmGC
- Nó mang lại tăng tốc khoảng 30%, lớn hơn tổng các tối ưu đo được khác
- Các tối ưu WasmGC khác trong V8 gồm load elimination, type-based optimizations, branch elimination, constant folding, escape analysis, common subexpression elimination...
- Thông tin kiểu của WasmGC cũng được dùng cho tối ưu runtime
- Nếu
ref.testcho thấy một kiểm tra kiểu cụ thể đã qua, thìref.castsang cùng kiểu đó phải thành công - Có thể loại bỏ cast trong các mẫu như downcast sau
instanceofcủa Java
- Nếu
- Trong WasmMVP, ranh giới vai trò giữa tối ưu của toolchain và của VM khá rõ, nhưng với WasmGC, do đặc tính của ngôn ngữ GC và khả năng tối ưu của biểu diễn WasmGC, hai phía này có thể chồng lấn nhiều hơn
Tình trạng hiện tại và điểm khởi đầu
- WasmGC đã đạt phase 4 tại W3C, tức là đã trở thành tiêu chuẩn hoàn chỉnh và được chốt
- Chrome 119 bao gồm hỗ trợ WasmGC
- Firefox 120 được kỳ vọng phát hành vào cuối cùng tháng đó cùng với hỗ trợ WasmGC
- Trong Flutter demo, Dart biên dịch bằng WasmGC vận hành logic ứng dụng gồm widget, layout và animation
- Các toolchain hỗ trợ WasmGC gồm:
- Mã nguồn cho ví dụ nhỏ ở phần công cụ phát triển là một chương trình WasmGC “hello world” viết tay
- Có thể thấy định nghĩa kiểu
$Nodevà cách tạo bằngstruct.new
- Có thể thấy định nghĩa kiểu
- Wiki của Binaryen nói về cách để compiler xuất ra mã WasmGC thân thiện với trình tối ưu
- GC Implementation - Lowering Tips
- Cũng có thể tham khảo các pass và flag Binaryen mà toolchain Java, Dart, Kotlin sử dụng
1 bình luận
Ý kiến trên Hacker News
WASM trông như một ví dụ về vòng eo mỏng (thin waist), và nếu thêm cả bộ thu gom rác thì cấu trúc sẽ không phải N×M mà là N+M. Tức là có thể đi theo hướng N ngôn ngữ + M máy ảo + G bộ thu gom rác, và V8 đã có sẵn một bộ thu gom rác trưởng thành
Tôi từng thắc mắc liệu có công cụ nào chuyển từ WASM sang JVM không, và thấy trên GitHub có một cái. Tôi chưa trực tiếp dùng thử; chỉ tìm vì JVM cũng có các bộ thu gom rác trưởng thành và song song
Tôi không ngờ WASMGC lại xuất hiện nhanh như vậy, nên giờ tôi cũng kỳ vọng WASM Threads cho tính song song thực sự, không chỉ song song I/O
Nếu có cơ hội giải quyết hiệu quả bất đồng bộ, tính song song và thu gom rác, WASM sẽ mạnh hơn và có thể không trở thành nguồn gây rối hay khó khăn cho lập trình viên. Tôi nghĩ lý do WASI quan trọng cũng là vì nó có cơ hội định nghĩa một API ổn định như POSIX
1: https://www.oilshell.org/blog/2022/02/diagrams.html
2: https://github.com/cretz/asmble
Hy vọng các ý tưởng và phần giải thích về cách ánh xạ biểu diễn trung gian WASM sang bytecode JVM sẽ hữu ích cho những người tạo ra một triển khai chính thức hơn. Hiện không có kế hoạch hỗ trợ WASM GC
“Hơn 20 công ty công cụ lập trình cung cấp khoảng 26 ngôn ngữ lập trình trên .NET, bao gồm C++, Perl, Python, Java, COBOL, RPG, Haskell”
Nguồn: https://news.microsoft.com/2001/10/22/massive-industry-and-d...
Không hẳn vì giới học thuật đặc biệt táo bạo với JVM, mà vì các chương trình JVM được dùng rộng rãi và thường được sử dụng theo cách gây áp lực lên một kỹ thuật thu gom rác đơn lẻ
[^1]: https://www.baeldung.com/jvm-garbage-collectors. Azul JVM cũng có một bộ thu gom rác khác riêng. Đây chỉ là những gì tôi biết, chắc cũng còn khá nhiều thứ tôi đã bỏ sót
Có lẽ họ nói vậy khi so với coroutine, nhưng coroutine là tuần tự. Dù thứ tự thực thi có thể tùy ý, ta vẫn có thể dựa vào việc chúng không chạy cùng lúc
Nếu wasm chấp nhận thread thì có lẽ đây lại là một tình huống “Worse is Better” đáng tiếc nữa. Thread gần như là một trong những mô hình đồng thời tệ nhất mà chúng ta từng nghĩ ra. Tất nhiên là trừ những thứ như concurrent COMEFROM
Công cụ Julia WASM có thể tạo các ứng dụng hỗ trợ hoặc cần tính năng này. Ví dụ, có một ví dụ biên dịch ODE solver sang WASM tại https://tshort.github.io/WebAssemblyCompiler.jl/stable/examp...
Để chạy ngay thì cần Chrome v119, vì đây là phiên bản đầu tiên bật hỗ trợ thu gom rác. Có thêm chi tiết trên trang đầu của trình biên dịch WASM https://tshort.github.io/WebAssemblyCompiler.jl/stable/
Hy vọng kiểu
Memory{T}mới sẽ giúp biên dịch được nhiều mã hơnCó cảm giác như “wasm là LLVM mới”. Tôi tò mò liệu có ai cũng cảm thấy tương tự không
Tôi hiểu nó đang cố làm gì và cũng đã xem các bản demo cho thấy sức mạnh đó, nhưng phần lớn vẫn rất cấp thấp về mặt kỹ thuật, và khi dùng thực tế thường trở nên khá phiền phức
Tôi muốn biết khi nào thì nó sẽ sẵn sàng để được chấp nhận rộng rãi hơn, đến mức đáng chọn làm mục tiêu thay cho cách hiện tại
Do cái tên nên thường có hiểu lầm này: ban đầu LLVM có ý định là một máy ảo, nhưng thực tế chưa bao giờ như vậy và hiện tại cũng không phải. Ngay câu đầu tiên trên trang chủ cũng nói rõ điều đó: https://llvm.org/
Về cơ bản, nó là một tập hợp các thư viện C++ triển khai một biểu diễn trung gian thay đổi theo thời gian, và là công cụ hỗ trợ viết trình biên dịch
Khoảng 10 năm trước Google từng có một dự án nhắm tới phạm vi tương tự WASM, và có vẻ họ đã mắc hiểu lầm này. Họ nghĩ LLVM là một máy ảo. Có lẽ là thứ gì đó như PNaCl
Hơi giống cách LuaJIT cố định Lua ở Lua 5.1. Lua không phải là một chuẩn, nhưng để tái triển khai thì có thể cố định một phiên bản cụ thể. Tuy nhiên cách đó có vấn đề rõ ràng: bên tái triển khai không biết hết tất cả các lỗi mà họ cũng sẽ đóng băng cùng theo thời gian
Có lúc tôi từng nhướng mày trước những “thỏa hiệp” của WASM, nhưng có một điều không thể nghi ngờ: WASM thực sự là máy ảo
Tôi đã xem bài trình bày về WASM GC, và những người tạo ra nó đã nói rất thẳng thắn về các điểm đánh đổi. Ví dụ như ban đầu cần runtime cast, và overhead đo được ở mức hợp lý. Thái độ như vậy lại tạo cảm giác đáng tin hơn
https://old.reddit.com/r/ProgrammingLanguages/comments/17crk...
Thành thật mà nói, tôi không hiểu rõ wasm. Không rõ chính xác chúng ta đang cố giải quyết vấn đề gì
Tôi tự hỏi liệu mục tiêu có phải là viết ứng dụng bằng các ngôn ngữ không phải JavaScript hoặc không phải mã được chuyển đổi sang JavaScript hay không. Tôi cũng không rõ điều đó có bao gồm phần tương tác với lớp hiển thị DOM của trình duyệt không. Theo hiểu biết của tôi thì thực tế có vẻ không làm được điều đó; nếu đúng vậy, liệu mục tiêu có phải là chạy ứng dụng trong một canvas chuyên dụng bên trong DOM, giống Flash không? Nếu thế thì tôi không biết ngách đó lớn đến đâu
Ở một luồng khác cũng có nhắc đến việc dùng wasm cho Cloudflare Workers. Có lẽ vì nó hoạt động thông qua trình thông dịch JavaScript. Nhưng nếu mọi người muốn viết Cloudflare Workers bằng runtime tùy ý, chẳng phải Cloudflare chỉ cần thêm hỗ trợ cho các runtime khác là được sao? Họ hẳn có đủ năng lực làm chuyện đó
Hoặc ngoài mối liên kết với hệ sinh thái JavaScript, tôi tò mò liệu wasm với tư cách bytecode có điểm gì thực sự xuất sắc riêng hay không
Tôi có cảm giác mình đã bỏ lỡ một tài liệu nhập môn giải thích vì sao công nghệ này thú vị, nhưng đến thời điểm này thì hỏi cũng hơi ngại
LLVM không cung cấp “sandbox bảo mật dễ dùng sẵn” nếu không viết khá nhiều mã. wasmer có backend LLVM, nhưng cá nhân tôi cho rằng đây là điểm khác biệt lớn nhất của WASM
Nó đi theo cùng hướng với LLVM, nhưng vẫn còn cách rất xa
Dù nó tuyệt vời đến đâu và mở ra nhiều khả năng đến mức nào, tôi vẫn cứ nghĩ mãi về việc trình duyệt ngày nay cực kỳ phức tạp, và rào cản để tự làm một cái gần như quá dốc
Tôi không hiểu vì sao nền tảng hypermedia thành công và dễ tiếp cận nhất thế giới lại phải dễ triển khai. Dĩ nhiên hệ thống trực tuyến thành công nhất thế giới sẽ phức tạp và nhiều tính năng. Vì thế chúng ta mới dùng nó, và vì thế nó mới thắng
Việc cuối cùng thứ này cũng được làm ra và phát hành thật ấn tượng. Kế hoạch đưa GC vào WASM đã được nghe nói trong nhiều năm, và tôi từng không chắc liệu nó có thực sự xảy ra hay không
Tôi tò mò không biết nó sẽ giúp được bao nhiêu cho các ngôn ngữ nhắm tới WASM nhưng gặp vấn đề binary phình to vì phải kèm theo runtime. Theo tôi nhớ thì chỉ riêng hello world của Blazor cũng cần khoảng 1MB, không rõ WasmGC có giúp được gì ở đây không
Tất nhiên điều đáng lo là nếu đó là tính năng chỉ .NET cần, động lực để bổ sung sẽ không lớn. Đến lúc đó, một tính năng kiểu
includecho phép cache một phiên bản GC cụ thể để các WASM assembly khác có thể tải vào có khi còn hữu ích hơn, dù có gây ra không ít đau đớn[0] - https://github.com/WebAssembly/gc/issues/77
C và Rust không kèm garbage collector, nhưng vẫn phải đóng gói malloc/free để quản lý bộ nhớ. Lý do Java nhỏ hơn ở đây là vì hoàn toàn không cần đóng gói mã quản lý bộ nhớ
https://developer.chrome.com/blog/wasmgc/
Với Blazor thì có lẽ chỉ giúp phần GC. Theo tôi nhớ, Blazor phải gửi kèm toàn bộ runtime dotnet
Hỗ trợ wasm mới của Kotlin khá đáng mong đợi. Có một phiên bản thử nghiệm của Compose Multiplatform có thể nhắm tới trình duyệt, và nó dự kiến sẽ dùng WASM
Về cơ bản, Compose Multiplatform là Google Jetpack Compose cho Android được bổ sung hỗ trợ các nền tảng khác
Tính đến vài ngày trước, hỗ trợ iOS đang ở alpha và dự kiến sẽ lên beta vào năm sau. Hỗ trợ Android và desktop hiện đã ổn định. Khi chúng ổn định, về thực chất có thể viết ứng dụng UI chạy trên gần như mọi nền tảng
wasm compiler sẽ được phát hành cùng bản major tiếp theo của Kotlin là Kotlin 2.0, trong đó có compiler mới k2. Có vẻ khoảng đầu năm sau là khả thi. k2 hiện có ở dạng beta và có thể bật trong Kotlin 1.9.x
Điểm mạnh của hệ sinh thái Kotlin multiplatform là đã có nhiều thư viện chạy trên nhiều nền tảng. Vì vậy wasm compiler cũng sẽ nhanh chóng trở thành một phần của hệ sinh thái đó và thừa hưởng các thư viện tốt. Nhìn chung chỉ cần đổi thiết lập build để nhắm tới hệ sinh thái đó, rồi triển khai các hành vi riêng theo nền tảng còn thiếu
Một điểm thú vị khác trong mảng này là sử dụng và liên kết các thư viện viết bằng các ngôn ngữ khác nhau. Ví dụ, nhiều phần phụ thuộc nền tảng rất có thể sẽ dựa vào các thư viện C hoặc Rust đã tồn tại. Trong nhiều trường hợp, chúng cũng có thể là cùng những thư viện mà Kotlin Native dùng
Tôi cũng tò mò liệu desktop, web, iOS, Android có dùng cùng widget không. Tôi hiểu là trên Android thì native. Không rõ trên các nền tảng khác nó có mô phỏng style khác hay không. Câu hỏi cốt lõi là trên các nền tảng không phải Android, ứng dụng Compose Multiplatform cho cảm giác như thế nào
Ví dụ Dart trên web thì cá nhân tôi thấy rất giật lag, và Electron trên desktop cũng vậy. Dart trên desktop thì ổn, nhưng các ứng dụng nhìn chung có nút và khoảng trắng lớn, nên cảm giác giống ứng dụng Android chạy trong emulator hơn là ứng dụng native thực sự
Tôi cũng tò mò liệu có đáng khuyến nghị Kotlin làm ngôn ngữ cho dự án mới không
Tôi tự hỏi có ai giải thích được vì sao bài blog này và bài công bố của Chrome không nhắc đến Go không
Go cũng dùng garbage collection, nên tạo cảm giác như nó không hưởng lợi được từ thay đổi này
Tôi tự hỏi liệu việc runtime để lộ một thư viện cấp phát tích hợp mà C/C++/Rust có thể dùng có hợp lý không
Chương trình có thể chọn thư viện đó thay vì đóng gói thư viện cấp phát riêng của mình
Các primitive của Wasm GC được thiết kế để đạt cải thiện lớn nhất bằng phần bổ sung nhỏ nhất có thể. Khi các primitive khác như SIMD được thêm vào cũng vậy, vì chúng là “các primitive gần như tối thiểu” để đạt được chức năng đó. Ở đây cần các khối xây dựng nhỏ nhất có thể
Nhưng API bộ cấp phát bộ nhớ như malloc/free không phải là tính năng tối thiểu. Bộ cấp phát bộ nhớ thực ra là một tập hợp các chính sách và quyết định thiết kế, rồi thuật toán mới theo đó mà ra. Khối xây dựng cơ bản trong lĩnh vực đó là “một mảnh bộ nhớ tuyến tính thuộc sở hữu của bộ cấp phát”, và đó chính là bộ nhớ tuyến tính mà WASM đã có từ ngày đầu
Việc từng runtime riêng lẻ cung cấp thứ này có thể hợp lý. Ví dụ, truyền một phần bộ nhớ tuyến tính cho một wasm import tích hợp và để bộ cấp phát do runtime triển khai xử lý. Nhưng tôi cho rằng khả năng nó được chuẩn hóa là rất thấp. Ngoài ra, phần lớn công cụ cho các ngôn ngữ Wasm không có GC được điều chỉnh theo cách port codebase hiện có cùng bộ cấp phát của chúng. Rốt cuộc sẽ là tăng thêm mã phải bảo trì cho một triển khai dùng một lần, nên có thể không đáng công sức bỏ ra
Nếu không có tính xác định, khác biệt trong hành vi chương trình có thể trở nên quan trọng. Ví dụ, nếu một trình duyệt đưa vào một bộ cấp phát “thông minh” tái sử dụng bộ nhớ tốt hơn, thì một chương trình bị thiếu bộ nhớ do phân mảnh bộ nhớ tuyến tính trên trình duyệt khác lại có thể chạy thành công trên trình duyệt đó. Trong lịch sử, các trình duyệt đã rất nỗ lực chuẩn hóa hành vi để tránh những khác biệt như vậy
Việc chuẩn hóa hành vi của triển khai malloc/free cũng khó vì nhiều lý do. Thứ nhất, độ phức tạp lớn, như cách xử lý free list, dùng kích thước chunk nào, v.v. Quá nhiều để đưa vào đặc tả. Thứ hai, nếu chuẩn hóa một hành vi cụ thể thì sẽ không thể cải tiến được nữa, trong khi các ý tưởng malloc/free tốt hơn vẫn đang xuất hiện
Vì những lý do này, tôi hoài nghi về khả năng nó được đưa vào đặc tả wasm
Ngược lại, GC tránh được các vấn đề này. Vì giá trị con trỏ không quan sát được, nên không có gì cần đặc tả
allocvà các hàm liên quan làm hàm runtime để mã truyền thống gọi, và cho phép bất kỳ GC nào xây dựng chồng lên trên đóTôi hơi hoài nghi về hướng đi này. Nó đang làm tăng đáng kể độ phức tạp của WebAssembly
Garbage collector là một lớp trừu tượng bị rò rỉ. Có cái hỗ trợ con trỏ nội bộ, có cái thì không. Có cái hỗ trợ tác vụ song song dùng chung bộ nhớ, có cái thì không. Có cái cần nén nên C FFI trở nên khó hơn, có cái thì không. Có cái phải tích hợp sâu với các cơ chế dùng cho green process/thread và stack có thể mở rộng, có cái thì không
Nhìn vào các ngôn ngữ như Erlang, JavaScript, Python, Go, có thể thấy các lựa chọn ở cấp ngôn ngữ phần nào được phản ánh vào garbage collector
Ý tưởng về một máy ảo đa năng/phổ quát hỗ trợ nhiều ngôn ngữ đã được thử nhiều lần với JVM, CLR, Parrot, v.v., và mức độ thành công khá hạn chế. Tôi tò mò lần này có gì khác
JVM/CLR trước hết tạo ra máy ảo, đặc tả lệnh ngôn ngữ trung gian và runtime, rồi sau đó phân phối càng rộng càng tốt với kỳ vọng được client phổ biến chấp nhận. Tức là kỳ vọng rằng “VM ngôn ngữ trung gian” hấp dẫn đến mức sẽ lan ra toàn ngành. Kỳ vọng này chỉ đúng một phần. JVM/CLR đã lan rộng trên desktop và server, nhưng trong trình duyệt web thì Java Applet và Microsoft Silverlight thất bại, và cũng không được chấp nhận rộng rãi trên các nền tảng di động
WASM đi theo thứ tự ngược lại. Nó xuất phát ngược từ thứ đã được triển khai và chấp nhận trên toàn ngành, tức JavaScript, để tạo ra “máy ảo, đặc tả lệnh ngôn ngữ trung gian, runtime”
Nhìn từ góc độ này, cái gọi là “ngôn ngữ đồ chơi” JavaScript là một con ngựa thành Troy kéo dài 20 năm để trước hết được triển khai rộng rãi trên mọi client. Giờ thì ngành công nghiệp về cơ bản đang nói: “Có ai nhận ra rằng chúng ta đã có JavaScript, một runtime phổ quát trên server + desktop + trình duyệt + di động chưa? Hãy tạo một runtime ngôn ngữ trung gian để làm nó nhanh lên”
Cũng có vài vấn đề kỹ thuật. Sun JVM không có con trỏ nguyên thủy nên khó trở thành đích biên dịch hiệu năng cao cho các ngôn ngữ dựa trên con trỏ như C/C++, còn MS CLR thì không dùng được trên macOS. CLR tối thiểu của Silverlight là ngoại lệ. Nhưng hơn các hạn chế kỹ thuật đó, trình tự thời gian mà JavaScript được triển khai như một con ngựa thành Troy vô hại có sức giải thích lớn hơn
Wasm ở mức thấp hơn hầu hết các định dạng bytecode nêu trên. Điều này vẫn đúng ngay cả khi tính cả Wasm GC, vốn thêm struct và array có kiểu tĩnh, cùng đề xuất function-references để lấy các hàm có kiểu. Wasm GC còn hỗ trợ tường minh cho con trỏ gắn thẻ
i31refVì những điểm này, Wasm GC tổng quát hơn các nỗ lực kể trên chính bởi nó ở mức thấp hơn
Việc tạo một VM “đa năng” hoặc “phổ quát” hỗ trợ nhiều ngôn ngữ một cách ngang hàng và mượt mà không phải là mục tiêu rõ ràng của WASM-GC. Quan điểm là mỗi triển khai có thể cần các thủ thuật riêng và ngữ nghĩa đặc thù trên nền hỗ trợ cơ bản mà WASM cung cấp; còn FFI và khả năng tương tác giữa các ngôn ngữ được xem là vấn đề hoàn toàn riêng, nên như vậy là chấp nhận được
Garbage collection của JavaScript sẽ tiếp tục tồn tại, và có vẻ là thứ bám rễ dai dẳng nhất trong các ví dụ đã nêu
Trong nhiều trường hợp, dù kém hơn, các ngôn ngữ và ứng dụng/thư viện khác vẫn phải thích nghi với nó
wasm cung cấp tính năng GC để các ngôn ngữ runtime bộ nhớ được quản lý có thể nhắm tới môi trường wasm mà không bị khổ vì giới hạn của mô hình bộ nhớ hạn chế, và thứ yếu là để giảm kích thước bundle
wasm có khả năng sẽ hỗ trợ các tham số GC có thể điều chỉnh nhiều hơn để phù hợp hơn với đặc tính của ngôn ngữ guest. Ngoài ra, khác với các runtime ngôn ngữ mục đích chung đem ra so sánh, người triển khai ngôn ngữ hoàn toàn không có lựa chọn tự tạo một runtime tùy chỉnh
Nhiều mối lo ngại về tính khả thi hiện tại của WASM GC được bàn đến ở đây. Bản Google Dịch tiếng Anh:
https://habr-com.translate.goog/ru/articles/757182/?_x_tr_sl...
Bản gốc:
https://habr.com/ru/articles/757182/
Đây là bài viết của tác giả TeaVM, người đã dành 10 năm để làm cho Java và mã JVM chạy hiệu quả trong trình duyệt. https://teavm.org/
Cơ chế chuyển đổi Java-to-JavaScript hiện có của TeaVM sử dụng JS GC của trình duyệt mà vẫn có hiệu năng tốt. Sẽ rất thú vị để xem liệu WASM GC khi trưởng thành hơn có thể nhanh hơn nữa hay không
Ghi chú về các vấn đề được bàn trong bài: vấn đề cần một shadow stack thủ công đã được giải quyết trong WasmGC. Như liên kết nói, nó giống với cách hoạt động trong JS
Việc thiếu try-catch đã được giải quyết bằng đề xuất xử lý ngoại lệ Wasm, hiện đã được phát hành trên các trình duyệt: https://github.com/WebAssembly/exception-handling/blob/main/...
Kiểm tra null phần lớn cũng được giải quyết bằng WasmGC. Đặc tả định nghĩa các kiểu cục bộ không thể null, và VM có thể tối ưu hóa bằng tín hiệu như kỹ thuật được nhắc đến trong bài. Ví dụ Wizard làm như vậy
Khởi tạo lớp là một vấn đề khó, đúng như bài viết nói. J2Wasm và Binaryen đang làm việc để tối ưu hóa việc này bằng phân tích tĩnh ở cấp toolchain. Một PR gần đây tôi viết đã đạt tiến triển theo hướng này: https://github.com/WebAssembly/binaryen/pull/6061
Chi phí vtable được nhắc đến trong bài có thể là một vấn đề. Tuy nhiên hiện vẫn chưa biết các số đo tốt. Có một vài ý tưởng giải pháp post-MVP cho method dispatch, nhưng chưa có gì cụ thể
Về kiểm tra null và trap, từng có thảo luận về các biến thể lệnh GC ném ngoại lệ thay vì trap. Nhưng theo đo đạc, hiện nó chưa nổi lên như một vấn đề lớn nên mức ưu tiên thấp
Tác giả nói rằng stack walking, tín hiệu và kiểm soát bộ nhớ là các lĩnh vực quan trọng là đúng
Nhìn chung, nhờ WasmGC và xử lý ngoại lệ, Java mà J2Wasm xuất ra hiện nay đang ở vị thế khá tốt. Thường nhanh hơn J2CL, vốn biên dịch Java sang JavaScript. Dù vậy rõ ràng vẫn còn dư địa để cải thiện