- Porffor, JavaScript’i çalışma anında değil önceden derleyerek WebAssembly ve native binary üreten bir araştırma projesidir
- Bir interpreter’ı birlikte paketlemeyen yaklaşımı sayesinde, mevcut JS→Wasm projelerine göre çıktının 10–30 kat daha küçük ve hızlı olmasını hedefler
- Native build’lerde de runtime paketlenmediği için binary boyutu 1000 kata kadar küçülebilir; örnekte yaklaşık 90 MB’tan 100 KB’ın altına düşüyor
- JS ile yazılmıştır,
evaliçermez ve TypeScript’i ayrı bir build aşaması olmadan native olarak destekleyen bir yapı sunduğunu öne çıkarır - AOT, statik analiz optimizasyonu ve çalıştırma öncesi derleme için avantajlıdır; ancak
evalgibi dinamik JS değerlendirmeleri zordur ve henüz birçok JS’in çalışmadığı erken aşamadadır
Porffor’un oluşturduğu çalıştırma biçimi
- Porffor, JavaScript’i WebAssembly ve native binary olarak Ahead-of-Time derleyen bir araştırma projesidir
- Bu sayfayı Porffor ile derlenmiş bir TypeScript binary’si sunuyor
- Baştan itibaren AOT düşünülerek yazıldığı için, mevcut JS çalıştırma biçimlerinde zor olan optimizasyonları denemeye uygun bir yapıya sahiptir
WebAssembly ve native çıktılar arasındaki fark
-
JS → Wasm
- Porffor’un WebAssembly çıktısı, mevcut JS→Wasm projelerine göre 10–30 kat daha küçük ve hızlıdır
- Temel fark, JS’i doğrudan derlemesi ve interpreter’ı bundle etmemesidir
- JS’i Wasm üzerinde çalıştırmak sandbox içinde çalıştırmayı mümkün kılar; ancak büyük performans kayıpları doğurabilir. Porffor bu maliyeti azaltmaya odaklanır
- Uygulanabilir kullanım örnekleri:
- Sunucu tarafı JS hosting: Edge runtime’larda Wasm sandboxing ile aşırı izolasyona gerek kalmadan güvenli çalıştırma sunabilir
- AOT’nin düşük overhead’i, JIT’e kıyasla aynı donanımda daha fazla müşteriyi minimum performans kaybıyla çalıştırma olasılığı yaratır
- Tersine mühendisliğe direnç: Hassas JS için derlenmiş kod, obfuscation’a kıyasla tersine mühendisliği daha zor hale getirebilir
-
JS → Native
- Runtime paketlemeden JS’i gerçekten derlediği için binary boyutu 1000 kata kadar küçülebilir
- Örnek boyut yaklaşık 90 MB → 100 KB altıdır
- İçeride JS’i önce C’ye, ardından native’e derlediğinden, C’nin kullanılabildiği yerlerde JS de kullanılabilir
- Uygulanabilir kullanım örnekleri:
- Embedded sistemler, oyun konsolları vb. ortamlarda hızlı JS çalıştırma
- 1 MB’ın altında tek tıkla çalıştırılabilir dosyaya derlenen küçük JS CLI uygulamaları
AOT’nin sağladığı avantajlar ve kısıtlar
- Geleneksel interpreter’lar veya çok aşamalı JIT’ler, başlangıç süresi ile JS performansı arasında denge kurmak zorundadır
- AOT önce derleyip sonra çalıştırdığı için derleme hızı geliştirici deneyimi açısından önemlidir, ancak kullanıcı deneyimini etkilemez
- Bu yöntem, C++ ve Rust’ta olduğu gibi statik analiz tabanlı optimizasyonlar yapmaya alan açar
- Başlıca dezavantajı,
evalgibi dinamik JS değerlendirmelerinin olmaması ve JS motorunun yeniden yapılmasını gerektirmesidir - Henüz erken aşamada olduğundan birçok JS çalışmaz; ancak iyileştirme çalışmaları devam etmektedir
- ECMAScript uyumluluğundaki ilerlemeyi izlemek için her commit’te resmi test paketi Test262 çalıştırılır
1 yorum
Hacker News görüşleri
Porffor'un ana geliştiricisi Oliver, Porffor üzerinde tam zamanlı çalışacağını duyurdu: https://x.com/canadahonk/status/1818347311417938237
https://news.ycombinator.com/user?id=defunkt
Benzer bir şeyi düşünmüştüm ama JavaScript'te çok daha iyi performans elde etmenin zor olduğunu düşünüyorum. Muhtemelen yapılabilecek en iyi şey, JS'yi V8 C++ çağrılarına transpile etmek olurdu
Gerçekten etkileyici optimizasyonlar, TypeScript veya ona yakın bir şeyi derlerken ortaya çıkar. Tiplerden yararlanırsanız büyük kazanç elde edebilirsiniz ve tipi olmayan kısımlar varsayılan olarak yavaş JS çağrılarına düşer. Arayüzler sanal fonksiyon tablolarına veya doğrudan çağrılara indirgenebilir ve map yerine struct'lar üzerinde çalışılabilir.
IntveFloattipleri tanımlanıp gerektiğindeNumber'a düşürülürken register içinde tutulabilirAsıl sorun, TS ve V8'in ikisinin de hızlı değişen standart dışı hedefler olması. Böyle projeler büyük bir ekip gerektirir ve uyumluluğu korumak başlı başına ayrı bir iş haline gelir
Basit bir örnek olarak, TypeScript tamsayı ile kayan noktalıyı ayırmaz; ikisini de number olarak ele alır. Bu yüzden tüm dizi erişimlerinde tür dönüşümü gerekir. Statik derlemeye yardımcı olacak şekilde tasarlanmış bir TypeScript olsaydı, muhtemelen bu ayrım olurdu
Daha büyük sorun ise TypeScript'in yapısal alt türleme özelliği. Bu özellik yüzünden derleyicinin, bir fonksiyona geçirilen ilkel olmayan argümanların fiziksel yapısını statik olarak belirlemesi pratikte imkansızdır. JIT dinamik şekil analizi yapabildiği için, her alan erişiminde JIT'ten daha kötü performans çıkabilir
JS için statik tip analiz araçları oluşturma konusunda çok iş yapıldı ve oldukça kapsamlı analizler de mümkün. Aklıma gelen örneklerden biri, biraz eski olsa da, TAJS
TypeScript'te de
integergibi bir tip belirtilebilse güzel olurdu. Normal TS→JS derlemesindeconst val: int,const val: numberile aynı şekilde ele alınsa bile, TS'yi anlayan modern bir runtime bu ek bilgiyi kullanabilirdiconst counter: Numbergibi bir sözdiziminin kabul edilip edilemeyeceğini merak ediyorumSite mi değişti, yoksa ben mi bir şeyi kaçırdım bilmiyorum
windmill.dev'de kullanıcılar kod dağıtırken Bun build kullanılarak script ve tüm bağımlılıkları tek bir JS dosyasında paketleniyor; bu dosya yüklenerek cold start ve bellek kullanımı iyileştiriliyor. Paket boyutu nedeniyle çıktı S3'te saklanıyor
Her şeyi native olarak paketleyebilseydiniz oyun tamamen değişirdi. Bun'ın cold start'ı ne kadar iyi olursa olsun, doğrudan küçük bir binary olarak native çalıştırmayı geçmesi zor
Daha fazla JS runtime’ının Wasm’a yaklaşımını görmek güzel. Bu proje, React Native projelerinde iOS ve Android hızını artırmak için Facebook’un JS motoru olan Static Hermes’i hatırlatıyor.
İkisi de JS test262 uyumluluğunu hedefliyor; Porffor hem native hem de Wasm çıktılarını desteklerken Static Hermes şu anda ağırlıklı olarak native çıktıya odaklanıyor. Porffor saf JS ile yazılmış ve kendisini derleyebilme yönünde ilerliyor; Static Hermes ise LLVM’e dayanıyor. Porffor’da async/promise/await desteği hâlâ sınırlıyken Static Hermes bunu bazı kısıtlarla destekliyor. Static Hermes C++ ile, Porffor ise ağırlıklı olarak JS ile yazılmış. İkisi de TypeScript’i destekliyor ancak Static Hermes TS AST’yi Flow’a transpile ediyor, Porffor ise bunu yerel olarak destekliyor. Static Hermes’te
evalgibi derlenmesi zor JS durumları için yedek bir interpreter var, Porffor ise yalnızca ahead-of-time derlemeyi destekliyor.Genel olarak bu projenin ivme kazanıp edge’deki JavaScript motorlarını daha hızlı hâle getirip getiremeyeceğini görmek heyecan verici. Wasmer’den Syrus olarak bırakıyorum.
https://github.com/facebook/hermes/discussions/1137
https://github.com/tc39/test262
https://wasmer.io
Ancak bu bizim odak noktamız değil; esas olarak React Native’e odaklanıyoruz. O ortamda WASM’in pek bir anlamı yok.
Static Hermes’in en önemli özelliği, runtime sağlamlığını garanti eden type checker’ıdır. Porffor çok ilgi çekici; bir süredir takip ediyorum ve başarılı olmasını diliyorum.
Kiesel’e benzer bir yaklaşım: https://kiesel.dev/
Array.prototype.filter,Math.sin,atobgibi built-in işlevler kısmen kendisini derliyor.Son zamanlarda Porffor temel düzeyde async/promise/await desteği de sunmaya başladı. Henüz çok iyi çalışmıyor.
JavaScript’in kolay derlenebilen bir alt kümesi var; zor olan kısım onun dışındaki uzun kuyruk. Yine de bu sınırın tam olarak nerede olduğuna ve o alt kümeden ne kadar fayda sağlanabileceğine dair araştırmaların yapılması harika.
String.blinkdesteklenmesini içtenlikle seviyorum. Geliştiricinin mizah ve oyunculuk duygusuna sahip olması her zaman iyi bir işarettir.Uygulaması da
function() { return "" + this + ""; }düzeyinde önemsiz olduğu için, ECMAScript host’u web tarayıcısı olmasa bile uygulanabilir. Böyle durumlarda bu isteğe bağlıdır. Bunun “mizah ya da oyunculuk” ile ilgili olmasını beklemezdim.String.blink, test262 içinde yer aldığı için proje hedefine ulaşmak istiyorsa fiilen bunu desteklemesi gerekiyor.Gözden kaçırdığım ince farkın ne olduğunu merak ediyorum. Neden “ahead-of-time derlenen JS motoru”, “JS-to-Wasm derleyicisi”nden daha iyi bir tanım olsun, emin değilim. Bu daha çok bir çerçeveleme stratejisiyse, o da kabul edilebilir.
Burada açıklanan sürümleme şeması biraz şüpheli görünüyor.
Bazı değişiklikler yüzünden kimi Test262 testlerinde gerileme yaşanırsa sürüm numarası da birlikte geri gidebilir. Yani Porffor aynı anda hem tek yönlü artan sürüm numaralarına hem de gerekli değişikliklerin Test262 gerilemesine yol açabilmesine sahip olamaz.
https://github.com/CanadaHonk/porffor?tab=readme-ov-file#ver...
Galce’de “mor” anlamına geliyor.
Farklı kullanım amaçlarına sahip birden fazla JS motorunun ortaya çıkmasını görmek ferahlatıcı.
Uygulamalara eklenti gömmek için quickjs’e, llrt üzerinden daha fazla Node uyumlu API ekleme işi üzerinde çalışıyordum.
https://github.com/awslabs/llrt