From d5652f522c696f27c07ddbeff9d25c43c6de34fc Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Thu, 10 Oct 2024 08:19:51 -0700 Subject: [PATCH] Implement the `ref.cast` Wasm GC instruction (#9437) --- crates/cranelift/src/lib.rs | 2 ++ .../src/translate/code_translator.rs | 33 ++++++++++++++++--- crates/environ/src/trap_encoding.rs | 5 +++ tests/wast.rs | 2 -- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/crates/cranelift/src/lib.rs b/crates/cranelift/src/lib.rs index bf03d02d8eb8..73772ac5cb12 100644 --- a/crates/cranelift/src/lib.rs +++ b/crates/cranelift/src/lib.rs @@ -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. diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs index 210f7ce2079b..2e066350d18d 100644 --- a/crates/cranelift/src/translate/code_translator.rs +++ b/crates/cranelift/src/translate/code_translator.rs @@ -2755,6 +2755,34 @@ pub fn translate_operator( )?; 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. @@ -2764,10 +2792,7 @@ pub fn translate_operator( // 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:?}")); } diff --git a/crates/environ/src/trap_encoding.rs b/crates/environ/src/trap_encoding.rs index ce5c4af21283..6c08471fd7ca 100644 --- a/crates/environ/src/trap_encoding.rs +++ b/crates/environ/src/trap_encoding.rs @@ -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, @@ -119,6 +122,7 @@ impl Trap { NullReference ArrayOutOfBounds AllocationTooLarge + CastFailure CannotEnterComponent } @@ -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}") diff --git a/tests/wast.rs b/tests/wast.rs index ec95ffb3ba16..d3cd7d24761d 100644 --- a/tests/wast.rs +++ b/tests/wast.rs @@ -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() {