Eval of Julia code
Julia Dilinin kodu nasıl çalıştırdığını öğrenmenin en zor kısımlarından biri, bir kod bloğunu yürütmek için tüm parçaların nasıl bir araya geldiğini öğrenmektir.
Her bir kod parçası genellikle, potansiyel olarak tanıdık olmayan isimlerle birçok adımda bir yolculuk yapar, bunlar arasında (herhangi bir sırayla): flisp, AST, C++, LLVM, eval, typeinf, macroexpand, sysimg (veya sistem görüntüsü), bootstrapping, derleme, ayrıştırma, yürütme, JIT, yorumlama, kutulama, kutudan çıkarma, içsel fonksiyon ve ilkel fonksiyon bulunur; bunların hepsi istenen sonuca (umarım) dönüşmeden önce.

Julia Execution
Tüm sürecin 10,000 fitlik görünümü aşağıdaki gibidir:
- Kullanıcı
juliabaşlatır. cli/loader_exe.cdosyasındakimain()C fonksiyonu çağrılır. Bu fonksiyon, komut satırı argümanlarını işler,jl_optionsyapısını doldurur veARGSdeğişkenini ayarlar. Ardından Julia'yı başlatır (şu çağrıyı yaparak:julia_initininit.c), bu da daha önce derlenmiş sysimg dosyasını yükleyebilir. Son olarak, kontrolü Julia'ya devretmek içinBase._start()çağrısını yapar._start()kontrolü devraldığında, sonraki komut dizisi verilen komut satırı argümanlarına bağlıdır. Örneğin, bir dosya adı sağlandıysa, o dosyayı çalıştırmaya devam edecektir. Aksi takdirde, etkileşimli bir REPL başlatacaktır.- Kullanıcının REPL ile etkileşimi hakkında detayları atlayarak, programın çalıştırmak istediği bir kod bloğuna ulaştığını söyleyelim.
- Eğer çalıştırılacak kod bloğu bir dosyada ise,
jl_load(char *filename)dosyayı yüklemek için çağrılır ve parse ile yüklenir. Her kod parçası daha sonraevalile çalıştırılması için geçirilir. - Her bir kod parçası (veya AST), sonuçlara dönüştürmek için
eval()'ya iletilir. eval()her bir kod parçasını çalıştırmaya çalışırjl_toplevel_eval_flex().jl_toplevel_eval_flex()kodun "toplevel" bir eylem olup olmadığını (örneğinusingveyamodulegibi) belirler; bu, bir fonksiyonun içinde geçersiz olur. Eğer öyleyse, kodu toplevel yorumlayıcısına iletir.jl_toplevel_eval_flex()ardından expands makroları ortadan kaldırmak ve AST'yi daha basit bir şekilde çalıştırmak için "aşağı indirmek" amacıyla kullanılan kod.jl_toplevel_eval_flex()daha sonra AST'yi JIT derleyip derlemeyeceğine veya doğrudan yorumlayacağına karar vermek için bazı basit sezgiler kullanır.- Çalışmanın büyük kısmı kodu yorumlamak için
evalininterpreter.ctarafından yönetilmektedir. - Eğer bunun yerine kod derlenirse, işin büyük kısmı
codegen.cpptarafından halledilir. Bir Julia fonksiyonu, belirli bir argüman türü seti ile ilk kez çağrıldığında, type inference o fonksiyon üzerinde çalıştırılacaktır. Bu bilgi, daha hızlı kod üretmek için codegen adımında kullanılır. - Sonunda, kullanıcı REPL'i kapatır veya programın sonuna ulaşılır ve
_start()metodu döner. - Çıkmadan hemen önce,
main()jl_atexit_hook(exit_code)çağrısını yapar. Bu, Julia içindeatexit()ile kayıtlı olan herhangi bir fonksiyonu çağıranBase._atexit()'i çağırır. Ardındanjl_gc_run_all_finalizers()çağrısını yapar. Son olarak, tümlibuvhandle'larını nazikçe temizler ve bunların boşalmasını ve kapanmasını bekler.
Parsing
Julia ayrıştırıcısı, femtolisp'te yazılmış küçük bir lisp programıdır; kaynak kodu, Julia içinde src/flisp içinde dağıtılmaktadır.
Arayüz işlevleri esasen jlfrontend.scm içinde tanımlanmıştır. ast.c içindeki kod, bu geçişi Julia tarafında yönetmektedir.
Bu aşamada ilgili diğer dosyalar julia-parser.scm, Julia kodunu tokenleştiren ve bir AST'ye dönüştüren, ve julia-syntax.scm, karmaşık AST temsillerini daha basit, "aşağıya indirilmiş" AST temsillerine dönüştüren dosyalardır; bu temsiller analiz ve yürütme için daha uygundur.
Eğer Julia'yı tamamen yeniden inşa etmeden ayrıştırıcıyı test etmek istiyorsanız, ön yüzü kendi başına aşağıdaki gibi çalıştırabilirsiniz:
$ cd src
$ flisp/flisp
> (load "jlfrontend.scm")
> (jl-parse-file "<filename>")Macro Expansion
eval() bir makro ile karşılaştığında, ifadenin değerlendirilmeden önce o AST düğümünü genişletir. Makro genişletme, 4d61726b646f776e2e436f64652822222c20226576616c28292229_40726566 (Julia'da) ile jl_macroexpand() (flisp'te yazılmış) parser fonksiyonu ve Julia makrosu (başka ne ile yazılabilir ki - Julia) aracılığıyla fl_invoke_julia_macro() ile elden ele geçişi içerir ve geri döner.
Tipik olarak, makro genişletme, Meta.lower()/jl_expand() çağrısı sırasında birinci adım olarak çağrılır, ancak doğrudan macroexpand()/jl_macroexpand() çağrısıyla da tetiklenebilir.
Type Inference
Tip çıkarımı, Julia'da typeinf() in compiler/typeinfer.jl ile uygulanır. Tip çıkarımı, bir Julia fonksiyonunu inceleme ve her bir değişkeninin türleri için sınırlar belirleme sürecidir; ayrıca fonksiyonun dönüş değerinin türü için de sınırlar belirler. Bu, bilinen değiştirilemez değerlerin kutusunun açılması ve alan ofsetleri ile fonksiyon işaretçileri gibi çeşitli çalışma zamanı işlemlerinin derleme zamanı yükseltilmesi gibi birçok gelecekteki optimizasyonu mümkün kılar. Tip çıkarımı, sabit yayılımı ve iç içe alma gibi diğer adımları da içerebilir.
JIT Code Generation
Codegen, bir Julia AST'sini yerel makine koduna dönüştürme sürecidir.
JIT ortamı, jl_init_codegen in codegen.cpp ile erken bir çağrı ile başlatılır.
Talep üzerine, bir Julia yöntemi emit_function(jl_method_instance_t*) fonksiyonu tarafından yerel bir işleve dönüştürülür. (Not: MCJIT kullanıldığında (LLVM v3.4+), her işlev yeni bir modüle JIT edilmelidir.) Bu fonksiyon, tüm işlev yayımlanana kadar emit_expr() fonksiyonunu özyinelemeli olarak çağırır.
Bu dosyanın geri kalan kısmı, belirli kod desenlerinin çeşitli manuel optimizasyonlarına ayrılmıştır. Örneğin, emit_known_call() birçok ilkel fonksiyonu (tanımlı olan builtins.c) argüman türlerinin çeşitli kombinasyonları için inline yapmayı bilir.
Kod oluşturmanın diğer kısımları çeşitli yardımcı dosyalar tarafından yönetilmektedir:
JIT fonksiyonları için geri izleme işlemlerini yönetir
abi_*.cppdosyaları ile birlikte ccall ve llvmcall FFI'yi yönetir.Çeşitli düşük seviyeli içsel işlevlerin yayılımını yönetir
System Image
Sistem görüntüsü, bir dizi Julia dosyasının önceden derlenmiş bir arşividir. Julia ile dağıtılan sys.ji dosyası, sysimg.jl dosyasını çalıştırarak oluşturulan bir sistem görüntüsüdür ve sonuçta elde edilen ortamı (Türler, Fonksiyonlar, Modüller ve tanımlı tüm diğer değerler dahil) bir dosyaya serileştirir. Bu nedenle, Main, Core ve Base modüllerinin (ve başlatma işleminin sonunda ortamda bulunan diğer her şeyin) dondurulmuş bir versiyonunu içerir. Bu serileştirici/serileştirici çözümleyici, jl_save_system_image/jl_restore_system_image in staticdata.c tarafından uygulanmaktadır.
Eğer bir sysimg dosyası yoksa (jl_options.image_file == NULL), bu aynı zamanda komut satırında --build seçeneğinin verildiğini de gösterir, bu nedenle nihai sonuç yeni bir sysimg dosyası olmalıdır. Julia başlatılırken, minimal Core ve Main modülleri oluşturulur. Ardından, mevcut dizinden boot.jl adlı bir dosya değerlendirilir. Julia daha sonra komut satırı argümanı olarak verilen herhangi bir dosyayı değerlendirir ve sona ulaşana kadar devam eder. Son olarak, elde edilen ortamı gelecekteki bir Julia çalışması için başlangıç noktası olarak kullanılmak üzere bir "sysimg" dosyasına kaydeder.