- เมื่อนำ ภาษา GC อย่าง Java, Kotlin, Dart, Python, C# ไปยัง WebAssembly นั้น WasmGC ไม่ใช่การคอมไพล์ VM เดิมใหม่ แต่ใช้โครงสร้าง GC, อาร์เรย์ และระบบชนิดข้อมูลของ Wasm เอง
- การพอร์ตแบบ WasmMVP ดั้งเดิมนำ VM และการปรับแต่งประสิทธิภาพเดิมกลับมาใช้ได้ง่าย แต่มีต้นทุนจากการใส่ GC หรือ
malloc/freeไว้ใน linear memory รวมถึงข้อจำกัดเรื่องการอ้างอิงบนสแต็ก, circular reference และ fragmentation - WasmGC ให้ VM จัดการอ็อบเจ็กต์และหน่วยความจำโดยตรง จึงลดขนาดไบนารีได้ และในเบนช์มาร์ก
fannkuchมีขนาด 2.3K เล็กกว่า C/Rust ที่ 6.1~9.6K - WasmGC เป็น intermediate representation ระดับสูงกว่า จึงทำให้ Binaryen
wasm-optและการปรับแต่งรันไทม์ของ V8 สำคัญ โดยมีกรณีที่เบนช์มาร์ก Java ดีขึ้นเฉลี่ย 1.9× และ Google Sheets Calc Engine ดีขึ้นราว 30% - แม้มาตรฐานและการรองรับในเบราว์เซอร์จะคืบหน้าแล้ว แต่เพราะไม่ใช่วิธีคอมไพล์ VM เดิมทั้งก้อน จึงต้องมี งาน toolchain ใหม่ เพื่อลดระดับโครงสร้างของภาษาให้เป็น primitive ของ WasmGC
สองแนวทางในการนำภาษา GC ไปยัง Wasm
- การพอร์ตภาษา GC ไปยัง WebAssembly แบ่งได้กว้าง ๆ เป็นสองสาย
- การพอร์ตแบบดั้งเดิม: คอมไพล์ VM ของภาษาที่มีอยู่ไปเป็น WasmMVP ซึ่งเป็น WebAssembly Minimum Viable Product ที่ออกในปี 2017
- การพอร์ตแบบ WasmGC: คอมไพล์ภาษาไปยังโครงสร้าง GC ของ Wasm ตามที่นิยามไว้ในข้อเสนอ GC
- การพอร์ตแบบดั้งเดิมใกล้เคียงกับโมเดลที่ใช้ย้ายภาษาไปยังสถาปัตยกรรม CPU ใหม่ คือแชร์ parser, การรองรับไลบรารี, GC และ optimizer ของ VM แล้วเพิ่มเพียงแบ็กเอนด์ใหม่
- การพอร์ตแบบ WasmGC ใกล้เคียงกับการย้ายภาษาไปยัง VM ใหม่ มากกว่าย้ายไปยังสถาปัตยกรรมใหม่
- เช่นเดียวกับ J2CL ที่คอมไพล์ Java ไปเป็น JavaScript โดยแทนอ็อบเจ็กต์ของภาษาเป็นอ็อบเจ็กต์ของ VM ปลายทาง และให้ GC ของ VM ปลายทางเป็นผู้จัดการ
- WasmGC มุ่งให้อยู่ในระดับต่ำกว่า JavaScript VM, JVM, CLR แต่ยังสูงกว่า WasmMVP ตรงที่ให้โครงสร้างและอาร์เรย์ที่ VM จัดการ รวมถึงความสัมพันธ์ของชนิดข้อมูล
จุดเด่นและข้อจำกัดของการพอร์ต WasmMVP แบบดั้งเดิม
- จุดเด่นที่สุดของการพอร์ตแบบดั้งเดิมคือสามารถนำโค้ด VM, implementation ของภาษา และการปรับแต่งประสิทธิภาพเดิมกลับมาใช้ได้แทบทั้งหมด
- ผลลัพธ์ WasmMVP ใช้โครงสร้างพื้นฐานของ WasmMVP เช่น linear memory, table และ function
- มักมีการรัน Wasm อยู่ใน VM ที่มี GC อยู่แล้ว เช่น เบราว์เซอร์, Node.js, workerd, Deno, Bun
- ในสภาพแวดล้อมนี้ หากรวม implementation ของ GC ไว้ในไบนารี Wasm จะทำให้เกิด ขนาดที่เพิ่มขึ้นโดยไม่จำเป็น
- แม้แต่ภาษาอย่าง C, C++, Rust ที่ใช้ linear memory หากมีการจัดสรรหน่วยความจำที่มีนัยสำคัญ ก็ต้องรวมโค้ด
malloc/freeเข้าไปด้วย dlmallocมีขนาด 6K ส่วนemmallocที่ให้ความสำคัญกับขนาดก็ยังเกิน 1K
- WasmGC ให้ VM จัดการหน่วยความจำอัตโนมัติ จึงไม่จำเป็นต้องใส่ GC หรือ
malloc/freeไว้ใน Wasm- ในเบนช์มาร์ก
fannkuchจากบทความ WasmGC ก่อนหน้านี้ WasmGC มีขนาด 2.3K ส่วน C/Rust อยู่ที่ 6.1~9.6K
- ในเบนช์มาร์ก
การเก็บกวาดวงจร, การอ้างอิงบนสแต็ก และ fragmentation
- บนเบราว์เซอร์ Wasm มักโต้ตอบกับ JavaScript และ Web API อยู่บ่อยครั้ง แต่ด้วย WasmMVP และ reference types เพียงอย่างเดียว การเก็บกวาดวงจรแบบละเอียดในลิงก์สองทิศทางระหว่าง Wasm กับ JS ทำได้ยาก
- ลิงก์ไปยังอ็อบเจ็กต์ JS สามารถเก็บไว้ได้เฉพาะใน table ของ Wasm
- ลิงก์จาก JS กลับมายัง Wasm อาจอ้างอิงทั้งอินสแตนซ์ Wasm เป็นเสมือนอ็อบเจ็กต์ขนาดใหญ่ชิ้นเดียว
- WasmGC นิยามอ็อบเจ็กต์ Wasm ที่ VM รับรู้ จึงสามารถสร้าง reference ที่เหมาะสมระหว่าง Wasm กับ JavaScript ได้
- ภาษา GC ต้องรับรู้ reference บนสแต็ก ด้วย เช่น local variable ใน call scope
- ในการพอร์ตแบบดั้งเดิม โปรแกรมไม่สามารถตรวจสอบสแต็กของตัวเองได้เพราะ sandboxing ของ Wasm
- ทางเลือกคือใช้ shadow stack หรือทำ GC เฉพาะเวลาที่ไม่มี reference อยู่บนสแต็ก เช่น ระหว่าง turn ของ event loop ของ JavaScript
- การรองรับ stack scanning ของ Wasm ในอนาคตอาจช่วยการพอร์ตแบบดั้งเดิมได้
- วิธีที่จัดการ reference บนสแต็กโดยอัตโนมัติแบบไม่มี overhead ในปัจจุบันคือ WasmGC
malloc/freeใน linear memory ของ WasmMVP อาจทำให้เกิด memory fragmentation ในโปรแกรมที่รันยาว- แม้หน่วยความจำที่ไม่ได้ใช้รวมจะเพียงพอ แต่ถ้าไม่มีบล็อกขนาดใหญ่ที่ต่อเนื่องกัน การจัดสรรขนาดใหญ่อาจล้มเหลว
- fragmentation ทำให้โมดูล Wasm ต้องขยายหน่วยความจำบ่อยขึ้น และนำไปสู่ overhead กับข้อผิดพลาด out-of-memory ได้
- WasmGC ให้ VM เคลื่อนย้ายอ็อบเจ็กต์เพื่อ compact GC heap ได้ จึงหลีกเลี่ยง fragmentation ได้
เครื่องมือนักพัฒนาและ semantics ของภาษา
- ในการพอร์ต WasmMVP แบบดั้งเดิม อ็อบเจ็กต์ถูกวางเป็นไบต์ใน linear memory ทำให้เครื่องมือนักพัฒนามองเห็นข้อมูลชนิดข้อมูลระดับสูงได้ยาก
- ใน WasmGC นั้น VM จัดการอ็อบเจ็กต์ GC จึงผสานกับเครื่องมือได้ง่ายขึ้น
- ในแท็บ Memory ของ Chrome DevTools สามารถดู heap snapshot ของโปรแกรม WasmGC ได้
- ในตัวอย่าง linked list จะแสดงชื่อชนิด
$Nodeและฟิลด์$nextที่อ้างอิงอ็อบเจ็กต์ถัดไป - ยังให้ข้อมูล heap snapshot ทั่วไป เช่น จำนวนอ็อบเจ็กต์, shallow size, retained size
- debugger ของ Chrome DevTools ก็ทำงานกับอ็อบเจ็กต์ WasmGC ได้
- การพอร์ตแบบดั้งเดิมคือการคอมไพล์ VM เดิมใหม่ จึงมักได้ semantics ของภาษาตามที่คาดหวังไว้โดยตรง
- การพอร์ตแบบ WasmGC ต้องแทนโครงสร้างของภาษาด้วยชนิด GC ใหม่อย่าง struct และ array ดังนั้นอาจต้องประนีประนอม semantics เพื่อประสิทธิภาพ
- ฟิลด์ของ struct ใน WasmGC มี index และชนิดข้อมูลคงที่ ทำให้ภาษาที่ต้องการเข้าถึงฟิลด์แบบไดนามิกกว่านี้อาจเจอความยากลำบาก
- ปัจจุบัน WasmGC ยังไม่มี interior pointer และคาดว่าข้อจำกัดเหล่านี้จะดีขึ้นเมื่อเวลาผ่านไป
- กรณีอื่น ๆ ที่คอมไพล์ไปยัง VM ปลายทางก็มีการเลือก semantics เช่นกัน
- พฤติกรรมตัวเลขของ dart2js ต่างจาก Dart VM
- สตริงของ IronPython ทำงานเหมือนสตริงของ C#
- ในทางกลับกัน dart2wasm ทำงานโดยไม่ต้องประนีประนอม semantics ของตัวเลข เพราะ Wasm สามารถแทนชนิดตัวเลขที่ Dart ต้องการได้อย่างมีประสิทธิภาพ
งาน toolchain ที่จำเป็นสำหรับการพอร์ต WasmGC
- การพอร์ต WasmGC ไม่ใช่วิธีคอมไพล์ VM เดิมใหม่แบบง่าย ๆ
- โค้ดบางส่วนที่ไม่ได้ผสานโดยตรงกับ runtime GC เช่น parser logic หรือการปรับแต่งแบบ AOT สามารถนำกลับมาใช้ได้
- โดยทั่วไปต้องใช้โค้ดใหม่จำนวนมากเพื่อลดระดับโครงสร้างของภาษาให้เป็น struct และ array ของ WasmGC
- VM ที่เขียนด้วย C อย่าง Lua VM สามารถคอมไพล์เป็น Wasm ได้ในไม่กี่นาที แต่การพอร์ต Lua ไปยัง WasmGC ต้องตัดสินใจและ implement ว่าจะแทนโครงสร้างของ Lua ภายใต้ข้อจำกัดของระบบชนิดข้อมูล WasmGC อย่างไร
- ข้อเสียใหญ่ของการพอร์ต WasmGC คือ ความพยายามด้าน toolchain
- สถานะในอุดมคติคือระบบชนิดข้อมูลของ WasmGC รองรับทุกภาษาได้อย่างมีประสิทธิภาพ และแต่ละภาษามีการ implement พอร์ต WasmGC ของตนเอง
- ฟีเจอร์เพิ่มเติมของระบบชนิดข้อมูล WasmGC ในอนาคตอาจช่วยส่วนแรกได้
- การแชร์งาน toolchain ร่วมกันจะช่วยลดภาระของส่วนที่สองได้
เหตุผลที่ WasmGC สามารถถูกปรับแต่งได้ดีกว่า
- WasmGC เป็น intermediate representation ที่มีระดับสูงกว่า WasmMVP จึงมีพื้นที่ให้ปรับแต่งมากกว่า
- ในฟังก์ชันตัวอย่าง โค้ดที่จัดสรรอ็อบเจ็กต์ GC สองครั้ง เก็บ
10ลงในฟิลด์ แล้วคืนค่า ในเชิงตรรกะสามารถลดเหลือreturn 10ได้- ใน WasmMVP การจัดสรรจะถูกเปลี่ยนเป็นการเรียก
mallocและmallocเป็นฟังก์ชันซับซ้อนที่มี side effect ต่อ linear memory ทำให้ optimizer มั่นใจได้ยากว่าการจัดสรรครั้งที่สองไม่ได้เปลี่ยนฟิลด์ของอ็อบเจ็กต์แรก - ใน WasmGC การจัดสรรถูกแทนด้วยคำสั่ง
struct.newและสามารถอนุมานได้ว่าเป็นงานของ VM จึงติดตาม reference และค่าฟิลด์ได้
- ใน WasmMVP การจัดสรรจะถูกเปลี่ยนเป็นการเรียก
- WasmGC ยังมี function pointer แบบ explicit อย่าง
ref.func, การเรียกผ่านสิ่งนี้ด้วยcall_refและชนิดข้อมูลของฟิลด์ใน struct/array - เหตุผลที่ WasmMVP ทำความเร็วได้ใกล้เคียง native มักเป็นเพราะคอมไพเลอร์ปรับแต่งที่ทรงพลังอย่าง LLVM ทำการปรับแต่งส่วนใหญ่ก่อนสร้าง Wasm
- LLVM ไม่รองรับ WasmGC และภาษา GC จำนวนมากก็ไม่ได้ใช้ LLVM ดังนั้น WasmGC จึงต้องมีโมเดลการปรับแต่งแบบอื่น
การปรับแต่งด้วย Binaryen และ wasm-opt
- WasmGC สามารถทำการปรับแต่งทั่วไปหลังลดระดับลงมาเป็น Wasm แล้ว ทำให้ toolchain ของหลายภาษาแชร์ optimizer แบบ Wasm-to-Wasm ร่วมกันได้
- ทีม V8 ลงทุนกับการรองรับ WasmGC ใน Binaryen ซึ่งเป็นโปรเจกต์ปรับแต่ง toolchain ของ WebAssembly
- แต่ละ toolchain สามารถใช้ Binaryen ผ่านเครื่องมือบรรทัดคำสั่ง
wasm-optได้
- แต่ละ toolchain สามารถใช้ Binaryen ผ่านเครื่องมือบรรทัดคำสั่ง
- Binaryen มีการปรับแต่งสำหรับ WasmMVP อยู่แล้ว เช่น inlining, constant propagation, dead code elimination และส่วนใหญ่ก็ใช้กับ WasmGC ได้ด้วย
- การปรับแต่งสำคัญที่เพิ่มเข้ามาสำหรับ WasmGC มีดังนี้
- Escape analysis: ย้ายการจัดสรร heap ไปเป็น local
- Devirtualization: แปลง indirect call เป็น direct call
- การลบ dead code ระดับ global ที่ทรงพลังขึ้น
- Whole-program type-aware content flow analysis, GUFA
- Cast optimizations: ลบ cast ที่ซ้ำซ้อนและย้ายตำแหน่ง cast
- Type pruning
- Type merging
- การ refine type สำหรับ local, global, field และ signature
- การปรับแต่ง GC ใหม่ของ Binaryen และวิธีใช้งานถูกรวบรวมไว้ใน Binaryen docs
- เมื่อวัดประสิทธิภาพ Java จากเอาต์พุตของ J2Wasm พบว่า
wasm-optเพิ่มความเร็วได้ในทุกเบนช์มาร์ก และเร็วขึ้นเฉลี่ย 1.9×
การปรับแต่ง WasmGC ใน V8
- ภาษา GC มีโมเดลประสิทธิภาพต่างจากภาษาอย่าง C, C++, Rust ที่พึ่งพา inlining ตอนคอมไพล์มาก
- ภาษา GC อย่าง Java, Dart มักให้ VM ทำ inlining และ optimization ใน runtime
- ใน Java การเรียกทุกครั้งเริ่มต้นเป็น indirect call
- คลาสลูกสามารถ override ฟังก์ชันของคลาสแม่ได้ และกรณีเรียกลูกผ่าน reference ของชนิดคลาสแม่ก็เช่นกัน
- หาก toolchain แปลง indirect call เป็น direct call ได้ก็เป็นประโยชน์ แต่ในโค้ด Java จริงมีหลายเส้นทางที่อนุมานแบบ static ได้ยากว่าเป็น direct call
- V8 implement speculative inlining สำหรับ WasmGC
- สังเกต indirect call ขณะ runtime
- หาก call site ใดมีพฤติกรรมเรียบง่าย เช่น มี target ของการเรียกน้อย ก็ทำ inlining พร้อม guard check
- Google Sheets Calc Engine เป็น codebase Java ที่คำนวณสูตรสเปรดชีต และเดิมคอมไพล์เป็น JavaScript ด้วย J2CL
- ทีม V8 ร่วมมือกับ Sheets และ J2CL เพื่อพอร์ตโค้ดนี้ไปยัง WasmGC
- ในโค้ดนี้ speculative inlining ให้ผลมากที่สุดในบรรดาการปรับแต่งเดี่ยว ๆ ที่ V8 implement ให้ WasmGC
- ความเร็วเพิ่มขึ้นราว 30% ซึ่งมากกว่าการปรับปรุงจาก optimization อื่น ๆ ที่วัดได้ทั้งหมดรวมกัน
- การปรับแต่ง WasmGC อื่น ๆ ของ V8 ได้แก่ load elimination, type-based optimizations, branch elimination, constant folding, escape analysis, common subexpression elimination เป็นต้น
- ข้อมูลชนิดของ WasmGC ยังถูกใช้ในการปรับแต่ง runtime ด้วย
- หาก
ref.testผ่านการตรวจชนิดใดชนิดหนึ่งแล้วref.castไปเป็นชนิดเดียวกันควรต้องสำเร็จ - สามารถลบ cast ในแพตเทิร์นอย่าง downcast หลัง
instanceofของ Java ได้
- หาก
- ใน WasmMVP การแบ่งบทบาทระหว่าง toolchain กับการปรับแต่งของ VM ค่อนข้างชัดเจน แต่ใน WasmGC บทบาทของการปรับแต่งใน toolchain และ VM อาจทับซ้อนกันมากขึ้น เพราะคุณลักษณะของภาษา GC และความเป็นไปได้ในการปรับแต่ง representation ของ WasmGC
สถานะปัจจุบันและจุดเริ่มต้น
- WasmGC ไปถึง phase 4 ที่ W3C แล้ว จึงเป็นมาตรฐานที่สมบูรณ์และ finalized
- Chrome 119 รวมการรองรับ WasmGC แล้ว
- คาดว่า Firefox 120 จะออกพร้อมการรองรับ WasmGC ในช่วงปลายเดือนเดียวกัน
- ใน Flutter demo Dart ที่คอมไพล์ด้วย WasmGC ขับเคลื่อน application logic รวมถึง widget, layout และ animation
- toolchain ที่รองรับ WasmGC มีดังนี้
- ซอร์สโค้ด ตัวอย่างเล็ก ๆ ในส่วนเครื่องมือนักพัฒนา เป็นตัวอย่างโปรแกรม WasmGC “hello world” ที่เขียนด้วยมือ
- สามารถดูการนิยามชนิด
$Nodeและวิธีสร้างด้วยstruct.newได้
- สามารถดูการนิยามชนิด
- Binaryen wiki กล่าวถึงวิธีให้คอมไพเลอร์ปล่อยโค้ด WasmGC ที่เหมาะต่อการปรับแต่ง
- GC Implementation - Lowering Tips
- ยังสามารถอ้างอิง pass และ flag ของ Binaryen ที่ toolchain ของ Java, Dart, Kotlin ใช้งานได้
1 ความคิดเห็น
ความเห็นจาก Hacker News
WASM ดูเหมือนจะเป็นตัวอย่างของ thin waist และถ้าเพิ่ม garbage collector เข้าไปด้วย โครงสร้างก็จะกลายเป็น N+M แทน N×M กล่าวคืออาจไปได้ในรูป N ภาษา + M virtual machine + G garbage collector และใน V8 ก็มี garbage collector ที่พัฒนาเต็มที่อยู่แล้ว
สงสัยว่ามีเครื่องมือจาก WASM ไป JVM หรือไม่ แล้วก็พบว่ามีอันหนึ่งบน GitHub ไม่ได้ลองใช้เอง แค่ไปค้นหาเพราะ JVM เองก็มี garbage collector ที่พัฒนาเต็มที่และรองรับการทำงานแบบขนาน
เพราะไม่คิดว่า WASMGC จะออกมาได้เร็วขนาดนี้ ตอนนี้เลยเริ่มคาดหวัง WASM Threads สำหรับ parallelism ที่แท้จริง ไม่ใช่แค่ I/O parallelism
ถ้ามีโอกาสจัดการ async, parallelism และ garbage collection ได้อย่างมีประสิทธิภาพ WASM ก็จะแข็งแกร่งขึ้นและอาจไม่กลายเป็นแหล่งของความสับสนหรือความยุ่งยากสำหรับนักพัฒนา เหตุผลที่ WASI สำคัญก็เพราะมันเป็นโอกาสในการกำหนด API ที่เสถียรพอๆ กับ POSIX
1: https://www.oilshell.org/blog/2022/02/diagrams.html
2: https://github.com/cretz/asmble
หวังว่าแนวคิดและคำอธิบายว่ามีการแมป WASM intermediate representation ไปเป็น JVM bytecode อย่างไร จะช่วยคนที่กำลังทำ implementation ที่เป็นทางการมากขึ้นได้ ตอนนี้ยังไม่มีแผนรองรับ WASM GC
“ผู้ผลิตเครื่องมือเขียนโปรแกรมมากกว่า 20 รายกำลังนำเสนอภาษาโปรแกรมราว 26 ภาษา บน .NET รวมถึง C++, Perl, Python, Java, COBOL, RPG และ Haskell”
ที่มา: https://news.microsoft.com/2001/10/22/massive-industry-and-d...
ไม่ใช่ว่าวงวิชาการกล้าทดลองกับ JVM เป็นพิเศษ แต่เป็นเพราะโปรแกรมบน JVM ถูกใช้อย่างแพร่หลาย และรูปแบบการใช้งานก็มักกดดันเทคนิค garbage collection แบบใดแบบหนึ่งอยู่เสมอ
[^1]: https://www.baeldung.com/jvm-garbage-collectors. Azul JVM ก็มี garbage collector ที่แยกออกไปอีกตัวหนึ่ง นี่เป็นแค่ที่ฉันรู้ และคงยังมีอีกหลายตัวที่ตกหล่นไป
ดูเหมือนว่าจะพูดเทียบกับ coroutine แต่ coroutine นั้นเป็นแบบลำดับ ถึงลำดับการทำงานอาจไม่แน่นอน แต่ก็ยังพึ่งพาได้ว่ามันจะไม่ทำงานพร้อมกันจริงๆ
ถ้า wasm รับเอา thread มาใช้ ก็คงจะเป็นอีกหนึ่งกรณีน่าเสียดายของ “Worse is Better” thread เป็นหนึ่งในโมเดล concurrency ที่แย่ที่สุดเท่าที่เราเคยคิดขึ้นมาได้ แน่นอนว่าไม่นับอะไรอย่าง concurrent COMEFROM
เครื่องมือ Julia WASM สามารถรองรับฟีเจอร์นี้ หรือใช้สร้างแอปที่ต้องการฟีเจอร์นี้ได้ ตัวอย่างเช่นมีตัวอย่างการคอมไพล์ ODE solver เป็น WASM ที่ https://tshort.github.io/WebAssemblyCompiler.jl/stable/examp...
ถ้าจะให้ทำงานได้ทันทีต้องใช้ Chrome v119 เพราะเวอร์ชันนี้เป็นเวอร์ชันแรกที่เปิดใช้การรองรับ garbage collection ดูรายละเอียดเพิ่มเติมได้ที่หน้าแรกของ WASM compiler https://tshort.github.io/WebAssemblyCompiler.jl/stable/
หวังว่าด้วย type ใหม่
Memory{T}จะทำให้สามารถคอมไพล์โค้ดได้มากขึ้นให้ความรู้สึกประมาณว่า “wasm คือ LLVM ตัวใหม่” เลย สงสัยว่ามีใครรู้สึกคล้ายกันไหม
เข้าใจว่ากำลังพยายามทำอะไร และก็เคยเห็นเดโมที่แสดงพลังของมันแล้ว แต่โดยมากมันก็ยังคงเป็นเรื่องเชิงเทคนิคระดับล่างมาก และในหลายกรณีก็ค่อนข้างยุ่งยากหากจะนำไปใช้จริง
เลยสงสัยว่าคิดว่าเมื่อไหร่มันจะพร้อมสำหรับการยอมรับในวงกว้างมากพอให้เลือกใช้เป็นเป้าหมายแทนแนวทางปัจจุบัน
ชื่อนี่แหละที่ทำให้เกิดความเข้าใจผิดกันบ่อย LLVM ในช่วงแรกตั้งใจให้ดูเหมือน virtual machine แต่จริง ๆ แล้วไม่เคยเป็น และตอนนี้ก็ยังไม่ใช่ ประโยคแรกบนหน้าเว็บก็ระบุชัดเจน: https://llvm.org/
โดยพื้นฐานแล้วมันคือชุดไลบรารี C++ ที่ทำงานกับ intermediate representation ซึ่งเปลี่ยนแปลงไปตามกาลเวลา และเป็นเครื่องมือช่วยเขียนคอมไพเลอร์
เมื่อราว 10 ปีก่อน Google เคยมีโปรเจกต์ที่เล็งพื้นที่คล้าย WASM และดูเหมือนจะเข้าใจผิดตรงนี้ คือมอง LLVM เป็น virtual machine น่าจะเป็นอะไรอย่าง PNaCl
คล้ายกับที่ LuaJIT ตรึง Lua ไว้ที่ Lua 5.1 อยู่บ้าง Lua เองไม่ใช่มาตรฐาน แต่ก็สามารถตรึงเวอร์ชันหนึ่งไว้เพื่อให้ reimplement ได้ เพียงแต่วิธีนั้นมีปัญหาชัดเจน คือฝั่งที่นำไป reimplement อาจไม่รู้บั๊กทั้งหมดที่ถูกตรึงติดไปพร้อมกับช่วงเวลานั้น
ผมเคยเลิกคิ้วกับ “จุดประนีประนอม” ของ WASM อยู่บ้าง แต่มีสิ่งหนึ่งที่เถียงไม่ได้คือ WASM เป็น virtual machine จริง ๆ
ผมดูงานนำเสนอ WASM GC แล้ว คนที่สร้างมันพูดถึงจุดประนีประนอมอย่างตรงไปตรงมา เช่น ในช่วงแรกจำเป็นต้องมี runtime cast และ overhead ที่วัดได้ก็อยู่ในระดับสมเหตุสมผล ท่าทีแบบนี้กลับทำให้น่าเชื่อถือ
https://old.reddit.com/r/ProgrammingLanguages/comments/17crk...
พูดตรง ๆ คือ ผมไม่ค่อยเข้าใจ wasm ไม่ชัดเจนว่าเรากำลังพยายามแก้ปัญหาอะไรอยู่กันแน่
สงสัยว่าเป้าหมายคือการเขียนแอปพลิเคชันด้วยภาษาอื่นที่ไม่ใช่ JavaScript หรือโค้ดที่คอมไพล์เป็น JavaScript หรือไม่ และสิ่งนั้นรวมถึงส่วนที่ต้องโต้ตอบกับชั้นแสดงผล DOM ของเบราว์เซอร์หรือเปล่า เท่าที่ผมเข้าใจ ดูเหมือนจริง ๆ แล้วมันทำไม่ได้ ถ้าใช่ เป้าหมายก็คือรันแอปในแคนวาสเฉพาะภายใน DOM แบบ Flash หรือไม่ ถ้าเป็นอย่างนั้นก็ไม่แน่ใจว่าช่องเฉพาะนั้นใหญ่แค่ไหน
ในอีกเธรดหนึ่งก็มีคนพูดถึงการใช้ wasm กับ Cloudflare Workers น่าจะเพราะมันทำงานผ่าน JavaScript interpreter แต่ถ้าผู้คนอยากเขียน Cloudflare Workers ด้วย runtime อะไรก็ได้ Cloudflare จะเพิ่มการรองรับ runtime อื่นไปเลยไม่ได้หรือ ดูแล้วน่าจะมีศักยภาพพอ
หรือว่านอกจากการเชื่อมต่อกับ ecosystem ของ JavaScript แล้ว wasm มีจุดเด่นที่ ยอดเยี่ยมในตัวเองในฐานะ bytecode หรือไม่
รู้สึกเหมือนพลาดบทความแนะนำที่อธิบายว่าทำไมเทคโนโลยีนี้ถึงน่าสนใจ และตอนนี้จะมาถามก็ดูเขิน ๆ นิดหน่อย
LLVM ไม่ได้ให้ “sandbox ด้านความปลอดภัยที่ใช้ง่ายโดยปริยาย” หากไม่มีการเขียนโค้ดเพิ่มพอสมควร wasmer มี LLVM backend ก็จริง แต่สำหรับผม จุดนี้คือความแตกต่างที่ใหญ่ที่สุดของ WASM
มันกำลังไปในทิศทางเดียวกับ LLVM แต่ก็ยังห่างจากจุดนั้นอยู่มาก
ต่อให้มันยอดเยี่ยมและเปิดความเป็นไปได้มากแค่ไหน ก็อดคิดไม่ได้ว่าเบราว์เซอร์ทุกวันนี้ ซับซ้อนอย่างสุดขีด และอุปสรรคในการสร้างเองก็สูงชันจนแทบเกินไป
ไม่เข้าใจว่าทำไมแพลตฟอร์มไฮเปอร์มีเดียที่ประสบความสำเร็จและเข้าถึงได้มากที่สุดในโลกถึงจำเป็นต้องถูกทำให้ติดตั้งหรืออิมพลีเมนต์ได้ง่ายด้วย เป็นเรื่องธรรมดาอยู่แล้วที่ระบบออนไลน์ซึ่งประสบความสำเร็จที่สุดในโลกจะซับซ้อนและมีฟีเจอร์มาก นั่นแหละคือเหตุผลที่เราใช้มัน และนั่นแหละคือเหตุผลที่มันชนะ
น่าประทับใจที่ท้ายที่สุดแล้วสิ่งนี้ถูกสร้างและออกมาใช้งานจริง แผนที่จะใส่ GC ลงใน WASM มีคนพูดถึงกันมาหลายปีแล้ว และก็ไม่แน่ใจว่าจะเกิดขึ้นจริงหรือไม่
สงสัยว่ามันจะช่วยได้มากแค่ไหนสำหรับภาษาที่คอมไพล์ไปยัง WASM แล้วมีปัญหาเรื่อง ไบนารีขนาดใหญ่ เพราะต้องพก runtime มาด้วย เท่าที่จำได้ Blazor แค่ hello world ก็ต้องใช้ราว 1MB แล้ว เลยไม่แน่ใจว่า WasmGC จะช่วยตรงนี้ได้ไหม
แน่นอนว่าสิ่งที่น่ากังวลคือ ถ้าเป็นฟีเจอร์ที่มีแค่ .NET ต้องการ แรงจูงใจในการเพิ่มเข้ามาก็คงไม่มากนัก ถึงตอนนั้นฟีเจอร์คล้าย
includeที่สามารถ cache GC เวอร์ชันหนึ่งไว้ แล้วให้ WASM assembly อื่นโหลดมาใช้ต่อได้ อาจมีประโยชน์มากกว่า แม้มันจะสร้างความยุ่งยากก็ตาม[0] - https://github.com/WebAssembly/gc/issues/77
C และ Rust ไม่ได้รวม garbage collector แต่ก็ยังต้องพกตัวห่อของ malloc/free มาด้วยเพื่อจัดการหน่วยความจำ ส่วนเหตุผลที่ Java เล็กกว่าที่นี่คือไม่จำเป็นต้องพก โค้ดจัดการหน่วยความจำ มาเลย
https://developer.chrome.com/blog/wasmgc/
สำหรับ Blazor น่าจะช่วยเฉพาะเรื่อง GC เท่านั้น เท่าที่จำได้ Blazor ยังต้องส่ง dotnet runtime ทั้งชุดไปด้วย
การรองรับ wasm ใหม่ของ Kotlin น่าตื่นเต้นมาก มี Compose Multiplatform รุ่นทดลองที่สามารถ target เบราว์เซอร์ได้ และมันมีแผนจะใช้ WASM
โดยพื้นฐานแล้ว Compose Multiplatform คือ Google Jetpack Compose สำหรับ Android ที่เพิ่มการรองรับแพลตฟอร์มอื่นเข้ามา
ณ ไม่กี่วันก่อน การรองรับ iOS ยังเป็นอัลฟา และมีแผนจะเป็นเบต้าในปีหน้า ส่วน Android และเดสก์ท็อปตอนนี้เสถียรแล้ว เมื่อสิ่งเหล่านี้นิ่งดี ก็แทบจะเขียนแอป UI ที่ทำงานได้บนเกือบทุกแพลตฟอร์ม
ตัวคอมไพเลอร์ wasm มีกำหนดออกมาพร้อมกับรีลีสใหญ่ถัดไปของ Kotlin คือ Kotlin 2.0 ซึ่งจะรวมคอมไพเลอร์ใหม่ k2 มาด้วย ดูแล้วน่าจะได้เห็นช่วงต้นปีหน้า ตอนนี้ k2 เปิดให้ใช้แบบเบต้าและเปิดใช้ได้ใน Kotlin 1.9.x
ข้อดีของ ecosystem แบบ Kotlin Multiplatform คือมีไลบรารีจำนวนมากที่ทำงานได้อยู่แล้วบนหลายแพลตฟอร์ม ดังนั้นคอมไพเลอร์ wasm ก็น่าจะกลายเป็นส่วนหนึ่งของระบบนี้ได้อย่างรวดเร็วและได้รับประโยชน์จากไลบรารีดี ๆ เหล่านั้น โดยทั่วไปก็แค่เปลี่ยนการตั้งค่า build ให้ target ecosystem นี้ แล้วค่อยเติมพฤติกรรมเฉพาะแพลตฟอร์มที่ยังขาดอยู่
อีกประเด็นที่น่าสนใจในพื้นที่นี้คือการใช้และเชื่อมต่อไลบรารีที่เขียนด้วยภาษาต่างกัน เช่น ส่วนที่เฉพาะแพลตฟอร์มจำนวนมากก็น่าจะพึ่งพาไลบรารี C หรือ Rust ที่มีอยู่แล้ว และในหลายกรณีก็อาจเป็นไลบรารีเดียวกับที่ Kotlin Native ใช้อยู่
อยากรู้ว่าใช้ widget ชุดเดียวกันบนเดสก์ท็อป เว็บ iOS และ Android หรือไม่ เข้าใจว่า Android เป็น native แต่บนแพลตฟอร์มอื่นไม่แน่ใจว่ามันเลียนแบบสไตล์ของแต่ละแพลตฟอร์มหรือเปล่า คำถามหลักคือแอป Compose Multiplatform บนแพลตฟอร์มที่ไม่ใช่ Android ให้ ความรู้สึก แบบไหน
อย่างเช่น Dart บนเว็บ สำหรับผมรู้สึกหน่วงมาก และ Electron บนเดสก์ท็อปก็เป็นแบบนั้นเหมือนกัน ส่วน Dart บนเดสก์ท็อปโอเคกว่า แต่แอปส่วนใหญ่มีปุ่มกับระยะห่างที่ใหญ่ ทำให้รู้สึกเหมือนแอป Android ที่รันอยู่ใน emulator มากกว่าแอป native จริง ๆ
แล้วก็สงสัยว่า Kotlin น่าแนะนำเป็นภาษาสำหรับโปรเจ็กต์ใหม่หรือไม่
สงสัยว่ามีใครอธิบายได้ไหมว่าทำไมทั้งบทความบล็อกนี้และโพสต์ประกาศของ Chrome ถึงไม่พูดถึง Go เลย
Go ก็ใช้ garbage collection เหมือนกัน เลยให้ความรู้สึกว่ามันอาจไม่ได้ประโยชน์จากการเปลี่ยนแปลงนี้
สงสัยว่าการที่รันไทม์เปิดเผย ไลบรารีตัวจัดสรรหน่วยความจำ ในตัวที่ C/C++/Rust ใช้งานได้ จะสมเหตุสมผลหรือไม่
แทนที่โปรแกรมจะต้องพ่วงไลบรารีตัวจัดสรรของตัวเองเข้าไป ก็น่าจะเลือกใช้ไลบรารีนั้นได้
primitive ของ Wasm GC ถูกออกแบบมาเพื่อให้ได้ประโยชน์มากที่สุดจากการเพิ่มเข้ามาให้น้อยที่สุด เช่นเดียวกับ primitive อื่นอย่าง SIMD ที่ถูกเพิ่มเข้ามา เพราะมันเป็น “primitive ขั้นต่ำโดยประมาณ” ที่จำเป็นต่อการทำให้ความสามารถนั้นเกิดขึ้นได้ ที่นี่จึงต้องการ building block ที่เล็กที่สุดเท่าที่เป็นไปได้
แต่ API ตัวจัดสรรหน่วยความจำ อย่าง malloc/free ไม่ใช่ความสามารถขั้นต่ำ ตัวจัดสรรหน่วยความจำจริง ๆ แล้วคือชุดของนโยบายและการตัดสินใจด้านการออกแบบ แล้วอัลกอริทึมค่อยตามมาจากตรงนั้น building block พื้นฐานของพื้นที่นี้คือ “ส่วนของ linear memory ที่ตัวจัดสรรเป็นเจ้าของ” ซึ่งก็คือ linear memory ที่ WASM มีมาตั้งแต่วันแรกอยู่แล้ว
การที่รันไทม์แต่ละตัวจะมีสิ่งนี้ให้ก็พอจะสมเหตุสมผลได้ เช่น ส่ง linear memory บางส่วนให้กับ wasm import ในตัว แล้วให้ตัวจัดสรรที่รันไทม์เป็นคนจัดการ แต่คิดว่าแทบไม่มีโอกาสที่จะถูกทำให้เป็นมาตรฐาน นอกจากนี้ เครื่องมือส่วนใหญ่สำหรับภาษา Wasm ที่ไม่มี GC ก็ออกแบบมาให้พอร์ต codebase เดิมพร้อมตัวจัดสรรของมันมาด้วยอยู่แล้ว สุดท้ายจึงกลายเป็นว่าต้องมีโค้ดสำหรับดูแลรักษาเพิ่มขึ้นเพื่อรองรับ implementation แบบครั้งคราว ซึ่งอาจไม่คุ้มกับความพยายามที่ลงไป
ถ้าไม่กำหนดแน่ชัด ความแตกต่างของพฤติกรรมโปรแกรมก็อาจมีนัยสำคัญได้ เช่น ถ้าเบราว์เซอร์บางตัวใส่ตัวจัดสรรที่ “ฉลาด” กว่าและนำหน่วยความจำกลับมาใช้ซ้ำได้ดีกว่า โปรแกรมที่บนเบราว์เซอร์อื่นอาจหน่วยความจำหมดเพราะ linear memory แตกเป็นชิ้น ๆ ก็อาจรันสำเร็จบนเบราว์เซอร์นั้นได้ ในอดีตเบราว์เซอร์พยายามอย่างมากที่จะทำให้พฤติกรรมเป็นมาตรฐานเพื่อหลีกเลี่ยงความต่างแบบนี้
การทำให้พฤติกรรมของ implementation ของ malloc/free เป็นมาตรฐานก็ยุ่งยากด้วยหลายเหตุผล อย่างแรก มีความซับซ้อนมาก เช่น จะจัดการ free list อย่างไร จะใช้ขนาดชังก์แบบไหน ฯลฯ ซึ่งมีมากเกินไปสำหรับใส่ในสเปก อย่างที่สอง ถ้ามาตรฐานกำหนดพฤติกรรมแบบใดแบบหนึ่ง ก็จะปรับปรุงต่อไม่ได้ ทั้งที่แนวคิด malloc/free ที่ดีกว่าก็ยังมีออกมาอยู่เรื่อย ๆ
ด้วยเหตุผลเหล่านี้ จึงค่อนข้างสงสัยว่ามันจะมีโอกาสเข้าไปอยู่ในสเปก wasm
ในทางกลับกัน GC เลี่ยงปัญหาเหล่านี้ได้ เพราะค่า pointer ไม่สามารถสังเกตได้ จึงไม่มีอะไรให้ต้องกำหนดในสเปก
allocและฟังก์ชันที่เกี่ยวข้องเป็นฟังก์ชันของรันไทม์ให้โค้ดแบบดั้งเดิมเรียกใช้ แล้วก็เปิดให้ซ้อน GC แบบใดก็ได้ไว้ด้านบนค่อนข้างสงสัยกับแนวทางนี้อยู่พอสมควร มันกำลังเพิ่ม ความซับซ้อน ของ WebAssembly อย่างมาก
ตัวเก็บขยะเป็น abstraction ที่รั่วไหล บางตัวรองรับ internal pointer และบางตัวไม่รองรับ บางตัวรองรับงานขนานที่แชร์หน่วยความจำและบางตัวไม่รองรับ บางตัวต้องมีการบีบอัด ทำให้ C FFI ยากขึ้น และบางตัวไม่ต้องทำ บางตัวต้องผสานลึกกับกลไกที่ใช้กับ green process/thread และ stack ที่ขยายได้ แต่บางตัวก็ไม่ต้อง
ถ้าดูภาษาอย่าง Erlang, JavaScript, Python, Go จะเห็นว่าการเลือกในระดับภาษาสะท้อนอยู่ในตัวเก็บขยะในระดับหนึ่ง
แนวคิดเรื่อง เครื่องเสมือน แบบทั่วไป/อเนกประสงค์ที่รองรับหลายภาษาเคยถูกลองมาหลายครั้งแล้ว เช่น JVM, CLR, Parrot เป็นต้น และความสำเร็จก็มีจำกัด อยากรู้ว่าครั้งนี้ต่างออกไปอย่างไร
JVM/CLR สร้างเครื่องเสมือน สเปกคำสั่งภาษากลาง และรันไทม์ขึ้นมาก่อน แล้วค่อยพยายามกระจายให้กว้างที่สุด โดยหวังว่าจะเกิดการยอมรับฝั่งไคลเอนต์แบบสากล กล่าวคือคาดหวังว่า “VM สำหรับภาษากลาง” จะมีเสน่ห์พอจนแพร่ไปทั้งอุตสาหกรรม ความคาดหวังนี้ถูกต้องเพียงบางส่วน JVM/CLR แพร่หลายในเดสก์ท็อปและเซิร์ฟเวอร์ แต่ในเว็บเบราว์เซอร์ Java Applet และ Microsoft Silverlight ล้มเหลว และบนแพลตฟอร์มมือถือก็ไม่ได้รับการยอมรับอย่างกว้างขวาง
WASM ทำในลำดับตรงกันข้าม โดยเริ่มย้อนกลับจากสิ่งที่ถูกเผยแพร่และยอมรับทั่วทั้งอุตสาหกรรมอยู่แล้ว นั่นคือ JavaScript แล้วค่อยสร้าง “เครื่องเสมือน สเปกคำสั่งภาษากลาง และรันไทม์” ขึ้นมา
มองจากมุมนี้ JavaScript ซึ่งถูกเรียกว่า “ภาษาของเล่น” จึงเป็น ม้าโทรจัน ตลอด 20 ปีเพื่อให้ถูกกระจายไปยังไคลเอนต์ทุกแห่งก่อน ตอนนี้อุตสาหกรรมกำลังพูดทำนองว่า “มีใครสังเกตไหมว่าเรามี JavaScript ซึ่งเป็นรันไทม์สากลอยู่แล้วบนเซิร์ฟเวอร์+เดสก์ท็อป+เบราว์เซอร์+มือถือ? งั้นมาสร้างรันไทม์ภาษากลางให้มันเร็วขึ้นกันเถอะ”
ยังมีปัญหาทางเทคนิคอยู่บ้าง Sun JVM ไม่มี raw pointer จึงยากจะเป็นเป้าหมายที่ให้ประสิทธิภาพดีสำหรับภาษาที่อิง pointer อย่าง C/C++ ส่วน MS CLR ใช้บน macOS ไม่ได้ โดยมี CLR แบบย่อของ Silverlight เป็นข้อยกเว้น แต่ยิ่งกว่าข้อจำกัดทางเทคนิคเหล่านี้ คำอธิบายที่ทรงพลังกว่าคือลำดับเวลาที่ JavaScript ถูกเผยแพร่ราวกับม้าโทรจันที่ไม่เป็นพิษเป็นภัย
Wasm มีระดับต่ำกว่าฟอร์แมตไบต์โค้ดส่วนใหญ่ที่กล่าวถึงข้างต้น แม้จะรวม Wasm GC ที่เพิ่ม struct และ array แบบมีชนิดคงที่ ตลอดจนข้อเสนอ function-references ที่นำเข้าฟังก์ชันแบบมีชนิดแล้วก็ตาม Wasm GC ยังรองรับ tagged pointer
i31refอย่างชัดเจนด้วยด้วยเหตุนี้ Wasm GC จึงมีความทั่วไปมากกว่าความพยายามที่ยกตัวอย่างไปข้างต้น เพราะมันอยู่ในระดับที่ต่ำกว่า
การสร้าง VM “ทั่วไป” หรือ “อเนกประสงค์” ที่รองรับหลายภาษาอย่างเท่าเทียมและลื่นไหลไม่ใช่เป้าหมายที่ประกาศไว้อย่างชัดเจนของ WASM-GC โดยคาดว่าแต่ละ implementation อาจต้องมีแฮ็กของตัวเองและความหมายเชิงพฤติกรรมเฉพาะบนพื้นฐานการรองรับขั้นต่ำที่ WASM มีให้ และมองว่า FFI กับการทำงานร่วมกันข้ามภาษาเป็นคนละปัญหาโดยสิ้นเชิง จึงถือว่ายอมรับได้
การเก็บขยะของ JavaScript จะยังคงอยู่ต่อไป และดูเหมือนเป็นตัวอย่างที่ฝังรากเหนียวแน่นที่สุดในบรรดาที่กล่าวมา
ในหลายกรณี ภาษาอื่นและแอปพลิเคชัน/ไลบรารีจำเป็นต้องปรับตัวเข้าหามัน แม้ว่ามันจะด้อยกว่าก็ตาม
wasm ให้ฟีเจอร์ GC เพื่อให้ภาษารันไทม์แบบ managed memory สามารถกำหนดเป้าหมายสภาพแวดล้อม wasm ได้โดยไม่ต้องทนทุกข์จากข้อจำกัดของโมเดลหน่วยความจำที่มีข้อจำกัด และในลำดับรองลงมาคือเพื่อลดขนาดบันเดิล
เป็นไปได้ว่า wasm จะรองรับ พารามิเตอร์ GC ที่ปรับแต่งได้มากกว่า เพื่อให้เข้ากับคุณลักษณะของภาษา guest ได้ดีขึ้น อีกทั้งต่างจากรันไทม์ภาษาทั่วไปที่ใช้เป็นตัวเปรียบเทียบ ผู้พัฒนาภาษาไม่มีทางเลือกที่จะสร้างรันไทม์แบบปรับแต่งเองได้ตั้งแต่แรก
มีการกล่าวถึงข้อกังวลหลายประการเกี่ยวกับความเป็นไปได้ของ WASM GC ไว้ที่นี่ ฉบับแปลอังกฤษด้วย Google Translate:
https://habr-com.translate.goog/ru/articles/757182/?_x_tr_sl...
ต้นฉบับ:
https://habr.com/ru/articles/757182/
นี่เป็นบทความจากผู้สร้าง TeaVM ซึ่งทำงานเรื่องทำให้โค้ด Java และ JVM รันได้อย่างมีประสิทธิภาพในเบราว์เซอร์มานาน 10 ปี https://teavm.org/
การแปลง Java-to-JavaScript แบบเดิมของ TeaVM ก็มีประสิทธิภาพดีแม้จะใช้ JS GC ของเบราว์เซอร์อยู่แล้ว ก็น่าสนใจที่จะรอดูว่าเมื่อ WASM GC พัฒนาสุกงอมขึ้นแล้วจะทำงานได้เร็วกว่านั้นหรือไม่
ถ้าจะฝากบันทึกเกี่ยวกับปัญหาที่บทความพูดถึง ปัญหาที่ว่าต้องใช้ manual shadow stack นั้นถูกแก้ใน WasmGC แล้ว ตามที่ลิงก์บอก มันทำงานแบบเดียวกับที่ทำบน JS
การไม่มี try-catch ก็ถูกแก้แล้วด้วยข้อเสนอ Wasm exception handling ที่ปล่อยใช้ในเบราว์เซอร์แล้ว: https://github.com/WebAssembly/exception-handling/blob/main/...
การตรวจสอบ null ก็ถูกแก้ด้วย WasmGC เป็นส่วนใหญ่เช่นกัน สเปกระบุ local type ที่เป็น non-nullable ได้ และ VM ก็สามารถ optimize โดยใช้ signal ตามเทคนิคที่บทความกล่าวถึงได้ เช่น Wizard ก็ทำแบบนั้น
การ initialize class เป็นปัญหาที่ยากจริงอย่างที่บทความบอก J2Wasm และ Binaryen กำลังพยายาม optimize เรื่องนี้ด้วย static analysis ระดับ toolchain และ PR ที่ผมเขียนล่าสุดก็ช่วยให้คืบหน้าไปในทิศทางนี้: https://github.com/WebAssembly/binaryen/pull/6061
overhead ของ vtable ที่บทความกล่าวถึงอาจเป็นปัญหาได้ แต่ตอนนี้ยังไม่มีตัวเลขวัดที่ดีนัก มีไอเดียสำหรับทางแก้ post-MVP ของ method dispatch อยู่บ้าง แต่ยังไม่มีอะไรที่เป็นรูปธรรม
เรื่อง null check กับ trap นั้น เคยมีการคุยกันเรื่อง variant ของคำสั่ง GC ที่โยน exception แทน trap แต่จากการวัดผลมันยังไม่ใช่ปัญหาใหญ่ในตอนนี้ เลยมีลำดับความสำคัญต่ำ
ผู้เขียนบทความพูดถูกที่บอกว่า stack walking, signal และ memory control เป็นพื้นที่สำคัญ
โดยรวมแล้ว ด้วย WasmGC และ exception handling ทำให้ Java ที่ J2Wasm ส่งออกในปัจจุบันอยู่ในจุดที่ค่อนข้างดี มักจะเร็วกว่า J2CL ที่คอมไพล์ Java ไปเป็น JavaScript แม้แบบนั้นก็ยังมีพื้นที่ให้ปรับปรุงอีกชัดเจน