From fddb433d2a13879ad80772e119afbf82a089a30d Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Fri, 27 Feb 2026 10:27:59 -0800 Subject: [PATCH] [test] Improve array.init_elem tests Test the identities of the initialized elements. This would have caught a bug in the binaryen interpreter where the first element of the range was copied `n` times. Also add a test that initializing from the same element segment multiple times writes the same references each time (rather than re-evaluating the initializer expressions, for example). This catches another bug in the binaryen interpreter. See https://github.com/WebAssembly/binaryen/pull/8349. --- test/core/gc/array_init_elem.wast | 75 +++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/test/core/gc/array_init_elem.wast b/test/core/gc/array_init_elem.wast index fd028bbf59..ff601c8ae1 100644 --- a/test/core/gc/array_init_elem.wast +++ b/test/core/gc/array_init_elem.wast @@ -42,23 +42,30 @@ ) (module - (type $t_f (func)) - (type $arrref (array (ref $t_f))) (type $arrref_mut (array (mut funcref))) - (global $g_arrref (ref $arrref) (array.new $arrref (ref.func $dummy) (i32.const 12))) (global $g_arrref_mut (ref $arrref_mut) (array.new_default $arrref_mut (i32.const 12))) (table $t 1 funcref) - (elem $e1 func $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy) - - (func $dummy - ) - - (func (export "array_call_nth") (param $1 i32) - (table.set $t (i32.const 0) (array.get $arrref_mut (global.get $g_arrref_mut) (local.get $1))) - (call_indirect $t (i32.const 0)) + (elem $e1 func $zero $one $two $three $four $five $six $seven $eight $nine $ten $eleven) + + (func $zero (result i32) (i32.const 0)) + (func $one (result i32) (i32.const 1)) + (func $two (result i32) (i32.const 2)) + (func $three (result i32) (i32.const 3)) + (func $four (result i32) (i32.const 4)) + (func $five (result i32) (i32.const 5)) + (func $six (result i32) (i32.const 6)) + (func $seven (result i32) (i32.const 7)) + (func $eight (result i32) (i32.const 8)) + (func $nine (result i32) (i32.const 9)) + (func $ten (result i32) (i32.const 10)) + (func $eleven (result i32) (i32.const 11)) + + (func (export "array_call_nth") (param $n i32) (result i32) + (table.set $t (i32.const 0) (array.get $arrref_mut (global.get $g_arrref_mut) (local.get $n))) + (call_indirect $t (result i32) (i32.const 0)) ) (func (export "array_init_elem-null") @@ -98,11 +105,53 @@ ;; normal cases (assert_return (invoke "array_init_elem" (i32.const 2) (i32.const 3) (i32.const 2))) (assert_trap (invoke "array_call_nth" (i32.const 1)) "uninitialized element") -(assert_return (invoke "array_call_nth" (i32.const 2))) -(assert_return (invoke "array_call_nth" (i32.const 3))) +(assert_return (invoke "array_call_nth" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "array_call_nth" (i32.const 3)) (i32.const 4)) (assert_trap (invoke "array_call_nth" (i32.const 4)) "uninitialized element") ;; init_data/elem with dropped segments traps for non-zero length (assert_return (invoke "drop_segs")) (assert_return (invoke "array_init_elem" (i32.const 0) (i32.const 0) (i32.const 0))) (assert_trap (invoke "array_init_elem" (i32.const 0) (i32.const 0) (i32.const 1)) "out of bounds table access") + +(module + (type $arrref_mut (array (mut arrayref))) + + (global $g_arrref_mut (ref $arrref_mut) (array.new_default $arrref_mut (i32.const 2))) + + (elem $e1 arrayref + (item (array.new_default $arrref_mut (i32.const 1))) + (item (array.new_default $arrref_mut (i32.const 2))) + ) + + (func (export "array_init_elem") (param $1 i32) (param $2 i32) (param $3 i32) + (array.init_elem $arrref_mut $e1 (global.get $g_arrref_mut) (local.get $1) (local.get $2) (local.get $3)) + ) + + (func (export "array_len_nth") (param $n i32) (result i32) + (array.len (array.get $arrref_mut (global.get $g_arrref_mut) (local.get $n))) + ) + + (func (export "array_eq_elems") (param $i i32) (param $j i32) (result i32) + (ref.eq + (array.get $arrref_mut (global.get $g_arrref_mut) (local.get $i)) + (array.get $arrref_mut (global.get $g_arrref_mut) (local.get $j)) + ) + ) +) + +;; Array starts uninitialized +(assert_trap (invoke "array_len_nth" (i32.const 0)) "null array reference") +(assert_trap (invoke "array_len_nth" (i32.const 1)) "null array reference") + +;; Initialize the array +(assert_return (invoke "array_init_elem" (i32.const 0) (i32.const 0) (i32.const 2))) +(assert_return (invoke "array_len_nth" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "array_len_nth" (i32.const 1)) (i32.const 2)) +(assert_return (invoke "array_eq_elems" (i32.const 0) (i32.const 1)) (i32.const 0)) + +;; Copy the first element at the second index and check that they are equal. +(assert_return (invoke "array_init_elem" (i32.const 1) (i32.const 0) (i32.const 1))) +(assert_return (invoke "array_len_nth" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "array_len_nth" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "array_eq_elems" (i32.const 0) (i32.const 1)) (i32.const 1))