tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

arrays.js (66591B)


      1 // |jit-test| test-also=--gc-zeal=2
      2 
      3 // Test array instructions on different valtypes
      4 
      5 const GENERAL_TESTS = [
      6  [
      7    'i32',
      8    0,
      9    0xce,
     10  ], [
     11    'i64',
     12    0n,
     13    0xabcdefn,
     14  ], [
     15    'f32',
     16    0,
     17    13.5,
     18  ], [
     19    'f64',
     20    0,
     21    13.5,
     22  ], [
     23    'externref',
     24    null,
     25    'hello',
     26  ],
     27 ];
     28 
     29 for (let [valtype, def, nondef] of GENERAL_TESTS) {
     30  let {create, createDefault, get, set, len} = wasmEvalText(`(module
     31    (type $a (array (mut ${valtype})))
     32 
     33    (; new T[0] = { 1... }  ;)
     34    (func (export "create") (param i32 ${valtype}) (result eqref)
     35      local.get 1
     36      local.get 0
     37      array.new $a
     38    )
     39 
     40    (; new T[0] ;)
     41    (func (export "createDefault") (param i32) (result eqref)
     42      local.get 0
     43      array.new_default $a
     44    )
     45 
     46    (; 0[1] ;)
     47    (func (export "get") (param eqref i32) (result ${valtype})
     48      local.get 0
     49      ref.cast (ref null $a)
     50      local.get 1
     51      array.get $a
     52    )
     53 
     54    (; 0[1] = 2 ;)
     55    (func (export "set") (param eqref i32 ${valtype})
     56      local.get 0
     57      ref.cast (ref null $a)
     58      local.get 1
     59      local.get 2
     60      array.set $a
     61    )
     62 
     63    (; len(a) ;)
     64    (func (export "len") (param eqref) (result i32)
     65      local.get 0
     66      ref.cast (ref null $a)
     67      array.len
     68    )
     69  )`).exports;
     70 
     71  function checkArray(array, length, init, setval) {
     72    // Check length
     73    assertEq(len(array), length);
     74    assertEq(wasmGcArrayLength(array), length);
     75 
     76    // Check init value
     77    for (let i = 0; i < length; i++) {
     78      assertEq(wasmGcReadField(array, i), init);
     79      assertEq(get(array, i), init);
     80    }
     81 
     82    // Set every element to setval
     83    for (let i = 0; i < length; i++) {
     84      set(array, i, setval);
     85 
     86      // Check there is no overwrite
     87      for (let j = i + 1; j < length; j++) {
     88        assertEq(wasmGcReadField(array, j), init);
     89        assertEq(get(array, j), init);
     90      }
     91    }
     92 
     93    // Check out of bounds conditions
     94    for (let loc of [-1, length, length + 1]) {
     95      assertErrorMessage(() => {
     96        get(array, loc);
     97      }, WebAssembly.RuntimeError, /out of bounds/);
     98      assertErrorMessage(() => {
     99        set(array, loc, setval);
    100      }, WebAssembly.RuntimeError, /out of bounds/);
    101    }
    102  }
    103 
    104  for (let arrayLength = 0; arrayLength <= 25; arrayLength++) {
    105    checkArray(createDefault(arrayLength), arrayLength, def, nondef);
    106    checkArray(create(arrayLength, nondef), arrayLength, nondef, def);
    107  }
    108 }
    109 
    110 // Check packed array reads and writes
    111 
    112 for (let [fieldtype, max] of [
    113  [
    114    'i8',
    115    0xff,
    116  ], [
    117    'i16',
    118    0xffff,
    119  ]
    120 ]) {
    121  let {create, getS, getU, set} = wasmEvalText(`(module
    122    (type $a (array (mut ${fieldtype})))
    123 
    124    (; new T[0] = { 1... }  ;)
    125    (func (export "create") (param i32 i32) (result eqref)
    126      local.get 1
    127      local.get 0
    128      array.new $a
    129    )
    130 
    131    (; 0[1] ;)
    132    (func (export "getS") (param eqref i32) (result i32)
    133      local.get 0
    134      ref.cast (ref null $a)
    135      local.get 1
    136      array.get_s $a
    137    )
    138 
    139    (; 0[1] ;)
    140    (func (export "getU") (param eqref i32) (result i32)
    141      local.get 0
    142      ref.cast (ref null $a)
    143      local.get 1
    144      array.get_u $a
    145    )
    146 
    147    (; 0[1] = 2 ;)
    148    (func (export "set") (param eqref i32 i32)
    149      local.get 0
    150      ref.cast (ref null $a)
    151      local.get 1
    152      local.get 2
    153      array.set $a
    154    )
    155  )`).exports;
    156 
    157  // Check zero and sign extension
    158  let a = create(1, 0);
    159  set(a, 0, max);
    160  assertEq(getS(a, 0), -1);
    161  assertEq(getU(a, 0), max);
    162 
    163  // JS-API defaults to sign extension
    164  assertEq(wasmGcReadField(a, 0), getS(a, 0));
    165 
    166  // Check array.new truncates init value
    167  assertEq(wasmGcReadField(create(1, max + 1), 0), 0);
    168 
    169  // Check array.set truncates
    170  let b = create(1, 0);
    171  set(b, 0, max + 1);
    172  assertEq(getU(b, 0), 0);
    173 
    174  // Check no overwrite on set
    175  let c = create(2, 0);
    176  set(c, 0, max << 4);
    177  assertEq(getU(c, 0), (max << 4) & max);
    178  assertEq(getU(c, 1), 0);
    179 }
    180 
    181 // Check arrays must be mutable to mutate
    182 
    183 assertErrorMessage(() => wasmEvalText(`(module
    184    (type $a (array i32))
    185    (func
    186      (array.set $a
    187        (array.new $a
    188          i32.const 0xff
    189          i32.const 10)
    190        i32.const 0
    191        i32.const 0
    192      )
    193    )
    194 )
    195 `), WebAssembly.CompileError, /array is not mutable/);
    196 
    197 // Check operations trap on null
    198 
    199 assertErrorMessage(() => {
    200  wasmEvalText(`(module
    201    (type $a (array (mut i32)))
    202    (func
    203      ref.null $a
    204      i32.const 0
    205      array.get $a
    206      drop
    207    )
    208    (start 0)
    209  )`);
    210 }, WebAssembly.RuntimeError, /null/);
    211 
    212 assertErrorMessage(() => {
    213  wasmEvalText(`(module
    214    (type $a (array (mut i32)))
    215    (func
    216      ref.null $a
    217      i32.const 0
    218      i32.const 0
    219      array.set $a
    220    )
    221    (start 0)
    222  )`);
    223 }, WebAssembly.RuntimeError, /null/);
    224 
    225 assertErrorMessage(() => {
    226  wasmEvalText(`(module
    227    (type $a (array (mut i32)))
    228    (func
    229      ref.null $a
    230      array.len
    231      drop
    232    )
    233    (start 0)
    234  )`);
    235 }, WebAssembly.RuntimeError, /null/);
    236 
    237 // Check an extension postfix is present iff the element is packed
    238 
    239 for ([fieldtype, packed] of [
    240  ['i8', true],
    241  ['i16', true],
    242  ['i32', false],
    243  ['i64', false],
    244  ['f32', false],
    245  ['f64', false],
    246 ]) {
    247  let extensionModule = `(module
    248      (type $a (array ${fieldtype}))
    249      (func
    250        ref.null $a
    251        i32.const 0
    252        array.get_s $a
    253        drop
    254      )
    255      (func
    256        ref.null $a
    257        i32.const 0
    258        array.get_u $a
    259        drop
    260      )
    261    )`;
    262  let noExtensionModule = `(module
    263      (type $a (array ${fieldtype}))
    264      (func
    265        ref.null $a
    266        i32.const 0
    267        array.get $a
    268        drop
    269      )
    270    )`;
    271 
    272  if (packed) {
    273    wasmValidateText(extensionModule);
    274    wasmFailValidateText(noExtensionModule, /must specify signedness/);
    275  } else {
    276    wasmFailValidateText(extensionModule, /must not specify signedness/);
    277    wasmValidateText(noExtensionModule);
    278  }
    279 }
    280 
    281 //////////////////////////////////////////////////////////////////////////////
    282 //
    283 // array.new_fixed
    284 /*
    285  validation:
    286    array-type imm-operand needs to be "in range"
    287    array-type imm-operand must refer to an array type
    288    operands (on stack) must all match ("be compatible with") the array elem
    289      type
    290    number of operands (on stack) must not be less than the num-of-elems
    291      imm-operand
    292    zero elements doesn't fail compilation
    293    reftypes elements doesn't fail compilation
    294    trying to create a 1-billion-element array fails gracefully
    295  run:
    296    resulting 4-element array is as expected
    297    resulting zero-element array is as expected
    298    resulting 30-element array is as expected
    299 */
    300 
    301 // validation: array-type imm-operand needs to be "in range"
    302 assertErrorMessage(() => wasmEvalText(`(module
    303    (type $a (array i8))
    304    (func (result eqref)
    305      i32.const 66
    306      i32.const 77
    307      array.new_fixed 2 2  ;; type index 2 is the first invalid one
    308    )
    309 )
    310 `), WebAssembly.CompileError, /type index out of range/);
    311 
    312 // validation: array-type imm-operand must refer to an array type
    313 assertErrorMessage(() => wasmEvalText(`(module
    314    (type $a (func (param f64) (result f64)))
    315    (func (result eqref)
    316      i32.const 66
    317      i32.const 77
    318      array.new_fixed $a 2
    319    )
    320 )
    321 `), WebAssembly.CompileError, /not an array type/);
    322 
    323 // validation: operands (on stack) must all match ("be compatible with")
    324 //   the array elem type
    325 assertErrorMessage(() => wasmEvalText(`(module
    326    (type $a (array i32))
    327    (func (result eqref)
    328      f32.const 66.6
    329      f64.const 77.7
    330      array.new_fixed $a 2
    331    )
    332 )
    333 `), WebAssembly.CompileError, /expression has type f64 but expected i32/);
    334 
    335 // validation: number of operands (on stack) must not be less than the
    336 //   num-of-elems imm-operand
    337 assertNoWarning(() => wasmEvalText(`(module
    338    (type $a (array f32))
    339    (func
    340      f64.const 66.6  ;; we won't put this in the array
    341      f32.const 77.7
    342      f32.const 88.8
    343      array.new_fixed $a 2  ;; use up 88.8 and 77.7 and replace with array
    344      drop            ;; dump the array
    345      f64.const 99.9
    346      f64.mul         ;; check the 66.6 value is still on the stack
    347      drop            ;; now should be empty
    348    )
    349 )
    350 `));
    351 // (more)
    352 assertErrorMessage(() => wasmEvalText(`(module
    353    (type $a (array i64))
    354    (func (param i64) (result eqref)
    355       local.get 0
    356       array.new_fixed $a 2
    357    )
    358 )
    359 `), WebAssembly.CompileError, /popping value from empty stack/);
    360 
    361 // validation: zero elements doesn't fail compilation
    362 assertNoWarning(() => wasmEvalText(`(module
    363    (type $a (array i32))
    364    (func (result eqref)
    365       array.new_fixed $a 0
    366    )
    367 )
    368 `));
    369 
    370 // validation: reftyped elements doesn't fail compilation
    371 assertNoWarning(() => wasmEvalText(`(module
    372    (type $a (array eqref))
    373    (func (param eqref) (result eqref)
    374       local.get 0
    375       array.new_fixed $a 1
    376    )
    377 )
    378 `));
    379 
    380 // run: resulting 4-element array is as expected
    381 {
    382    let { newFixed } = wasmEvalText(`(module
    383        (type $a (array i8))
    384        (func (export "newFixed") (result eqref)
    385                i32.const 66
    386                i32.const 77
    387                i32.const 88
    388                i32.const 99
    389                array.new_fixed $a 4
    390        )
    391        )`).exports;
    392    let a = newFixed();
    393    assertEq(wasmGcArrayLength(a), 4);
    394    assertEq(wasmGcReadField(a, 0), 66);
    395    assertEq(wasmGcReadField(a, 1), 77);
    396    assertEq(wasmGcReadField(a, 2), 88);
    397    assertEq(wasmGcReadField(a, 3), 99);
    398 }
    399 
    400 // run: resulting zero-element array is as expected
    401 {
    402    let { newFixed } = wasmEvalText(`(module
    403        (type $a (array i16))
    404        (func (export "newFixed") (result eqref)
    405                array.new_fixed $a 0
    406        )
    407        )`).exports;
    408    let a = newFixed();
    409    assertEq(wasmGcArrayLength(a), 0);
    410 }
    411 
    412 // run: resulting 30-element array is as expected
    413 {
    414    let { newFixed } = wasmEvalText(`(module
    415        (type $a (array i16))
    416        (func (export "newFixed") (result eqref)
    417                i32.const 1
    418                i32.const 2
    419                i32.const 3
    420                i32.const 4
    421                i32.const 5
    422                i32.const 6
    423                i32.const 7
    424                i32.const 8
    425                i32.const 9
    426                i32.const 10
    427                i32.const 11
    428                i32.const 12
    429                i32.const 13
    430                i32.const 14
    431                i32.const 15
    432                i32.const 16
    433                i32.const 17
    434                i32.const 18
    435                i32.const 19
    436                i32.const 20
    437                i32.const 21
    438                i32.const 22
    439                i32.const 23
    440                i32.const 24
    441                i32.const 25
    442                i32.const 26
    443                i32.const 27
    444                i32.const 28
    445                i32.const 29
    446                i32.const 30
    447                array.new_fixed $a 30
    448        )
    449        )`).exports;
    450    let a = newFixed();
    451    assertEq(wasmGcArrayLength(a), 30);
    452    for (i = 0; i < 30; i++) {
    453        assertEq(wasmGcReadField(a, i), i + 1);
    454    }
    455 }
    456 
    457 // run: resulting 10_000-element array is as expected
    458 {
    459    let initializers = '';
    460    for (let i = 0; i < 10_000; i++) {
    461      initializers += `i32.const ${i + 1}\n`;
    462    }
    463    let { newFixed } = wasmEvalText(`(module
    464        (type $a (array i16))
    465        (func (export "newFixed") (result eqref)
    466                ${initializers}
    467                array.new_fixed $a 10000
    468        )
    469        )`).exports;
    470    let a = newFixed();
    471    assertEq(wasmGcArrayLength(a), 10000);
    472    for (i = 0; i < 10000; i++) {
    473        assertEq(wasmGcReadField(a, i), i + 1);
    474    }
    475 }
    476 
    477 //////////////////////////////////////////////////////////////////////////////
    478 //
    479 // array.new_data
    480 /*
    481  validation:
    482    array-type imm-operand needs to be "in range"
    483    array-type imm-operand must refer to an array type
    484    array-type imm-operand must refer to an array of numeric elements
    485    segment index must be "in range"
    486  run:
    487    if segment is "already used" (active, or passive that has subsequently
    488      been dropped), then only a zero length array can be created
    489    range to copy would require OOB read on data segment
    490    resulting array is as expected
    491 */
    492 
    493 // validation: array-type imm-operand needs to be "in range"
    494 assertErrorMessage(() => wasmEvalText(`(module
    495        (type $a (array i8))
    496        (data $d "1337")
    497        (func (export "newData") (result eqref)
    498                (; offset=0 into data ;) i32.const 0
    499                (; size=4 into data ;) i32.const 4
    500                array.new_data 2 $d
    501        )
    502 )`), WebAssembly.CompileError, /type index out of range/);
    503 
    504 // validation: array-type imm-operand must refer to an array type
    505 assertErrorMessage(() => wasmEvalText(`(module
    506        (type $a (func (param f32) (result f32)))
    507        (data $d "1337")
    508        (func (export "newData") (result eqref)
    509                (; offset=0 into data ;) i32.const 0
    510                (; size=4 into data ;) i32.const 4
    511                array.new_data $a $d
    512        )
    513 )`), WebAssembly.CompileError, /not an array type/);
    514 
    515 // validation: array-type imm-operand must refer to an array of numeric elements
    516 assertErrorMessage(() => wasmEvalText(`(module
    517        (type $a (array eqref))
    518        (data $d "1337")
    519        (func (export "newData") (result eqref)
    520                (; offset=0 into data ;) i32.const 0
    521                (; size=4 into data ;) i32.const 4
    522                array.new_data $a $d
    523        )
    524 )`), WebAssembly.CompileError,
    525                   /element type must be i8\/i16\/i32\/i64\/f32\/f64\/v128/);
    526 
    527 // validation: segment index must be "in range"
    528 assertErrorMessage(() => wasmEvalText(`(module
    529        (type $a (array i8))
    530        (data $d "1337")
    531        (func (export "newData") (result eqref)
    532                (; offset=0 into data ;) i32.const 0
    533                (; size=4 into data ;) i32.const 4
    534                array.new_data $a 1  ;; 1 is the lowest invalid dseg index
    535        )
    536 )`), WebAssembly.CompileError, /segment index is out of range/);
    537 
    538 // run: if segment is "already used" (active, or passive that has subsequently
    539 //        been dropped), then only a zero length array can be created #1
    540 {
    541    let { newData } = wasmEvalText(`(module
    542        (memory 1)
    543        (type $a (array i8))
    544        (data $d (offset (i32.const 0)) "1337")
    545        (func (export "newData") (result eqref)
    546                (; offset=0 into data ;) i32.const 0
    547                (; size=4 into data ;) i32.const 4
    548                array.new_data $a $d
    549        )
    550        )`).exports;
    551    assertErrorMessage(() => {
    552        newData();
    553    },WebAssembly.RuntimeError, /index out of bounds/);
    554 }
    555 
    556 // run: if segment is "already used" (active, or passive that has subsequently
    557 //        been dropped), then only a zero length array can be created #2
    558 {
    559    let { newData } = wasmEvalText(`(module
    560        (memory 1)
    561        (type $a (array i8))
    562        (data $d (offset (i32.const 0)) "1337")
    563        (func (export "newData") (result eqref)
    564                (; offset=4 into data ;) i32.const 4
    565                (; size=0 into data ;) i32.const 0
    566                array.new_data $a $d
    567        )
    568        )`).exports;
    569    assertErrorMessage(() => {
    570        newData();
    571    },WebAssembly.RuntimeError, /index out of bounds/);
    572 }
    573 
    574 // run: if segment is "already used" (active, or passive that has subsequently
    575 //        been dropped), then only a zero length array can be created #3
    576 {
    577    let { newData } = wasmEvalText(`(module
    578        (memory 1)
    579        (type $a (array i8))
    580        (data $d (offset (i32.const 0)) "1337")
    581        (func (export "newData") (result eqref)
    582                (; offset=0 into data ;) i32.const 0
    583                (; size=0 into data ;) i32.const 0
    584                array.new_data $a $d
    585        )
    586        )`).exports;
    587    let arr = newData();
    588    assertEq(wasmGcArrayLength(arr), 0);
    589 }
    590 
    591 // run: range to copy would require OOB read on data segment
    592 {
    593    let { newData } = wasmEvalText(`(module
    594        (type $a (array i8))
    595        (data $d "1337")
    596        (func (export "newData") (result eqref)
    597                (; offset=0 into data ;) i32.const 1
    598                (; size=4 into data ;) i32.const 4
    599                array.new_data $a $d
    600        )
    601        )`).exports;
    602    assertErrorMessage(() => {
    603        newData();
    604    },WebAssembly.RuntimeError, /index out of bounds/);
    605 }
    606 
    607 // run: zero-length copies are allowed
    608 {
    609  let { newData } = wasmEvalText(`(module
    610      (type $a (array i8))
    611      (data $d "1337")
    612      (func (export "newData") (result eqref)
    613              (; offset=0 into data ;) i32.const 0
    614              (; size=0 into data ;) i32.const 0
    615              array.new_data $a $d
    616      )
    617      )`).exports;
    618  let arr = newData();
    619  assertEq(wasmGcArrayLength(arr), 0);
    620 }
    621 
    622 // run: a zero-length copy from the end is allowed
    623 {
    624  let { newData } = wasmEvalText(`(module
    625      (type $a (array i8))
    626      (data $d "1337")
    627      (func (export "newData") (result eqref)
    628              (; offset=4 into data ;) i32.const 4
    629              (; size=0 into data ;) i32.const 0
    630              array.new_data $a $d
    631      )
    632      )`).exports;
    633  let arr = newData();
    634  assertEq(wasmGcArrayLength(arr), 0);
    635 }
    636 
    637 // run: even empty data segments are allowed
    638 {
    639  let { newData } = wasmEvalText(`(module
    640      (type $a (array i8))
    641      (data $d "")
    642      (func (export "newData") (result eqref)
    643              (; offset=0 into data ;) i32.const 0
    644              (; size=0 into data ;) i32.const 0
    645              array.new_data $a $d
    646      )
    647      )`).exports;
    648  let arr = newData();
    649  assertEq(wasmGcArrayLength(arr), 0);
    650 }
    651 
    652 // run: resulting array is as expected
    653 {
    654    let { newData } = wasmEvalText(`(module
    655        (type $a (array i8))
    656        (data $other "\\\\9")
    657        (data $d "1337")
    658        (func (export "newData") (result eqref)
    659                (; offset=0 into data ;) i32.const 0
    660                (; size=4 into data ;) i32.const 4
    661                array.new_data $a $d
    662        )
    663        )`).exports;
    664    let arr = newData();
    665    assertEq(wasmGcArrayLength(arr), 4);
    666    assertEq(wasmGcReadField(arr, 0), 48+1);
    667    assertEq(wasmGcReadField(arr, 1), 48+3);
    668    assertEq(wasmGcReadField(arr, 2), 48+3);
    669    assertEq(wasmGcReadField(arr, 3), 48+7);
    670 }
    671 
    672 //////////////////////////////////////////////////////////////////////////////
    673 //
    674 // array.new_elem
    675 /*
    676  validation:
    677    array-type imm-operand needs to be "in range"
    678    array-type imm-operand must refer to an array type
    679    array-type imm-operand must refer to an array of ref typed elements
    680    destination elem type must be a supertype of src elem type
    681    segment index must be "in range"
    682  run:
    683    if segment is "already used" (active, or passive that has subsequently
    684      been dropped), then only a zero length array can be created
    685    range to copy would require OOB read on elem segment
    686    resulting array is as expected
    687 */
    688 
    689 // validation: array-type imm-operand needs to be "in range"
    690 assertErrorMessage(() => wasmEvalText(`(module
    691        (type $a (array funcref))
    692        (elem $e func $f1 $f2 $f3 $f4)
    693        (func $f1 (export "f1"))
    694        (func $f2 (export "f2"))
    695        (func $f3 (export "f3"))
    696        (func $f4 (export "f4"))
    697        (func (export "newElem") (result eqref)
    698                (; offset=0 into elem ;) i32.const 0
    699                (; size=4 into elem ;) i32.const 4
    700                array.new_elem 3 $e
    701        )
    702 )`), WebAssembly.CompileError, /type index out of range/);
    703 
    704 // validation: array-type imm-operand must refer to an array type
    705 assertErrorMessage(() => wasmEvalText(`(module
    706        (type $a (func (param i64) (result f64)))
    707        (elem $e func $f1 $f2 $f3 $f4)
    708        (func $f1 (export "f1"))
    709        (func $f2 (export "f2"))
    710        (func $f3 (export "f3"))
    711        (func $f4 (export "f4"))
    712        (func (export "newElem") (result eqref)
    713                (; offset=0 into elem ;) i32.const 0
    714                (; size=4 into elem ;) i32.const 4
    715                array.new_elem $a $e
    716        )
    717 )`), WebAssembly.CompileError, /not an array type/);
    718 
    719 // validation: array-type imm-operand must refer to an array of ref typed
    720 //   elements
    721 assertErrorMessage(() => wasmEvalText(`(module
    722        (type $a (array f32))
    723        (elem $e func $f1 $f2 $f3 $f4)
    724        (func $f1 (export "f1"))
    725        (func $f2 (export "f2"))
    726        (func $f3 (export "f3"))
    727        (func $f4 (export "f4"))
    728        (func (export "newElem") (result eqref)
    729                (; offset=0 into elem ;) i32.const 0
    730                (; size=4 into elem ;) i32.const 4
    731                array.new_elem $a $e
    732        )
    733 )`), WebAssembly.CompileError, /element type is not a reftype/);
    734 
    735 // validation: destination elem type must be a supertype of src elem type
    736 assertErrorMessage(() => wasmEvalText(`(module
    737        (type $a (array eqref))
    738        (elem $e func $f1)
    739        (func $f1 (export "f1"))
    740        ;; The implied copy here is from elem-seg-of-funcrefs to
    741        ;; array-of-eqrefs, which must fail, because funcref isn't
    742        ;; a subtype of eqref.
    743        (func (export "newElem") (result eqref)
    744                (; offset=0 into elem ;) i32.const 0
    745                (; size=0 into elem ;) i32.const 0
    746                array.new_elem $a $e
    747        )
    748 )`), WebAssembly.CompileError, /incompatible element types/);
    749 
    750 // validation: segment index must be "in range"
    751 assertErrorMessage(() => wasmEvalText(`(module
    752        (type $a (array funcref))
    753        (elem $e func $f1 $f2 $f3 $f4)
    754        (func $f1 (export "f1"))
    755        (func $f2 (export "f2"))
    756        (func $f3 (export "f3"))
    757        (func $f4 (export "f4"))
    758        (func (export "newElem") (result eqref)
    759                (; offset=0 into elem ;) i32.const 0
    760                (; size=4 into elem ;) i32.const 4
    761                array.new_elem $a 1  ;; 1 is the lowest invalid eseg index
    762        )
    763 )`), WebAssembly.CompileError, /segment index is out of range/);
    764 
    765 // run: if segment is "already used" (active, or passive that has subsequently
    766 //        been dropped), then only a zero length array can be created #1
    767 {
    768    let { newElem } = wasmEvalText(`(module
    769        (table 4 funcref)
    770        (type $a (array funcref))
    771        (elem $e (offset (i32.const 0)) func $f1 $f2 $f3 $f4)
    772        (func $f1 (export "f1"))
    773        (func $f2 (export "f2"))
    774        (func $f3 (export "f3"))
    775        (func $f4 (export "f4"))
    776        (func (export "newElem") (result eqref)
    777                (; offset=0 into elem ;) i32.const 0
    778                (; size=4 into elem ;) i32.const 4
    779                array.new_elem $a $e
    780        )
    781        )`).exports;
    782    assertErrorMessage(() => {
    783        newElem();
    784    }, WebAssembly.RuntimeError, /index out of bounds/);
    785 }
    786 
    787 // run: if segment is "already used" (active, or passive that has subsequently
    788 //        been dropped), then only a zero length array can be created #2
    789 {
    790    let { newElem } = wasmEvalText(`(module
    791        (table 4 funcref)
    792        (type $a (array funcref))
    793        (elem $e (offset (i32.const 0)) func $f1 $f2 $f3 $f4)
    794        (func $f1 (export "f1"))
    795        (func $f2 (export "f2"))
    796        (func $f3 (export "f3"))
    797        (func $f4 (export "f4"))
    798        (func (export "newElem") (result eqref)
    799                (; offset=4 into elem ;) i32.const 4
    800                (; size=0 into elem ;) i32.const 0
    801                array.new_elem $a $e
    802        )
    803        )`).exports;
    804    assertErrorMessage(() => {
    805        newElem();
    806    }, WebAssembly.RuntimeError, /index out of bounds/);
    807 }
    808 
    809 // run: if segment is "already used" (active, or passive that has subsequently
    810 //        been dropped), then only a zero length array can be created #3
    811 {
    812    let { newElem } = wasmEvalText(`(module
    813        (table 4 funcref)
    814        (type $a (array funcref))
    815        (elem $e (offset (i32.const 0)) func $f1 $f2 $f3 $f4)
    816        (func $f1 (export "f1"))
    817        (func $f2 (export "f2"))
    818        (func $f3 (export "f3"))
    819        (func $f4 (export "f4"))
    820        (func (export "newElem") (result eqref)
    821                (; offset=0 into elem ;) i32.const 0
    822                (; size=0 into elem ;) i32.const 0
    823                array.new_elem $a $e
    824        )
    825        )`).exports;
    826    let arr = newElem();
    827    assertEq(wasmGcArrayLength(arr), 0);
    828 }
    829 
    830 // run: range to copy would require OOB read on elem segment
    831 {
    832    let { newElem } = wasmEvalText(`(module
    833        (type $a (array funcref))
    834        (elem $e func $f1 $f2 $f3 $f4)
    835        (func $f1 (export "f1"))
    836        (func $f2 (export "f2"))
    837        (func $f3 (export "f3"))
    838        (func $f4 (export "f4"))
    839        (func (export "newElem") (result eqref)
    840                (; offset=0 into elem ;) i32.const 1
    841                (; size=4 into elem ;) i32.const 4
    842                array.new_elem $a $e
    843        )
    844        )`).exports;
    845    assertErrorMessage(() => {
    846        newElem();
    847    },WebAssembly.RuntimeError, /index out of bounds/);
    848 }
    849 
    850 // run: zero-length copies are allowed
    851 {
    852  let { newElem, f1, f2, f3, f4 } = wasmEvalText(`(module
    853      (type $a (array funcref))
    854      (elem $e func $f1 $f2 $f3 $f4)
    855      (func $f1 (export "f1"))
    856      (func $f2 (export "f2"))
    857      (func $f3 (export "f3"))
    858      (func $f4 (export "f4"))
    859      (func (export "newElem") (result eqref)
    860              (; offset=0 into elem ;) i32.const 0
    861              (; size=0 into elem ;) i32.const 0
    862              array.new_elem $a $e
    863      )
    864      )`).exports;
    865  let arr = newElem();
    866  assertEq(wasmGcArrayLength(arr), 0);
    867 }
    868 
    869 // run: a zero-length copy from the end is allowed
    870 {
    871  let { newElem, f1, f2, f3, f4 } = wasmEvalText(`(module
    872      (type $a (array funcref))
    873      (elem $e func $f1 $f2 $f3 $f4)
    874      (func $f1 (export "f1"))
    875      (func $f2 (export "f2"))
    876      (func $f3 (export "f3"))
    877      (func $f4 (export "f4"))
    878      (func (export "newElem") (result eqref)
    879              (; offset=4 into elem ;) i32.const 4
    880              (; size=0 into elem ;) i32.const 0
    881              array.new_elem $a $e
    882      )
    883      )`).exports;
    884  let arr = newElem();
    885  assertEq(wasmGcArrayLength(arr), 0);
    886 }
    887 
    888 // run: even empty elem segments are allowed
    889 {
    890    let { newElem, f1, f2, f3, f4 } = wasmEvalText(`(module
    891        (type $a (array funcref))
    892        (elem $e func)
    893        (func (export "newElem") (result eqref)
    894                (; offset=0 into elem ;) i32.const 0
    895                (; size=0 into elem ;) i32.const 0
    896                array.new_elem $a $e
    897        )
    898        )`).exports;
    899    let arr = newElem();
    900    assertEq(wasmGcArrayLength(arr), 0);
    901 }
    902 
    903 // run: resulting array is as expected
    904 {
    905    let { newElem, f1, f2, f3, f4 } = wasmEvalText(`(module
    906        (type $a (array funcref))
    907        (elem $e func $f1 $f2 $f3 $f4)
    908        (func $f1 (export "f1"))
    909        (func $f2 (export "f2"))
    910        (func $f3 (export "f3"))
    911        (func $f4 (export "f4"))
    912        (func (export "newElem") (result eqref)
    913                (; offset=0 into elem ;) i32.const 0
    914                (; size=4 into elem ;) i32.const 4
    915                array.new_elem $a $e
    916        )
    917        )`).exports;
    918    let arr = newElem();
    919    assertEq(wasmGcArrayLength(arr), 4);
    920    assertEq(wasmGcReadField(arr, 0), f1);
    921    assertEq(wasmGcReadField(arr, 1), f2);
    922    assertEq(wasmGcReadField(arr, 2), f3);
    923    assertEq(wasmGcReadField(arr, 3), f4);
    924 }
    925 
    926 //////////////////////////////////////////////////////////////////////////////
    927 //
    928 // array.init_data
    929 /*
    930  validation:
    931    array-type imm-operand needs to be "in range"
    932    array-type imm-operand must refer to an array type
    933    array-type imm-operand must refer to an array of numeric elements
    934    array-type imm-operand must be mutable
    935    segment index must be "in range"
    936  run:
    937    array must not be null
    938    if segment is "already used" (active, or passive that has subsequently
    939      been dropped), then only a zero length array can be created
    940    range to copy would require OOB read on data segment
    941    range to copy would require OOB write on array
    942    resulting array is as expected
    943 */
    944 
    945 // validation: array-type imm-operand needs to be "in range"
    946 assertErrorMessage(() => wasmEvalText(`(module
    947  (type $a (array i8))
    948  (data $d "1337")
    949  (func (export "initData")
    950    (; array to init ;)       (array.new_default $a (i32.const 4))
    951    (; offset=0 into array ;) i32.const 0
    952    (; offset=0 into data ;)  i32.const 0
    953    (; size=4 elements ;)     i32.const 4
    954    array.init_data 2 $d
    955  )
    956 )`), WebAssembly.CompileError, /type index out of range/);
    957 
    958 // validation: array-type imm-operand must refer to an array type
    959 assertErrorMessage(() => wasmEvalText(`(module
    960  (type $a (func (param f32) (result f32)))
    961  (data $d "1337")
    962  (func (export "initData")
    963    (; array to init ;)       (array.new_default $a (i32.const 4))
    964    (; offset=0 into array ;) i32.const 0
    965    (; offset=0 into data ;)  i32.const 0
    966    (; size=4 elements ;)     i32.const 4
    967    array.init_data $a $d
    968  )
    969 )`), WebAssembly.CompileError, /not an array type/);
    970 
    971 // validation: array-type imm-operand must refer to an array of numeric elements
    972 assertErrorMessage(() => wasmEvalText(`(module
    973  (type $a (array eqref))
    974  (data $d "1337")
    975  (func (export "initData")
    976    (; array to init ;)       (array.new_default $a (i32.const 4))
    977    (; offset=0 into array ;) i32.const 0
    978    (; offset=0 into data ;)  i32.const 0
    979    (; size=4 elements ;)     i32.const 4
    980    array.init_data $a $d
    981  )
    982 )`), WebAssembly.CompileError, /element type must be i8\/i16\/i32\/i64\/f32\/f64\/v128/);
    983 
    984 // validation: array-type imm-operand must be mutable
    985 assertErrorMessage(() => wasmEvalText(`(module
    986  (type $a (array i8))
    987  (data $d "1337")
    988  (func (export "initData")
    989    (; array to init ;)       (array.new_default $a (i32.const 4))
    990    (; offset=0 into array ;) i32.const 0
    991    (; offset=0 into data ;)  i32.const 0
    992    (; size=4 elements ;)     i32.const 4
    993    array.init_data $a $d
    994  )
    995 )`), WebAssembly.CompileError,
    996             /destination array is not mutable/);
    997 
    998 // validation: segment index must be "in range"
    999 assertErrorMessage(() => wasmEvalText(`(module
   1000  (type $a (array (mut i8)))
   1001  (data $d "1337")
   1002  (func (export "initData")
   1003    (; array to init ;)       (array.new_default $a (i32.const 4))
   1004    (; offset=0 into array ;) i32.const 0
   1005    (; offset=0 into data ;)  i32.const 0
   1006    (; size=4 elements ;)     i32.const 4
   1007    array.init_data $a 1  ;; 1 is the lowest invalid dseg index
   1008  )
   1009  (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1010 )`), WebAssembly.CompileError, /segment index is out of range/);
   1011 
   1012 // run: array must not be null
   1013 {
   1014  let { initData } = wasmEvalText(`(module
   1015    (type $a (array (mut i8)))
   1016    (data $d "1337")
   1017    (func (export "initData")
   1018      (; array to init ;)       (ref.null $a)
   1019      (; offset=0 into array ;) i32.const 0
   1020      (; offset=0 into data ;)  i32.const 0
   1021      (; size=4 elements ;)     i32.const 4
   1022      array.init_data $a $d
   1023    )
   1024    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1025  )`).exports;
   1026  assertErrorMessage(() => {
   1027    initData();
   1028  }, WebAssembly.RuntimeError, /dereferencing null pointer/);
   1029 }
   1030 
   1031 // run: if segment is "already used" (active, or passive that has subsequently
   1032 //        been dropped), then only a zero length init can be performed #1
   1033 {
   1034  let { initData } = wasmEvalText(`(module
   1035    (memory 1)
   1036    (type $a (array (mut i8)))
   1037    (data $d (offset (i32.const 0)) "1337")
   1038    (func (export "initData")
   1039      (; array to init ;)       (array.new_default $a (i32.const 4))
   1040      (; offset=0 into array ;) i32.const 0
   1041      (; offset=0 into data ;)  i32.const 0
   1042      (; size=4 elements ;)     i32.const 4
   1043      array.init_data $a $d
   1044    )
   1045    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1046  )`).exports;
   1047  assertErrorMessage(() => {
   1048    initData();
   1049  }, WebAssembly.RuntimeError, /index out of bounds/);
   1050 }
   1051 
   1052 // run: if segment is "already used" (active, or passive that has subsequently
   1053 //        been dropped), then only a zero length init can be performed #2
   1054 {
   1055  let { initData } = wasmEvalText(`(module
   1056    (memory 1)
   1057    (type $a (array (mut i8)))
   1058    (data $d (offset (i32.const 0)) "1337")
   1059    (func (export "initData")
   1060      (; array to init ;)       (array.new_default $a (i32.const 4))
   1061      (; offset=0 into array ;) i32.const 0
   1062      (; offset=4 into data ;)  i32.const 4
   1063      (; size=0 elements ;)     i32.const 0
   1064      array.init_data $a $d
   1065    )
   1066    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1067  )`).exports;
   1068  assertErrorMessage(() => {
   1069    initData();
   1070  },WebAssembly.RuntimeError, /index out of bounds/);
   1071 }
   1072 
   1073 // run: if segment is "already used" (active, or passive that has subsequently
   1074 //        been dropped), then only a zero length init can be performed #3
   1075 {
   1076  let { initData } = wasmEvalText(`(module
   1077    (memory 1)
   1078    (type $a (array (mut i8)))
   1079    (data $d (offset (i32.const 0)) "1337")
   1080    (func (export "initData")
   1081      (; array to init ;)       (array.new_default $a (i32.const 4))
   1082      (; offset=0 into array ;) i32.const 0
   1083      (; offset=0 into data ;)  i32.const 0
   1084      (; size=0 elements ;)     i32.const 0
   1085      array.init_data $a $d
   1086    )
   1087    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1088  )`).exports;
   1089  initData();
   1090 }
   1091 
   1092 // run: if segment is "already used" (active, or passive that has subsequently
   1093 //        been dropped), then only a zero length init can be performed #4
   1094 {
   1095  let { initData } = wasmEvalText(`(module
   1096    (type $a (array (mut i8)))
   1097    (data $d "1337")
   1098    (func (export "initData")
   1099      data.drop $d
   1100 
   1101      (; array to init ;)       (array.new_default $a (i32.const 4))
   1102      (; offset=0 into array ;) i32.const 0
   1103      (; offset=0 into data ;)  i32.const 0
   1104      (; size=4 elements ;)     i32.const 4
   1105      array.init_data $a $d
   1106    )
   1107    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1108  )`).exports;
   1109  assertErrorMessage(() => {
   1110    initData();
   1111  },WebAssembly.RuntimeError, /index out of bounds/);
   1112 }
   1113 
   1114 // run: if segment is "already used" (active, or passive that has subsequently
   1115 //        been dropped), then only a zero length init can be performed #5
   1116 {
   1117  let { initData } = wasmEvalText(`(module
   1118    (type $a (array (mut i8)))
   1119    (data $d "1337")
   1120    (func (export "initData")
   1121      data.drop $d
   1122 
   1123      (; array to init ;)       (array.new_default $a (i32.const 4))
   1124      (; offset=0 into array ;) i32.const 0
   1125      (; offset=0 into data ;)  i32.const 0
   1126      (; size=0 elements ;)     i32.const 0
   1127      array.init_data $a $d
   1128    )
   1129    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1130  )`).exports;
   1131  initData();
   1132 }
   1133 
   1134 // run: if segment is "already used" (active, or passive that has subsequently
   1135 //        been dropped), then only a zero length init can be performed #6
   1136 {
   1137  let { initData } = wasmEvalText(`(module
   1138    (memory 1)
   1139    (type $a (array (mut i8)))
   1140    (data $d "1337")
   1141    (func (export "initData")
   1142      data.drop $d
   1143 
   1144      (; array to init ;)       (array.new_default $a (i32.const 4))
   1145      (; offset=4 into array ;) i32.const 4
   1146      (; offset=0 into data ;)  i32.const 0
   1147      (; size=0 elements ;)     i32.const 0
   1148      array.init_data $a $d
   1149    )
   1150    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1151  )`).exports;
   1152  initData();
   1153 }
   1154 
   1155 // run: range to copy would require OOB read on data segment #1
   1156 {
   1157  let { initData } = wasmEvalText(`(module
   1158    (type $a (array (mut i8)))
   1159    (data $d "1337")
   1160    (func (export "initData")
   1161      (; array to init ;)       (array.new_default $a (i32.const 4))
   1162      (; offset=0 into array ;) i32.const 0
   1163      (; offset=1 into data ;)  i32.const 1
   1164      (; size=4 elements ;)     i32.const 4
   1165      array.init_data $a $d
   1166    )
   1167    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1168  )`).exports;
   1169  assertErrorMessage(() => {
   1170    initData();
   1171  },WebAssembly.RuntimeError, /index out of bounds/);
   1172 }
   1173 
   1174 // run: range to copy would require OOB read on data segment #2
   1175 {
   1176  let { initData } = wasmEvalText(`(module
   1177    (type $a (array (mut i16)))
   1178    (data $d "1337")
   1179    (func (export "initData")
   1180      (; array to init ;)       (array.new_default $a (i32.const 4))
   1181      (; offset=0 into array ;) i32.const 0
   1182      (; offset=1 into data ;)  i32.const 1
   1183      (; size=2 elements ;)     i32.const 2 ;; still 4 bytes
   1184      array.init_data $a $d
   1185    )
   1186    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1187  )`).exports;
   1188  assertErrorMessage(() => {
   1189    initData();
   1190  },WebAssembly.RuntimeError, /index out of bounds/);
   1191 }
   1192 
   1193 // run: range to copy would require OOB write on array #1
   1194 {
   1195  let { initData } = wasmEvalText(`(module
   1196    (type $a (array (mut i8)))
   1197    (data $d "1337")
   1198    (func (export "initData")
   1199      (; array to init ;)       (array.new_default $a (i32.const 4))
   1200      (; offset=1 into array ;) i32.const 1
   1201      (; offset=0 into data ;)  i32.const 0
   1202      (; size=4 elements ;)     i32.const 4
   1203      array.init_data $a $d
   1204    )
   1205    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1206  )`).exports;
   1207  assertErrorMessage(() => {
   1208    initData();
   1209  },WebAssembly.RuntimeError, /index out of bounds/);
   1210 }
   1211 
   1212 // run: range to copy would require OOB write on array #2
   1213 {
   1214  let { initData } = wasmEvalText(`(module
   1215    (type $a (array (mut i16)))
   1216    (data $d "1337")
   1217    (func (export "initData")
   1218      (; array to init ;)       (array.new_default $a (i32.const 2))
   1219      (; offset=1 into array ;) i32.const 1
   1220      (; offset=0 into data ;)  i32.const 0
   1221      (; size=4 elements ;)     i32.const 2
   1222      array.init_data $a $d
   1223    )
   1224    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1225  )`).exports;
   1226  assertErrorMessage(() => {
   1227    initData();
   1228  },WebAssembly.RuntimeError, /index out of bounds/);
   1229 }
   1230 
   1231 // run: zeroes everywhere
   1232 {
   1233  let { initData } = wasmEvalText(`(module
   1234    (type $a (array (mut i8)))
   1235    (data $d "")
   1236    (func (export "initData") (result eqref)
   1237      (local $arr (ref $a))
   1238      (local.set $arr (array.new_default $a (i32.const 0)))
   1239 
   1240      (; array to init ;)       local.get $arr
   1241      (; offset=0 into array ;) i32.const 0
   1242      (; offset=0 into data ;)  i32.const 0
   1243      (; size=0 elements ;)     i32.const 0
   1244      array.init_data $a $d
   1245 
   1246      local.get $arr
   1247    )
   1248    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1249  )`).exports;
   1250  let arr = initData();
   1251  assertEq(wasmGcArrayLength(arr), 0);
   1252 }
   1253 
   1254 // run: resulting array is as expected
   1255 {
   1256  let { initData } = wasmEvalText(`(module
   1257    (type $a (array (mut i8)))
   1258    (data $other "\\\\9")
   1259    (data $d "xX1337Xx")
   1260    (func (export "initData") (result eqref)
   1261      (local $arr (ref $a))
   1262      (local.set $arr (array.new_default $a (i32.const 6)))
   1263 
   1264      (; array to init ;)       local.get $arr
   1265      (; offset=1 into array ;) i32.const 1
   1266      (; offset=2 into data ;)  i32.const 2
   1267      (; size=4 elements ;)     i32.const 4
   1268      array.init_data $a $d
   1269 
   1270      local.get $arr
   1271    )
   1272    (func data.drop 0) ;; force write of data count section, see https://github.com/bytecodealliance/wasm-tools/pull/1194
   1273  )`).exports;
   1274  let arr = initData();
   1275  assertEq(wasmGcArrayLength(arr), 6);
   1276  assertEq(wasmGcReadField(arr, 0), 0);
   1277  assertEq(wasmGcReadField(arr, 1), 48+1);
   1278  assertEq(wasmGcReadField(arr, 2), 48+3);
   1279  assertEq(wasmGcReadField(arr, 3), 48+3);
   1280  assertEq(wasmGcReadField(arr, 4), 48+7);
   1281  assertEq(wasmGcReadField(arr, 5), 0);
   1282 }
   1283 
   1284 //////////////////////////////////////////////////////////////////////////////
   1285 //
   1286 // array.init_elem
   1287 /*
   1288  validation:
   1289    array-type imm-operand needs to be "in range"
   1290    array-type imm-operand must refer to an array type
   1291    array-type imm-operand must refer to an array of ref typed elements
   1292    array-type imm-operand must be mutable
   1293    destination elem type must be a supertype of src elem type
   1294    segment index must be "in range"
   1295  run:
   1296    array must not be null
   1297    if segment is "already used" (active, or passive that has subsequently
   1298      been dropped), then only a zero length array can be created
   1299    range to copy would require OOB read on element segment
   1300    range to copy would require OOB write on array
   1301    resulting array is as expected
   1302 */
   1303 
   1304 // validation: array-type imm-operand needs to be "in range"
   1305 assertErrorMessage(() => wasmEvalText(`(module
   1306  (type $a (array (mut funcref)))
   1307  (elem $e func $f1 $f2 $f3 $f4)
   1308  (func $f1 (export "f1"))
   1309  (func $f2 (export "f2"))
   1310  (func $f3 (export "f3"))
   1311  (func $f4 (export "f4"))
   1312  (func (export "initElem")
   1313    (; array to init ;)       (array.new_default $a (i32.const 4))
   1314    (; offset=0 into array ;) i32.const 0
   1315    (; offset=0 into elem ;)  i32.const 0
   1316    (; size=4 into elem ;)    i32.const 4
   1317    array.init_elem 4 $e
   1318  )
   1319 )`), WebAssembly.CompileError, /type index out of range/);
   1320 
   1321 // validation: array-type imm-operand must refer to an array type
   1322 assertErrorMessage(() => wasmEvalText(`(module
   1323  (type $a (func (param i64) (result f64)))
   1324  (elem $e func $f1 $f2 $f3 $f4)
   1325  (func $f1 (export "f1"))
   1326  (func $f2 (export "f2"))
   1327  (func $f3 (export "f3"))
   1328  (func $f4 (export "f4"))
   1329  (func (export "initElem")
   1330    (; array to init ;)       (array.new_default $a (i32.const 4))
   1331    (; offset=0 into array ;) i32.const 0
   1332    (; offset=0 into elem ;)  i32.const 0
   1333    (; size=4 into elem ;)    i32.const 4
   1334    array.init_elem $a $e
   1335  )
   1336 )`), WebAssembly.CompileError, /not an array type/);
   1337 
   1338 // validation: array-type imm-operand must refer to an array of ref typed
   1339 //   elements
   1340 assertErrorMessage(() => wasmEvalText(`(module
   1341  (type $a (array (mut f32)))
   1342  (elem $e func $f1 $f2 $f3 $f4)
   1343  (func $f1 (export "f1"))
   1344  (func $f2 (export "f2"))
   1345  (func $f3 (export "f3"))
   1346  (func $f4 (export "f4"))
   1347  (func (export "initElem")
   1348    (; array to init ;)       (array.new_default $a (i32.const 4))
   1349    (; offset=0 into array ;) i32.const 0
   1350    (; offset=0 into elem ;)  i32.const 0
   1351    (; size=4 into elem ;)    i32.const 4
   1352    array.init_elem $a $e
   1353  )
   1354 )`), WebAssembly.CompileError, /element type is not a reftype/);
   1355 
   1356 // validation: array-type imm-operand must be mutable
   1357 assertErrorMessage(() => wasmEvalText(`(module
   1358  (type $a (array funcref))
   1359  (elem $e func $f1 $f2 $f3 $f4)
   1360  (func $f1 (export "f1"))
   1361  (func $f2 (export "f2"))
   1362  (func $f3 (export "f3"))
   1363  (func $f4 (export "f4"))
   1364  (func (export "initElem")
   1365    (; array to init ;)       (array.new_default $a (i32.const 4))
   1366    (; offset=0 into array ;) i32.const 0
   1367    (; offset=0 into elem ;)  i32.const 0
   1368    (; size=4 into elem ;)    i32.const 4
   1369    array.init_elem $a $e
   1370  )
   1371 )`), WebAssembly.CompileError, /destination array is not mutable/);
   1372 
   1373 // validation: destination elem type must be a supertype of src elem type
   1374 assertErrorMessage(() => wasmEvalText(`(module
   1375  (type $a (array (mut eqref)))
   1376  (elem $e func $f1)
   1377  (func $f1 (export "f1"))
   1378  ;; The copy here is from elem-seg-of-funcrefs to
   1379  ;; array-of-eqrefs, which must fail, because funcref isn't
   1380  ;; a subtype of eqref.
   1381  (func (export "initElem")
   1382    (; array to init ;)       (array.new_default $a (i32.const 4))
   1383    (; offset=0 into array ;) i32.const 0
   1384    (; offset=0 into elem ;)  i32.const 0
   1385    (; size=4 into elem ;)    i32.const 4
   1386    array.init_elem $a $e
   1387  )
   1388 )`), WebAssembly.CompileError, /incompatible element types/);
   1389 
   1390 // validation: segment index must be "in range"
   1391 assertErrorMessage(() => wasmEvalText(`(module
   1392  (type $a (array (mut funcref)))
   1393  (elem $e func $f1 $f2 $f3 $f4)
   1394  (func $f1 (export "f1"))
   1395  (func $f2 (export "f2"))
   1396  (func $f3 (export "f3"))
   1397  (func $f4 (export "f4"))
   1398  (func (export "initElem")
   1399    (; array to init ;)       (array.new_default $a (i32.const 4))
   1400    (; offset=0 into array ;) i32.const 0
   1401    (; offset=0 into elem ;)  i32.const 0
   1402    (; size=4 into elem ;)    i32.const 4
   1403    array.init_elem $a 1 ;; 1 is the lowest invalid eseg index
   1404  )
   1405 )`), WebAssembly.CompileError, /segment index is out of range/);
   1406 
   1407 // run: array must not be null
   1408 {
   1409  let { initElem } = wasmEvalText(`(module
   1410    (type $a (array (mut funcref)))
   1411    (elem $e func $f1 $f2 $f3 $f4)
   1412    (func $f1 (export "f1"))
   1413    (func $f2 (export "f2"))
   1414    (func $f3 (export "f3"))
   1415    (func $f4 (export "f4"))
   1416    (func (export "initElem")
   1417      (; array to init ;)       (ref.null $a)
   1418      (; offset=0 into array ;) i32.const 0
   1419      (; offset=0 into elem ;)  i32.const 0
   1420      (; size=4 into elem ;)    i32.const 4
   1421      array.init_elem $a $e
   1422    )
   1423  )`).exports;
   1424  assertErrorMessage(() => {
   1425    initElem();
   1426  }, WebAssembly.RuntimeError, /dereferencing null pointer/);
   1427 }
   1428 
   1429 // run: if segment is "already used" (active, or passive that has subsequently
   1430 //        been dropped), then only a zero length array can be created #1
   1431 {
   1432  let { initElem } = wasmEvalText(`(module
   1433    (table 4 funcref)
   1434    (type $a (array (mut funcref)))
   1435    (elem $e (offset (i32.const 0)) func $f1 $f2 $f3 $f4)
   1436    (func $f1 (export "f1"))
   1437    (func $f2 (export "f2"))
   1438    (func $f3 (export "f3"))
   1439    (func $f4 (export "f4"))
   1440    (func (export "initElem")
   1441      (; array to init ;)       (array.new_default $a (i32.const 4))
   1442      (; offset=0 into array ;) i32.const 0
   1443      (; offset=0 into elem ;)  i32.const 0
   1444      (; size=4 into elem ;)    i32.const 4
   1445      array.init_elem $a $e
   1446    )
   1447  )`).exports;
   1448  assertErrorMessage(() => {
   1449    initElem();
   1450  }, WebAssembly.RuntimeError, /index out of bounds/);
   1451 }
   1452 
   1453 // run: if segment is "already used" (active, or passive that has subsequently
   1454 //        been dropped), then only a zero length array can be created #2
   1455 {
   1456  let { initElem } = wasmEvalText(`(module
   1457    (table 4 funcref)
   1458    (type $a (array (mut funcref)))
   1459    (elem $e (offset (i32.const 0)) func $f1 $f2 $f3 $f4)
   1460    (func $f1 (export "f1"))
   1461    (func $f2 (export "f2"))
   1462    (func $f3 (export "f3"))
   1463    (func $f4 (export "f4"))
   1464    (func (export "initElem")
   1465      (; array to init ;)       (array.new_default $a (i32.const 4))
   1466      (; offset=0 into array ;) i32.const 0
   1467      (; offset=4 into elem ;)  i32.const 4
   1468      (; size=0 into elem ;)    i32.const 0
   1469      array.init_elem $a $e
   1470    )
   1471  )`).exports;
   1472  assertErrorMessage(() => {
   1473    initElem();
   1474  }, WebAssembly.RuntimeError, /index out of bounds/);
   1475 }
   1476 
   1477 // run: if segment is "already used" (active, or passive that has subsequently
   1478 //        been dropped), then only a zero length array can be created #3
   1479 {
   1480  let { initElem } = wasmEvalText(`(module
   1481    (table 4 funcref)
   1482    (type $a (array (mut funcref)))
   1483    (elem $e (offset (i32.const 0)) func $f1 $f2 $f3 $f4)
   1484    (func $f1 (export "f1"))
   1485    (func $f2 (export "f2"))
   1486    (func $f3 (export "f3"))
   1487    (func $f4 (export "f4"))
   1488    (func (export "initElem")
   1489      (; array to init ;)       (array.new_default $a (i32.const 4))
   1490      (; offset=0 into array ;) i32.const 0
   1491      (; offset=0 into elem ;)  i32.const 0
   1492      (; size=0 into elem ;)    i32.const 0
   1493      array.init_elem $a $e
   1494    )
   1495  )`).exports;
   1496  initElem();
   1497 }
   1498 
   1499 // run: if segment is "already used" (active, or passive that has subsequently
   1500 //        been dropped), then only a zero length init can be performed #4
   1501 {
   1502  let { initElem } = wasmEvalText(`(module
   1503    (type $a (array (mut funcref)))
   1504    (elem $e func $f1 $f2 $f3 $f4)
   1505    (func $f1 (export "f1"))
   1506    (func $f2 (export "f2"))
   1507    (func $f3 (export "f3"))
   1508    (func $f4 (export "f4"))
   1509    (func (export "initElem")
   1510      elem.drop $e
   1511 
   1512      (; array to init ;)       (array.new_default $a (i32.const 4))
   1513      (; offset=0 into array ;) i32.const 0
   1514      (; offset=0 into elem ;)  i32.const 0
   1515      (; size=4 into elem ;)    i32.const 4
   1516      array.init_elem $a $e
   1517    )
   1518  )`).exports;
   1519  assertErrorMessage(() => {
   1520    initElem();
   1521  },WebAssembly.RuntimeError, /index out of bounds/);
   1522 }
   1523 
   1524 // run: if segment is "already used" (active, or passive that has subsequently
   1525 //        been dropped), then only a zero length init can be performed #5
   1526 {
   1527  let { initElem } = wasmEvalText(`(module
   1528    (type $a (array (mut funcref)))
   1529    (elem $e func $f1 $f2 $f3 $f4)
   1530    (func $f1 (export "f1"))
   1531    (func $f2 (export "f2"))
   1532    (func $f3 (export "f3"))
   1533    (func $f4 (export "f4"))
   1534    (func (export "initElem")
   1535      elem.drop $e
   1536 
   1537      (; array to init ;)       (array.new_default $a (i32.const 4))
   1538      (; offset=0 into array ;) i32.const 0
   1539      (; offset=0 into elem ;)  i32.const 0
   1540      (; size=4 into elem ;)    i32.const 0
   1541      array.init_elem $a $e
   1542    )
   1543  )`).exports;
   1544  initElem();
   1545 }
   1546 
   1547 // run: if segment is "already used" (active, or passive that has subsequently
   1548 //        been dropped), then only a zero length init can be performed #6
   1549 {
   1550  let { initElem } = wasmEvalText(`(module
   1551    (type $a (array (mut funcref)))
   1552    (elem $e func $f1 $f2 $f3 $f4)
   1553    (func $f1 (export "f1"))
   1554    (func $f2 (export "f2"))
   1555    (func $f3 (export "f3"))
   1556    (func $f4 (export "f4"))
   1557    (func (export "initElem")
   1558      elem.drop $e
   1559 
   1560      (; array to init ;)       (array.new_default $a (i32.const 4))
   1561      (; offset=0 into array ;) i32.const 4
   1562      (; offset=0 into elem ;)  i32.const 0
   1563      (; size=4 into elem ;)    i32.const 0
   1564      array.init_elem $a $e
   1565    )
   1566  )`).exports;
   1567  initElem();
   1568 }
   1569 
   1570 // run: range to copy would require OOB read on elem segment
   1571 {
   1572  let { initElem } = wasmEvalText(`(module
   1573    (type $a (array (mut funcref)))
   1574    (elem $e func $f1 $f2 $f3 $f4)
   1575    (func $f1 (export "f1"))
   1576    (func $f2 (export "f2"))
   1577    (func $f3 (export "f3"))
   1578    (func $f4 (export "f4"))
   1579    (func (export "initElem")
   1580      (; array to init ;)       (array.new_default $a (i32.const 4))
   1581      (; offset=0 into array ;) i32.const 0
   1582      (; offset=0 into elem ;)  i32.const 1
   1583      (; size=4 into elem ;)    i32.const 4
   1584      array.init_elem $a $e
   1585    )
   1586  )`).exports;
   1587  assertErrorMessage(() => {
   1588    initElem();
   1589  },WebAssembly.RuntimeError, /index out of bounds/);
   1590 }
   1591 
   1592 // run: range to copy would require OOB write on array
   1593 {
   1594  let { initElem } = wasmEvalText(`(module
   1595    (type $a (array (mut funcref)))
   1596    (elem $e func $f1 $f2 $f3 $f4)
   1597    (func $f1 (export "f1"))
   1598    (func $f2 (export "f2"))
   1599    (func $f3 (export "f3"))
   1600    (func $f4 (export "f4"))
   1601    (func (export "initElem")
   1602      (; array to init ;)       (array.new_default $a (i32.const 4))
   1603      (; offset=0 into array ;) i32.const 1
   1604      (; offset=0 into elem ;)  i32.const 0
   1605      (; size=4 into elem ;)    i32.const 4
   1606      array.init_elem $a $e
   1607    )
   1608  )`).exports;
   1609  assertErrorMessage(() => {
   1610    initElem();
   1611  },WebAssembly.RuntimeError, /index out of bounds/);
   1612 }
   1613 
   1614 // run: zeroes everywhere
   1615 {
   1616  let { initElem, f1, f2, f3, f4 } = wasmEvalText(`(module
   1617    (type $a (array (mut funcref)))
   1618    (elem $e func)
   1619    (func (export "initElem") (result eqref)
   1620      (local $arr (ref $a))
   1621      (local.set $arr (array.new_default $a (i32.const 0)))
   1622 
   1623      (; array to init ;)       local.get $arr
   1624      (; offset=0 into array ;) i32.const 0
   1625      (; offset=0 into elem ;)  i32.const 0
   1626      (; size=0 into elem ;)    i32.const 0
   1627      array.init_elem $a $e
   1628 
   1629      local.get $arr
   1630    )
   1631  )`).exports;
   1632  let arr = initElem();
   1633  assertEq(wasmGcArrayLength(arr), 0);
   1634 }
   1635 
   1636 // run: resulting array is as expected
   1637 {
   1638  let { initElem, f1, f2, f3, f4 } = wasmEvalText(`(module
   1639    (type $a (array (mut funcref)))
   1640    (elem $e func $f5 $f5 $f1 $f2 $f3 $f4 $f5 $f5)
   1641    (func $f1 (export "f1"))
   1642    (func $f2 (export "f2"))
   1643    (func $f3 (export "f3"))
   1644    (func $f4 (export "f4"))
   1645    (func $f5)
   1646    (func (export "initElem") (result eqref)
   1647      (local $arr (ref $a))
   1648      (local.set $arr (array.new_default $a (i32.const 6)))
   1649 
   1650      (; array to init ;)       local.get $arr
   1651      (; offset=1 into array ;) i32.const 1
   1652      (; offset=2 into elem ;)  i32.const 2
   1653      (; size=4 into elem ;)    i32.const 4
   1654      array.init_elem $a $e
   1655 
   1656      local.get $arr
   1657    )
   1658  )`).exports;
   1659  let arr = initElem();
   1660  assertEq(wasmGcArrayLength(arr), 6);
   1661  assertEq(wasmGcReadField(arr, 0), null);
   1662  assertEq(wasmGcReadField(arr, 1), f1);
   1663  assertEq(wasmGcReadField(arr, 2), f2);
   1664  assertEq(wasmGcReadField(arr, 3), f3);
   1665  assertEq(wasmGcReadField(arr, 4), f4);
   1666  assertEq(wasmGcReadField(arr, 5), null);
   1667 }
   1668 
   1669 //////////////////////////////////////////////////////////////////////////////
   1670 //
   1671 // array.copy
   1672 /*
   1673  validation:
   1674    dest array must be mutable
   1675    validation: src and dest arrays must have compatible element types
   1676  run:
   1677    check for OOB conditions on src/dest arrays for non-zero length copies
   1678    check for OOB conditions on src/dest arrays for zero length copies
   1679    check resulting arrays are as expected
   1680    check that null src or dest array causes a trap
   1681 */
   1682 
   1683 // validation: dest array must be mutable
   1684 assertErrorMessage(() => wasmEvalText(`(module
   1685    (type $a (array i32))
   1686    (func (param eqref)
   1687      (array.copy $a $a (local.get 0) (i32.const 1)
   1688                        (local.get 0) (i32.const 2) (i32.const 3))
   1689    )
   1690 )
   1691 `), WebAssembly.CompileError, /array is not mutable/);
   1692 
   1693 // validation: src and dest arrays must have compatible element types #1
   1694 assertErrorMessage(() => wasmEvalText(`(module
   1695    (type $a32 (array (mut i32)))
   1696    (type $a8  (array i8))
   1697    (func (param eqref)
   1698      (array.copy $a32 $a8 (local.get 0) (i32.const 1)
   1699                           (local.get 0) (i32.const 2) (i32.const 3))
   1700    )
   1701 )
   1702 `), WebAssembly.CompileError, /incompatible element types/);
   1703 
   1704 // validation: src and dest arrays must have compatible element types #2
   1705 assertErrorMessage(() => wasmEvalText(`(module
   1706    (type $a64 (array (mut i64)))
   1707    (type $aER (array eqref))
   1708    (func (param eqref)
   1709      (array.copy $a64 $aER (local.get 0) (i32.const 1)
   1710                            (local.get 0) (i32.const 2) (i32.const 3))
   1711    )
   1712 )
   1713 `), WebAssembly.CompileError, /incompatible element types/);
   1714 
   1715 // validation: src and dest arrays must have compatible element types #3
   1716 //
   1717 // We can only copy from a child (sub) reftype to a parent (super) reftype [or
   1718 // to the same reftype.]  Here, we have an array of eqref and an array of
   1719 // arrays.  An array is a child type of eqref, so it's invalid to try and copy
   1720 // eqrefs into the array of arrays.
   1721 assertErrorMessage(() => wasmEvalText(`(module
   1722    (type $ty (array i32))
   1723    (type $child  (array (mut (ref $ty))))
   1724    (type $parent (array (mut eqref)))
   1725    (func (param (ref null $child) (ref null $parent))
   1726      ;; implied copy from parent to child -> not allowed
   1727      (array.copy $child $parent (local.get 1) (i32.const 1)
   1728                                 (local.get 0) (i32.const 2) (i32.const 3))
   1729    )
   1730 )
   1731 `), WebAssembly.CompileError, /incompatible element types/);
   1732 
   1733 // run: check for OOB conditions on src/dest arrays for non-zero length copies
   1734 // run: check for OOB conditions on src/dest arrays for zero length copies
   1735 // run: check resulting arrays are as expected
   1736 const ARRAY_COPY_TESTS = [
   1737    // Format is:
   1738    //   array element type
   1739    //   corresponding value type
   1740    //   source array
   1741    //   first expected result
   1742    //   second expected result
   1743    //
   1744    // Value-type cases
   1745    [ 'i32', 'i32',
   1746      [22, 33, 44, 55, 66, 77],
   1747      [22, 55, 66, 77, 66, 77],
   1748      [22, 33, 22, 33, 44, 77]
   1749    ],
   1750    [ 'i64', 'i64',
   1751      [0x2022002220002n, 0x3033003330003n, 0x4044004440004n,
   1752       0x5055005550005n, 0x6066006660006n, 0x7077007770007n],
   1753      [0x2022002220002n, 0x5055005550005n, 0x6066006660006n,
   1754       0x7077007770007n, 0x6066006660006n, 0x7077007770007n],
   1755      [0x2022002220002n, 0x3033003330003n, 0x2022002220002n,
   1756       0x3033003330003n, 0x4044004440004n, 0x7077007770007n]
   1757    ],
   1758    [ 'f32', 'f32',
   1759      [22.0, 33.0, 44.0, 55.0, 66.0, 77.0],
   1760      [22.0, 55.0, 66.0, 77.0, 66.0, 77.0],
   1761      [22.0, 33.0, 22.0, 33.0, 44.0, 77.0]
   1762    ],
   1763    [ 'f64', 'f64',
   1764      [22.0, 33.0, 44.0, 55.0, 66.0, 77.0],
   1765      [22.0, 55.0, 66.0, 77.0, 66.0, 77.0],
   1766      [22.0, 33.0, 22.0, 33.0, 44.0, 77.0]
   1767    ],
   1768    [ 'externref', 'externref',
   1769      ['two', 'three', 'four',  'five',  'six', 'seven'],
   1770      ['two',  'five',  'six', 'seven',  'six', 'seven'],
   1771      ['two', 'three',  'two', 'three', 'four', 'seven']
   1772    ],
   1773    // non-Value-type cases
   1774    [ 'i8', 'i32',
   1775      [22, 33, 44, 55, 66, 77],
   1776      [22, 55, 66, 77, 66, 77],
   1777      [22, 33, 22, 33, 44, 77]
   1778    ],
   1779    [ 'i16', 'i32',
   1780      [22, 33, 44, 55, 66, 77],
   1781      [22, 55, 66, 77, 66, 77],
   1782      [22, 33, 22, 33, 44, 77]
   1783    ]
   1784 ];
   1785 
   1786 for (let [elemTy, valueTy, src, exp1, exp2] of ARRAY_COPY_TESTS) {
   1787    let { arrayNew, arrayCopy } = wasmEvalText(
   1788     `(module
   1789        (type $arrTy (array (mut ${elemTy})))
   1790        (func (export "arrayNew")
   1791              (param ${valueTy} ${valueTy} ${valueTy}
   1792                     ${valueTy} ${valueTy} ${valueTy})
   1793              (result eqref)
   1794          local.get 0
   1795          local.get 1
   1796          local.get 2
   1797          local.get 3
   1798          local.get 4
   1799          local.get 5
   1800          array.new_fixed $arrTy 6
   1801        )
   1802        (func (export "arrayCopy")
   1803              (param eqref i32 eqref i32 i32)
   1804          (array.copy $arrTy $arrTy
   1805            (ref.cast (ref null $arrTy) local.get 0) (local.get 1)
   1806            (ref.cast (ref null $arrTy) local.get 2) (local.get 3) (local.get 4)
   1807          )
   1808        )
   1809      )`
   1810    ).exports;
   1811 
   1812    assertEq(src.length, 6);
   1813    assertEq(exp1.length, 6);
   1814    assertEq(exp2.length, 6);
   1815 
   1816    function eqArrays(a1, a2) {
   1817        function len(arr) {
   1818            return Array.isArray(arr) ? arr.length : wasmGcArrayLength(arr);
   1819        }
   1820        function get(arr, i) {
   1821            return Array.isArray(arr) ? arr[i] : wasmGcReadField(arr, i);
   1822        }
   1823        assertEq(len(a1), 6);
   1824        assertEq(len(a2), 6);
   1825        for (i = 0; i < 6; i++) {
   1826            if (get(a1, i) !== get(a2, i))
   1827                return false;
   1828        }
   1829        return true;
   1830    }
   1831    function show(who, arr) {
   1832        print(who + ": " + arr[0] + " " + arr[1] + " " + arr[2] + " "
   1833                         + arr[3] + " " + arr[4] + " " + arr[5] + " ");
   1834    }
   1835 
   1836    // Check that "normal" copying gives expected results.
   1837    let srcTO;
   1838    srcTO = arrayNew(src[0], src[1], src[2], src[3], src[4], src[5]);
   1839    arrayCopy(srcTO, 1, srcTO, 3, 3);
   1840    assertEq(eqArrays(srcTO, exp1), true);
   1841 
   1842    srcTO = arrayNew(src[0], src[1], src[2], src[3], src[4], src[5]);
   1843    arrayCopy(srcTO, 2, srcTO, 0, 3);
   1844    assertEq(eqArrays(srcTO, exp2), true);
   1845 
   1846    // Check out-of-bounds conditions
   1847    let exp1TO = arrayNew(exp1[0], exp1[1], exp1[2], exp1[3], exp1[4], exp1[5]);
   1848    let exp2TO = arrayNew(exp2[0], exp2[1], exp2[2], exp2[3], exp2[4], exp2[5]);
   1849 
   1850    // dst overrun, wants to write [5, 6]
   1851    assertErrorMessage(() => {
   1852        arrayCopy(exp1TO, 5, exp2TO, 1, 2);
   1853    },WebAssembly.RuntimeError, /index out of bounds/);
   1854 
   1855    // dst overrun, wants to write [7, 8]
   1856    assertErrorMessage(() => {
   1857        arrayCopy(exp1TO, 7, exp2TO, 1, 2);
   1858    },WebAssembly.RuntimeError, /index out of bounds/);
   1859 
   1860    // dst zero-len overrun, wants to write no elements, but starting at 9
   1861    assertErrorMessage(() => {
   1862        arrayCopy(exp1TO, 9, exp2TO, 1, 0);
   1863    },WebAssembly.RuntimeError, /index out of bounds/);
   1864 
   1865    // src overrun, wants to read [5, 6]
   1866    assertErrorMessage(() => {
   1867        arrayCopy(exp1TO, 1, exp2TO, 5, 2);
   1868    },WebAssembly.RuntimeError, /index out of bounds/);
   1869 
   1870    // src overrun, wants to read [7, 8]
   1871    assertErrorMessage(() => {
   1872        arrayCopy(exp1TO, 1, exp2TO, 7, 2);
   1873    },WebAssembly.RuntimeError, /index out of bounds/);
   1874 
   1875    // src zero-len overrun, wants to read no elements, but starting at 9
   1876    assertErrorMessage(() => {
   1877        arrayCopy(exp1TO, 1, exp2TO, 9, 0);
   1878    },WebAssembly.RuntimeError, /index out of bounds/);
   1879 }
   1880 
   1881 // run: check that null src or dest array causes a trap #1
   1882 {
   1883  let { shouldTrap } = wasmEvalText(`(module
   1884    (type $a (array (mut f32)))
   1885    (func (export "shouldTrap")
   1886      ref.null $a
   1887      i32.const 1
   1888      (array.new_fixed $a 3 (f32.const 1.23) (f32.const 4.56) (f32.const 7.89))
   1889      i32.const 1
   1890      i32.const 1
   1891      array.copy $a $a
   1892    )
   1893  )`).exports;
   1894  assertErrorMessage(() => {
   1895    shouldTrap();
   1896  }, WebAssembly.RuntimeError, /null/);
   1897 }
   1898 
   1899 // run: check that null src or dest array causes a trap #2
   1900 {
   1901  let { shouldTrap } = wasmEvalText(`(module
   1902    (type $a (array (mut f32)))
   1903    (func (export "shouldTrap")
   1904      (array.new_fixed $a 3 (f32.const 1.23) (f32.const 4.56) (f32.const 7.89))
   1905      i32.const 1
   1906      ref.null $a
   1907      i32.const 1
   1908      i32.const 1
   1909      array.copy $a $a
   1910    )
   1911  )`).exports;
   1912  assertErrorMessage(() => {
   1913    shouldTrap();
   1914  }, WebAssembly.RuntimeError, /null/);
   1915 }
   1916 
   1917 //////////////////////////////////////////////////////////////////////////////
   1918 //
   1919 // array.fill
   1920 /*
   1921  validation:
   1922    array must be mutable
   1923    value must be compatible with array element type
   1924  run:
   1925    null array causes a trap
   1926    OOB conditions on array for non-zero length copies
   1927    OOB conditions on array for zero length copies
   1928    resulting arrays are as expected (all types)
   1929 */
   1930 
   1931 // validation: array must be mutable
   1932 assertErrorMessage(() => wasmEvalText(`(module
   1933  (type $a (array i32))
   1934  (func
   1935    (array.new_default $a (i32.const 8))
   1936    i32.const 0
   1937    i32.const 123
   1938    i32.const 8
   1939    array.fill $a
   1940  )
   1941 )
   1942 `), WebAssembly.CompileError, /array is not mutable/);
   1943 
   1944 // validation: value must be compatible with array element type #1
   1945 assertErrorMessage(() => wasmEvalText(`(module
   1946  (type $a (array (mut i32)))
   1947  (func
   1948    (array.new_default $a (i32.const 8))
   1949    i32.const 0
   1950    i64.const 123
   1951    i32.const 8
   1952    array.fill $a
   1953  )
   1954 )
   1955 `), WebAssembly.CompileError, /type mismatch/);
   1956 
   1957 // validation: value must be compatible with array element type #2
   1958 assertErrorMessage(() => wasmEvalText(`(module
   1959  (type $a (array (mut eqref)))
   1960  (func
   1961    (array.new_default $a (i32.const 8))
   1962    i32.const 0
   1963    ref.null any
   1964    i32.const 8
   1965    array.fill $a
   1966  )
   1967 )
   1968 `), WebAssembly.CompileError, /type mismatch/);
   1969 
   1970 // run: null array causes a trap
   1971 {
   1972  const { arrayFill } = wasmEvalText(`(module
   1973    (type $a (array (mut i32)))
   1974    (func (export "arrayFill")
   1975      ref.null $a
   1976      i32.const 0
   1977      i32.const 123
   1978      i32.const 8
   1979      array.fill $a
   1980    )
   1981  )`).exports;
   1982  assertErrorMessage(() => {
   1983    arrayFill();
   1984  }, WebAssembly.RuntimeError, /dereferencing null pointer/);
   1985 }
   1986 
   1987 // run: OOB conditions on array for non-zero length copies
   1988 {
   1989  const { arrayFill } = wasmEvalText(`(module
   1990    (type $a (array (mut i32)))
   1991    (func (export "arrayFill")
   1992      (array.new_default $a (i32.const 8))
   1993      i32.const 1
   1994      i32.const 123
   1995      i32.const 8
   1996      array.fill $a
   1997    )
   1998  )`).exports;
   1999  assertErrorMessage(() => {
   2000    arrayFill();
   2001  }, WebAssembly.RuntimeError, /index out of bounds/);
   2002 }
   2003 
   2004 // run: OOB conditions on array for zero length copies
   2005 {
   2006  const { arrayFill } = wasmEvalText(`(module
   2007    (type $a (array (mut i32)))
   2008    (func (export "arrayFill")
   2009      (array.new_default $a (i32.const 8))
   2010      i32.const 8
   2011      i32.const 123
   2012      i32.const 0
   2013      array.fill $a
   2014    )
   2015  )`).exports;
   2016  arrayFill();
   2017 }
   2018 
   2019 // run: arrays are as expected (all types)
   2020 {
   2021  const TESTS = [
   2022    { type: 'i8', val: 'i32.const 123', get: 'array.get_u', test: 'i32.eq' },
   2023    { type: 'i16', val: 'i32.const 123', get: 'array.get_u', test: 'i32.eq' },
   2024    { type: 'i32', val: 'i32.const 123', test: 'i32.eq' },
   2025    { type: 'i64', val: 'i64.const 123', test: 'i64.eq' },
   2026    { type: 'f32', val: 'f32.const 3.14', test: 'f32.eq' },
   2027    { type: 'f64', val: 'f64.const 3.14', test: 'f64.eq' },
   2028    { type: 'eqref', val: 'global.get 0', test: 'ref.eq' },
   2029  ];
   2030  if (wasmSimdEnabled()) {
   2031    TESTS.push({ type: 'v128', val: 'v128.const i32x4 111 222 333 444', test: '(v128.xor) (i32.eq (v128.any_true) (i32.const 0))' });
   2032  }
   2033 
   2034  for (const { type, val, get = 'array.get', test } of TESTS) {
   2035    const { arrayFill, isDefault, isFilled } = wasmEvalText(`(module
   2036      (type $a (array (mut ${type})))
   2037      (type $s (struct))
   2038      (global (ref $s) (struct.new_default $s))
   2039      (func (export "arrayFill") (result (ref $a))
   2040        (local $arr (ref $a))
   2041        (local.set $arr (array.new_default $a (i32.const 4)))
   2042 
   2043        local.get $arr
   2044        i32.const 1
   2045        ${val}
   2046        i32.const 2
   2047        array.fill $a
   2048 
   2049        local.get $arr
   2050      )
   2051      (func (export "isDefault") (param (ref $a) i32) (result i32)
   2052        (${get} $a (local.get 0) (local.get 1))
   2053        (${get} $a (array.new_default $a (i32.const 1)) (i32.const 0))
   2054        ${test}
   2055      )
   2056      (func (export "isFilled") (param (ref $a) i32) (result i32)
   2057        (${get} $a (local.get 0) (local.get 1))
   2058        ${val}
   2059        ${test}
   2060      )
   2061    )`).exports;
   2062    const arr = arrayFill();
   2063    assertEq(isDefault(arr, 0), 1, `expected default value for ${type} but got filled`);
   2064    assertEq(isFilled(arr, 1), 1, `expected filled value for ${type} but got default`);
   2065    assertEq(isFilled(arr, 2), 1, `expected filled value for ${type} but got default`);
   2066    assertEq(isDefault(arr, 3), 1, `expected default value for ${type} but got filled`);
   2067  }
   2068 }
   2069 
   2070 // Test whether array data pointers are correctly tracked in stack maps.
   2071 {
   2072  const { newArray, test } = wasmEvalText(`(module
   2073    (type $a (array i32))
   2074    (import "" "gc" (func $gc))
   2075    (func (export "newArray") (result (ref $a))
   2076      (array.new $a (i32.const 123) (i32.const 4))
   2077    )
   2078    (func (export "test") (param $arr (ref $a)) (result i32)
   2079      (local i32)
   2080      (local i32)
   2081 
   2082      (array.get $a (local.get $arr) (i32.const 1))
   2083      local.set 1
   2084      call $gc
   2085      (array.get $a (local.get $arr) (i32.const 2))
   2086      local.set 2
   2087 
   2088      (i32.add (local.get 1) (local.get 2))
   2089    )
   2090  )`, {"": {gc}}).exports;
   2091  const arr = newArray();
   2092  assertEq(isNurseryAllocated(arr), true);
   2093  const res = test(arr);
   2094  assertEq(res, 246);
   2095 }
   2096 
   2097 // Test that zero-length arrays allocate correctly
   2098 {
   2099  const { testNew, testNewDefault, testNewFixed } = wasmEvalText(`(module
   2100    (type $a (array f32))
   2101 
   2102    (func (export "testNew") (result eqref eqref eqref eqref)
   2103      (array.new $a (f32.const 123) (i32.const 0))
   2104      (array.new $a (f32.const 123) (i32.const 0))
   2105      (array.new $a (f32.const 123) (i32.const 0))
   2106      (array.new $a (f32.const 123) (i32.const 0))
   2107    )
   2108    (func (export "testNewDefault") (result eqref eqref eqref eqref)
   2109      (array.new_default $a (i32.const 0))
   2110      (array.new_default $a (i32.const 0))
   2111      (array.new_default $a (i32.const 0))
   2112      (array.new_default $a (i32.const 0))
   2113    )
   2114    (func (export "testNewFixed") (result eqref eqref eqref eqref)
   2115      (array.new_fixed $a 0)
   2116      (array.new_fixed $a 0)
   2117      (array.new_fixed $a 0)
   2118      (array.new_fixed $a 0)
   2119    )
   2120  )`).exports;
   2121  testNew();
   2122  testNewDefault();
   2123  testNewFixed();
   2124 }