text: // Copyright 2019 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  // Flags: --experimental-wasm-type-reflection --experimental-wasm-reftypes
  
  load('test/mjsunit/wasm/wasm-module-builder.js');
  
  (function TestTableType() {
    let table = new WebAssembly.Table({initial: 1, element: "externref"});
    let type = WebAssembly.Table.type(table);
    assertEquals(1, type.minimum);
    assertEquals("externref", type.element);
    assertEquals(2, Object.getOwnPropertyNames(type).length);
  
    table = new WebAssembly.Table({initial: 2, maximum: 15, element: "externref"});
    type = WebAssembly.Table.type(table);
    assertEquals(2, type.minimum);
    assertEquals(15, type.maximum);
    assertEquals("externref", type.element);
    assertEquals(3, Object.getOwnPropertyNames(type).length);
  })();
  
  (function TestGlobalType() {
    let global = new WebAssembly.Global({value: "externref", mutable: true});
    let type = WebAssembly.Global.type(global);
    assertEquals("externref", type.value);
    assertEquals(true, type.mutable);
    assertEquals(2, Object.getOwnPropertyNames(type).length);
  
    global = new WebAssembly.Global({value: "externref"});
    type = WebAssembly.Global.type(global);
    assertEquals("externref", type.value);
    assertEquals(false, type.mutable);
    assertEquals(2, Object.getOwnPropertyNames(type).length);
  
    global = new WebAssembly.Global({value: "anyfunc"});
    type = WebAssembly.Global.type(global);
    assertEquals("anyfunc", type.value);
    assertEquals(false, type.mutable);
    assertEquals(2, Object.getOwnPropertyNames(type).length);
  })();
  
  (function TestFunctionGlobalGetAndSet() {
    let builder = new WasmModuleBuilder();
    let fun1 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 7);
    let fun2 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 9);
    builder.addGlobal(kWasmAnyFunc, true).exportAs("f");
    builder.addFunction('get_global', kSig_a_v)
        .addBody([
          kExprGlobalGet, 0,
        ])
        .exportFunc();
    builder.addFunction('set_global', kSig_v_a)
        .addBody([
          kExprLocalGet, 0,
          kExprGlobalSet, 0,
        ])
        .exportFunc();
    let instance = builder.instantiate();
  
    // Test getting and setting "funcref" global via WebAssembly.
    assertEquals(null, instance.exports.get_global());
    instance.exports.set_global(fun1);
    assertEquals(fun1, instance.exports.get_global());
  
    // Test getting and setting "funcref" global via JavaScript.
    assertEquals(fun1, instance.exports.f.value);
    instance.exports.f.value = fun2;
    assertEquals(fun2, instance.exports.f.value);
  
    // Test the full round-trip of an "funcref" global.
    assertEquals(fun2, instance.exports.get_global());
  })();
  
  // This is an extension of "type-reflection.js/TestFunctionTableSetAndCall" to
  // multiple table indexes. If --experimental-wasm-reftypes is enabled by default
  // this test case can supersede the other one.
  (function TestFunctionMultiTableSetAndCall() {
    let builder = new WasmModuleBuilder();
    let v1 = 7; let v2 = 9; let v3 = 0.0;
    let f1 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => v1);
    let f2 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => v2);
    let f3 = new WebAssembly.Function({parameters:[], results:["f64"]}, _ => v3);
    let table = new WebAssembly.Table({element: "anyfunc", initial: 2});
    let table_index0 = builder.addImportedTable("m", "table", 2);
    let table_index1 = builder.addTable(kWasmAnyFunc, 1).exportAs("tbl").index;
    let sig_index = builder.addType(kSig_i_v);
    table.set(0, f1);
    builder.addFunction('call0', kSig_i_i)
        .addBody([
          kExprLocalGet, 0,
          kExprCallIndirect, sig_index, table_index0
        ])
        .exportFunc();
    builder.addFunction('call1', kSig_i_i)
        .addBody([
          kExprLocalGet, 0,
          kExprCallIndirect, sig_index, table_index1
        ])
        .exportFunc();
    let instance = builder.instantiate({ m: { table: table }});
  
    // Test table #0 first.
    assertEquals(v1, instance.exports.call0(0));
    assertSame(f1, table.get(0));
    table.set(1, f2);
    assertEquals(v2, instance.exports.call0(1));
    assertSame(f2, table.get(1));
    table.set(1, f3);
    assertTraps(kTrapFuncSigMismatch, () => instance.exports.call0(1));
    assertSame(f3, table.get(1));
  
    // Test table #1 next.
    assertTraps(kTrapFuncSigMismatch, () => instance.exports.call1(0));
    instance.exports.tbl.set(0, f1);
    assertEquals(v1, instance.exports.call1(0));
    assertSame(f1, instance.exports.tbl.get(0));
    instance.exports.tbl.set(0, f2);
    assertEquals(v2, instance.exports.call1(0));
    assertSame(f2, instance.exports.tbl.get(0));
    instance.exports.tbl.set(0, f3);
    assertTraps(kTrapFuncSigMismatch, () => instance.exports.call1(0));
    assertSame(f3, instance.exports.tbl.get(0));
  })();
  