3 điểm bởi GN⁺ 2023-07-22 | 1 bình luận | Chia sẻ qua WhatsApp
  • Dự án phụ rjvm để học Rust là một JVM đồ chơi phục vụ học tập, nhưng đã được triển khai đến mức có thể đọc các tệp .classjar thật, cũng như thực thi bytecode Java
  • Các tính năng chưa hỗ trợ gồm thread, reflection, annotation, I/O, trình biên dịch JIT và string interning, nhưng đã bao gồm luồng điều khiển, tạo đối tượng, gọi phương thức, ngoại lệ và garbage collection
  • Ví dụ dùng rt.jar thật của OpenJDK 7, nên các lớp như java.lang.StackTraceElement được tải từ JDK thật
  • Mã được chia thành ba Rust crate: reader, vm, vm_cli, bao quát từ phân tích cú pháp .class đến call stack, native method, mô hình hóa giá trị và đối tượng
  • Cột mốc cuối cùng là stop-the-world semispace copying collector; sau khi đạt mục tiêu, dự án đã dừng lại và cũng không có kế hoạch sửa các lỗi đã biết

JVM Rust phục vụ học tập rjvm

  • rjvm là một Java Virtual Machine đồ chơi được tạo ra để học Rust
  • Mã nguồn được công khai trên GitHub
  • Đây là một bản triển khai nhằm mục đích học tập hơn là một JVM nghiêm túc, nên không hỗ trợ các tính năng sau
    • Thread
    • Reflection
    • Annotation
    • I/O
    • Trình biên dịch JIT
    • String interning
  • Generic ban đầu nằm trong danh sách chưa hỗ trợ, nhưng thực tế lại hoạt động

Đã triển khai đến đâu

  • rjvm không chỉ là một parser đơn giản mà còn tự triển khai nhiều hoạt động của JVM
    • Luồng điều khiển như if, for
    • Tạo kiểu nguyên thủy và đối tượng
    • Gọi phương thức ảo và phương thức tĩnh
    • Xử lý ngoại lệ
    • Garbage collection
    • Phân giải lớp từ tệp jar
  • Mã kiểm thử có các ví dụ dùng Throwable, Exception, StackTraceElement
  • Vì không có I/O thật, thay vì System.out.println nó dùng một native method tên là tempPrint
  • Ví dụ dùng rt.jar thật của OpenJDK 7, và java.lang.StackTraceElement cũng được lấy từ JDK thật

Ba Rust crate

  • Dự án là một dự án Rust tiêu chuẩn, gồm ba crate
    • reader: chứa các kiểu dùng để đọc tệp .class và mô hình hóa nội dung của chúng
    • vm: cung cấp máy ảo có thể thực thi mã dưới dạng thư viện
    • vm_cli: chứa một launcher dòng lệnh đơn giản, tương tự tệp thực thi java
  • Đang cân nhắc tách crate reader thành kho riêng và phát hành lên crates.io

Phân tích cú pháp tệp .class

  • Mã Java được biên dịch bằng javac thành tệp .class, và thường được phân phối dưới dạng tệp .jar, vốn là định dạng zip
  • Để chạy mã Java, trước tiên cần tải tệp .class chứa bytecode do trình biên dịch tạo ra
  • Tệp class chứa cả những thông tin cần thiết cho thực thi và phân giải kiểu
    • Metadata như tên lớp và tên tệp nguồn
    • Tên superclass
    • Các interface đã implement
    • Field, kiểu field và annotation
    • Descriptor của phương thức, mệnh đề throws, annotation, thông tin generic
    • Bytecode, bảng exception handler, bảng số dòng
  • Crate reader phân tích cú pháp tệp class và trả về một Rust struct mô hình hóa lớp cùng nội dung của nó

Thực thi phương thức và call stack

  • API chính của crate vmVm::invoke, dùng để thực thi phương thức
  • Mỗi phương thức đang chạy có một CallFrame trong CallStack
  • Khi chạy main, call stack ban đầu rỗng, và một frame mới được tạo để thực thi
  • Mỗi lần gọi hàm, một frame mới được thêm vào call stack; khi phương thức chạy xong, frame đó được gỡ bỏ
  • Phần lớn phương thức được triển khai bằng bytecode Java, nhưng rjvm cũng hỗ trợ native method
    • Native method là phương thức do chính JVM trực tiếp triển khai, không phải bytecode Java
    • Ví dụ gồm System::currentTimeMillis, System::arraycopy, Throwable::fillInStackTrace
    • Trong rjvm, chúng được triển khai bằng hàm Rust
  • JVM là máy ảo dựa trên stack, nên các lệnh bytecode chủ yếu hoạt động trên stack giá trị
  • Mỗi call frame gắn với một stack giá trị và một tập biến cục bộ được định danh bằng chỉ số

Mô hình hóa giá trị và đối tượng

  • Value mô hình hóa các giá trị có thể được lưu trong biến cục bộ, phần tử stack và field của đối tượng
  • Value được triển khai bằng enum của Rust và gồm các trạng thái sau
    • Uninitialized
    • Int(i32)
    • Long(i64)
    • Float(f32)
    • Double(f64)
    • Object(AbstractObject<'a>)
    • Null
  • Sum type như enum của Rust rất phù hợp để biểu diễn việc một giá trị có thể thuộc một trong nhiều kiểu
  • Việc lưu trữ đối tượng ban đầu khởi đầu bằng một struct Object đơn giản dựa trên Vec<Value>, chứa tham chiếu lớp và các giá trị field
  • Sau khi triển khai garbage collector, nó được đổi sang một triển khai cấp thấp hơn, dùng nhiều con trỏ và phép cast
  • Hiện tại AbstractObject mô hình hóa đối tượng hoặc mảng thật, là con trỏ tới một mảng byte chứa vài header word và các giá trị field

Thực thi lệnh bytecode

  • Thực thi phương thức là quá trình xử lý từng lệnh bytecode một
  • JVM có hơn 200 lệnh, được mã hóa bằng 1 byte trong bytecode
  • Nhiều lệnh có đối số đi kèm, và một số lệnh có độ dài biến đổi
  • rjvm mô hình hóa các lệnh bytecode Java bằng kiểu Instruction
  • Khi thực thi phương thức, nó duy trì stack giá trị và mảng biến cục bộ, đồng thời khởi tạo program counter — địa chỉ lệnh sẽ chạy tiếp theo — bằng 0
  • Thông thường sau khi chạy một lệnh, program counter chuyển sang lệnh kế tiếp, nhưng lệnh nhảy có thể chuyển nó đến vị trí khác
  • Lệnh nhảy được dùng để triển khai các cấu trúc điều khiển luồng như if, for, while
  • Các lệnh gọi phương thức khác tồn tại như một nhóm riêng
    • Cách xác định phương thức nào sẽ được gọi gồm tra cứu ảo, tra cứu tĩnh, v.v.
    • Sau khi phân giải phương thức đích, một frame mới được thêm vào call stack và bắt đầu thực thi
    • Nếu giá trị trả về không phải void, giá trị trả về được push lên stack rồi việc thực thi tiếp tục

Xử lý ngoại lệ

  • Ngoại lệ phức tạp để triển khai vì chúng phá vỡ luồng điều khiển thông thường, khiến phương thức trả về sớm và có thể lan truyền dọc theo call stack
  • Mỗi khối catch tương ứng với một mục trong bảng ngoại lệ của phương thức
  • Mục trong bảng ngoại lệ chứa thông tin cần thiết để tìm handler
    • Phạm vi program counter áp dụng
    • Địa chỉ lệnh đầu tiên của khối catch
    • Tên lớp ngoại lệ mà khối đó bắt
  • CallFrame::execute_instruction dùng Result của Rust để biểu diễn kết quả thực thi lệnh
  • Kết quả thực thi lệnh được chia thành bốn trạng thái
    • Thành công và tiếp tục thực thi phương thức hiện tại
    • Thành công, và vì là lệnh return nên phương thức hiện tại kết thúc cùng giá trị trả về
    • Thất bại do lỗi VM nội bộ
    • Thất bại do một ngoại lệ Java được ném ra
  • Vòng lặp thực thi phương thức phân tích cú pháp lệnh, di chuyển program counter đến địa chỉ kế tiếp, rồi thực thi lệnh
  • Khi phát sinh ngoại lệ, nó tìm exception handler phù hợp với vị trí lệnh hiện tại
    • Nếu không có handler, ngoại lệ được truyền cho caller
    • Nếu có handler, đối tượng ngoại lệ được push lại lên stack và việc thực thi tiếp tục tại vị trí handler của catch
  • Result và pattern matching của Rust rất phù hợp để biểu diễn hành vi này trong cấu trúc mã

Garbage collection

  • Cột mốc lớn cuối cùng của rjvm là triển khai garbage collector
  • Thuật toán được chọn là stop-the-world semispace copying collector
  • Vì không có thread, cách stop-the-world tự nhiên được thỏa mãn
  • Triển khai là một biến thể đơn giản hơn của Cheney's algorithm, mã nằm trong gc.rs
  • Cách này chia bộ nhớ khả dụng thành hai semispace
    • Một vùng là vùng hoạt động, dùng để cấp phát đối tượng
    • Vùng còn lại để không sử dụng
    • Khi vùng hoạt động đầy, các đối tượng còn sống được sao chép sang semispace kia
    • Tất cả tham chiếu đối tượng được cập nhật để trỏ tới bản sao mới
    • Vai trò của hai semispace được hoán đổi
  • Quy trình này được ví như một cách tương tự blue-green deployment
  • Ưu và nhược điểm của thuật toán rất rõ ràng
    • Không thể dùng một nửa bộ nhớ tối đa, nên lãng phí bộ nhớ lớn
    • Cấp phát rất nhanh vì chỉ tăng con trỏ
    • Vì sao chép và nén đối tượng, không cần xử lý phân mảnh bộ nhớ
    • Nén đối tượng có thể cải thiện hiệu năng nhờ tận dụng cache line tốt hơn
  • Các Java VM thực tế thường dùng garbage collector theo thế hệ tinh vi hơn, như G1 hoặc parallel GC

Điểm kết thúc của dự án

  • Khi tạo rjvm, tác giả đã học được rất nhiều về Rust và triển khai máy ảo, đặc biệt hài lòng với việc triển khai được một garbage collector thật sự hoạt động
  • Garbage collector chưa đạt mức hoàn thiện cao, nhưng thực sự chạy được
  • Vì mục tiêu ban đầu đã đạt được, dự án dừng lại tại đây
  • Có các lỗi đã biết, nhưng không có kế hoạch sửa chúng
  • Rust là một ngôn ngữ đem lại trải nghiệm thú vị khi dùng để triển khai JVM, và trong các bài viết sau tác giả dự định trình bày chi tiết hơn về triển khai rjvm cũng như cách JVM hoạt động

1 bình luận

 
GN⁺ 2023-07-22
Các ý kiến trên Hacker News
  • Phần khó trong việc triển khai garbage collection là đảm bảo mọi tham chiếu đều được bắt làm root đúng cách, đặc biệt là với collector kiểu di chuyển
    Phương thức do_garbage_collection được đánh dấu là unsafe[1], nhưng không có mô tả phía gọi phải bảo đảm điều gì để có thể gọi nó một cách an toàn
    Tôi thắc mắc làm sao bảo đảm rằng mọi tham chiếu tới heap đều được bắt làm root, và đây không phải là vấn đề nhỏ[2][3][4]
    Ngoài ra, khi clone repository rồi chạy cargo test, tất cả test đều thất bại với lỗi should be able to add entries to the classpath: InvalidEntry(".../vm/rt.jar"): vm/tests/integration/real_code_tests.rs:15:10
    [1] https://github.com/andreabergia/rjvm/blob/be9c54066c64a82879...
    [2] https://manishearth.github.io/blog/2021/04/05/a-tour-of-safe...
    [3] https://without.boats/blog/shifgrethor-iii/
    [4] https://coredumped.dev/2022/04/11/implementing-a-safe-garbag...

    • VM này duy trì ngăn xếp lời gọi ảo riêng thay vì dùng ngăn xếp lời gọi native, nên khá trực quan
      Vì vậy có thể duyệt ngăn xếp đó để tìm tham số và biến cục bộ rồi dùng chúng làm root
      Cách này có chi phí hiệu năng, nhưng việc tracing cho garbage collection đơn giản hơn nhiều, và cũng dễ triển khai các primitive về đồng thời và luồng điều khiển như coroutine hay continuation hơn
    • Garbage collector về cơ bản là kiểu ghi sổ thật tỉ mỉ nên khá dễ, nhưng ngay khi bắt đầu làm garbage collection đồng thời thì nó trở nên khó như địa ngục
  • Dự án tốt, xin chúc mừng
    Tuy nhiên phần “không hỗ trợ: generic” khiến tôi thấy hơi lạ
    Tôi tò mò không rõ JVM cần hỗ trợ generic theo nghĩa nào
    Ở mức bytecode, do type erasure, chẳng phải có thể đơn giản xem tất cả là Object, tức kiểu tham chiếu, hay sao? Hay là đang nói tới parser định nghĩa class? Ngay cả vậy thì ngoài cú pháp cơ bản, dường như cũng không có logic kiểm tra xem class file có hợp lệ hay không

    • Về generic, trên reddit cũng có người nói tương tự, và điều đó đúng
      Việc thực sự cần làm chỉ là đọc thuộc tính Signature chứa thông tin generic của class, method và field (https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.ht...)
      Thực tế tôi vừa thử và đoạn code dưới đây cũng chạy :-)
      public class Generic { public static void main(String[] args) { List strings = new ArrayList(10); strings.add("hey"); strings.add("hackernews"); for (String s : strings) { tempPrint(s); } } private static native void tempPrint(String value); }
    • Có lẽ họ đang nói tới phép toán checkcast: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.ht...
      Ví dụ, nó sẽ được sinh ra nếu bạn viết code như final Main value = list.get(0);
      http://henrikeichenhardt.blogspot.com/2013/05/how-are-java-g...
    • Nhìn chung là đúng. Generic hiếm khi có ảnh hưởng tới reflection, nhưng hiện reflection cũng chưa được hỗ trợ, và nhìn chung khi biên dịch nó được thay bằng class hoặc interface gần nhất
      Ngược lại, việc không có string interning thì rất lạ. Triển khai cũng khá đơn giản, và nếu thiếu thứ này thì khó xem là JVM được
      Việc các chuỗi trở nên bằng nhau theo tham chiếu là quan trọng và là một phần của JLS
      Việc không có thread khiến toàn bộ nỗ lực này giống một dự án đồ chơi
  • Thật sự rất tuyệt. Khi tôi tham gia làm Java vào năm 1992, nó có tên là Oak, và nhóm của tôi đang hướng tới việc viết toàn bộ hệ điều hành bằng Java
    Ý tưởng là có thể giảm bề mặt tấn công của hệ điều hành nhúng nếu chỉ để lại phần tối thiểu cần thiết dưới dạng “mã máy”, tức các native method
    Ban đầu Java được nhắm tới để chạy ở những nơi như TV hay thiết bị gia dụng, và khi đó native method được làm bằng C chứ không phải Rust
    Một JVM viết bằng Rust bổ sung an toàn bộ nhớ khá mạnh cho toàn bộ quá trình này

    • Cá nhân tôi cho rằng Android đã đạt được điều đó ở một mức độ nào đó
      Rất nhiều logic hệ điều hành được viết bằng Java hoặc Kotlin, nhưng đồng thời cũng trộn lẫn nhiều system service bằng native code, và chúng được kết nối với nhau bằng Binder IPC nổi tiếng, hoặc tai tiếng
    • Ý tưởng này chắc chắn đã từng được thử vài lần [0, 1]
      [0] - https://en.wikipedia.org/wiki/Singularity_(operating_system)
      [1] - https://en.wikipedia.org/wiki/Midori_(operating_system)
    • Có vẻ đã từng có JavaOS, dù một thời gian nó không dành cho người dùng: https://en.wikipedia.org/wiki/JavaOS
    • Ngoài các bình luận cùng nhánh, còn có những thứ như SavageJE, microEJ, runtime Java bare metal của PTC và Aonix, hay SquawkVM của SunSPOT
  • Cũng đáng xem https://jacobin.org/, một triển khai JVM 17 viết bằng Go

    • Cũng có https://github.com/lihaoyi/Metascala, một JVM được triển khai bằng Scala và chạy trên JVM
    • Đây là một cái tên khá thú vị cho một dự án lập trình
      Jacobins là một câu lạc bộ chính trị cách mạng trong thời Cách mạng Pháp thập niên 1790, và cũng là tên của tạp chí tại https://jacobin.com
  • Tôi tò mò liệu có bị vấp giới hạn vì tham số lifetime trong chữ ký này không
    fn execute_instruction(&mut self, vm: &mut Vm<'a>, call_stack: &mut CallStack<'a>, instruction: Instruction) -> Result, MethodCallFailed<'a>>
    Nếu thêm lifetime vào biến thể Err của Result và lifetime đó là bất biến, thì như ở đây do vmcall_stack, thường sẽ không thể dùng toán tử ? hay trả về sớm[1]
    Khi đó xử lý lỗi sẽ dài dòng hơn và khó đọc hơn, nên tôi tò mò thực tế có đúng là trải nghiệm như vậy không
    [1] https://users.rust-lang.org/t/nll-and-early-return-not-allow...

  • Đây là một dự án học tập tuyệt vời, và thật tốt khi tác giả đang làm nó một cách vui vẻ
    Tự triển khai VM từ con số không thật sự rất thú vị, và trước đây tôi đã học được rất nhiều khi làm những việc như vậy
    Nếu muốn thử gắn garbage collection vào, bạn cũng có thể xem MMTk (https://www.mmtk.io/)
    Nó có các thuật toán thu gom chất lượng cao được thiết kế để cắm vào nhiều VM, và được viết bằng Rust

    • Nói thêm là MMTK chỉ dành cho x86
      Tôi từng định dùng cho một dự án đồ chơi nhưng vì dùng Mac nên đã bỏ cuộc
  • Làm rất tốt
    Tạo VM lúc nào cũng thú vị, và kết hợp với hệ thống kiểu của Rust hẳn là một trải nghiệm học tập hấp dẫn
    Nếu đang tìm việc, có thể liên hệ với tôi qua Twitter, Mastodon hoặc email công ty. Nhìn user ID của tôi ở đây là sẽ tìm được

  • Khi thấy những dự án tuyệt vời như thế này, tôi có cảm giác choáng ngợp
    Sẽ rất hay nếu tác giả gốc giải thích nên bắt đầu với Rust như thế nào và nắm vững nền tảng đến mức nào thì mới có thể thử làm thứ như thế này

    • Tôi cũng cảm thấy vậy
      Không muốn đi lạc đề quá nhiều, nhưng cá nhân tôi gần đây đang vật lộn khá nhiều với cảm xúc này
      Tôi đã làm lập trình viên phần mềm chuyên nghiệp gần 10 năm, và nhìn vào vị trí hiện tại cũng như khả năng thực sự đưa sản phẩm ra thị trường, tôi biết mình có năng lực và cũng biết mình không phải là một lập trình viên giả mạo
      Thế nhưng gần đây khi đọc blog của các lập trình viên, tôi lại bị choáng ngợp như thể mình không biết đủ nhiều và không phải là lập trình viên “thực thụ”
      Tôi nghĩ cảm xúc này nảy sinh vì tôi tự dựng lên trong đầu hình mẫu lập trình viên lý tưởng rồi so sánh bản thân với tiêu chuẩn tưởng tượng đó
      Tôi vừa ngưỡng mộ những người có kiến thức sâu rộng, diễn đạt rõ ràng và súc tích, vừa tự hỏi tại sao mình không được như họ
      Sau khi tan làm rồi chăm sóc gia đình, tôi hầu như không còn năng lượng để làm thêm gì nữa, và tôi cũng biết lập trình không phải là tất cả, nhưng tôi vẫn muốn học hỏi và phát triển hơn
      Tôi biết điều đó không lành mạnh cũng không hợp lý, nhưng gần đây đó là cảm xúc khó gạt bỏ
    • Thành thật mà nói, mỗi lần mở HN, khoảng một nửa thời gian tôi đều cảm thấy hội chứng kẻ mạo danh
      Trước đây tôi từng có chút kinh nghiệm với VM, và vài năm trước cũng từng viết một loạt bài ngắn trên blog
      Ở công ty trước, để giải quyết một vấn đề rất đặc thù của khách hàng, tôi cũng từng động chạm một chút đến bytecode JVM
      Vài năm trước tôi cũng đã đọc cuốn https://craftinginterpreters.com/ xuất sắc, và lấy ý tưởng từ đó
      Nhưng dự án này rõ ràng là lớn và phức tạp
      Nó tốn rất nhiều thời gian, và như nhiều dự án phụ của tôi, cũng đã bị bỏ xó vài lần, nhưng tôi rất vui vì đã hoàn thành :-)
    • Tôi không phải chuyên gia Rust và cũng không phải tác giả gốc, nhưng có thể lấy một công nghệ khác là socket làm ví dụ
      Gần đây tôi đào sâu vào socket, nhưng chỉ 2 tuần trước tôi vẫn chỉ có hiểu biết ở mức cao, thu được từ việc đọc lướt các trang manual, tài liệu, bài blog, v.v.
      Vì muốn hiểu các nền tảng mạng, tôi quyết định đọc càng nhiều càng tốt, và một tuần sau đã học đủ để viết mã socket bằng Python và C
      Vì tôi khá rành Python, nên sau khi đào sâu rồi nhìn vào thư viện sockets, tôi hiểu nó tốt hơn
      Nếu muốn giỏi hơn công nghệ A trong ngôn ngữ X, tôi khuyên bạn nên đọc hoặc xem càng nhiều càng tốt về công nghệ A, rồi thử xây thứ gì đó bằng ngôn ngữ Y
      Sau đó khi quay lại ngôn ngữ X, bạn đã học được khá nhiều khái niệm xung quanh công nghệ A rồi
    • Chỉ cần chia nhỏ ra là được
      Một VM cho ngôn ngữ đơn giản sẽ có biểu diễn đối tượng trong bộ nhớ, trình thông dịch bytecode, một bộ thu gom rác đơn giản và bộ nạp
      Có thể xem trình thông dịch bytecode như một stack, cách biểu diễn hàm trên stack đó, và một vòng lặp diễn giải từng bytecode rồi di chuyển program counter
    • Quan trọng là bạn code bao nhiêu trong thời gian rảnh. Trung bình mỗi tuần bao nhiêu giờ
      Nếu là 0 giờ thì tất nhiên không có gì đáng trách, và cũng có nhiều việc khác cần tập trung, nhưng không có gì ngạc nhiên khi một người làm dự án phụ trung bình 10–20 giờ mỗi tuần trong nhiều năm lại tạo ra kết quả ấn tượng
  • Tranh thủ quảng bá một dự án tương tự một cách trơ trẽn: https://github.com/tenaf0/rust-jvm3

  • Tôi đang làm một hệ điều hành miễn phí cho các máy clone 386(486) AT. Chỉ là sở thích thôi, không lớn và chuyên nghiệp như gnu :-)

    • Có một hướng dẫn no-std viết kernel demo bằng Rust: https://os.phil-opp.com
      osdev.org, sandpile.org, RBIL, freevga cũng đáng tham khảo
      Vấn đề đau đầu nhất là hỗ trợ phần cứng
      Cũng có nhiều sách giấy vintage hay chứa các công thức như port I/O đáng tin cậy hoặc các mẹo phần cứng không được tài liệu hóa
      Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4
      Microsoft MS-DOS Programmer's Reference, bao gồm cả các lời gọi BIOS real-mode
      PC Interrupts
      Undocumented PC
      PC Intern
      Programmer's Guide To The EGA, VGA, And Super VGA Cards
      Graphics Programming Black Book Special Edition
      Ngoài ra, cũng đáng thử nghiệm những tiến bộ trong phát triển hệ điều hành sau thời đại kernel nguyên khối, microkernel và hybrid
      Các cấu trúc dựa trên capability như seL4 có nhiều lợi thế bản chất về hiệu năng và bảo mật, bao gồm capability và IPC xuất sắc
      Lớp tương thích POSIX cũng quan trọng. Ngay cả hệ điều hành nhúng không có khái niệm thread hay process cũng có thể triển khai POSIX
      Hypervisor sẽ dễ thêm hơn nhiều nếu có Intel VT-[xd], còn nếu không thì có thể lùi về emulation. Emulation kiểu dịch chuyển đổi có hiệu năng rất tốt
      Cần thành thạo việc tổng quát hóa và làm nhanh các interrupt handler, tránh race condition, và dùng các mẫu lock-free
      Cũng cần viết lại hoặc trap các lệnh không được hỗ trợ, bao gồm x87 và MMX
      Lý do microkernel thuần túy thất bại là độ phức tạp trong việc sắp xếp và quản lý nhiều tài nguyên theo kiểu giao dịch đã tăng lên
      Kiến trúc microkernel về lý thuyết có lợi thế lớn về bảo mật và vận hành, nhưng ở dạng thuần túy thì chưa được chấp nhận rộng rãi