Tolok Ukur
Phasis kira-kira dua orde magnitudo lebih lambat daripada V8 pada JavaScript yang dibatasi oleh dispatch. Batas atas itu merupakan biaya bawaan interpreter yang di-host oleh PHP dibandingkan dengan compiler JIT native. Pertanyaan bagi embedder bukanlah "bagaimana perbandingannya dengan V8" — melainkan "apakah cukup cepat untuk kebutuhan saya." Untuk sebagian besar beban kerja embedding, jawabannya ya.
Saat batas atas tidak menjadi masalah
- Templating — render gaya SSR untuk halaman biasa dalam waktu jauh di bawah 10 ms.
- Aturan validasi — JS yang diberikan pengguna untuk validasi formulir selesai dalam hitungan mikrodetik.
- Transformasi data —
array.map(transform)pada ratusan item selesai dalam hitungan puluhan milidetik. - Runner sandbox — skrip singkat dari pengguna dengan batas host 1 detik menyisakan banyak ruang.
Saat batas atas menjadi masalah
- Loop dalam yang berat komputasi — pemrosesan gambar, reduksi array besar, simulasi. Pindahkan komputasinya ke pustaka PHP native dan ekspos sebagai fungsi host.
- Animasi real-time — apa pun yang berjalan pada 60 fps. JS tersebut sebaiknya berada di klien (browser, aplikasi native), bukan di engine tertanam.
- Implementasi ulang JS untuk algoritma yang mahal secara komputasi — kriptografi, kompresi, parsing. PHP memiliki padanan native yang 1000× lebih cepat; gunakan padanan tersebut.
Model mental yang tepat: Phasis adalah lapisan perekat untuk logika berbentuk JS yang disematkan dalam aplikasi berbentuk PHP. Host PHP menangani komputasi; lapisan JS menangani konfigurasi, percabangan, dan transformasi kecil.
Hal yang membuat engine cepat (dibandingkan tree-walker naif)
- VM Bytecode — sebagian besar dispatch yang sering terjadi berjalan melalui switch opcode milik
VM::execute, bukan AST. - Call stack khusus — setiap pemanggilan JS menjaga status di dalam
VM::executedan menyimpan frame pemanggil ke dalam pool; tidak ada frame PHP baru untuk setiap pemanggilan JS. Lihat VM Bytecode § Call stack khusus. - Cache inline — cache monomorfik per-PC membuat pembacaan metode prototipe pada instans (pola
c.method()) melewati penelusuran rantai prototipe. - Generator snapshot frame — isi generator sederhana ditangguhkan dengan menangkap status dispatch ke objek heap, alih-alih melintasi Fiber PHP.
- Transpiler JsToPhp — isi fungsi yang berat pada numerik / variabel lokal (termasuk pembacaan
obj.method(),new Ctor(), danthis.member) dikompilasi menjadi closure PHP yang diturunkan oleh tracing JIT PHP 8.5 menjadi kode mesin native. - Cache JSON.stringify —
JSON.stringify(o)menyimpan output-nya pada objek masukan dengan invalidasi versi transitif, mempercepat idiom deep-cloneJSON.parse(JSON.stringify(o)).
Mengukur beban kerja Anda sendiri
php bench/run.php
Perintah ini menjalankan rangkaian microbench yang disertakan di bench/microbench.js — beberapa beban kerja sintetis (aritmetika loop, fungsi rekursif, pembuatan objek, pemanggilan metode prototipe, penambahan array, bolak-balik JSON, dan sebagainya) dan mencetak median waktu nyata untuk tiap pengujian. Berguna sebagai pemeriksaan kewajaran; angka saat ini di-commit ke BENCH.md pada setiap kali CI menjalankan benchmark.
Untuk kode Anda sendiri, ganti dengan skrip apa pun:
php -d xdebug.mode=off bench/run.php path/to/your-script.js
Untuk pembuatan profil tingkat PHP, profiler Xdebug bekerja dengan Phasis sama seperti pada aplikasi PHP lainnya. Jalankan skrip melalui xdebug.mode=profile dan periksa output cachegrind untuk melihat kelas Phasis\ mana yang paling dominan.
Peta jalan
Hal-hal yang paling berpotensi memperkecil kesenjangan V8, diurutkan secara kasar berdasarkan tingkat kemudahan penerapan:
- Cache inline polimorfik — izinkan satu titik pemanggilan
LOAD_MEMBERmenyimpan 2-4 bentuk cache sebelum kembali ke dispatch lambat. Membantu kode yang memproses receiver heterogen. yield*dan try-with-yield pada jalur generator snapshot frame — bentuk-bentuk ini saat ini dialihkan ke tree-walker berbasis Fiber. Masing-masing memerlukan penanganan state machine secara eksplisit (penerusan delegate-iterator, stack handler yang dipertahankan selama suspend) sebelum aman untuk snapshot.- Generator asinkron dan
awaitpada snapshot — spesifikasi menggabungkan penangguhan generator dengan antrean microtask. Setelah isi bytecode mendukungyielddanawait, generator asinkron juga akan kompatibel dengan snapshot. - Inferensi tipe parameter di JsToPhp — parameter fungsi secara default bertipe numerik, sehingga
function (obj) { obj.method() }membuat compiler keluar lebih awal. Inferensi parameter bertipe objek berdasarkan penggunaannya di dalam isi fungsi akan memungkinkan pemanggilan metode pada argumen fungsi tanpa mengharuskan receiver dibuat secara lokal melaluinew. - Emisi opcache langsung — lewati langkah
eval()milik JsToPhp dengan menulis opcode berformat opcache secara langsung. Ini item yang paling rumit; yang lain dapat dikerjakan dalam arsitektur yang ada.
Semua ini tidak diperlukan untuk beban kerja embedding yang ditargetkan Phasis.