1 puan yazan GN⁺ 2025-11-19 | 1 yorum | WhatsApp'ta paylaş
  • YJIT ve ZJIT, Ruby 3.x’te Ruby kodunu makine diline dönüştürerek yürütme hızını artıran JIT derleyici yapılarıdır
  • YJIT, her fonksiyon veya blok çağrısının sayısını sayar ve belirli bir eşiğe ulaşıldığında ilgili kodu makine diline dönüştürür
  • Dönüştürülen kod YJIT blokları içinde saklanır ve her blok, birden fazla YARV komutunu karşılayan ARM64 makine dili komutlarına çevrilir
  • Branch Stub kullanarak çalışma anında gerçek veri tiplerini gözlemler ve buna uygun makine dili komutlarını seçerek üretir
  • Bu yapı, Ruby’nin çalışma performansını artırma ve dinamik tip işlemeyi verimli hale getirme hedeflerini aynı anda gerçekleştiren temel mekanizmadır

Chapter 4: Ruby’yi makine diline derlemek

Interpreting vs. Compiling Ruby Code

  • Orijinal metinde ayrıntı yok

Counting Method and Block Calls

  • YJIT, programın fonksiyon ve blok çağrı sayılarını izleyerek hotspot kodu belirler
    • Her fonksiyon veya blok için YARV komut dizisinin yanında jit_entry ve jit_entry_calls değerleri saklanır
    • jit_entry başlangıçta null’dır; daha sonra YJIT tarafından oluşturulan makine dili kodunun işaretçisini saklar
    • jit_entry_calls her çağrıldığında 1 artar
  • Çağrı sayısı eşik değere ulaştığında YJIT ilgili kodu makine diline derler
    • Ruby 3.5’te varsayılan eşik küçük programlar için 30 çağrı, büyük uygulamalar için 120 çağrıdır
    • Çalıştırma sırasında --yjit-call-threshold seçeneğiyle değiştirilebilir
  • Bu yöntemle YJIT, yalnızca sık çalıştırılan kodu makine diline dönüştürerek verimli bir yürütme yolu sağlar

YJIT Blocks

  • YJIT, ürettiği makine dili komutlarını YJIT blokları içinde saklar
    • YJIT bloğu, Ruby bloğundan farklıdır ve YARV komutlarının belirli bir bölümünü temsil eder
    • Her Ruby fonksiyonu veya bloğu birden fazla YJIT bloğundan oluşur
  • Örnek programda blok 30. kez çalıştığında YJIT derlemeye başlar
    • İlk YARV komutu olan getlocal_WC_1 makine diline çevrilerek yeni bir YJIT bloğu oluşturulur
    • Ardından getlocal_WC_0 komutu da derlenip aynı bloğa eklenir
  • Figure 4-8’e göre YJIT, M1 işlemcisindeki x1 ve x9 yazmaçlarına değer yükleyen ARM64 komutları üretir
    • getlocal_WC_1, önceki stack frame’in yerel değişkenini; getlocal_WC_0 ise mevcut stack’teki değişkeni stack’e kaydeder
    • Üretilen makine dili komutları aynı işi yerine getirir

YJIT Branch Stubs

  • YJIT, opt_plus komutunu derlerken operand tiplerini bilememe sorunu ile karşılaşır
    • Tamsayı, string, kayan nokta gibi tiplere göre gerekli makine dili komutları değişir
    • Örneğin tamsayı toplaması adds komutunu kullanırken, kayan nokta toplaması farklı komutlar gerektirir
  • Bunu çözmek için YJIT, önceden analiz etmek yerine çalışma anında gözlemleme yaklaşımını kullanır
    • Program çalışırken gerçekten iletilen değerlerin tipini kontrol eder ve buna uygun makine dili üretir
  • Bu davranış için Branch Stub kullanılır
    • Yeni bir branch için henüz bağlı bir blok yoksa geçici olarak bir stub’a bağlanır
    • Daha sonra gerçek tip belirlendiğinde ilgili stub uygun blokla değiştirilir

ZJIT (yalnızca anılıyor)

  • İçindekilerde ZJIT ile ilgili bir bölüm yer alsa da, metinde ayrıntılı açıklama yok

Özet

  • YJIT, Ruby 3.5’te dinamik tipli bir dilin yürütme verimliliğini artırmak için kullanılan bir JIT derleyicisidir
  • Çağrı sayısına dayalı derleme tetikleme, YJIT blok yapısı ve Branch Stub ile çalışma anında tip doğrulama temel unsurlardır
  • ARM64 mimarisinde gerçek makine dili komutlarına dönüştürerek Ruby kodunun çalışma hızını artırır
  • ZJIT, yeni nesil bir JIT olarak anılsa da metinde ayrıntı verilmez

1 yorum

 
GN⁺ 2025-11-19
Hacker News görüşleri
  • Eskiden MacRuby, LLVM kullanarak macOS üzerinde yerel koda derlenir ve Objective‑C framework’leriyle entegre olurdu
    Oldukça hoş bir fikirdi, ama sonunda Apple’ın yönünü Swift’e çevirdiği anlaşılıyor
    Yeni sürüm çıkarsa Ruby Under a Microscope kitabını mutlaka satın alıp okumayı düşünüyorum. Ruby’yi hâlâ seviyorum ama onu gerçekten kullanma fırsatım pek olmadı

    • MacRuby’nin yaratıcısı Apple’dan ayrıldıktan sonra RubyMotion’ı yaptı
      Şimdi işi başkaları sürdürüyor, ama şu sıralar daha çok DragonRuby’ye (oyun odaklı bir Ruby implementasyonu) odaklanılmış gibi görünüyor
    • MacRuby, yazar ayrıldıktan sonra RubyMotion ile devam etti
      Bilgi için wiki sayfası da var
    • Hâlâ Objective‑C kullanarak macOS, iOS ve iPadOS için uygulama geliştirebilirsiniz
      Yalnız eski API’lerin bazıları artık desteklenmiyor olabilir
    • Birçok dille çalışmış biri olarak bakınca, Apple’ın Swift’e geçişi bana Microsoft’un VB6’dan VB.Net’e geçişini hatırlatıyor
      VB6 gerçekten çok hızlı geliştirme sağlıyordu ve Direct3D ile ASP Classic’e kadar kullanılabiliyordu
      Ruby’nin zarafeti ve geliştirme kolaylığı bana o dönemi hatırlatıyor
      Eğer Ruby’de VB6 seviyesinde GUI araçları olsaydı, popülerliği epey farklı olabilirdi
  • Pat’in projeyi sürdürmeye devam ettiğini görmek gerçekten sevindirici
    İlk Ruby Under a Microscope kitabı ve blog yazıları bana büyük ilham vermişti
    Yıllar önce Euruko konferansında onunla bizzat tanışmıştım; gerçekten harika biriydi

    • Güzel yorum için teşekkürler
  • Ruby Under a Microscope’u ilk okuduğumda gerçekten çok keyif almıştım
    Hatta o sayede geçmişte CTF çözümünde de faydalanmıştım
    Son zamanlarda Ruby’nin iç implementasyonunu takip etmiyorum ama yeni sürüm çıkarsa kesin almayı düşünüyorum

    • 2002’den 2010’a kadar Ruby’yi çok kullandım, sonrasında ise neredeyse tamamen bıraktım
      Bu yazıyı görünce kitabın yeni sürümünü yeniden okumak istedim
  • Madem Ruby derlemesinden bahsediliyor, Stripe geliştiricilerinin yaptığı Sorbet compiler’ı deneyen oldu mu diye merak ediyorum
    Sorbet Compiler’ın açık kaynak yapılmasıyla ilgili yazı

    • Şimdi depodan kaldırılmış ve artık geliştirilmiyor gibi görünüyor; bu da üzücü
      AOT derleme Ruby’de gerçekten çok zor
      Sorbet’in yaklaşımını ilginç kılan şey, Ruby’nin tip denetimini temel alarak hızlı yollar oluşturabilmesi
      Ben de kişisel bir proje olarak bir Ruby derleyicisi yapıyorum; hokstad.com/compiler ile
      writing-a-compiler-in-ruby kaynaklarına bakıyorum
      Şu anda RubySpec’i geçmeye odaklandım, ileride tip tabanlı optimizasyonları da denemeyi düşünüyorum
  • Ruby derlemesiyle doğrudan ilgili değil ama Enterprise Integration with Ruby kitabı, Ruby’yi web dışındaki alanlarda kullanma konusunda bana ciddi içgörü kazandırmıştı

  • MRuby’yi keşfettiğimden beri, projelerimi ve script’lerimi bağımsız çalıştırılabilir dosyalara dönüştürmenin keyfine kapılmış durumdayım

  • Ruby Under a Microscope’un hâlâ güncelleniyor olmasına seviniyorum
    Ruby’nin iç işleyişini anlamak isteyen herkes için bunun mutlaka okunması gereken bir kitap olduğunu düşünüyorum

  • YJIT’te bir blok birden çok kez çalıştırıldığında, giriş tiplerine göre derlemenin nasıl takip edildiğini merak ediyordum
    Ruby’nin int, float gibi farklı tipleri nasıl ele aldığını öğrenmek istiyorum

    • İşin özü zaten YJIT’in temelinde bu var
      Gerçek tip bilgisi gelene kadar derlemeyi erteleyen bir “bekle‑gör” yaklaşımı kullanıyor
      Her tip için blokların ayrı sürümlerini tutuyor ve duruma göre uygun olanı çağırıyor
      Bu algoritmaya Basic Block Versioning deniyor
      Shopify’den Maxime Chevalier‑Boisvert bunu RubyConf 2021 konuşma videosunda güzelce anlatıyor
      Yeni JIT motoru ZJIT ise görünüşe göre farklı bir yaklaşım kullanıyor
  • Dinamik tipli dilleri JIT ile hızlandırmanın bedeli genelde artan bellek kullanımı oluyor
    Shopify gibi büyük bir şirket değilseniz bu daha da büyük bir sorun olabilir

    • Ama küçük şirketlerin uygulamaları da genelde küçük oluyor
      Günümüzde bulut instance’ları çekirdek başına yaklaşık 4GiB bellek veriyor, bu yüzden birkaç yüz MB’lık JIT kodu rahatlıkla karşılanabilir
  • YJIT’in yalnızca fonksiyon çağrı sayısını sayarak hotspot bulması bana biraz basit görünmüştü
    JavaScript JIT’lerinde olduğu gibi döngü içindeki ağır işlemleri tespit eden bir mekanizma var mı diye merak ettim
    Ruby’nin blok yapısı böyle bir optimizasyona yardımcı olabilir gibi geliyor

    • Evet, Ruby döngü gövdesini blok olarak ele aldığı için
      JIT bu blokları ayrı birer fonksiyon gibi işleyip döngüleri doğal şekilde optimize edebiliyor
      Bu konu bir sonraki bölümde daha derin ele alınacak