#8298 made `Span` aligned on 8 on 64-bit platforms. Utilize this property to compare `Span`s as a single `u64` instead of 2 x `u32`s. This removes some really weird assembly which compiler otherwise produces, using expensive SIMD operations for a simple comparison: https://godbolt.org/z/sEf9MGvsr
Note: This only affects comparing `&Span`s. Makes no difference when comparing owned `Span`s.
#8298 made `Span` aligned on 8 on 64-bit platforms. Utilize this property to hash `Span` as a single `u64` instead of 2 x `u32`s. This reduces hashing a `Span` with `FxHash` to 3 instructions (down from 7), and 1 register (down from 3). https://godbolt.org/z/4q36xrWG8
`Span` consists of 2 x `u32` (8 bytes total). Align `Span` on 8 bytes on 64-bit platforms. This means that, on 64-bit platforms, `Span` can be treated as equivalent to a `u64` and stored in a single register (instead of requiring 2).
A side-effect is that all AST structs also become aligned on 8. This will be a useful property later on as we can remove alignment calculations from `Allocator::alloc` (since everything now has same alignment).
`BooleanLiteral` (and `BoundaryAssertion`, `CharacterClassEscape` and `IndexedReference` from `oxc_regular_expression` crate) increase from 12 bytes to 16 bytes due to the higher alignment. But this makes no practical difference as they'd almost always end up with padding around them in arena anyway, as they'll be surrounded by 8-aligned types.
The lexer benchmarks had a problem. The lexer alone cannot make sense of regexp literals, template literals, or JSX text elements - it needs the parser "driving" it.
So lexer was producing plenty of errors on some benchmarks. This is unrealistic - when driven by the parser, the lexer produces no errors. Generating diagnostics is relatively expensive, so this was skewing the benchmarks somewhat.
Solve this by cleaning up the input source text to replace these syntaxes with string literals prior to running the benchmarks.
Unfortunately lexer benchmarks don't exercise the code paths for these syntaxes, but there isn't much we can do about that. We can judge by the parser benchmarks, which are the more important ones anyway.
Add `#[inline]` or `#[inline(always)]` to many of `Box`'s methods. In particular, `Box::new_in` should absolutely always be inlined, for the same reasons that `Allocator::alloc` should be.
Prevent memory leaks by statically preventing `Drop` types from being allocated in the arena.
Attempting to allocate any `Drop` type in the arena now produces a compilation failure.
The stabilization of `const {}` blocks in Rust 1.79.0 gave the mechanism required to enforce this at compile time without a mess of generics and traits, and in a way which should not hurt compile times (and zero runtime cost).
This PR is what discovered `CompactString`s being stored in arena in the mangler (fixed in #8557).
Note: The compilation failure occurs in `cargo build` not `cargo check`. So unfortunately errors don't appear in Rust Analyser, only when you run `cargo build`. From what I've read, stable Rust does not offer any solution to this at present. But the errors are reasonably clear what the problem is, and point to the line where it occurs.
Do not expose that our arena allocator is based on Bumpalo, by removing `Deref` and `DerefMut` impls. Instead implement the methods we use on `Allocator` itself.
That our allocator is based on Bumpalo is now an internal implementation detail. This will allow us to replace the allocator in future, and enables statically preventing `Drop` types from being stored in the arena (next PR in this stack).
I've intentionally only implemented a small subset of `Bump`'s methods - only `alloc`, `alloc_str`, and `reset`. This will make it simpler to implement a new allocator in future, without having to cover all of bumpalo's large API surface. In the meantime, if it turns out we need additional methods, it will be simple to add them, by just delegating to that method on `Bump`.
Wrap `bumpalo::collections::String` in a new type instead of exporting it directly. This opens the door to:
1. Replacing it with our own `String` type which wraps our `Vec` type, rather than having 2 different implementations of `Vec` (`String` is just a wrapper around `Vec`, but a *different* `Vec` implementation).
2. Adding additional methods to `String` (`String::from_utf8` added in this PR).
- Enhanced default_param_last to handle optional parameters based on the
corresponding typescript-eslint rule.
- Added additional test cases from the typescript-eslint rule.
Closes https://github.com/oxc-project/oxc/issues/8556
CI Clippy task catch lint errors which only appear in release mode (e.g. the one fixed in #8539).
Add a profile for this. `cargo clippy --profile dev-no-debug-assertions` is about 35% faster than `cargo clippy --release` (and is slightly faster than plain `cargo clippy`) but catches the same problems.
This slows down the Clippy CI task, but it still remains faster than running conformance, so I don't think it's likely to slow down CI overall.
There are many `eslint-plugin-vitest` rules that have an equivalent Rust
implementation for the Jest plugin. This PR ports all Jest rules that
passes the Vitest plugin's unit tests.
Some existing Jest rule implementations are not included in the
compatible list, for example:
- `no-large-snapshots` - difference in config initial values
- `no-mocks-import` - mention of the word "Jest" in diagnostics
- `prefer-called-with` - Vitest plugin implements a fix but Jest plugin
didn't
- `prefer-spy-on` - mention of the word "Jest" in diagnostics
- `prefer-to-contain` - the fix is missing
- `valid-title` - configuration options are slightly different
To get a list of already implemented Jest rules, simply run:
```bash
ls crates/oxc_linter/src/rules/jest | sed 's/\.rs$//;s/_/-/g'
```
Optimize mangler by creating identifiers in an inline array, instead of using the more expensive `CompactString`, and optimize `base54` function.
There's an unfortunate workaround necessary because of debug mode. In "normal" mode, identifiers are maximum 11 bytes (`usize::MAX` -> `ZrN6rN6rN6r`) but in debug mode they can be up to 25 bytes (`usize::MAX` -> `slot_18446744073709551615`). So this PR splits `build_with_symbols_and_scopes` into 2 branches for "normal" and "debug" modes with a generic function parameterized by max length of the string.
This is not ideal - it will increase binary size a bit, but everything else I tried (e.g. allocating strings into arena) was much slower.
The main motivation for this change wasn't actually performance. While working on allocator, I discovered that `CompactString`s were being allocated in arena (`reserved_names: ArenaVec<CompactStr>`), and wanted to remove them.
Use `oxc_allocator::HashMap` in `ScopeTree`, replacing `hashbrown::HashMap`. `oxc_allocator::HashMap` is non-drop, so it may reduce drop time of `ScopeTree` a little.
Add `HashMap` type to `oxc_allocator`. `HashMap` is a thin wrapper around `hashbrown::HashMap`, which allocates in the arena. The inner map is wrapped in `ManuallyDrop`, so `HashMap` is non-`Drop` (same as `oxc_allocator::Vec`).
We use `FxHasher` for all hash maps, so I figured just make that part of the type, rather than having to specify the hasher everywhere we use `HashMap`.
Remove line from `oxc_allocator::Vec` docs saying "Should only be used for storing AST types.". We are now using `Vec` in `Semantic` too, and there's no problem with that.
Fix spans in class static blocks and class properties transforms. When a static block is converted to an IIFE, the IIFE should take the span of the static block.
#8530 introduced a small change. Previously the IIFE had the span of the original expression which is being wrapped, but after that PR it got a dummy `SPAN`. Fix that.
Follow-on after #8529. Pure refactor. `wrap_arrow_function_iife` receive an owned `Expression`, instead of `&mut Expression`.
This does require a bit more repeated code in the caller, but still I think it's more appropriate for a utility function. If we use it again elsewhere, it's non-obvious if it replaces the input `&mut Expression` with a `NullLiteral` via `move_expression`. Better to leave that to the caller.