-
Notifications
You must be signed in to change notification settings - Fork 786
exnref-related error in writing binary #3114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The relevant code snippet (from wasm-objdump) is
So it looks like the problem is that the block is not annotated with an input type. Even though there is an exnref on the stack, the exnref is not available inside the block without a block parameter annotation. The robust fix would be to implement block parameters throughout Binaryen, which I hope to do sometime after Poppy IR is done, but perhaps there is a more short-term fix as well. |
Thanks for looking into it @tlively ! I don't think a short-term fix is needed as it's an experimental feature. We can just keep that one test disabled for now. |
Hmm, I wonder how this has not been discovered so far; this is rather a serious bug.. As @tlively said, having block input type can solve this. But this makes EH dependent on multivalue, which I'm not sure if I want. (I elaborated a little more on this later in this comment) And I was aware that Binaryen does not support block input parameters anyway, so this is a bug ;( I've been trying hard to avoid generating a wrapping A little background: But this can break. When the original code looks like try
...
catch
drop
br 0
end Here (try
(do
(block $label0
...
)
)
(catch
(block $label1 ;; cannot be deleted because there's a br targeting this!
(drop (pop exnref))
(br $label1)
)
)
) So This is also what happens for i32.const 0
if
br 0
else
br 0
end Corresponding Binaryen IR: (if
(i32.const 0)
(then
(block $label0
(br $label0)
)
(else
(block $label1
(br $label1)
)
)
) By the way, I'm wondering, even though this code is semantically correct for Oh and by the way, even if we change the EH spec soon, this problem is not gonna go away; currently So there can be multiple ways to solve this.
(try
...
(catch
(block $label1
(drop (pop exnref))
(br $label1)
)
)
) to this: (this is actually how we handle a similar situation in the s expression parser for (block $label1
(try
...
(catch
(drop (pop exnref))
(br $label1)
)
)
) Anyway, sorry for the long comment. This is not urgent; The EH spec is in churn anyway, so this does not have to be resolved in short order. But I guess we have to resolve it one way or the other at some point. |
I wonder if we could do something hacky in the binary writer to omit the block in the catch even if it is a branch target. In the emitted binary, all the branches that target the block would then target the I don't see supporting block parameters in the IR as a high priority since the code size improvements they unlock are so modest. I would like to get around to them eventually as a matter of completeness, though, and if there are more situations like this where we wish we had them, that would make them more important. So right now I wouldn't expect them soon. |
(block $label1
(try
...
(catch
(drop (pop exnref))
(br $label1)
)
)
) Yeah but this adds two unnecessary instructions. I think Or we can do even a hackier thing in binary writer so that we can make the branch target But anyway, |
Yeah, that's what I was thinking :) Definitely a hack, but would avoid needing to depend on block params and multivalue. The code transformation you propose would work, but without the hack in the BinaryenIRWriter, we'd be losing the property that any valid Binaryen IR can be written directly to a valid WebAssembly (since it would have to go through that transformation first). |
Not sure if I understand. What I suggested is a hack in the binary reader side, not the writer side. We can make the reader create that kind of structure, and after that every valid Binaryen IR can be written to a valid WebAssembly. We do a somewhat similar thing for |
Aha, that makes sense. That still means it would be possible to programmatically create valid Binaryen IR that is written to an invalid binary, but I don't think that's a big problem given how niche this edge case is. |
I think it would be fine to emit an outer block, (block $label1
(try With that I think the parser could make sure to not emit a block inside the catch that has a break to it. And optimizations could remove it when possible, MergeBlocks tries to move blocks "outside" as much as possible (so they can be merged), and RemovedUnusedBrs has a bunch of patterns for removing unneeded branches and blocks that they appear to target. That should handle ifs properly today. We may want to add some patterns to those passes for try-catch if necessary (but optimizing it seems not urgent). |
emcc-0-base.wasm.gz
The attached wasm file is the wasm-ld output for
test_exceptions_3
with wasm exceptions. The wasm-ld output is valid after https://bugs.llvm.org/show_bug.cgi?id=47413 but the test cannot be enabled yet as runningresults in an invalid wasm, wabt says
(doing another roundtrip results in a valid wasm, and is why this wasn't noticed before - we do one fewer roundtrip now on many tests since at
-O0
we don't run wasm-opt at all if we don't need to).cc @aheejin
The text was updated successfully, but these errors were encountered: