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.
  • eval works 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.