Skip to content

Commit 3e724d7

Browse files
authored
Add cast types (#12996)
1 parent c94f373 commit 3e724d7

3 files changed

Lines changed: 466 additions & 51 deletions

File tree

crates/fuzzing/src/generators/gc_ops/ops.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ impl GcOps {
368368
let Some(op) = op.fixup(&self.limits, num_types) else {
369369
continue;
370370
};
371+
let op = StackType::fixup_cast(op, &self.types, &encoding_order);
371372

372373
debug_assert!(operand_types.is_empty());
373374
op.operand_types(&mut operand_types);
@@ -584,6 +585,22 @@ macro_rules! for_each_gc_op {
584585
type_index = type_index.checked_rem(num_types)?;
585586
})]
586587
NullTypedStruct { type_index: u32 },
588+
589+
#[operands([Some(Struct(Some(sub_type_index)))])]
590+
#[results([Struct(Some(super_type_index))])]
591+
#[fixup(|_limits, num_types| {
592+
sub_type_index = sub_type_index.checked_rem(num_types)?;
593+
super_type_index = super_type_index.checked_rem(num_types)?;
594+
})]
595+
RefCastUpward { sub_type_index: u32, super_type_index: u32 },
596+
597+
#[operands([Some(Struct(Some(super_type_index)))])]
598+
#[results([Struct(Some(sub_type_index))])]
599+
#[fixup(|_limits, num_types| {
600+
sub_type_index = sub_type_index.checked_rem(num_types)?;
601+
super_type_index = super_type_index.checked_rem(num_types)?;
602+
})]
603+
RefCastDownward { sub_type_index: u32, super_type_index: u32 },
587604
}
588605
};
589606
}
@@ -890,6 +907,66 @@ impl GcOp {
890907
encoding_bases.typed_table_base + type_index,
891908
));
892909
}
910+
Self::RefCastUpward {
911+
sub_type_index: _,
912+
super_type_index,
913+
} => {
914+
// The value on the stack is already the subtype, so this
915+
// cast always succeeds.
916+
let heap_type = wasm_encoder::HeapType::Concrete(
917+
encoding_bases.struct_type_base + super_type_index,
918+
);
919+
func.instruction(&Instruction::RefCastNullable(heap_type));
920+
}
921+
Self::RefCastDownward {
922+
sub_type_index,
923+
super_type_index,
924+
} => {
925+
// Fallible downcast that never traps:
926+
//
927+
// local.tee $my_temp
928+
// ;; Test if the downcast will succeed.
929+
// ref.test ...
930+
// if (result (ref null $my_sub))
931+
// ;; The downcast will succeed, do a downcast-or-trap
932+
// ;; operation which we know will not trap.
933+
// local.get $my_temp
934+
// ref.cast ...
935+
// else
936+
// ;; The downcast would fail, so just create a null
937+
// ;; reference instead.
938+
// ref.null ...
939+
// end
940+
let sub_wasm_type = encoding_bases.struct_type_base + sub_type_index;
941+
let sub_heap_type = wasm_encoder::HeapType::Concrete(sub_wasm_type);
942+
let temp_local = encoding_bases.typed_local_base + super_type_index;
943+
944+
// Tee the supertype value into a temp local (saves and
945+
// leaves the value on the stack for ref.test).
946+
func.instruction(&Instruction::LocalTee(temp_local));
947+
948+
// Test if the downcast will succeed.
949+
func.instruction(&Instruction::RefTestNullable(sub_heap_type));
950+
951+
// if (result (ref null $sub_type))
952+
func.instruction(&Instruction::If(wasm_encoder::BlockType::Result(
953+
ValType::Ref(RefType {
954+
nullable: true,
955+
heap_type: sub_heap_type,
956+
}),
957+
)));
958+
959+
// The downcast will succeed; do the cast.
960+
func.instruction(&Instruction::LocalGet(temp_local));
961+
func.instruction(&Instruction::RefCastNullable(sub_heap_type));
962+
963+
func.instruction(&Instruction::Else);
964+
965+
// The downcast would fail; produce null instead.
966+
func.instruction(&Instruction::RefNull(sub_heap_type));
967+
968+
func.instruction(&Instruction::End);
969+
}
893970
}
894971
}
895972
}

0 commit comments

Comments
 (0)