Files
Dunqing 2f5cdb1231 feat(minifier): add property name mangling (#24740)
Oxc can shorten variable names and private class names, but it cannot shorten property names such as `obj._field`. This change adds optional property mangling. It replaces #23772 and gives bundlers a way to use the same property names across several files.

### Feature

- `include` selects names to mangle. `exclude` and `reserved` keep names unchanged.
- The cache can give a property a fixed output name or keep it unchanged.
- The mangler supports member access, object and class keys, destructuring, optional chains, the left side of `in`, and JSX property names.
- `mangle_quoted` also handles strings and template literals used directly as property keys. `/* @__KEY__ */` and `/* #__KEY__ */` can mark one other string or template literal as a property key.
- Short names are assigned in a stable order. More common properties get shorter names. Existing and reserved names are avoided.
- Bundlers can collect names from several programs, create one shared map, and apply it to every program.
- Numeric keys, `__proto__`, `constructor`, `prototype`, TypeScript-only keys, and private names are never changed by this pass.

### Design

Property names are part of JavaScript syntax, not local scope. For this reason, the code lives in `oxc_minifier`. It only reuses the short-name generator from `oxc_mangler`.

For one program, the order is:

```text
collect names → assign names → rewrite once → compress → mangle variables and private names
```

Property names are rewritten before compression because compression can remove information about quotes and comments.

For several programs, a bundler collects names from each program, merges the results, assigns one shared map, and rewrites each program once. Collection can run in parallel. All programs must use the same options.

The shared map keeps property names consistent inside one build. The cache has a different job: it keeps fixed names and reservations across separate minify calls.

### Example

With `include: "^_"` and `mangle_quoted: true`:

```js
obj[`_field`] = 1;
obj._field = 2;
```

becomes:

```js
obj[`e`] = 1;
obj.e = 2;
```

### Limitation

- Property mangling is unsafe when other code still uses the old property name. Public APIs and names shared with external code, host APIs, imported namespace objects, or separate builds must be excluded or reserved.
- Quote handling is per use. Without `mangle_quoted`, `obj._field` may change while `obj["_field"]` does not.
- The mangler cannot find names built at runtime or stored in arbitrary strings. Code that uses `eval`, `Function`, or `with` must reserve any affected names.
- Compression may create a matching property after this pass has finished. For example, `'f' + 'oo_'` may later become `foo_` and will not be mangled.
- TypeScript enum reverse mappings are not supported because the transform creates quoted strings.
- Multi-program support is a caller API. The caller must collect every program that shares mangled properties before assigning names.

The public `oxc-minify` API is stacked in #24741. The downstream multi-chunk integration is shown in rolldown/rolldown#10374.

Supersedes #23772.

AI assistance: OpenAI Codex and Claude were used for research, implementation, review, and testing. The contributor is responsible for reviewing and understanding the changes before submission.
2026-08-17 07:50:51 +00:00
..

Oxc allocations stats

This task keeps track of the number of system allocations as well as arena allocations and the total number of bytes allocated. This is used for monitoring possible regressions in allocations and improvements in memory usage.

Update the snapshots with cargo allocs.

Metrics

Recorded per file and per stage (parser, semantic, transformer, minifier, formatter):

  • file size - size of the source text
  • sys allocs / sys reallocs / sys deallocs - system allocator activity during the stage
  • sys alloc bytes - total bytes requested from the system allocator during the stage (allocation sizes plus reallocation growth)
  • sys peak growth - high-water mark of live heap memory during the stage, relative to the live bytes when the stage started; captures transient heap the stage needs even when it frees it again before finishing
  • arena allocs / arena reallocs - arena allocator activity during the stage
  • arena size - bytes used in the arena at the end of the stage (cumulative: the arena is not reset between stages, so this includes the AST built by the parser)

Arena chunk allocations and deallocations are excluded from all sys metrics: chunk sizes are quantized and platform-dependent (whether an arena needs one more chunk depends on byte totals that vary across architectures), and for long-lived arenas chunk growth reflects the arena's history rather than the stage's own behavior. Arenas mark their chunk operations for the tracking allocator to skip.

Cross-platform reproducibility

Allocation counts are identical on all platforms: the task pins mimalloc as the global allocator and excludes arena chunk allocations from the system allocation counts. arena size is not exactly reproducible: type layout differs slightly across architectures (e.g. hashbrown's table control groups are 16 bytes on x86_64 vs 8 bytes on aarch64), which shifts arena byte totals by up to ~128 bytes per file. So that a snapshot generated on any platform passes CI on the others, the snapshots are YAML: cargo allocs parses the committed snapshot and keeps a byte metric's committed value when the measured one is within that metric's tolerance (arena size: 1024 bytes; sys alloc bytes and sys peak growth: 1%, minimum 4 kB); only differences beyond the tolerance rewrite the value.