Object.create instead of __proto__ literals (#27816)
## Summary
oxlint's raw transfer deserializer creates every AST node as an object
literal with `__proto__: NodeProto` (for the lazy `loc` getter). V8
creates such object literals on a slow path: it builds a plain object,
then changes its prototype with a runtime call.
This PR changes the raw transfer codegen (`LocFieldAdder` in
`tasks/ast_tools/src/generators/raw_transfer.rs`) to create nodes with
`Object.create(NodeProto)` followed by property assignments:
```js
// `main`
node = (parent = { __proto__: NodeProto, type: "CallExpression", callee: null, /* ... */ });
// This PR
node = (parent = (node$0 = Object.create(NodeProto), node$0.type = "CallExpression", node$0.callee = null, /* ... */ node$0));
```
Nodes keep the same prototype, own properties, property order and
attributes. `napi/parser`'s deserializers are unaffected.
## Benchmark
Deserialization time when linting
[vscode](https://github.com/microsoft/vscode) @ `3db52ff` (15,122 files,
53.4M AST nodes) with a single JS rule which visits `DebuggerStatement`
(to make sure deserialization isn't eliminated as dead code). Apple M4
Pro, Node 26.5.0, release build.
Measured by timing each [`deserializeProgramOnly` call in
`initAst`](https://github.com/oxc-project/oxc/blob/6fe4c1b9117a35561fb40b843da92a3bdbe2bff3/apps/oxlint/src-js/plugins/source_code.ts#L86)
with `performance.now()` (local instrumentation, not part of this PR),
summed over all 15,086 deserialized files. Medians of 5 interleaved
runs, after a warmup run.
| | Deserialize |
|---|--:|
| `main` | 4.49 s |
| This PR | 0.91 s (**4.9×** faster) |
---
AI disclosure: this PR was written with AI assistance (Claude Code).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
⚓ Oxc
/oʊ ɛks siː/
The Oxidation Compiler is a collection of high-performance tools for JavaScript and TypeScript written in Rust.
Oxc is part of VoidZero's vision for a unified, high-performance toolchain for JavaScript. It powers Rolldown (Vite's bundler) and enables the next generation of ultra-fast development tools that work seamlessly together.
For more information, check out our website at oxc.rs.
* Oxidation is the chemical process that creates rust
🙋 Who's using Oxc?
Rolldown and Nuxt use Oxc for parsing. Rolldown also uses Oxc for transformation and minification. Nova, swc-node, and knip use oxc_resolver for module resolution. Preact, Shopify, ByteDance, and Shopee use oxlint for linting.
🔧 Lint or Format a Codebase
🧰 Build Tooling on Top of Oxc
- Parse JavaScript and TypeScript: Parser
- Transform TypeScript, JSX, and modern JavaScript: Transformer
- Minify JavaScript for production builds: Minifier
- Resolve modules for JavaScript and TypeScript: Resolver
✍️ Contribute
Check out some of the good first issues or ask us on Discord.
See CONTRIBUTING.md for guidance, or read the complete contributing guide on our website →
If you are unable to contribute by code, you can still participate by:
- Add a GitHub Star to the project
- Join us on Discord
- Follow me on X and post about this project
📚 Other Resources
Sponsored By
📖 License
Oxc is free and open-source software licensed under the MIT License.
Thank you to namespace.so for powering our CI/CD pipelines with fast, free macOS and Linux runners.
Oxc ports or copies code from other open source projects, their licenses are listed in Third-party library licenses.