Charles Wang 481b638b70 perf(linter/plugins): create AST nodes with 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)
2026-10-29 01:14:18 +00:00
…



Oxc logo


MIT licensed Build Status Code Coverage CodSpeed Badge

Discord chat Playground Website

⚓ 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.

See more projects using Oxc →

🔧 Lint or Format a Codebase

  • Lint: Oxlint — npx oxlint@latest
  • Format: Oxfmt — npx oxfmt@latest

🧰 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:

📚 Other Resources

Sponsored By

Our sponsors

📖 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.

Languages
Rust 80.6%
JavaScript 12.3%
TypeScript 7%