Skip to content

Conversation

@keithw
Copy link
Contributor

@keithw keithw commented Jan 28, 2026

This PR adds an atomic feature to the validator, exposing a FuncValidator::atomic_op function that tries to validate an operator and leaves the validator unchanged if the operator is invalid.

The feature adds a "rollback log" to the OperatorValidator; the log keeps track of any information destroyed during validation of the operator, so that the validator can be rolled back to its initial state if the operator turns out to be invalid. I tried to make this basically performance-neutral for anybody who doesn't need this. The rollback log is only present if the atomic feature is enabled, and it's only used if atomic_op is being used (i.e. the visit functions and FuncValidator::op don't use it).

We're using this as part of a Wasm development/teaching environment where we'd like the validator to be in a predictable state after an invalid operator.

@keithw keithw requested a review from a team as a code owner January 28, 2026 18:44
@keithw keithw requested review from dicej and removed request for a team January 28, 2026 18:44
@alexcrichton
Copy link
Member

If performance is ok to compromise on a bit here, the Clone-ability of a FunctionValidator might be sufficient here because the validator could be cloned before the operation and then thrown away if validation succeeded. That'd likely have some quadratic performance in terms of stack depth, however, so I can see how that wouldn't be desirable for handling large functions.

@keithw
Copy link
Contributor Author

keithw commented Jan 30, 2026

Yeah, we are validating basically on every keystroke, so having to duplicate the operand/control/init stacks on every operator (valid or not) is probably too expensive for us.

@alexcrichton
Copy link
Member

Would you be up for doing some quick measurements with the scale of wasm files you're expecting to see what it's like? I'd naively expect keystrokes to be dozens-of-milliseconds apart which is probably more than enough time to clone the validator and such, so my hunch is that it's probably not that noticable but if you're dealing with clang.wasm it might still be noticable.

The reason I ask is that this is pretty invasive in the validator in terms of hooking into the critical points of dealing with all the internal validator state. It's not unreasonable per-se and I'd agree that a compile-time feature is the way to go here, but even with that this is something that may not be that easy to maintain over time. Given that I'd like to try to push on the clone-ability of the validator (which in contrast should be pretty easy to maintain) and see if that works. If it doesn't work though it doesn't work, and this seems reasonable enough.

FuncValidator::atomic_op validates an operator, leaving
the validator unchanged if the operator is invalid.
@keithw
Copy link
Contributor Author

keithw commented Feb 3, 2026

Sure, here's a (very) rough measurement... Let's say the largest file we'd plan to edit is around 100,000 lines. (The clang.wasm that used to be a w2c2 example is >10M lines.) The worst case is probably something like "a single function with 100,000 lines of i32.const 0". Running on an AMD Ryzen 7 PRO 4750U @ ~3.9 GHz:

  • Without the copy, this takes <1 ms to validate.

  • With an approach that clones the OperatorValidator on every operator, this is taking about 0.9-1.0 seconds to validate.

  • On the atomic branch, it's again <1 ms.

(Edit to add: These numbers are for a release build running on native Linux x86-64; the real application is going to be running in Wasm in a browser which I think also makes us a little more concerned about possible performance gotchas.)

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