Files
overlookmotel 0b7ce7edd9 perf(linter/plugins): create global prop vars at top level of modules (#22928)
Oxlint's JS-side code is processed by a TSDown plugin that transforms global property accesses to `const`s imported from `globals.ts`. e.g.:

```js
function foo(obj) {
  return Object.keys(obj);
}
```

is transformed to:

```js
import { ObjectKeys } from "./utils/globals.ts";

function foo(obj) {
  return ObjectKeys(obj);
}
```

The purpose of this transform is:

1\. Better perf - avoid a property lookup/check on each call.
2\. More robust in the face of user code (plugins) altering globals e.g. `Object.keys = function myWeirdFunction() {}`.

While delving into the assembly that V8 produces while reviewing #22238, I discovered that in fact the transform was having a _negative_ effect on perf, because TSDown puts the global `const`s in a separate chunk `global.js`. Because the consts are in a different module, this actually makes them _more_ costly to access, rather than less.

In fact, it turns out that TurboFan doesn't insert a check at all in the original code - it instead has machinery to trigger de-opt if the global is reassigned. So the original perf rationale for this transform was completely misguided - it doesn't in fact produce a perf gain at all! We still want to keep it for the robustness advantage, but we don't want it to be perf _loss_, as it was before this PR.

This PR fixes the perf by instead defining consts inline in each file. The example above is now transformed to:

```js
const ObjectKeys = Object.keys;

function foo(obj) {
  return ObjectKeys(obj);
}
```

This also removes the need to manually maintain the `globals.ts` file. It's now automatic.

Additionally, improve the transform in a few minor ways:

1. Support deeper nested global props e.g. `Object.prototype.toString`.
2. Skip converting e.g. `Array.prototype.slice.call(arguments)` (because `.call` requires `this`, so `ArrayPrototypeSliceCall(arguments)` is incorrect).
3. Do replace methods which take `this` (e.g. `Promise.resolve`) when they're not used in a method call.

Note: The robustness advantage of this transform may appear to be marginal, and not worth the bother of having this transform at all. Personally, I think it's worthwhile. Oxlint JS-side code has access to a slice of Rust's memory as a `Uint8Array`. Writing to that buffer could cause UB, reading/writing out of bounds, or other serious problems on Rust side, so IMO it's critical to protect against that in every way we can.
2026-06-03 00:53:31 +00:00
..