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: --expose-wasm --experimental-wasm-eh --allow-natives-syntax
  
  // Note that this test does not pass --experimental-wasm-anyref on purpose so
  // that we make sure the two flags can be controlled separately/independently.
  
  load("test/mjsunit/wasm/wasm-module-builder.js");
  
  // First we just test that "except_ref" global variables are allowed.
  (function TestGlobalExceptRefSupported() {
    print(arguments.callee.name);
    let builder = new WasmModuleBuilder();
    let g = builder.addGlobal(kWasmExceptRef);
    builder.addFunction("push_and_drop_except_ref", kSig_v_v)
        .addBody([
          kExprGetGlobal, g.index,
          kExprDrop,
        ]).exportFunc();
    let instance = builder.instantiate();
  
    assertDoesNotThrow(instance.exports.push_and_drop_except_ref);
  })();
  
  // Test default value that global "except_ref" variables are initialized with.
  (function TestGlobalExceptRefDefaultValue() {
    print(arguments.callee.name);
    let builder = new WasmModuleBuilder();
    let g = builder.addGlobal(kWasmExceptRef);
    builder.addFunction('push_and_return_except_ref', kSig_e_v)
        .addBody([kExprGetGlobal, g.index])
        .exportFunc();
    let instance = builder.instantiate();
  
    assertEquals(null, instance.exports.push_and_return_except_ref());
  })();
  
  // Test storing a caught exception into an exported mutable "except_ref" global.
  (function TestGlobalExceptRefSetCaught() {
    print(arguments.callee.name);
    let builder = new WasmModuleBuilder();
    let except = builder.addException(kSig_v_i);
    let g = builder.addGlobal(kWasmExceptRef, true).exportAs("exn");
    builder.addFunction('catch_and_set_except_ref', kSig_v_i)
        .addBody([
          kExprTry, kWasmStmt,
            kExprGetLocal, 0,
            kExprThrow, except,
          kExprCatch,
            kExprSetGlobal, g.index,
          kExprEnd,
        ]).exportFunc();
    let instance = builder.instantiate();
  
    assertDoesNotThrow(() => instance.exports.catch_and_set_except_ref(23));
    let exception = instance.exports.exn.value;  // Exported mutable global.
    assertInstanceof(exception, WebAssembly.RuntimeError);
    assertEquals(except, %GetWasmExceptionId(exception, instance));
  })();
  
  // Test storing a parameter into an exported mutable "except_ref" global.
  (function TestGlobalExceptRefSetParameter() {
    print(arguments.callee.name);
    let builder = new WasmModuleBuilder();
    let g = builder.addGlobal(kWasmExceptRef, true).exportAs("exn");
    builder.addFunction('set_param_except_ref', kSig_v_e)
        .addBody([
          kExprTry, kWasmStmt,
            kExprGetLocal, 0,
            kExprRethrow,
          kExprCatch,
            kExprSetGlobal, g.index,
          kExprEnd,
        ]).exportFunc();
    let exception = "my fancy exception";
    let instance = builder.instantiate();
  
    assertDoesNotThrow(() => instance.exports.set_param_except_ref(exception));
    assertEquals(exception, instance.exports.exn.value);
  })();
  
  // Test loading an imported "except_ref" global and re-throwing the exception.
  (function TestGlobalExceptRefGetImportedAndRethrow() {
    print(arguments.callee.name);
    let builder = new WasmModuleBuilder();
    let g_index = builder.addImportedGlobal("m", "exn", kWasmExceptRef);
    builder.addFunction('rethrow_except_ref', kSig_v_v)
        .addBody([
          kExprGetGlobal, g_index,
          kExprRethrow,
        ]).exportFunc();
    let exception = "my fancy exception";
    let instance = builder.instantiate({ "m": { "exn": exception }});
  
    assertThrowsEquals(() => instance.exports.rethrow_except_ref(), exception);
  })();
  
  // Test loading an exported mutable "except_ref" being changed from the outside.
  (function TestGlobalExceptRefGetExportedMutableAndRethrow() {
    print(arguments.callee.name);
    let builder = new WasmModuleBuilder();
    let g = builder.addGlobal(kWasmExceptRef, true).exportAs("exn");
    builder.addFunction('rethrow_except_ref', kSig_v_v)
        .addBody([
          kExprGetGlobal, g.index,
          kExprRethrow,
        ]).exportFunc();
    let instance = builder.instantiate();
  
    let exception1 = instance.exports.exn.value = "my fancy exception";
    assertThrowsEquals(() => instance.exports.rethrow_except_ref(), exception1);
    let exception2 = instance.exports.exn.value = "an even fancier exception";
    assertThrowsEquals(() => instance.exports.rethrow_except_ref(), exception2);
  })();
  
  // TODO(mstarzinger): Add the following test once proposal makes it clear how
  // far interaction with the mutable globals proposal is intended to go.
  // Test loading an imported mutable "except_ref" being changed from the outside.
  /*(function TestGlobalExceptRefGetImportedMutableAndRethrow() {
    print(arguments.callee.name);
    let builder = new WasmModuleBuilder();
    let g_index = builder.addImportedGlobal("m", "exn", kWasmExceptRef, true);
    builder.addFunction('rethrow_except_ref', kSig_v_v)
        .addBody([
          kExprGetGlobal, g_index,
          kExprRethrow,
        ]).exportFunc();
    let exception1 = "my fancy exception";
    let desc = { value: 'except_ref', mutable: true };
    let mutable_global = new WebAssembly.Global(desc, exception1);
    let instance = builder.instantiate({ "m": { "exn": mutable_global }});
  
    assertThrowsEquals(() => instance.exports.rethrow_except_ref(), exception1);
    let exception2 = mutable_global.value = "an even fancier exception";
    assertThrowsEquals(() => instance.exports.rethrow_except_ref(), exception2);
  })();*/
  
  // Test custom initialization index for a global "except_ref" variable.
  (function TestGlobalExceptRefInitIndex() {
    print(arguments.callee.name);
    let builder = new WasmModuleBuilder();
    let g1_index = builder.addImportedGlobal("m", "exn", kWasmExceptRef);
    let g2 = builder.addGlobal(kWasmExceptRef);
    g2.init_index = g1_index;  // Initialize {g2} to equal {g1}.
    builder.addFunction('push_and_return_except_ref', kSig_e_v)
        .addBody([kExprGetGlobal, g2.index])
        .exportFunc();
    let exception = { x: "my fancy exception" };
    let instance = builder.instantiate({ "m": { "exn": exception }});
  
    assertSame(exception, instance.exports.push_and_return_except_ref());
  })();
  