khagankhan opened PR #13101 from khagankhan:struct-fields to bytecodealliance:main:
Structs with fields
StructNew: Consumes
ExternRefvalues from the operand stack for ref-typed fields instead of always synthesizingref.null extern. POD fields still get default values. The consumed count is tracked inexternref_from_stackand used during encoding via scratch locals to interleave stack values with defaults in field declaration order. POD constants do not need to come from the stack since we can always synthesize them, butexternref(and concrete struct ref types in the future) should be consumed from the stack when available. This is implemented as a special case in the fixup loop rather than changing the#[operands()]attribute or introducing new stack value types, because the number of ref fields a struct will consume is not known statically since it depends on the struct type's field layout. The rest of the ops use static operand and result types so making them dynamic would be a larger refactor with little benefit. When the top of the abstract stack has consecutiveExternRefvalues, fixup pops them and records the count inexternref_from_stack, letting the encoding know how many live values to retrieve vialocal.set/local.getinstead of synthesizingref.null extern.StructSet: Consumes one
ExternReffrom the stack when the target mutable field is a ref type, using it as the field value instead ofref.null extern. During fixup, it finds the first mutable field starting fromfield_index(scanning forward, wrapping around) and sets it. if no mutable field exists, the struct ref is discarded.StructGet/StructSet null guards: Both now check for null refs before accessing fields (
ref.is_null+if/else), preventing null reference traps.Other changes
- Added new tests and
StructFieldmutations.
+cc @fitzgen @eeide
khagankhan requested wasmtime-fuzz-reviewers for a review on PR #13101.
khagankhan requested fitzgen for a review on PR #13101.
khagankhan commented on PR #13101:
@fitzgen I know this maybe a lot here but what I need the most is to know whether this solution makes sense or do we need something else like maybe adding d PODs as GcOps and to Stack or something else.
github-actions[bot] added the label fuzzing on PR #13101.
github-actions[bot] commented on PR #13101:
Subscribe to Label Action
cc @fitzgen
<details>
This issue or pull request has been labeled: "fuzzing"Thus the following users have been cc'd because of the following labels:
- fitzgen: fuzzing
To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.
Learn more.
</details>
khagankhan updated PR #13101.
khagankhan updated PR #13101.
fitzgen submitted PR review:
Thanks! Sorry that it took a little while to review this one.
fitzgen created PR review comment:
This can just
.unwrap():usize::try_from(my_u32).unwrap()is common enough that it doesn't need a diagnostic message and it also shouldn't ever fail on our supported architectures anyway. Same with the other instances of this here.
fitzgen created PR review comment:
Also this pattern is probably a little more straight forward as:
let idx = ctx.rng().gen_index(FieldType::ALL.len()); let idx = u32::try_from(idx).unwrap();And maybe even better deduplicated as a
fn FieldType::random(rng: &mut mutatis::Rng) -> u32helper function.
fitzgen created PR review comment:
You should be able to just collect the fields into a
Box<[_]>in the first place rather than collect and then callinto_boxed_slice().
fitzgen created PR review comment:
I'm a bit confused here: why are we special-casing
externref-typed fields here? Why are they different fromi32-typed fields, for example? In either case, we need an operand of each field's type so I don't understand why we're not handling them uniformly.
khagankhan submitted PR review.
khagankhan created PR review comment:
My thinking was that reusing an
externrefor concretely typed references already on the stack may be more interesting. For example values fromtable.setortable.get. Sinceexternrefis GC related I wanted to distinguish it from something like i32.P.S. I do not like special cases. If this is not useful we can synthesize
externreftoo. We can also add them asStackTypesorGcOps. But this may just generate and discard values and waste mutation and execution cycles.
khagankhan submitted PR review.
khagankhan created PR review comment:
I will choose the first one and address the feedback. I can make PRs in the future if this turns out to be non-ideal.
khagankhan updated PR #13101.
khagankhan commented on PR #13101:
Thanks @fitzgen ! Ready for the next round of reviews
khagankhan updated PR #13101.
fitzgen submitted PR review.
fitzgen created PR review comment:
My thinking was that reusing an
externrefor concretely typed references already on the stack may be more interesting. For example values fromtable.setortable.get. Sinceexternrefis GC related I wanted to distinguish it from something like i32.Yep, but reusing (for example)
i32values from the stack is also more interesting (since maybe they came from astruct.get) so why wouldn't we also do it fori32s? It seems to me that we should have a uniform approach to attempting to reuse values from the stack as much as possible.A first pass might be something like this:
let operands_needed = inst.operand_types(); if types_match(&stack, &operands_needed) { break 'fixup_stack; } else { let i = first_index_where_types_do_not_match(&stack, &operands_needed); for ty in &operands_needed[i..] { insts.push(make_const(ty)); stack.push(ty); } } stack.truncate(stack.len() - operands_needed.len()); insts.push(inst); stack.extend(inst.result_types());And this should work for all types/values, not just
externrefs ori32s.In the future, we could even try searching up the stack (probably a limited amount) for an existing value of our target type, but this would require some spilling-to-temp-locals infrastructure, which probably makes sense eventually but probably should happen in its own dedicated PR rather than in the middle of some other stuff.
How does this sound? Or am I completely missing something?
fitzgen edited PR review comment.
khagankhan submitted PR review.
khagankhan created PR review comment:
Great! :saluting_face:
Last updated: May 03 2026 at 22:13 UTC