Skip to content

Implement table.init - #6827

Merged
kripken merged 38 commits into
WebAssembly:mainfrom
kripken:table.init
Aug 16, 2024
Merged

kripken merged 38 commits into
WebAssembly:mainfrom
kripken:table.init

Conversation

@kripken

@kripken kripken commented Aug 8, 2024

Copy link
Copy Markdown
Member

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
Comment thread src/wasm-interpreter.h Outdated
droppedElementSegments.count(curr->segment)) {
trap("out of bounds segment access in table.init");
}
if ((uint64_t)offsetVal + sizeVal > segment->data.size()) {

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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.

Comment thread src/wasm-interpreter.h
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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.

Comment thread test/lit/passes/table64-lowering.wast Outdated
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_table_init
(table.init $t64 $elem64 (i64.const 0) (i64.const 5) (i64.const 10))

Copy link
Copy Markdown
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 thread src/wasm/wasm-validator.cpp Outdated
Comment on lines +2449 to +2452
shouldBeEqualOrFirstIsUnreachable(curr->size->type,
destTable->indexType,
curr,
"table.copy size must be valid");

Copy link
Copy Markdown
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 thread src/wasm/wasm-validator.cpp Outdated
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
Copy Markdown
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.

Comment thread src/ir/child-typer.h Outdated
}

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

Copy link
Copy Markdown
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

kripken commented Aug 15, 2024 •

Copy link
Copy Markdown
Member Author

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
@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