
# Benchmarkresultater

Phasis er **omtrent to størrelsesordener langsommere end V8** ved dispatch-begrænsede JavaScript. Denne grænse skyldes den iboende omkostning ved en fortolker hostet i PHP sammenlignet med en native JIT-compiler. Spørgsmålet for en indlejrer er ikke "hvordan klarer den sig mod V8" — men "er den hurtig nok til det, jeg laver." For de fleste indlejringsarbejdsbelastninger er svaret ja.

## Når grænsen ikke betyder noget

- **Skabelongengivelse** — SSR-lignende gengivelse af en typisk side på langt under 10 ms.
- **Valideringsregler** — brugerleveret JS til formularvalidering afsluttes på mikrosekunder.
- **Datatransformationer** — `array.map(transform)` over hundredvis af elementer afsluttes på titals millisekunder.
- **Sandbox-kørsler** — korte brugerleverede scripts med en værtsgrænse på 1 sekund efterlader masser af råderum.

## Når grænsen betyder noget

- **Beregningsintensive indre løkker** — billedbehandling, reduktioner over store arrays, simuleringer. Flyt beregningen til et native PHP-bibliotek, og eksponér det som en [værtsfunktion](https://phasis.inline0.dev/da/docs/interop/host-functions).
- **Animation i realtid** — alt, der driver 60 fps. Den slags JS hører hjemme i klienten (browser, native app), ikke i den indlejrede motor.
- **JS-genimplementeringer af beregningstunge algoritmer** — kryptografi, komprimering, parsing. PHP har native ækvivalenter, der er 1000× hurtigere; brug dem.

Den rette mentale model: Phasis er et **limlag** til logik formet som JS, indlejret i applikationer formet som PHP. Værten i PHP håndterer beregning; laget i JS håndterer konfiguration, forgreninger og små transformationer.

## Hvad der gør motoren hurtig (sammenlignet med en naiv træfortolker)

- **Bytecode-VM** — det meste hot dispatch går gennem `VM::execute`s opcode-switch, ikke AST'en.
- **Brugerdefineret kaldestak** — hvert JS-kald holder tilstanden i `VM::execute` og gemmer kalderens frame i en pool; ingen ny PHP-frame for hvert JS-kald. Se [Bytecode VM § Brugerdefineret kaldestak](https://phasis.inline0.dev/da/docs/advanced/bytecode-vm).
- **Inline-caches** — en monomorf cache pr. PC gør, at opslag af prototypemetoder på instanser (formen `c.method()`) springer gennemgangen af prototypekæden over.
- **Generators med framesnapshot** — enkle generator-bodies suspenderes ved at indfange dispatch-tilstanden i et heap-objekt i stedet for at passere gennem en PHP Fiber.
- **JsToPhp-transpilerer** — bodies med mange tal eller lokale variabler (herunder læsninger af `obj.method()`, `new Ctor()` og `this.member`) kompileres til PHP-closures, som PHP 8.5 sænker til native maskinkode med sin tracing-JIT.
- **JSON.stringify-cache** — `JSON.stringify(o)` cacher sit output på inputobjektet med transitiv versionsinvalidering og gør dermed deep-clone-idiomet `JSON.parse(JSON.stringify(o))` hurtigere.

## Mål din egen arbejdsbelastning

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

Dette kører mikrobenchmark-pakken, der leveres under `bench/microbench.js` — en håndfuld syntetiske arbejdsbelastninger (løkkearitmetik, rekursive funktioner, objektoprettelse, kald af prototypemetoder, array-push, JSON tur-retur osv.) og udskriver medianvæggtid pr. test. Nyttigt som et hurtigt tjek; de aktuelle tal er gemt i [`BENCH.md`](https://github.com/inline0/phasis/blob/main/BENCH.md) ved hver CI-benchmarkkørsel.

For din egen kode kan du indsætte et vilkårligt script:

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

Til profilering på PHP-niveau fungerer Xdebugs profiler med Phasis præcis som med enhver anden PHP-applikation. Kør et script under `xdebug.mode=profile`, og undersøg cachegrind-outputtet for at se, hvilke `Phasis\`-klasser der dominerer.

## Køreplan

Hvad der vil mindske forskellen til V8 mest, sorteret omtrent efter hvor let det er at gennemføre:

- **Polymorfe inline-caches** — lad et enkelt `LOAD_MEMBER`-kaldested holde 2-4 cachede former, før det falder tilbage til langsom dispatch. Hjælper kode, der behandler heterogene modtagere.
- **`yield*` og try-with-yield på generatorstien med framesnapshot** — disse former går i øjeblikket til den Fiber-baserede træfortolker. Hver kræver eksplicit tilstandsmaskinehåndtering (videresendelse af delegeret iterator, handlerstak bevaret under suspendering), før de kan bruge snapshots.
- **Async generators og `await` på snapshots** — specifikationen kombinerer generatorsuspendering med microtask-køen. Når bytecode-bodyen understøtter både `yield` og `await`, kan async generators også bruge snapshots.
- **Inferens af parametertyper i JsToPhp** — funktionsparametre får som standard typen tal, så `function (obj) { obj.method() }` får compileren til at give op. Udledning af parametre med objekttype ud fra deres brug i bodyen ville muliggøre metodekald på funktionsargumenter uden at kræve, at modtageren oprettes lokalt via `new`.
- **Direkte emission af opcache** — spring JsToPhp's `eval()`-trin over ved at skrive opcodes direkte i opcache-format. Det mest omfattende punkt; de øvrige kan gennemføres inden for den eksisterende arkitektur.

Intet af dette er nødvendigt for de indlejringsarbejdsbelastninger, Phasis retter sig mod.
