Skip to content

Conversation

@overlookmotel
Copy link
Member

@overlookmotel overlookmotel commented Oct 16, 2024

oxc_allocator::Vec is intended for storing AST types in the arena. Vec is intended to be non-drop, because all AST types are non-drop. If they were not, it would be a memory leak, because those types will not have drop called on them when the allocator is dropped.

However, oxc_allocator::Vec is currently a wrapper around allocator_api2::vec::Vec, which is drop. That unintentionally makes oxc_allocator::Vec drop too.

This PR fixes this by wrapping the inner allocator_api2::vec::Vec in ManuallyDrop. This makes oxc_allocator::Vec non-drop.

The wider consequence of this change is that the compiler is now able to see that loads of other types which contain oxc_allocator::Vec are also non-drop. Once it can prove that, it can remove a load of code which handles dropping these types in the event of a panic. This probably also then allows it to make many further optimizations on that simplified code.

Strictly speaking, this PR is a breaking change. If oxc_allocator::Vec is abused to store drop types, then in some circumstances this change could produce a memory leak where there was none before. However, we've always been clear that only non-drop types should be stored in the arena, so such usage was always a bug.

#6622 fixes the only place in Oxc where we mistakenly stored non-drop types in Vec.

The change to oxc_prettier is because compiler can now deduce that Doc is non-drop, which causes clippy to raise a warning about using then instead of then_some.

As follow-up, we should:

  1. Wrap other allocator_api2 types (e.g. IntoIter) in ManuallyDrop too, so compiler can prove they are non-drop too (or reimplement Vec ourselves - test: reduce size of vec #6488).
  2. Introduce static checks to prevent non-drop types being used in Box and Vec, to make memory leaks impossible, and detect them at compile time.

@graphite-app
Copy link
Contributor

graphite-app bot commented Oct 16, 2024

Your org has enabled the Graphite merge queue for merging into main

Add the label “0-merge” to the PR and Graphite will automatically add it to the merge queue when it’s ready to merge. Or use the label “hotfix” to add to the merge queue as a hot fix.

You must have a Graphite account and log in to Graphite in order to use the merge queue. Sign up using this link.

Copy link
Member Author

overlookmotel commented Oct 16, 2024

@github-actions github-actions bot added the C-cleanup Category - technical debt or refactoring. Solution not expected to change behavior label Oct 16, 2024
@overlookmotel overlookmotel changed the title refactor(allocator): make Vec non-drop fix(allocator)!: make Vec non-drop Oct 16, 2024
@github-actions github-actions bot added the C-bug Category - Bug label Oct 16, 2024
@codspeed-hq
Copy link

codspeed-hq bot commented Oct 16, 2024

CodSpeed Performance Report

Merging #6623 will improve performances by 8.41%

Comparing 10-16-refactor_allocator_make_vec_non-drop (e1c2d30) with main (de99391)

Summary

⚡ 3 improvements
✅ 27 untouched benchmarks

Benchmarks breakdown

Benchmark main 10-16-refactor_allocator_make_vec_non-drop Change
transformer[antd.js] 50.4 ms 47.7 ms +5.73%
transformer[checker.ts] 20.2 ms 18.6 ms +8.41%
transformer[pdf.mjs] 7.6 ms 7 ms +8.01%

@overlookmotel overlookmotel force-pushed the 10-16-refactor_allocator_make_vec_non-drop branch from 90ddf67 to 749695e Compare October 16, 2024 12:52
@Boshen
Copy link
Member

Boshen commented Oct 16, 2024

What does this all mean?

@overlookmotel
Copy link
Member Author

@Boshen I think this change is worthwhile. It's improving perf pretty much across the board, and #6626 demonstrates that it does not introduce any memory leaks within Oxc.

However, we should probably first check that Rolldown is not erroneously using Vec to store any drop types. I think that's doubtful, but if it was, this change would produce a memory leak in Rolldown. What's the easiest way to do that? Build Rolldown on top of #6626?

Alternatively, we could hold off merging this until we have static checks (like #6626, but more robust) that make it impossible to put Drop types into Box / Vec / the arena.

@Dunqing Dunqing force-pushed the 10-16-fix_isolated_declarations_fix_memory_leak branch from 7156eaa to 2673397 Compare October 16, 2024 15:05
Base automatically changed from 10-16-fix_isolated_declarations_fix_memory_leak to main October 16, 2024 15:10
@Dunqing Dunqing force-pushed the 10-16-refactor_allocator_make_vec_non-drop branch from 8ddc979 to 3e8b3ed Compare October 16, 2024 15:10
@overlookmotel overlookmotel force-pushed the 10-16-refactor_allocator_make_vec_non-drop branch from 3e8b3ed to 45bdb68 Compare October 16, 2024 15:34
@Boshen Boshen self-assigned this Oct 17, 2024
@Boshen
Copy link
Member

Boshen commented Oct 17, 2024

I'll test Rolldown after the next oxc release.

@overlookmotel overlookmotel marked this pull request as ready for review October 17, 2024 15:44
@overlookmotel
Copy link
Member Author

OK great. I think this can be merged then. I'll leave it to you to merge Boshen in case you want to check the code first.

@Boshen Boshen added the 0-merge Merge with Graphite Merge Queue label Oct 19, 2024
Copy link
Member

Boshen commented Oct 19, 2024

Merge activity

  • Oct 19, 11:43 AM EDT: The merge label '0-merge' was detected. This PR will be added to the Graphite merge queue once it meets the requirements.
  • Oct 19, 11:43 AM EDT: A user added this pull request to the Graphite merge queue.
  • Oct 19, 11:48 AM EDT: A user merged this pull request with the Graphite merge queue.

`oxc_allocator::Vec` is intended for storing AST types in the arena. `Vec` is intended to be non-drop, because all AST types are non-drop. If they were not, it would be a memory leak, because those types will not have `drop` called on them when the allocator is dropped.

However, `oxc_allocator::Vec` is currently a wrapper around `allocator_api2::vec::Vec`, which *is* drop. That unintentionally makes `oxc_allocator::Vec` drop too.

This PR fixes this by wrapping the inner `allocator_api2::vec::Vec` in `ManuallyDrop`. This makes `oxc_allocator::Vec` non-drop.

The wider consequence of this change is that the compiler is now able to see that loads of other types which contain `oxc_allocator::Vec` are also non-drop. Once it can prove that, it can remove a load of code which handles dropping these types in the event of a panic. This probably also then allows it to make many further optimizations on that simplified code.

Strictly speaking, this PR is a breaking change. If `oxc_allocator::Vec` is abused to store drop types, then in some circumstances this change could produce a memory leak where there was none before. However, we've always been clear that only non-drop types should be stored in the arena, so such usage was always a bug.

#6622 fixes the only place in Oxc where we mistakenly stored non-drop types in `Vec`.

The change to `oxc_prettier` is because compiler can now deduce that `Doc` is non-drop, which causes clippy to raise a warning about using `then` instead of `then_some`.

As follow-up, we should:

1. Wrap other `allocator_api2` types (e.g. `IntoIter`) in `ManuallyDrop` too, so compiler can prove they are non-drop too (or reimplement `Vec` ourselves - #6488).
2. Introduce static checks to prevent non-drop types being used in `Box` and `Vec`, to make memory leaks impossible, and detect them at compile time.
@Boshen Boshen force-pushed the 10-16-refactor_allocator_make_vec_non-drop branch from 45bdb68 to e1c2d30 Compare October 19, 2024 15:43
@graphite-app graphite-app bot merged commit e1c2d30 into main Oct 19, 2024
@graphite-app graphite-app bot deleted the 10-16-refactor_allocator_make_vec_non-drop branch October 19, 2024 15:48
graphite-app bot pushed a commit that referenced this pull request Mar 14, 2025
Just like #6623. Since we have control over the `Vec` implementation, we can remove the `drop` operations and eventually revert the changes made in #6623 directly.
graphite-app bot pushed a commit that referenced this pull request Mar 14, 2025
Partially revert #6623, It still keeps the check for non-`drop` element of `Vec`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

0-merge Merge with Graphite Merge Queue C-bug Category - Bug C-cleanup Category - technical debt or refactoring. Solution not expected to change behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants