← haandevENTR

JavaScript'i önceden derlemek: bytecode, JIT ve Bun AoT

Bun artık TypeScript'i doğrudan makine koduna derleyebiliyor. Bunun ne anlama geldiğini görmek için önce bir JavaScript motorunun kodu nasıl çalıştırdığına, sonra aynı şeyi deneyen Android, Java ve Hermes'in neyle karşılaştığına bakmak gerekiyor. Hepsi aynı noktaya varıyor: önceden derleyen bir derleyicinin derleme anında bilmesi gerekir JIT'in çalışma anında öğrendiğini, ve JavaScript'te bu bilginin tek kaynağı tiplerdir.

1. Soru: --bytecode ile --aot arasındaki fark

Bun bir süredir bir programı tek bir çalıştırılabilir dosyaya paketleyebiliyor (bun build --compile) ve bu dosyaya önceden üretilmiş bytecode gömebiliyor (--bytecode). Yeni seçenek bun compile (bun build --compile --aot'un kısaltması) ise programı makine koduna derliyor.

İlk bakışta ikisi aynı işi yapıyor. İkisi de şunu söylüyor: kaynağı önceden işle, çalışma anında daha az iş kalsın. Aradaki farkı görmek için, bir JavaScript motorunun bir fonksiyonu ilk gördüğü andan makine koduna çevirdiği ana kadar ne yaptığını izlemek gerekiyor. İki seçenek bu zinciri farklı yerlerden kesiyor.

2. Bir JavaScript motoru kodu nasıl çalıştırır

Örnek olarak Bun'ın kullandığı motor olan JavaScriptCore'u (JSC) alalım. V8 ve SpiderMonkey ayrıntıda farklı, ama ana hatlar aynı.

  1. Ayrıştırma. Kaynak metin bir sözdizimi ağacına çevrilir. Motorlar bunu tembel yapar: bir fonksiyonun gövdesi ancak fonksiyon ilk çağrıldığında tam olarak ayrıştırılır.
  2. Bytecode. Ağaç, motorun kendi ara diline çevrilir. Bytecode makine kodu değildir; bir yorumlayıcının okuyacağı komut dizisidir.
  3. Yorumlayıcı (LLInt). Fonksiyon önce yorumlayıcıda çalışır; yorumlayıcı bytecode'u adım adım okur. Yavaştır, ama hemen başlar. Bu sırada motor profil tutar: her property erişimine hangi biçimde nesnelerin geldiğini, her çağrının hangi fonksiyona ulaştığını, her toplamanın tamsayılarla mı yapıldığını.
  4. Baseline JIT. Yeterince çalışmış bir fonksiyon, bytecode'unun basit bir makine kodu karşılığına çevrilir. Hâlâ genel durumu ele alır, ama yorumlama yükü kalkar.
  5. DFG ve FTL. Sık çalışmaya devam eden fonksiyonlar, profili kullanan optimize eden derleyicilere gider. FTL'nin arka ucu B3'tür; Apple'ın 2016'da JSC'de LLVM'in yerine koymak için yazdığı bir derleyici.

Son adımın kritik kelimesi spekülasyon. Profil, p.x erişimine hep aynı biçimde nesnelerin geldiğini söylüyorsa, optimize eden derleyici erişimi tek bir bellek okumasına çevirir ve başına küçük bir kontrol koyar. Bir gün başka biçimde bir nesne gelirse kontrol tutmaz, optimize edilmiş kod atılır ve fonksiyon yorumlayıcıya geri döner (deoptimization). JIT'in dinamik bir dilde hızlı olabilmesinin sebebi bu: tipleri bilmek zorunda değildir; onları gözlemler.

Bu düzenin bedeli sürecin başında ödenir: ayrıştırma, yorumlayıcıdaki yavaş ilk çalışmalar, profil için bellek ve arka plan iş parçacıklarında çalışan derleyicilerin CPU'su. Getirisi sürecin geri kalan ömründe alınır. Haftalarca açık kalan bir sunucu için bu iyi bir takastır. Başlayıp tek bir iş yapan ve 300 milisaniye sonra kapanan bir CLI aracı için bedel ödenir, ama getirinin çoğu hiç gelmez.

JAVASCRIPTCORE · KAYNAKTAN MAKİNE KODUNAprofil: nesne biçimleri, çağrı hedefleri, sayı türleriKaynakmetinAyrıştırmasözdizimi ağacıBytecodekomut dizisiLLIntyorumlayıcıBaselinebasit JITDFGoptimize eden JITFTL · B3optimize eden JITdeoptimization: tahmin tutmaz, yorumlayıcıya dönülürayrıştırma: açılışta CPUyavaş ilk çalışmalarprofil belleği, arka planda derleyici iş parçacıklarıhepsi her sürecin başında ödenir
JavaScriptCore'un katmanları. Yorumlayıcı çalışırken bir profil toplar, optimize eden katmanlar da ona göre derler; bir tahmin yanlış çıkınca kod atılır ve fonksiyon yorumlayıcıya döner.

3. Zincir nereden kesilebilir

Açılış maliyetini azaltmak isteyen biri bu zinciri üç yerden kesebilir.

Bytecode'u önbelleğe almak. İlk iki adım, ayrıştırma ve bytecode üretimi, derleme anında yapılır ve sonuç bir dosyaya yazılır. V8'in code cache'i ve Bun'ın --bytecode'u bu türdendir. Çalışma modeli değişmez: program yine yorumlayıcıda başlar, yine profil toplar, yine JIT ile ısınır. Kazanılan şey ayrıştırma süresidir.

Yığının anlık görüntüsünü almak. Program başlatılır, ilk kurulumu bitene kadar çalıştırılır ve o andaki bellek durumu bir dosyaya yazılır. Sonraki açılışlar bu görüntüden devam eder. V8'in startup snapshot'ları ve Node'un tek dosyalık çalıştırılabilir uygulamalarındaki snapshot seçeneği (20.6'dan beri) bu türdendir. Bu, kurulum maliyetini kaldırır; JIT'in ısınmasını kaldırmaz.

Bütün zinciri derleme anına taşımak. Makine kodu derleme anında üretilir ve çalışma anında JIT yoktur. Bu yalnızca açılış maliyetini değil, profil belleğini ve derleyici iş parçacıklarını da kaldırır. Ama 2. bölümdeki spekülasyonun dayandığı profili de kaldırır: derleme anında gözlemlenecek bir çalışma yoktur.

İlk iki kesim güvenlidir, çünkü JIT'e dokunmazlar. Üçüncüsü, JIT'in çalışırken öğreneceğini başka bir yerden bilmeyi gerektirir. Bunu deneyenlerin hepsi aynı soruyla karşılaştı.

HER ADIM NEREDE GERÇEKLEŞİRAyrıştırmaBytecodeYorumlayıcıBaseline JITOptimize eden JITOlduğu gibi çalıştırbun build --compileBytecode'u önbelleğe al… --compile --bytecodekesimÖnceden derlebun compilekullanılmazyalnızca evalkullanılmazB3, derlemedederleme anındaçalışma anında, her süreçte
Bytecode önbelleği yalnızca ilk iki adımı derleme anına taşır; yorumlayıcı ve JIT her süreçte yine çalışır. Önceden derleme optimize eden derleyicinin kendisini taşır ve yorumlayıcıyı yalnızca string'den üretilen kod için tutar.

4. Önceden derlemeyi daha önce deneyenler

Android: Dalvik, ART ve hibrit model. Android uygulamaları yıllarca Dalvik sanal makinesinde çalıştı; Dalvik 2010'da bir JIT kazandı. Android 5.0 (2014) Dalvik'in yerine ART'yi getirdi ve uygulamaları kurulum anında tamamen makine koduna derlemeye başladı. Uygulamalar hızlı açılıyordu, ama kurulumlar ve sistem güncellemeleri dakikalar sürüyordu ve derlenmiş kod depolamada ciddi yer kaplıyordu. Android 7.0 (2016) hibrite geçti: uygulama önce JIT'le çalışıyor, JIT hangi metotların sık çalıştığını kaydediyor ve cihaz boştayken yalnızca bu metotlar önceden derleniyor. Önceden derleme, bir profille beslendiğinde işe yaradı.

Java: GraalVM Native Image. GraalVM bir Java uygulamasını tek bir çalıştırılabilir dosyaya derleyebiliyor; JVM'in ısınması ortadan kalkıyor ve açılış milisaniyelere iniyor. Bunun bedeli kapalı dünya varsayımı: derleyici, programın ulaşabileceği bütün kodu derleme anında görmek zorunda. Reflection, dinamik sınıf yükleme ve çalışma anında üretilen proxy'ler ya yapılandırma dosyalarında önceden bildirilmeli ya da çalışmaz. Tepe performansta genellikle sıcak bir JVM'in gerisinde kalıyor, ve Oracle'ın cevabı yine profil: Oracle GraalVM'de enstrümanlı bir derleme gerçek iş üzerinde çalıştırılıyor ve program topladığı profille yeniden derleniyor.

JavaScript: Hermes ve Static Hermes. Meta, React Native için Hermes motorunu 2019'da yayımladı. Hermes'in ana kararı JIT'ten vazgeçmekti: JavaScript derleme anında bytecode'a çevriliyor ve uygulamanın içinde dağıtılıyor; telefonda yalnızca bir yorumlayıcı çalışıyor. Telefonlarda öncelik tepe hızı değil, açılış süresi ve bellekti, ve iOS üçüncü taraf uygulamaların çalışma anında çalıştırılabilir bellek oluşturmasına zaten izin vermiyor. 2023'te duyurulan Static Hermes daha da ileri gitti: tip anotasyonlu JavaScript'i C ve LLVM üzerinden makine koduna derliyor ve sağlam tipleri derleme anında güvenilir bilgi olarak kullanıyor. Bu çalışma daha sonra Hermes'in ana geliştirme hattı oldu; o hatta, dikkat çekici şekilde, o zamandan beri bir JIT de eklendi.

Üç hikâyeden çıkan ders aynı. Önceden derleme açılışı ve belleği güvenilir şekilde iyileştiriyor. Tepe performansı korumak için ise derleyicinin, JIT'in çalışma anında topladığı bilgiye derleme anında sahip olması gerekiyor. Android ve GraalVM bu bilgiyi bir önceki çalışmanın profilinden aldı. Static Hermes onu kaynak koddaki tiplerden almayı seçti.

ÜÇ KEZ ÖNCEDEN DERLEMEAndroidbilgi kaynağı: öncekiçalışmaların profiliDalvik JITART: kurulumda tamamen AOThibrit: JIT + profil yönlendirmeli AOTJavabilgi kaynağı: bir denemeçalışmasının profiliHotSpot JITGraalVM Native Imagesonra: PGO, Oracle GraalVM'deJavaScriptbilgi kaynağı: tipanotasyonlarıV8, JSC: katmanlı JIT'lerHermes: bytecode, JIT yokStatic Hermes: tipler → nativeBun AoT20082012201620202024
Her platform bir JIT'ten önceden derlemeye doğru ilerledi, ve her biri JIT'in eskiden gözlemleyerek öğrendiği bilgi için başka bir kaynak bulmak zorunda kaldı. Android ve Java onu bir profilde buldu; JavaScript onu tiplerde arıyor.

5. Bun'ın üç seçeneği

Bun, bu yelpazenin üç noktasına karşılık gelen üç yol sunuyor:

bun build --compile … --compile --bytecode bun compile
Dosyada ne var Paketlenmiş JS Paketlenmiş JS + JSC bytecode'u Makine kodu
Zincirin kesildiği yer Hiçbir yer Ayrıştırma ve bytecode'dan sonra Bütün zincir
Çalışma anında JIT Var Var Yok
TypeScript tipleri Silinir Silinir Denetlenir, sonra kullanılır
Hedef platform --target ile her platform --target ile her platform Yalnızca üzerinde çalıştığı platform
Durum Kararlı Kararlı Deneysel

--bytecode, 3. bölümdeki ilk kesimdir. Bun'ın kendi ölçümüne göre tsc bytecode ile iki kat hızlı açılıyor, büyük uygulamalar iki ila dört kat kazanıyor. Ama program açıldıktan sonra her şey bun run'daki gibidir.

bun compile üçüncü kesimdir. Giriş noktasından başlayarak importları izler, TypeScript'i tip denetiminden geçirir ve bütün program üzerinde her değişkene hangi nesnelerin ulaştığını, her çağrının hangi fonksiyona gittiğini hesaplar. Sonra ulaşılabilen her fonksiyon için, npm paketleri dahil, makine kodu üretir. Bunu, JSC'nin FTL'de kullandığı arka uçla, B3 ile yapar: Bun, JIT'in en üst katmanını fiilen derleme anına taşımış oluyor. Çıktı, Bun çalışma zamanının JIT'siz bir kopyasıdır. Linux 6.7 ve sonrasında süreç, çekirdekten yeni çalıştırılabilir bellek oluşturulmasını yasaklamasını bile istiyor (PR_SET_MDWE); yani JIT yalnızca kullanılmıyor değil, kullanılamıyor.

Dördüncü bölümdeki soru burada da geçerli: JIT'in profilden öğreneceğini bun compile nereden alıyor?

6. Bun AoT'nin bilgi kaynağı: TypeScript tipleri

Bun, Static Hermes'in yolunu seçiyor: bilgiyi tiplerden alıyor.

Bir değer programın kendi yarattığı bir değerse, tipi bir olgu olarak kabul edilir ve değer sabit bir bellek düzenine oturtulur. Bun'ın pull request'indeki örnekte iki number alanlı bir Vec, 16 baytlık bir başlık ve iki ham double'dır; tipi kanıtlanmış bir alanı okumak, Go ya da Rust'taki bir struct alanı gibi, tek bir yüklemedir. Değer dışarıdan geliyorsa, derleyicinin göremediği bir çağırandan gelen argüman ya da JSON.parse sonucu gibi, tip bir tahmin olarak kullanılır: bir kez test edilir, tutmazsa kod yavaş yola geçer. Bu, JIT'in spekülasyonuna benzer; farkı, tahminin gözlemden değil anotasyondan gelmesidir.

Bunun iki sonucu var. Birincisi, bun run tipleri siler ama bun compile tipleri denetler, ve tip hatası varsa çalıştırılabilir dosya üretmez. Aynı : number bir kipte yorum, diğerinde derleyici girdisidir. İkincisi, tipsiz kod AoT altında JIT'ten yavaş çalışabilir: tipin olmadığı yerde derleyici ne gözlemleyebilir ne de kanıtlayabilir, ve property'yi çalışma anında isimle arar. Bun'ın dokümantasyonu bunu açıkça söylüyor, ve bun compile --explain bu erişimleri en pahalısından başlayarak listeliyor.

JIT · GÖZLEMLERp.xAAAAprofil: hepA biçimiderlenir: biçim kontrolü + tek okumaBkontrol tutmaz: deoptimize et,yorumlayıcıya dön, yeniden izleçalışmadan öğrenir; tiplere ihtiyacı yokÖNCEDEN DERLEME · KANITLARp.xp'yi program kendisi yarattı:tip bir olgutek okumap dışarıdan geliyor (birargüman, JSON.parse):tip bir tahminbir test, sonra okuma;tutmazsa yavaş yolp'nin tipi yokisimle aramagözlenecek çalışma yok; yalnızca kanıtladığını kullanır
JIT, p'nin ne olduğunu programın çalışmasını izleyerek öğrenir. Önceden derleyen derleyicinin izleyecek bir çalışması yoktur; bu yüzden p.x'in ne kadar hızlı olacağı, tiplerin ona neyi kanıtlattığına bağlıdır.

7. Kısa ömürlü bir süreçte sonuçlar

Bun'ın ilk ciddi ölçümü Claude Code CLI'ı üzerinde. Bu seçim tesadüf değil: Anthropic, Bun'ı Aralık 2025'te satın aldı, Claude Code bir Bun çalıştırılabilir dosyası olarak dağıtılıyor, ve bir kodlama ajanı kısa ömürlü, sık başlatılan süreçlerin tipik örneği.

JIT dosyasıönceden derlenmiş dosyaİlk isteme kadar süre318 ms141 msTepe özel bellek185,4 MB44,7 MBCPU süresi1.542 ms512 msTepe RSS308,5 MB180,8 MBçubuklar JIT dosyasına göre · ölçüm Bun ekibinin
JIT'li ve önceden derlenmiş Claude Code CLI'ı. En büyük kazanç özel bellekte: bytecode yok, JIT'in derlediği kod yok, profil yok.

İkinci ölçüm daha uzun bir iş: TypeScript 6'nın 370 bin satırlık bir projede tip denetimi.

Duvar saati süresi Bellek CPU süresi
bun run altında TypeScript 6 (JIT) 14,00 sn 2.581 MB 29,2 sn
bun compile altında TypeScript 6 (AoT) 4,25 sn 963 MB 5,3 sn
TypeScript 7 (Go'ya yeniden yazılmış) 2,68 sn 1.256 MB 10,8 sn

Bu ikinci sonuç dikkat çekici, çünkü on dört saniye kısa bir süre değil, ve JIT yine kaybediyor. tsc büyük ve çok biçimli bir kod tabanı; JIT'in onu ısıtması saniyeler sürüyor, ve 29 saniyelik CPU'nun önemli bir kısmı derleyici iş parçacıklarına gidiyor. Yani bir sürecin kısa ömürlü sayılıp sayılmadığı yalnızca saniyeyle ölçülmüyor; programın büyüklüğüne de bağlı.

TypeScript 7 satırı 4. bölümdeki hikâyeyi uzatıyor. Microsoft, tsc'nin açılış ve bellek sorununu derleyiciyi Go'ya yeniden yazarak çözdü. Jarred Sumner ise AoT'yi Rust'a yeniden yazmak zorunda kalmama seçeneği olarak sunuyor. Bu rakamlara göre AoT o farkın büyük kısmını kapatıyor, ama tamamını değil.

8. Uzun ömürlü bir süreçte sonuçlar

Aynı pull request'te sunucu çatıları için tepe verim ölçümleri de var. İlk saniyede AoT bir ila iki kat önde; JIT henüz ısınmamış. Isındıktan sonra:

Çatı Sıcak durumda fark
Koa JIT %22,9 daha hızlı
Fastify JIT %16,9 daha hızlı
Elysia JIT %13,5 daha hızlı
Express JIT %7,1 daha hızlı
Hono, Bun.serve AoT yaklaşık %2,5 daha hızlı

Bu, GraalVM'in gösterdiği tablo. Açık kalan bir sunucuda ısınmanın bedeli bir kez ödenir, ve JIT'in gözlemlediği profil, derleyicinin kanıtlayabildiğinden daha zengindir. Sumner, önceden derlemenin genellikle daha düşük tepe performans verdiğini kabul ediyor; ekip açığı daha katı bir TypeScript türüyle ve kilitlenmiş built-in'lerle kapatmayı umuyor.

Tablodaki desen 6. bölümle örtüşüyor. AoT'nin yetiştiği çatılar, Hono ve Bun.serve, TypeScript'le yazılmış ve az katmanlı. En çok geride kaldığı Koa ve Express ise ara katman zincirleri üzerinden dinamik çağrılar yapan, daha eski, tipsiz JavaScript. AoT, tiplerden kanıtlayabildiği kadar hızlıdır.

Sıcak bir sunucuya AoT'nin hâlâ sunduğu şey bellektir. Tek bir sunucu için bu pek önemli değildir; yüzlerce küçük konteynerde ya da faturanın belleğe göre kesildiği yerde önemlidir. Otomatik ölçeklemede de her yeni kopya ilk saniyesinde soğuk bir süreçtir.

9. Kapalı dünyanın bedeli

GraalVM'in kapalı dünya varsayımı Bun'da da var, iki biçimde.

Built-in'ler kilitli. Derleyicinin arr.push(x)'i doğrudan işleme çevirebilmesi için Array.prototype.push'un çalışma anında değişmeyeceğini varsayması gerekir. Bun bu varsayımı zorunlu kılıyor: built-in nesnelerin mevcut üyeleri değiştirilemez, ve Array.prototype.push'a atama TypeError fırlatır. Object.prototype, RegExp.prototype, Promise.prototype ve generator prototipleri hiç değiştirilemez. Yeni üye eklemek serbesttir.

String'den üretilen kod yorumlanır. eval, new Function ve node:vm yasak değildir, ama makine koduna da derlenmez: aynı süreçte, aynı nesneler üzerinde, JSC'nin yorumlayıcısında çalışır. Sıcak yolunu new Function ile üreten doğrulayıcı ve serileştirici kütüphaneler bu yüzden AoT altında belirgin şekilde yavaşlar. Derleyicinin izleyemediği bir çağrı, örneğin globalThis[name](code), EvalError fırlatır. Diskten dinamik import() ile kod yüklemek varsayılan olarak kapalıdır.

Diğer sınırlar: çapraz derleme yok, breakpoint yok, ve büyük bir uygulamanın derlenmesi onlarca saniye ve gigabaytlarca bellek alıyor; derlemeler arasında önbellek de yok. Linux x64 test ediliyor; Windows'ta birçok test hâlâ başarısız.

10. V8 isolate'leriyle karşılaştırma

Açılış sorununa bambaşka bir cevap daha var. Cloudflare Workers ve Deno Deploy her istek için yeni bir süreç başlatmıyor; tek bir sıcak V8 süreci içinde her müşterinin kodu kendi isolate'inde çalışıyor. Cloudflare 2020'de bir Worker'ı yüklemenin maliyetini yaklaşık 5 milisaniye olarak verdi, TLS el sıkışmasının arkasına saklanacak kadar kısa; 2025'te ise limitleri büyüdükçe soğuk başlangıçları "ortadan kaldırmak" ifadesinin iddialı kaçtığını kabul etti.

İkinci bölümdeki maliyetleri birinin ödemesi gerekiyor; değişen, kimin ödediği:

Bedeli kim öder Nasıl geri alınır
Süreç başına bir JIT (bun run, Node) Her süreç, açılışta O sürecin kendi ömrü boyunca
Bir V8 isolate'i Platformun tek uzun ömürlü süreci Binlerce müşterinin kodu arasında paylaşılarak
AoT (bun compile) Geliştirici, derleme anında Her kopya bu maliyet olmadan başlar

Isolate, motorun ömrünü uzatır ve kısa işleri onun içine sığdırır. AoT ise motoru hiç başlatmaz. Birincisi bir platform çözümüdür: isolate'leri barındıran bir şirket gerekir, ve kod o platformun API'leriyle sınırlıdır. İkincisi bir araç zinciri çözümüdür: çıktı, her yerde tam bir süreç olarak çalışan sıradan bir çalıştırılabilir dosyadır; bedeli derleme süresi ve 9. bölümdeki sınırlardır.

Isolate'lerin zaten kullanıldığı yerde AoT'nin katkısı azdır, çünkü açılış sorunu orada çözülmüştür. AoT'nin yeri, her ölçeklemede bir konteyner ya da mikro-VM başlatılan ortamlar ve kullanıcılara dağıtılan CLI araçlarıdır.

DERLEME ANIÇALIŞMA ANISüreç başına bir JIT…Bir V8 isolate'itek platform süreci, bir kez ısınır; içinde birçok müşterinin kısa işleriÖnceden derlemebir kez derle…ısınma ya da derlemeJIT altında işderlenmiş kodda iş
Programı öğrenmenin bedeli bir yerde ödenir. Süreç başına JIT onu her süreçte öder; isolate, uzun yaşayan bir platformun içinde bir kez öder; önceden derleme ise hiçbir şey çalışmadan önce bir kez öder.

11. Ne zaman hangisi

Seçim iki şeye bağlı: sürecin ne kadar yaşadığına ve kodun ne kadarının tiplenmiş olduğuna.

Emin değilseniz Bun'ın önerisi ikisini de derleyip aynı yük altına koymak; bun compile --no-aot aynı çalıştırılabilir dosyayı JIT'li olarak üretiyor.

12. Sınırlar

  1. Rakamlar Bun ekibinin. Buradaki bütün Bun ölçümleri pull request'ten ve dokümantasyondan geliyor. Bağımsız bir tekrarını görmedim, kendim de hiçbir şey ölçmedim.
  2. Özellik deneysel ve hareket halinde. İlk önizlemede çalıştırılabilir dosyanın neredeyse iki kat büyük olduğu bildiriliyordu; birleştirilen pull request'e göre küçük programlar artık daha küçük çıkıyor. Rakamlar ve kısıtlar değişmeye devam edecek.
  3. Tepe performans açığı yapısal olabilir. Android ve GraalVM bu açığı profillerle kapattı. Bun onu tiplerle kapatmayı umuyor, ama bir JIT'in çalışma anında gördüğü, statik analizin kanıtlayabildiğinden fazladır. Açığın ne kadarının kapanabileceği açık bir soru.

13. Sonuç

--bytecode ile bun compile arasındaki fark, motorun zincirini nereden kestikleridir. Bytecode yalnızca ayrıştırmayı derleme anına taşır; JIT olduğu gibi kalır. bun compile bütün zinciri taşır ve JIT'i kaldırır.

JIT'i kaldırmak, onun çalışma anında topladığını kaybetmek demektir. Android ve Java bu bilgiyi bir önceki çalışmanın profilinden geri aldı. Bun, Static Hermes gibi, onu kaynak koddaki tiplerden alıyor. Karşılığında built-in'ler kilitleniyor, string'den üretilen kod yorumlanıyor, ve tipsiz kod yavaşlıyor.

JavaScript'te tipler uzun süre geliştiriciye yönelik bir bilgiydi: derleyici onları denetleyip atıyordu. bun compile'da tipler, JIT'in çalışma anında öğrendiğinin derleme anındaki karşılığı oluyor.

Kaynaklar

Bun

JavaScriptCore

Daha önceki önceden derleyiciler

Başka yerlerde açılış

Not: buradaki bütün Bun ölçümleri Bun ekibinin ve yukarıdaki pull request'ten alındı. Özellik deneysel; bayraklar, rakamlar ve kısıtlar bu yazı yazıldığından beri değişmiş olabilir.