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

Skip type checks on tables that don't need it #8172

Merged

Conversation

alexcrichton
Copy link
Member

This commit implements an optimization to skip type checks in
call_indirect for tables that don't require it. With the
function-references proposal it's possible to have tables of a single
type of function as opposed to today's default funcref which is a
heterogenous set of functions. In this situation it's possible that a
call_indirect's type tag matches the type tag of a
table-of-typed-funcref-values, meaning that it's impossible for the
type check to fail.

The type check of a function pointer in call_indirect is refactored
here to take the table's type into account. Various things are shuffled
around to ensure that the right traps still show up in the right places
but the important part is that, when possible, the type check is omitted
entirely.

Have the same function with slightly different variations to compare
codegen between the possible strategies.
This commit implements an optimization to skip type checks in
`call_indirect` for tables that don't require it. With the
function-references proposal it's possible to have tables of a single
type of function as opposed to today's default `funcref` which is a
heterogenous set of functions. In this situation it's possible that a
`call_indirect`'s type tag matches the type tag of a
`table`-of-typed-`funcref`-values, meaning that it's impossible for the
type check to fail.

The type check of a function pointer in `call_indirect` is refactored
here to take the table's type into account. Various things are shuffled
around to ensure that the right traps still show up in the right places
but the important part is that, when possible, the type check is omitted
entirely.
@alexcrichton alexcrichton requested review from a team as code owners March 18, 2024 20:23
@github-actions github-actions bot added cranelift Issues related to the Cranelift code generator cranelift:wasm labels Mar 18, 2024
Copy link
Contributor

@jameysharp jameysharp left a comment

Choose a reason for hiding this comment

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

This makes sense to me! I really like the way you've restructured things with the CheckIndirectCallTypeSignature enum.

crates/cranelift/src/func_environ.rs Outdated Show resolved Hide resolved
Co-authored-by: Jamey Sharp <jamey@minilop.net>
@alexcrichton alexcrichton added this pull request to the merge queue Mar 18, 2024
Comment on lines +1237 to +1255
// Otherwise if the types don't match then either (a) this is a
// null pointer or (b) it's a pointer with the wrong type.
// Figure out which and trap here.
//
// Note that the callee may be null in which case this load may
// trap. If so use the `IndirectCallToNull` trap code.
let mem_flags = ir::MemFlags::trusted().with_readonly();
let callee_sig_id = self.builder.ins().load(
sig_id_type,
mem_flags.with_trap_code(Some(ir::TrapCode::IndirectCallToNull)),
funcref_ptr,
i32::from(self.env.offsets.ptr.vm_func_ref_type_index()),
);
// If it's possible to have a null here then try to load the
// type information. If that fails due to the function being a
// null pointer, then this was a call to null. Otherwise if it
// succeeds then we know it won't match, so trap anyway.
if table.table.wasm_ty.nullable {
let mem_flags = ir::MemFlags::trusted().with_readonly();
self.builder.ins().load(
sig_id_type,
mem_flags.with_trap_code(Some(ir::TrapCode::IndirectCallToNull)),
funcref_ptr,
i32::from(self.env.offsets.ptr.vm_func_ref_type_index()),
);
}
self.builder.ins().trap(ir::TrapCode::BadSignature);
return CheckIndirectCallTypeSignature::StaticTrap;
Copy link
Member

Choose a reason for hiding this comment

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

FWIW, when the GC proposal is enabled, the static immediate type on the call_indirect will be allowed to be a subtype of the actual function's type.

We don't implement this yet, but will need to.

https://webassembly.github.io/gc/core/exec/instructions.html#exec-call-indirect

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh good point! I keep consistently forgetting that contra/covariance applies to params/results...

This makes me think we should remove the PartialEq implementation for types in wasmtime-types like we did in the embedder API as well

Copy link
Member

Choose a reason for hiding this comment

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

Yeah that wouldn't be a bad idea.

Merged via the queue into bytecodealliance:main with commit 0dee5a7 Mar 18, 2024
19 checks passed
@alexcrichton alexcrichton deleted the remove-call-indirect-typecheck branch March 18, 2024 22:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cranelift:wasm cranelift Issues related to the Cranelift code generator
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants