Skip to content

Conversation

nnethercote
Copy link
Contributor

The amount of code generated by derive(Arbitrary) is large, mostly due to the recursion count guard. This commit factors out that code with a new hidden function with_recursive_count.

Because with_recursive_count is mark with inline, the generated code should end up being much the same. But compile times are reduced by 30-40% because rustc's frontend has much less code to chew through.

@nnethercote
Copy link
Contributor Author

An example: for struct S(u32, u32);, the old derived arbitrary function looked like this:

        fn arbitrary(
            u: &mut arbitrary::Unstructured<'arbitrary>,
        ) -> arbitrary::Result<Self> {
            let guard_against_recursion = u.is_empty();
            if guard_against_recursion {
                RECURSIVE_COUNT_S
                    .with(|count| {
                        if count.get() > 0 {
                            return Err(arbitrary::Error::NotEnoughData);
                        }
                        count.set(count.get() + 1);
                        Ok(())
                    })?;
            }
            let result = (|| {
                Ok(
                    S(
                        arbitrary::Arbitrary::arbitrary(u)?,
                        arbitrary::Arbitrary::arbitrary(u)?,
                    ),
                )
            })();
            if guard_against_recursion {
                RECURSIVE_COUNT_S
                    .with(|count| {
                        count.set(count.get() - 1);
                    });
            }
            result
        }

it now looks like this:

        fn arbitrary(
            u: &mut arbitrary::Unstructured<'arbitrary>,
        ) -> arbitrary::Result<Self> {
            arbitrary::details::with_recursive_count(
                u,
                &RECURSIVE_COUNT_S,
                |mut u| {
                    Ok(
                        S(
                            arbitrary::Arbitrary::arbitrary(u)?,
                            arbitrary::Arbitrary::arbitrary(u)?,
                        ),
                    )
                },
            )
        }

The story is very similar for arbitrary_take_rest.

The amount of code generated by `derive(Arbitrary)` is large, mostly due
to the recursion count guard. This commit factors out that code with a
new hidden function `with_recursive_count`.

Because `with_recursive_count` is mark with `inline`, the generated code
should end up being much the same. But compile times are reduced by
30-40% because rustc's frontend has much less code to chew through.
@nnethercote nnethercote force-pushed the with_recursive_count branch from 07f9c25 to 40fe82d Compare August 13, 2025 03:53
Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thanks!

@fitzgen fitzgen merged commit 688b494 into rust-fuzz:main Aug 13, 2025
6 checks passed
@nnethercote nnethercote deleted the with_recursive_count branch August 13, 2025 23:38
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.

2 participants