Skip to content

selectors_vm: compile and drop the selector AST without recursion - #1

Open
robobun wants to merge 1 commit into
bunfrom
robobun/selector-compiler-iterative
Open

robobun wants to merge 1 commit into
bunfrom
robobun/selector-compiler-iterative

Conversation

@robobun

@robobun robobun commented Sep 6, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

  • A selector with many combinators, for example "p p p ... p" with 30000 compounds, parses fine but overflows the native stack when the program is compiled. In bun this is a silent SIGSEGV in HTMLRewriter.transform().
  • Compiler::compile_nodes (src/selectors_vm/compiler.rs) recurses through compile_descendants once per combinator. The derived drop glue for the AST recurses the same way when an Ast is dropped without compilation.

Fix

  • compile_nodes walks the tree with an explicit work list. Each node reserves the address ranges for its children and descendants first, then queues them. Siblings still land in one contiguous range.
  • Ast gets a Drop impl that moves the tree into a work list before the nodes are freed. Ast is the only owner of a node tree, so the compiler still destructures nodes by move.
  • Verified: deep_combinator_chain compiles a 100k deep chain for both and >, walks the program link by link, and drops an uncompiled AST. Without the compiler change, or without the Drop impl, the test aborts with a stack overflow. cargo test --features _integration_test: 208 + 3 + 38 + 2 pass. cargo clippy --all-targets: no new warnings. cargo fmt --check: clean.

Cost

Compile-only benchmark: 100 pre-parsed selectors, a fresh HtmlRewriter per 9-byte document, release build, min of 6 interleaved runs, against e1a306d.

selectors change
mixed -1.1 %
flat (div.cN) -0.1 %
chains (aN b c d > e f g h) +1.4 %

The work list holds no entry until a node has children, so a flat selector list allocates nothing extra.

Branches

Compiler::compile_nodes recursed once per combinator, so a selector such
as "p p p ..." with tens of thousands of compounds overflowed the native
stack in compile(). The derived drop glue for the AST recursed the same
way. Both now walk the tree with an explicit work list.
@robobun
robobun force-pushed the robobun/selector-compiler-iterative branch from 4340f76 to 0344121 Compare September 22, 2026 15:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant