Porffor: A from-scratch experimental ahead-of-time JS engine
Project goals and capabilities
- Porffor is presented as an ahead‑of‑time (AOT) JavaScript engine compiling JS/TS to native binaries or WASM, not just bundling an interpreter.
- Aims for high test262 conformance and eventual self‑hosting; currently partially self‑compiles built‑ins.
- Promises are supported but without a full event loop; async I/O and “advanced” async patterns are not yet there.
evalworks only with literal strings; dynamic strings are currently unsupported or error.
Potential use cases and perceived benefits
- Edge/serverless: interest in compiling bundled JS (e.g., from tools like Bun/esbuild) into compact native binaries to improve cold start, RAM use, and deployment size.
- Desire for linkable native libraries (.so) and smaller, less memory‑hungry JS‑based desktop/mobile apps, even without speedup over V8.
- Suggestion that Porffor could help JS compete with WASM‑first stacks like Blazor by delivering JS/TS as WASM/native.
Comparisons to other runtimes/approaches
- Compared to Static Hermes: both target test262, support TS, and can emit WASM; Porffor focuses on self‑hosting and AOT only, Hermes uses LLVM, has an interpreter fallback, and mature async.
- Compared with Bun, Node, QuickJS, etc.: Porffor differs by compiling JS itself to native/WASM instead of shipping a runtime or bytecode interpreter.
- LLVM reliance debated: some value LLVM’s mature optimizations; others argue self‑containment simplifies implementing features like
eval.
Types, static analysis, and performance ceilings
- Extensive discussion on whether JS/TS types can meaningfully improve AOT performance.
- Points raised:
- Modern JITs (e.g., V8) already do aggressive shape analysis; AOT may struggle to beat them without profile‑guided optimizations.
- TypeScript’s design (no int/float distinction, structural subtyping, unsound and complex type system) limits its utility for static layout and aggressive optimization.
- Some argue strong static analysis of plain JS and restricted TS subsets can still yield useful specialization and reduced overhead (including FFI boundary optimizations).
Async, eval, and WASM constraints
- Implementing fully dynamic features (
eval,Function) is hard in pure AOT; suggested approaches include bundling an interpreter or using self‑hosting inside the compiled binary. - WASM’s inability to modify running code complicates JIT‑style eval; workarounds using tables/globals are discussed but noted as complex.
Concerns, limitations, and rough edges
- Worries about:
- The “eval problem” being effectively ignored in practice.
- An “opaque supply chain attack” risk due to a new, complex toolchain.
- Non‑monotonic versioning tied to test262 pass counts.
- Some skepticism that AOT JS can significantly outperform top JIT engines; others say partial gains and better memory/packaging are still worthwhile.
- Early UX issues (e.g., REPL not supporting
help) noted, but overall many commenters are enthusiastic about the experimentation and potential.