Skip to content

Commit

Permalink
Implement the ref.cast Wasm GC instruction (#9437)
Browse files Browse the repository at this point in the history
  • Loading branch information
fitzgen authored Oct 10, 2024
1 parent 7bdb25e commit d5652f5
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 6 deletions.
2 changes: 2 additions & 0 deletions crates/cranelift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ pub const TRAP_HEAP_MISALIGNED: TrapCode =
TrapCode::unwrap_user(Trap::HeapMisaligned as u8 + TRAP_OFFSET);
pub const TRAP_TABLE_OUT_OF_BOUNDS: TrapCode =
TrapCode::unwrap_user(Trap::TableOutOfBounds as u8 + TRAP_OFFSET);
pub const TRAP_CAST_FAILURE: TrapCode =
TrapCode::unwrap_user(Trap::CastFailure as u8 + TRAP_OFFSET);

/// Creates a new cranelift `Signature` with no wasm params/results for the
/// given calling convention.
Expand Down
33 changes: 29 additions & 4 deletions crates/cranelift/src/translate/code_translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2755,6 +2755,34 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
)?;
state.push1(result);
}
Operator::RefCastNonNull { hty } => {
let r = state.pop1();
let heap_type = environ.convert_heap_type(*hty);
let cast_okay = environ.translate_ref_test(
builder,
WasmRefType {
heap_type,
nullable: false,
},
r,
)?;
environ.trapz(builder, cast_okay, crate::TRAP_CAST_FAILURE);
state.push1(r);
}
Operator::RefCastNullable { hty } => {
let r = state.pop1();
let heap_type = environ.convert_heap_type(*hty);
let cast_okay = environ.translate_ref_test(
builder,
WasmRefType {
heap_type,
nullable: true,
},
r,
)?;
environ.trapz(builder, cast_okay, crate::TRAP_CAST_FAILURE);
state.push1(r);
}
Operator::AnyConvertExtern => {
// Pop an `externref`, push an `anyref`. But they have the same
// representation, so we don't actually need to do anything.
Expand All @@ -2764,10 +2792,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
// representation, so we don't actually need to do anything.
}

Operator::RefCastNonNull { .. }
| Operator::RefCastNullable { .. }
| Operator::BrOnCast { .. }
| Operator::BrOnCastFail { .. } => {
Operator::BrOnCast { .. } | Operator::BrOnCastFail { .. } => {
return Err(wasm_unsupported!("GC operator not yet implemented: {op:?}"));
}

Expand Down
5 changes: 5 additions & 0 deletions crates/environ/src/trap_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ pub enum Trap {
/// Attempted an allocation that was too large to succeed.
AllocationTooLarge,

/// Attempted to cast a reference to a type that it is not an instance of.
CastFailure,

/// When the `component-model` feature is enabled this trap represents a
/// scenario where one component tried to call another component but it
/// would have violated the reentrance rules of the component model,
Expand Down Expand Up @@ -119,6 +122,7 @@ impl Trap {
NullReference
ArrayOutOfBounds
AllocationTooLarge
CastFailure
CannotEnterComponent
}

Expand Down Expand Up @@ -148,6 +152,7 @@ impl fmt::Display for Trap {
NullReference => "null reference",
ArrayOutOfBounds => "out of bounds array access",
AllocationTooLarge => "allocation size too large",
CastFailure => "cast failure",
CannotEnterComponent => "cannot enter component instance",
};
write!(f, "wasm trap: {desc}")
Expand Down
2 changes: 0 additions & 2 deletions tests/wast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,12 @@ fn should_fail(test: &Path, strategy: Strategy) -> bool {
"binary_gc.wast",
"br_on_cast_fail.wast",
"br_on_cast.wast",
"ref_cast.wast",
"table_sub.wast",
"type_canon.wast",
"type_equivalence.wast",
"type-rec.wast",
"type-subtyping.wast",
"unreached_valid.wast",
"i31.wast",
];

for part in test.iter() {
Expand Down

0 comments on commit d5652f5

Please sign in to comment.