Skip to content
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

Implement table.init #6827

Merged
merged 38 commits into from
Aug 16, 2024
Merged

Implement table.init #6827

merged 38 commits into from
Aug 16, 2024

Conversation

kripken
Copy link
Member

@kripken kripken commented Aug 8, 2024

Also use TableInit in the interpreter to initialize module's table state, which will
now handle traps properly, fixing #6431

The wasm-ctor-eval addition of tableSize is necessary here, as now tableSize
is called internally from the interpreter as part of using TableInit.

@kripken kripken requested a review from tlively August 8, 2024 23:30
droppedElementSegments.count(curr->segment)) {
trap("out of bounds segment access in table.init");
}
if ((uint64_t)offsetVal + sizeVal > segment->data.size()) {
Copy link
Member

Choose a reason for hiding this comment

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

What role does this uint64_t cast play?

Copy link
Member Author

Choose a reason for hiding this comment

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

We use this pattern to avoid a 32-bit overflow.

Copy link
Member

Choose a reason for hiding this comment

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

But Addresses are 64-bit already, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, fair point. Then this can be changed in the MemoryInit code I copied this from. I'll do that.

trap("out of bounds table access in table.init");
}
for (size_t i = 0; i < sizeVal; ++i) {
auto value = self()->visit(segment->data[offsetVal + i]).getSingleValue();
Copy link
Member

Choose a reason for hiding this comment

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

This is not correct, but I think it's the same as a bug we had with the instantiation logic before this change. Maybe it's a good time to fix it.

The problem is that a segment is a sequence of values, not instructions. If you do a table.init of a segment containing a bunch of struct.new instructions, you should get the same struct references every time, not fresh struct references.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, yeah, this is a bug that existed before and this refactoring just moves around a bit.

I'm actually not sure how best to fix it - seems like it requires some new data structure, at least - so I'll add a FIXME here for later.

Comment on lines 1527 to 1528
TableInit curr;
CHECK_ERR(visitTableInit(&curr));
Copy link
Member

Choose a reason for hiding this comment

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

This is going to need the table to be set on curr so it can figure out whether to read an i32 or an i64. Since we're not using child-typer in the validator yet, the only way to test that this is correct is by seeing how the instruction is parsed when one of its subsequent children is unreachable.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't follow. There is no implementation of visitTableInit - it's empty, then, from the parent of IRBuilder, which is UnifiedExpressionVisitor. That calls visitExpression, but there is no special code from TableInit there either. Am I mixed up..?

If this is some table64 complexity, then perhaps it is simpler if I make this PR only support table.init on wasm32?

Copy link
Member

Choose a reason for hiding this comment

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

visitTableInit ends up in visitExpression, which calls ConstraintCollector::visit. ConstraintCollector inherits from ChildTyper, which should implement a specific visitTableInit that will need to look up the table to figure out the index type.

But yes, this is to properly support table64, so one option would be to punt that to later. I think it would be better to handle it now, though.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, thanks, it is indeed in that other class. Done.

;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_table_init
(table.init $t64 $elem64 (i64.const 0) (i64.const 5) (i64.const 10))
Copy link
Member

Choose a reason for hiding this comment

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

As mentioned in the comments on the validator, this should be invalid because only the first operand should be an i64.

Comment on lines 2449 to 2452
shouldBeEqualOrFirstIsUnreachable(curr->size->type,
destTable->indexType,
curr,
"table.copy size must be valid");
Copy link
Member

Choose a reason for hiding this comment

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

This actually needs to be i32 if either of the input tables are 32-bit and i64 otherwise.

Comment on lines 2470 to 2475
shouldBeEqualOrFirstIsUnreachable(curr->offset->type,
table->indexType,
curr,
"table.init offset must be valid");
shouldBeEqualOrFirstIsUnreachable(
curr->size->type, Type(Type::i32), curr, "table.copy size must be i32");
curr->size->type, table->indexType, curr, "table.init size must be valid");
Copy link
Member

Choose a reason for hiding this comment

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

Only the destination is an i64 if the table is 64-bit. The offset and size are both still i32s.

@@ -736,6 +736,12 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
note(&curr->size, Type::i32);
}

void visitTableInit(TableInit* curr) {
note(&curr->dest, Type::i32);
Copy link
Member

Choose a reason for hiding this comment

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

This needs to be i64 if the referenced table is 64-bit.

@kripken
Copy link
Member Author

kripken commented Aug 15, 2024

Thanks for the helpful comments, all the validation and other issues should now be addressed.

@kripken kripken merged commit 958ff41 into WebAssembly:main Aug 16, 2024
13 checks passed
@kripken kripken deleted the table.init branch August 16, 2024 19:53
@gkdn gkdn mentioned this pull request Aug 31, 2024
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