1 poin oleh GN⁺ 2025-11-19 | 1 komentar | Bagikan ke WhatsApp
  • YJIT dan ZJIT adalah arsitektur compiler JIT yang mengubah kode Ruby menjadi bahasa mesin untuk meningkatkan kecepatan eksekusi di Ruby 3.x
  • YJIT menghitung jumlah pemanggilan setiap fungsi atau blok dan ketika mencapai ambang tertentu, kode tersebut diubah menjadi bahasa mesin
  • Kode yang telah dikonversi disimpan dalam blok YJIT, dan setiap blok mengubah beberapa instruksi YARV menjadi instruksi bahasa mesin ARM64 yang sesuai
  • Menggunakan Branch Stub untuk mengamati tipe data aktual saat runtime dan secara selektif menghasilkan instruksi bahasa mesin yang sesuai
  • Struktur ini adalah mekanisme inti untuk sekaligus mencapai peningkatan performa eksekusi Ruby dan efisiensi penanganan tipe dinamis

Chapter 4: Mengompilasi Ruby ke Bahasa Mesin

Interpreting vs. Compiling Ruby Code

  • Tidak ada rincian lebih lanjut di teks asli

Counting Method and Block Calls

  • YJIT melacak jumlah pemanggilan fungsi dan blok dalam program untuk mengidentifikasi kode hotspot
    • Menyimpan nilai jit_entry dan jit_entry_calls di samping setiap urutan instruksi YARV untuk fungsi atau blok
    • jit_entry pada awalnya bernilai null, lalu nanti menyimpan pointer ke kode mesin yang dihasilkan YJIT
    • jit_entry_calls bertambah 1 setiap kali dipanggil
  • Ketika jumlah pemanggilan mencapai ambang tertentu, YJIT mengompilasi kode tersebut ke bahasa mesin
    • Ambang default Ruby 3.5 adalah 30 kali untuk program kecil dan 120 kali untuk aplikasi berskala besar
    • Dapat diubah saat eksekusi dengan opsi --yjit-call-threshold
  • Dengan cara ini, YJIT hanya mengubah kode yang sering dijalankan menjadi bahasa mesin untuk menciptakan jalur eksekusi yang efisien
Iklan

YJIT Blocks

  • YJIT menyimpan instruksi bahasa mesin yang dihasilkan dalam blok YJIT
    • Blok YJIT berbeda dari blok Ruby, dan merepresentasikan sebagian rentang instruksi YARV
    • Setiap fungsi atau blok Ruby terdiri dari beberapa blok YJIT
  • Dalam program contoh, YJIT mulai mengompilasi saat blok dijalankan untuk ke-30 kalinya
    • Mengubah instruksi YARV pertama getlocal_WC_1 ke bahasa mesin dan membuat blok YJIT baru
    • Setelah itu mengompilasi instruksi getlocal_WC_0 tambahan dan memasukkannya ke blok yang sama
  • Menurut Figure 4-8, YJIT menghasilkan instruksi ARM64 untuk memuat nilai ke register x1 dan x9 pada prosesor M1
    • getlocal_WC_1 menyimpan variabel lokal dari stack frame sebelumnya, sedangkan getlocal_WC_0 menyimpan variabel dari stack saat ini ke stack
    • Instruksi bahasa mesin yang dihasilkan menjalankan perilaku yang sama

YJIT Branch Stubs

  • Saat YJIT mengompilasi instruksi opt_plus, muncul masalah karena tipe operand tidak diketahui
    • Instruksi bahasa mesin yang dibutuhkan berbeda tergantung pada tipe seperti integer, string, atau floating point
    • Contoh: penjumlahan integer menggunakan instruksi adds, sedangkan penjumlahan floating point memerlukan instruksi lain
    Iklan
  • Untuk menyelesaikannya, YJIT menggunakan pendekatan observasi saat runtime alih-alih analisis awal
    • Saat program berjalan, ia memeriksa tipe nilai yang benar-benar diteruskan lalu menghasilkan bahasa mesin yang sesuai
  • Untuk perilaku ini digunakan Branch Stub
    • Ketika cabang (branch) baru belum memiliki blok yang terhubung, ia sementara dihubungkan ke stub
    • Setelah tipe aktual diketahui, stub tersebut diganti dengan blok yang sesuai

ZJIT (hanya disebutkan)

  • Daftar isi mencakup bagian terkait ZJIT, tetapi tidak ada penjelasan rinci di isi utama

Ringkasan

  • YJIT adalah compiler JIT untuk meningkatkan efisiensi eksekusi bahasa bertipe dinamis di Ruby 3.5
  • Pemicu kompilasi berbasis jumlah pemanggilan, struktur blok YJIT, dan pemeriksaan tipe saat runtime melalui Branch Stub adalah inti utamanya
  • Mengubah kode menjadi instruksi bahasa mesin nyata pada arsitektur ARM64 untuk meningkatkan kecepatan eksekusi kode Ruby
  • ZJIT disebut sebagai JIT generasi berikutnya, tetapi tidak ada rincian lebih lanjut di isi utama

1 komentar

 
GN⁺ 2025-11-19
Komentar Hacker News
  • Dulu ada masa ketika MacRuby dikompilasi menjadi kode native di macOS dengan LLVM dan terintegrasi dengan framework Objective‑C
    Itu ide yang cukup keren, tetapi pada akhirnya Apple tampaknya beralih arah ke Swift
    Kalau versi barunya terbit, saya pasti akan membeli dan membaca buku Ruby Under a Microscope. Saya masih menyukai Ruby, tetapi tidak banyak kesempatan untuk benar-benar memakainya

    • Setelah pembuat MacRuby meninggalkan Apple, ia membuat RubyMotion
      Sekarang proyek itu dilanjutkan orang lain, tetapi saat ini kesannya fokusnya lebih besar ke DragonRuby (implementasi Ruby yang berfokus pada game)
    • Setelah penulis MacRuby pergi, proyek itu berlanjut sebagai RubyMotion
      Sebagai referensi, ada juga artikel wiki
    • Sampai sekarang pun kita masih bisa membuat aplikasi untuk macOS, iOS, dan iPadOS dengan Objective‑C
      Hanya saja, API lama mungkin sudah tidak lagi didukung
    • Dari sudut pandang orang yang pernah bekerja dengan banyak bahasa, perpindahan Apple ke Swift terasa mirip seperti saat Microsoft beralih dari VB6 ke VB.Net
      VB6 benar-benar sangat cepat untuk pengembangan, dan bisa dipakai sampai Direct3D maupun ASP Classic
      Keanggunan dan kemudahan pengembangan Ruby mengingatkan saya pada masa itu
      Jika Ruby punya alat GUI setara VB6, mungkin popularitasnya akan cukup berbeda
  • Senang sekali melihat Pat terus melanjutkan proyek ini
    Buku pertamanya, Ruby Under a Microscope, dan tulisan blognya memberi saya inspirasi besar
    Saya bahkan pernah bertemu langsung dengannya di konferensi Euruko, dan dia benar-benar orang yang luar biasa

    • Terima kasih untuk komentar yang hangat ini
  • Saat pertama kali membaca Ruby Under a Microscope, saya benar-benar menikmatinya
    Berkat buku itu, saya juga pernah memakainya saat memecahkan soal CTF
    Belakangan ini saya tidak lagi mengikuti implementasi internal Ruby, tetapi kalau versi baru keluar saya pasti akan membelinya

    • Saya banyak memakai Ruby dari 2002 sampai 2010, tetapi setelah itu hampir tidak menyentuhnya lagi
      Melihat tulisan ini membuat saya ingin membaca versi baru bukunya lagi
  • Ngomong-ngomong soal kompilasi Ruby, saya penasaran apakah ada yang pernah mencoba Sorbet compiler buatan para developer Stripe
    Tulisan pembukaan source Sorbet Compiler

    • Sekarang repositorinya sudah hilang, dan tampaknya tidak lagi dikembangkan, jadi cukup disayangkan
      Kompilasi AOT memang sangat sulit di Ruby
      Pendekatan Sorbet menarik karena bisa membuat jalur cepat berdasarkan pemeriksaan tipe Ruby
      Saya juga sedang membuat compiler Ruby sebagai proyek pribadi, sambil merujuk ke hokstad.com/compiler dan
      writing-a-compiler-in-ruby
      Saat ini saya fokus meloloskan RubySpec, dan nanti ingin mencoba optimasi berbasis tipe juga
  • Ini tidak berhubungan langsung dengan kompilasi Ruby, tetapi buku Enterprise Integration with Ruby memberi saya banyak wawasan tentang pemanfaatan Ruby di luar web

  • Sejak mengenal MRuby, saya jadi ketagihan mengubah proyek dan skrip saya menjadi executable mandiri

  • Senang melihat Ruby Under a Microscope masih terus diperbarui
    Menurut saya, ini bacaan wajib bagi siapa pun yang ingin memahami cara kerja internal Ruby

  • Saya penasaran, ketika sebuah blok YJIT dijalankan berkali-kali, bagaimana ia melacak kompilasi untuk tiap tipe input
    Saya ingin tahu bagaimana Ruby menangani berbagai tipe seperti int atau float

    • Itulah tepatnya inti YJIT
      Ia memakai pendekatan “wait‑and‑see” dengan menunda kompilasi sampai tipe aktual diberikan
      Versi blok untuk masing-masing tipe dikelola terpisah, lalu dipanggil sesuai kebutuhan
      Algoritme ini disebut Basic Block Versioning
      Maxime Chevalier‑Boisvert dari Shopify menjelaskannya dengan baik dalam video presentasi RubyConf 2021
      Engine JIT baru, ZJIT, tampaknya memakai pendekatan yang berbeda
  • Membuat bahasa bertipe dinamis menjadi cepat dengan JIT biasanya dibayar dengan peningkatan penggunaan memori
    Kalau bukan perusahaan besar seperti Shopify, ini mungkin justru jadi masalah yang lebih besar

    • Namun perusahaan kecil biasanya juga punya aplikasi yang lebih kecil
      Instance cloud modern memberi sekitar 4GiB memori per core, jadi kode JIT beberapa ratus MB masih sangat mungkin ditanggung
  • Cara YJIT menemukan hotspot dengan hanya menghitung jumlah pemanggilan fungsi terlihat sederhana
    Saya jadi penasaran apakah tidak ada fitur untuk mendeteksi komputasi berat di dalam loop seperti pada JIT JavaScript
    Struktur blok Ruby tampaknya juga bisa membantu optimasi seperti ini

    • Benar, Ruby memperlakukan isi loop sebagai blok
      Jadi JIT bisa memperlakukan blok sebagai fungsi terpisah dan secara alami mengoptimalkan perulangan
      Bagian ini akan dibahas lebih dalam di bab berikutnya