
# Teste de performanță

Phasis este **de aproximativ două ordine de mărime mai lent decât V8** pentru JavaScript limitate de dispecerizare. Acest plafon reflectă costul inerent al unui interpretor găzduit de PHP, în comparație cu un compilator JIT nativ. Întrebarea pentru cine îl încorporează nu este „cum se compară cu V8?”, ci „este suficient de rapid pentru ce am eu de făcut?”. Pentru majoritatea sarcinilor de încorporare, răspunsul este da.

## Când plafonul nu contează

- **Șabloane** — randarea tipică a unei pagini în stil SSR durează cu mult sub 10 ms.
- **Reguli de validare** — JS furnizat de utilizator pentru validarea formularelor se execută în microsecunde.
- **Transformări de date** — `array.map(transform)` asupra a sute de elemente se încheie în zeci de milisecunde.
- **Medii de execuție izolată** — scripturile scurte furnizate de utilizator, cu o limită de 1 secundă impusă de gazdă, lasă suficientă rezervă.

## Când plafonul contează

- **Bucle interne intensive în calcule** — procesarea imaginilor, reduceri pe tablouri mari, simulări. Mutați calculele într-o bibliotecă nativă PHP și expuneți-o ca [funcție gazdă](https://phasis.inline0.dev/ro/docs/interop/host-functions).
- **Animație în timp real** — orice rulează la 60 fps. Această JS trebuie să aibă loc în client (browser, aplicație nativă), nu în motorul încorporat.
- **Reimplementări JS ale algoritmilor costisitori din punct de vedere al calculului** — criptografie, comprimare, analiză sintactică. PHP are echivalente native de 1000× mai rapide; folosiți-le.

Modelul mental potrivit: Phasis este un **strat de legătură** pentru logica de tip JS încorporată în aplicații de tip PHP. Gazda PHP gestionează calculele; stratul JS gestionează configurarea, ramificarea și transformările mici.

## Ce face motorul rapid (comparativ cu un traversor de arbore naiv)

- **VM de bytecode** — majoritatea operațiilor hot de dispatch trec prin comutatorul de opcoduri al `VM::execute`, nu prin AST.
- **Callstack personalizat** — fiecare apel JS păstrează starea în `VM::execute` și salvează cadrul apelantului într-un pool; nu se creează un cadru PHP nou pentru fiecare apel JS. Consultați [VM de bytecode § Callstack personalizat](https://phasis.inline0.dev/ro/docs/advanced/bytecode-vm).
- **Cache-uri inline** — un cache monomorf per PC face ca citirile metodei prototipului pe instanță (forma `c.method()`) să sară peste parcurgerea lanțului de prototipuri.
- **Generatoare cu instantanee de cadre** — corpurile simple ale generatoarelor se suspendă capturând starea de dispatch într-un obiect heap, în loc să treacă printr-un Fiber PHP.
- **Transpiler JsToPhp** — corpurile axate pe valori numerice/localuri (inclusiv citirile `obj.method()`, `new Ctor()` și `this.member`) sunt compilate în closure-uri PHP, pe care JIT-ul de trasare al versiunii PHP 8.5 le transformă în cod mașină nativ.
- **Cache JSON.stringify** — `JSON.stringify(o)` își memorează rezultatul pe obiectul de intrare, cu invalidare tranzitivă a versiunilor, accelerând idiomul de clonare profundă `JSON.parse(JSON.stringify(o))`.

## Măsurarea propriului volum de lucru

```bash
php bench/run.php
```

Aceasta rulează suita de microbenchmark-uri livrată în `bench/microbench.js` — câteva sarcini sintetice (aritmetică în bucle, funcții recursive, crearea obiectelor, apeluri de metode ale prototipului, push în array, round-trip JSON etc.) și afișează timpul median per test. Utilă ca verificare orientativă; valorile curente sunt salvate în [`BENCH.md`](https://github.com/inline0/phasis/blob/main/BENCH.md) la fiecare rulare CI de benchmark.

Pentru propriul cod, înlocuiți cu orice script:

```bash
php -d xdebug.mode=off bench/run.php path/to/your-script.js
```

Pentru profilarea la nivel de PHP, profilerul Xdebug funcționează cu Phasis exact ca orice altă aplicație PHP. Rulați un script sub `xdebug.mode=profile` și inspectați rezultatul cachegrind pentru a vedea care clase `Phasis\` domină.

## Plan de dezvoltare

Ce ar reduce mai mult diferența față de V8, în ordinea aproximativă a dificultății:

- **Cache-uri inline polimorfe** — permiteți unui singur punct de apel `LOAD_MEMBER` să păstreze 2-4 forme în cache înainte de a reveni la dispatch lent. Ajută codul care procesează receptori eterogeni.
- **`yield*` și try-with-yield pe calea generatorului cu instantanee de cadre** — aceste forme sunt direcționate în prezent către parcurgătorul arborescent bazat pe Fiber. Fiecare necesită tratare explicită cu mașină de stări (redirecționarea iteratorului delegat, păstrarea stivei de handlere pe durata suspendării) înainte de a putea fi capturată în siguranță.
- **Generatoare asincrone și `await` pe instantanee** — specificația combină suspendarea generatorului cu coada de microtask-uri. Odată ce corpul bytecode acceptă atât `yield`, cât și `await`, generatoarele asincrone vor putea folosi și ele instantanee.
- **Inferența tipurilor parametrilor în JsToPhp** — parametrii funcțiilor au implicit tip numeric, așa că `function (obj) { obj.method() }` determină renunțarea compilatorului. Inferarea parametrilor de tip obiect din modul în care sunt folosiți în corp ar permite apelurile de metode asupra argumentelor funcțiilor, fără a cere ca receptorul să fie construit local prin `new`.
- **Emitere directă de opcoduri opcache** — săriți peste etapa `eval()` a JsToPhp scriind direct opcoduri în format opcache. Cel mai amplu element; celelalte pot fi realizate în arhitectura existentă.

Niciuna dintre acestea nu este necesară pentru sarcinile de integrare vizate de Phasis.
