tor-browser

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

instructions.js (33604B)


      1 // Tests for Wasm exception proposal instructions.
      2 
      3 // Test try blocks with no handlers.
      4 assertEq(
      5  wasmEvalText(
      6    `(module
      7       (func (export "f") (result i32)
      8         try (result i32) (i32.const 0) end))`
      9  ).exports.f(),
     10  0
     11 );
     12 
     13 assertEq(
     14  wasmEvalText(
     15    `(module
     16       (func (export "f") (result i32)
     17         try (result i32) (i32.const 0) (br 0) (i32.const 1) end))`
     18  ).exports.f(),
     19  0
     20 );
     21 
     22 assertEq(
     23  wasmEvalText(
     24    `(module
     25       (type (func))
     26       (tag $exn (type 0))
     27       (func (export "f") (result i32)
     28         try (result i32)
     29           try (result i32)
     30             (throw $exn)
     31             (i32.const 1)
     32           end
     33           drop
     34           (i32.const 2)
     35         catch $exn
     36           (i32.const 0)
     37         end))`
     38  ).exports.f(),
     39  0
     40 );
     41 
     42 assertEq(
     43  wasmEvalText(
     44    `(module
     45       (type (func))
     46       (tag $exn (type 0))
     47       (func (export "f") (result i32)
     48         try (result i32)
     49           try (result i32)
     50             try
     51               try
     52                 (throw $exn)
     53               end
     54             end
     55             (i32.const 1)
     56           end
     57           drop
     58           (i32.const 2)
     59         catch $exn
     60           (i32.const 0)
     61         end))`
     62  ).exports.f(),
     63  0
     64 );
     65 
     66 assertEq(
     67  wasmEvalText(
     68    `(module
     69       (type (func))
     70       (tag $exn (type 0))
     71       (func (export "f") (result i32)
     72         try (result i32)
     73           try (result i32)
     74             try
     75               try
     76                 (throw $exn)
     77               end
     78             catch_all
     79               rethrow 0
     80             end
     81             (i32.const 1)
     82           end
     83           drop
     84           (i32.const 2)
     85         catch $exn
     86           (i32.const 0)
     87         end))`
     88  ).exports.f(),
     89  0
     90 );
     91 
     92 // Test trivial try-catch with empty bodies.
     93 assertEq(
     94  wasmEvalText(
     95    `(module
     96       (type (func))
     97       (tag $exn (type 0))
     98       (func (export "f") (result i32)
     99         try nop catch $exn end
    100         (i32.const 0)))`
    101  ).exports.f(),
    102  0
    103 );
    104 
    105 assertEq(
    106  wasmEvalText(
    107    `(module
    108       (func (export "f") (result i32)
    109         try nop catch_all end
    110         (i32.const 0)))`
    111  ).exports.f(),
    112  0
    113 );
    114 
    115 // Test try block with no throws
    116 assertEq(
    117  wasmEvalText(
    118    `(module
    119       (type (func))
    120       (tag $exn (type 0))
    121       (func (export "f") (result i32)
    122         try (result i32)
    123           (i32.const 0)
    124         catch $exn
    125           (i32.const 1)
    126         end))`
    127  ).exports.f(),
    128  0
    129 );
    130 
    131 // Ensure catch block is really not run when no throw occurs.
    132 assertEq(
    133  wasmEvalText(
    134    `(module
    135       (type (func))
    136       (tag $exn (type 0))
    137       (func (export "f") (result i32) (local i32)
    138         try
    139           (local.set 0 (i32.const 42))
    140         catch $exn
    141           (local.set 0 (i32.const 99))
    142         end
    143         (local.get 0)))`
    144  ).exports.f(),
    145  42
    146 );
    147 
    148 // Simple uses of throw.
    149 assertEq(
    150  wasmEvalText(
    151    `(module
    152       (type (func (param i32)))
    153       (tag $exn (type 0))
    154       (func (export "f") (result i32)
    155         try (result i32)
    156           (i32.const 42)
    157           (throw $exn)
    158         catch $exn
    159           drop
    160           (i32.const 1)
    161         end))`
    162  ).exports.f(),
    163  1
    164 );
    165 
    166 assertEq(
    167  wasmEvalText(
    168    `(module
    169       (type (func (param i32)))
    170       (tag $exn (type 0))
    171       (func $foo (param i32) (result i32)
    172         (local.get 0) (throw $exn))
    173       (func (export "f") (result i32)
    174         try (result i32)
    175           (i32.const 42)
    176           (call $foo)
    177         catch $exn
    178           drop
    179           (i32.const 1)
    180         end))`
    181  ).exports.f(),
    182  1
    183 );
    184 
    185 // Simple uses of throw of some Wasm vectortype values (Simd128).
    186 if (wasmSimdEnabled()) {
    187  assertEq(
    188    wasmEvalText(
    189      `(module
    190         (type (func (param v128 v128 v128 v128)))
    191         (tag $exn (type 0))
    192         (func (export "f") (result i32)
    193           try (result i32)
    194             (v128.const i32x4 42 41 40 39)
    195             (v128.const f32x4 4.2 4.1 0.40 3.9)
    196             (v128.const i64x2 42 41)
    197             (v128.const f64x2 4.2 4.1)
    198             (throw $exn)
    199           catch $exn
    200             drop drop drop
    201             (i64x2.all_true)
    202           end))`
    203    ).exports.f(),
    204    1
    205  );
    206 
    207  assertEq(
    208    wasmEvalText(
    209      `(module
    210         (type (func (param v128 v128 v128 v128)))
    211         (tag $exn (type 0))
    212         (func $foo (param v128 v128 v128 v128) (result i32)
    213           (throw $exn (local.get 0)
    214                       (local.get 1)
    215                       (local.get 2)
    216                       (local.get 3)))
    217         (func (export "f") (result i32)
    218           try (result i32)
    219             (v128.const i32x4 42 41 40 39)
    220             (v128.const f32x4 4.2 4.1 0.40 3.9)
    221             (v128.const i64x2 42 41)
    222             (v128.const f64x2 4.2 4.1)
    223             (call $foo)
    224           catch $exn
    225             drop drop drop
    226             (i64x2.all_true)
    227           end))`
    228    ).exports.f(),
    229    1
    230  );
    231 
    232  {
    233    let imports =
    234        wasmEvalText(
    235          `(module
    236             (tag $exn (export "exn") (param v128))
    237             (func (export "throws") (param v128) (result v128)
    238               (throw $exn (local.get 0))
    239               (v128.const i32x4 9 10 11 12)))`).exports;
    240 
    241    let mod =
    242        `(module
    243           (import "m" "exn" (tag $exn (param v128)))
    244           (import "m" "throws" (func $throws (param v128) (result v128)))
    245           (func (export "f") (result i32) (local v128)
    246             (v128.const i32x4 1 2 3 4)
    247             (local.tee 0)
    248             try (param v128) (result v128)
    249               (call $throws)
    250             catch $exn
    251             catch_all (v128.const i32x4 5 6 7 8)
    252             end
    253             (local.get 0)
    254             (i32x4.eq)
    255             (i32x4.all_true)))`;
    256 
    257    assertEq(wasmEvalText(mod, { m : imports }).exports.f(), 1);
    258  }
    259 }
    260 
    261 // Further nested call frames should be ok.
    262 assertEq(
    263  wasmEvalText(
    264    `(module
    265       (type (func (param i32)))
    266       (tag $exn (type 0))
    267       (func $foo (param i32) (result i32)
    268         (local.get 0) (call $bar))
    269       (func $bar (param i32) (result i32)
    270         (local.get 0) (call $quux))
    271       (func $quux (param i32) (result i32)
    272         (local.get 0) (throw $exn))
    273       (func (export "f") (result i32)
    274         try (result i32)
    275           (i32.const 42)
    276           (call $foo)
    277         catch $exn
    278           drop
    279           (i32.const 1)
    280         end))`
    281  ).exports.f(),
    282  1
    283 );
    284 
    285 // Basic throwing from loop.
    286 
    287 assertEq(
    288  wasmEvalText(
    289    `(module
    290       (tag $exn)
    291       ;; For the purpose of this test, the params below should be increasing.
    292       (func (export "f") (param $depth_to_throw_exn i32)
    293                          (param $maximum_loop_iterations i32)
    294                          (result i32)
    295                          (local $loop_counter i32)
    296         ;; The loop is counting down.
    297         (local.get $maximum_loop_iterations)
    298         (local.set $loop_counter)
    299         (block $catch
    300           (loop $loop
    301             (if (i32.eqz (local.get $loop_counter))
    302                 (then
    303                   (return (i32.const 440)))
    304                 (else
    305                   try
    306                     (if (i32.eq (local.get $depth_to_throw_exn)
    307                                 (local.get $loop_counter))
    308                       (then
    309                         (throw $exn))
    310                       (else
    311                         (local.set $loop_counter
    312                                    (i32.sub (local.get $loop_counter)
    313                                             (i32.const 1)))))
    314                   catch $exn (br $catch)
    315                   catch_all
    316                   end))
    317               (br $loop))
    318             (return (i32.const 10001)))
    319         (i32.const 10000)))`
    320  ).exports.f(2, 4),
    321  10000
    322 );
    323 
    324 // Ensure conditional throw works.
    325 let conditional = wasmEvalText(
    326  `(module
    327     (type (func (param)))
    328     (tag $exn (type 0))
    329     (func (export "f") (param i32) (result i32)
    330       try (result i32)
    331         (local.get 0)
    332         if (result i32)
    333           (throw $exn)
    334         else
    335           (i32.const 42)
    336         end
    337       catch $exn
    338         (i32.const 99)
    339       end))`
    340 ).exports.f;
    341 
    342 assertEq(conditional(0), 42);
    343 assertEq(conditional(1), 99);
    344 
    345 // Ensure multiple & nested try-catch blocks work.
    346 assertEq(
    347  wasmEvalText(
    348    `(module
    349       (type (func (param)))
    350       (tag $exn (type 0))
    351       (func $foo (throw $exn))
    352       (func (export "f") (result i32) (local i32)
    353         try
    354           nop
    355         catch $exn
    356           (local.set 0 (i32.const 99))
    357         end
    358         try
    359           (call $foo)
    360         catch $exn
    361           (local.set 0 (i32.const 42))
    362         end
    363         (local.get 0)))`
    364  ).exports.f(),
    365  42
    366 );
    367 
    368 assertEq(
    369  wasmEvalText(
    370    `(module
    371       (type (func (param)))
    372       (tag $exn (type 0))
    373       (func (export "f") (result i32) (local i32)
    374         try
    375           try
    376             try
    377               (throw $exn)
    378             catch $exn
    379               (local.set 0 (i32.const 42))
    380             end
    381           catch $exn
    382             (local.set 0 (i32.const 97))
    383           end
    384         catch $exn
    385           (local.set 0 (i32.const 98))
    386         end
    387         (local.get 0)))`
    388  ).exports.f(),
    389  42
    390 );
    391 
    392 assertEq(
    393  wasmEvalText(
    394    `(module
    395       (tag $exn)
    396       (func (export "f") (result i32)
    397         try
    398           throw $exn
    399         catch $exn
    400           try
    401             (throw $exn)
    402           catch $exn
    403           end
    404         end
    405         (i32.const 27)))`
    406  ).exports.f(),
    407  27
    408 );
    409 
    410 {
    411  let nested_throw_in_block_and_in_catch =
    412      wasmEvalText(
    413        `(module
    414           (tag $exn)
    415           (func $throw
    416             (throw $exn))
    417           (func (export "f") (param $arg i32) (result i32)
    418             (block (result i32)
    419               try (result i32)
    420                 (call $throw)
    421                 (unreachable)
    422               catch $exn
    423                 (if (result i32)
    424                   (local.get $arg)
    425                   (then
    426                     try (result i32)
    427                       (call $throw)
    428                       (unreachable)
    429                     catch $exn
    430                       (i32.const 27)
    431                     end)
    432                   (else
    433                     (i32.const 11))
    434                  )
    435                end
    436              )
    437            ))`
    438      ).exports.f;
    439 
    440  assertEq(nested_throw_in_block_and_in_catch(1), 27);
    441  assertEq(nested_throw_in_block_and_in_catch(0), 11);
    442 }
    443 
    444 assertEq(
    445  wasmEvalText(
    446    `(module
    447       (tag $thrownExn)
    448       (tag $notThrownExn)
    449       (func (export "f") (result i32)
    450         try (result i32)
    451            try (result i32)
    452               (throw $thrownExn)
    453            catch $notThrownExn
    454               (i32.const 19)
    455            catch $thrownExn
    456               (i32.const 20)
    457            catch_all
    458               (i32.const 21)
    459            end
    460         end))`
    461  ).exports.f(),
    462  20
    463 );
    464 
    465 // Test that uncaught exceptions get propagated.
    466 assertEq(
    467  wasmEvalText(
    468    `(module
    469       (tag $thrownExn)
    470       (tag $notThrownExn)
    471       (func (export "f") (result i32) (local i32)
    472         try
    473           try
    474             try
    475               (throw $thrownExn)
    476              catch $notThrownExn
    477                 (local.set 0
    478                   (i32.or (local.get 0)
    479                           (i32.const 1)))
    480              end
    481             catch $notThrownExn
    482               (local.set 0
    483                 (i32.or (local.get 0)
    484                         (i32.const 2)))
    485             end
    486           catch $thrownExn
    487             (local.set 0
    488               (i32.or (local.get 0)
    489                       (i32.const 4)))
    490           end
    491         (local.get 0)))`
    492  ).exports.f(),
    493  4
    494 );
    495 
    496 // Test tag dispatch for catches.
    497 assertEq(
    498  wasmEvalText(
    499    `(module
    500       (type (func (param)))
    501       (tag $exn1 (type 0))
    502       (tag $exn2 (type 0))
    503       (tag $exn3 (type 0))
    504       (func (export "f") (result i32)
    505         try (result i32)
    506           throw $exn1
    507         catch $exn1
    508           i32.const 1
    509         catch $exn2
    510           i32.const 2
    511         catch $exn3
    512           i32.const 3
    513         end))`
    514  ).exports.f(),
    515  1
    516 );
    517 
    518 assertEq(
    519  wasmEvalText(
    520    `(module
    521       (type (func (param)))
    522       (tag $exn1 (type 0))
    523       (tag $exn2 (type 0))
    524       (tag $exn3 (type 0))
    525       (func (export "f") (result i32)
    526         try (result i32)
    527           throw $exn2
    528         catch $exn1
    529           i32.const 1
    530         catch $exn2
    531           i32.const 2
    532         catch $exn3
    533           i32.const 3
    534         end))`
    535  ).exports.f(),
    536  2
    537 );
    538 
    539 assertEq(
    540  wasmEvalText(
    541    `(module
    542       (type (func (param)))
    543       (tag $exn1 (type 0))
    544       (tag $exn2 (type 0))
    545       (tag $exn3 (type 0))
    546       (func (export "f") (result i32)
    547         try (result i32)
    548           throw $exn3
    549         catch $exn1
    550           i32.const 1
    551         catch $exn2
    552           i32.const 2
    553         catch $exn3
    554           i32.const 3
    555         end))`
    556  ).exports.f(),
    557  3
    558 );
    559 
    560 assertEq(
    561  wasmEvalText(
    562    `(module
    563       (type (func (param)))
    564       (tag $exn1 (type 0))
    565       (tag $exn2 (type 0))
    566       (tag $exn3 (type 0))
    567       (tag $exn4 (type 0))
    568       (func (export "f") (result i32)
    569         try (result i32)
    570           try (result i32)
    571             throw $exn4
    572           catch $exn1
    573             i32.const 1
    574           catch $exn2
    575             i32.const 2
    576           catch $exn3
    577             i32.const 3
    578           end
    579         catch $exn4
    580           i32.const 4
    581         end))`
    582  ).exports.f(),
    583  4
    584 );
    585 
    586 // Test usage of br before a throw.
    587 assertEq(
    588  wasmEvalText(
    589    `(module
    590       (type (func (param i32)))
    591       (tag $exn (type 0))
    592       (func (export "f") (result i32)
    593         try $l (result i32)
    594           (i32.const 2)
    595           (br $l)
    596           (throw $exn)
    597         catch $exn
    598           drop
    599           (i32.const 1)
    600         end))`
    601  ).exports.f(),
    602  2
    603 );
    604 
    605 assertEq(
    606  wasmEvalText(
    607    `(module
    608       (type (func (param)))
    609       (tag $exn (type 0))
    610       (func (export "f") (result i32)
    611         try $l (result i32)
    612           (throw $exn)
    613         catch $exn
    614           (i32.const 2)
    615           (br $l)
    616           rethrow 0
    617         end))`
    618  ).exports.f(),
    619  2
    620 );
    621 
    622 assertEq(
    623  wasmEvalText(
    624    `(module
    625       (type (func (param)))
    626       (tag $exn (type 0))
    627       (func (export "f") (result i32)
    628         try $l (result i32)
    629           (throw $exn)
    630         catch_all
    631           (i32.const 2)
    632           (br $l)
    633           rethrow 0
    634         end))`
    635  ).exports.f(),
    636  2
    637 );
    638 
    639 // Test br branching out of a catch block.
    640 assertEq(
    641  wasmEvalText(
    642    `(module
    643       (type (func (param i32)))
    644       (tag $exn (type 0))
    645       (func (export "f") (result i32)
    646         block $l (result i32)
    647           block (result i32)
    648             try (result i32)
    649               (i32.const 42)
    650               (throw $exn)
    651             catch $exn
    652               br $l
    653               (i32.const 99)
    654             end
    655           end
    656         end))`
    657  ).exports.f(),
    658  42
    659 );
    660 
    661 // Test dead catch block.
    662 assertEq(
    663  wasmEvalText(
    664    `(module
    665       (type (func))
    666       (tag $exn (type 0))
    667       (func (export "f") (result i32)
    668         i32.const 0
    669         return
    670         try nop catch $exn end))`
    671  ).exports.f(),
    672  0
    673 );
    674 
    675 assertEq(
    676  wasmEvalText(
    677    `(module
    678       (func (export "f") (result i32)
    679         i32.const 0
    680         return
    681         try nop catch_all end))`
    682  ).exports.f(),
    683  0
    684 );
    685 
    686 // Test catch with exception values pushed to stack.
    687 assertEq(
    688  wasmEvalText(
    689    `(module
    690       (type (func (param i32)))
    691       (type (func (param i32)))
    692       (type (func (param i64)))
    693       (tag $exn (type 0))
    694       (tag $foo (type 1))
    695       (tag $bar (type 2))
    696       (func (export "f") (result i32)
    697         try $l (result i32)
    698           (i32.const 42)
    699           (throw $exn)
    700         catch $exn
    701         catch_all
    702           (i32.const 99)
    703         end))`
    704  ).exports.f(),
    705  42
    706 );
    707 
    708 // Throw an exception carrying more than one value.
    709 assertEq(
    710  wasmEvalText(
    711    `(module
    712       (type (func (param i32 i64 f32 f64)))
    713       (tag $exn (type 0))
    714       (func (export "f") (result i32)
    715         try $l (result i32 i64 f32 f64)
    716           (i32.const 42)
    717           (i64.const 84)
    718           (f32.const 42.2)
    719           (f64.const 84.4)
    720           (throw $exn)
    721         catch $exn
    722         catch_all
    723           (i32.const 99)
    724           (i64.const 999)
    725           (f32.const 99.9)
    726           (f64.const 999.9)
    727         end
    728         drop drop drop))`
    729  ).exports.f(),
    730  42
    731 );
    732 
    733 // This should also work inside nested frames.
    734 assertEq(
    735  wasmEvalText(
    736    `(module
    737       (type (func (param i32 i64 f32 f64)))
    738       (tag $exn (type 0))
    739       (func $foo (param i32 i64 f32 f64) (result i32 i64 f32 f64)
    740         (local.get 0)
    741         (local.get 1)
    742         (local.get 2)
    743         (local.get 3)
    744         (throw $exn))
    745       (func (export "f") (result i32)
    746         try $l (result i32 i64 f32 f64)
    747           (i32.const 42)
    748           (i64.const 84)
    749           (f32.const 42.2)
    750           (f64.const 84.4)
    751           (call $foo)
    752         catch $exn
    753         catch_all
    754           (i32.const 99)
    755           (i64.const 999)
    756           (f32.const 99.9)
    757           (f64.const 999.9)
    758         end
    759         drop drop drop))`
    760  ).exports.f(),
    761  42
    762 );
    763 
    764 // Multiple tagged catch in succession.
    765 assertEq(
    766  wasmEvalText(
    767    `(module
    768       (type (func (param i32)))
    769       (tag $exn1 (type 0))
    770       (tag $exn2 (type 0))
    771       (func (export "f") (result i32)
    772         try (result i32)
    773           (i32.const 42)
    774           (throw $exn2)
    775         catch $exn1
    776         catch $exn2
    777         catch_all
    778           (i32.const 99)
    779         end))`
    780  ).exports.f(),
    781  42
    782 );
    783 
    784 assertEq(
    785  wasmEvalText(
    786    `(module
    787       (tag $exn0)
    788       (tag $exn1)
    789       (tag $exn2)
    790       (tag $exn3)
    791       (tag $exn4)
    792       (tag $exn5)
    793       (func (export "f") (result i32)
    794         try (result i32)
    795           (throw $exn4)
    796          catch $exn5 (i32.const 5)
    797          catch $exn2 (i32.const 2)
    798          catch $exn4 (i32.const 4) ;; Caught here.
    799          catch $exn4 (i32.const 44)
    800          end
    801        ))`
    802  ).exports.f(),
    803  4
    804 );
    805 
    806 // Try catch with block parameters.
    807 assertEq(
    808  wasmEvalText(
    809    `(module
    810       (type (func))
    811       (tag $exn (type 0))
    812       (func (export "f") (result i32)
    813         (i32.const 42)
    814         try (param i32) (result i32)
    815           nop
    816         catch $exn
    817           (i32.const 99)
    818         end))`
    819  ).exports.f(),
    820  42
    821 );
    822 
    823 assertEq(
    824  wasmEvalText(
    825    `(module
    826       (type (func (param i32)))
    827       (tag $exn (type 0))
    828       (func (export "f") (result i32)
    829         (i32.const 42)
    830         try $l (param i32) (result i32)
    831           (throw $exn)
    832         catch $exn
    833         catch_all
    834           (i32.const 99)
    835         end))`
    836  ).exports.f(),
    837  42
    838 );
    839 
    840 // Test the catch_all case.
    841 assertEq(
    842  wasmEvalText(
    843    `(module
    844       (type (func (param i32)))
    845       (tag $exn1 (type 0))
    846       (tag $exn2 (type 0))
    847       (func (export "f") (result i32)
    848         try $l (result i32)
    849           (i32.const 42)
    850           (throw $exn2)
    851         catch $exn1
    852         catch_all
    853           (i32.const 99)
    854         end))`
    855  ).exports.f(),
    856  99
    857 );
    858 
    859 assertEq(
    860  wasmEvalText(
    861    `(module
    862       (tag $exn (param i32))
    863       (func (export "f") (result i32)
    864         try (result i32)
    865           try (result i32)
    866             (i32.const 42)
    867             (throw $exn)
    868           catch_all
    869             (i32.const 99)
    870           end
    871         catch $exn
    872         end))`
    873  ).exports.f(),
    874  99
    875 );
    876 
    877 // Test foreign exception catch.
    878 assertEq(
    879  wasmEvalText(
    880    `(module
    881       (type (func))
    882       (import "m" "foreign" (func $foreign))
    883       (tag $exn (type 0))
    884       (func (export "f") (result i32) (local i32)
    885         try $l
    886           (call $foreign)
    887         catch $exn
    888         catch_all
    889           (local.set 0 (i32.const 42))
    890         end
    891         (local.get 0)))`,
    892    {
    893      m: {
    894        foreign() {
    895          throw 5;
    896        },
    897      },
    898    }
    899  ).exports.f(),
    900  42
    901 );
    902 
    903 // Exception handlers should not catch traps.
    904 assertErrorMessage(
    905  () =>
    906    wasmEvalText(
    907      `(module
    908         (type (func))
    909         (tag $exn (type 0))
    910         (func (export "f") (result i32) (local i32)
    911           try $l
    912             unreachable
    913           catch $exn
    914             (local.set 0 (i32.const 98))
    915           catch_all
    916             (local.set 0 (i32.const 99))
    917           end
    918           (local.get 0)))`
    919    ).exports.f(),
    920  WebAssembly.RuntimeError,
    921  "unreachable executed"
    922 );
    923 
    924 // Ensure that a RuntimeError created by the user is not filtered out
    925 // as a trap emitted by the runtime (i.e., the filtering predicate is not
    926 // observable from JS).
    927 assertEq(
    928  wasmEvalText(
    929    `(module
    930       (import "m" "foreign" (func $foreign))
    931       (func (export "f") (result i32)
    932         try (result i32)
    933           (call $foreign)
    934           (i32.const 99)
    935         catch_all
    936           (i32.const 42)
    937         end))`,
    938    {
    939      m: {
    940        foreign() {
    941          throw new WebAssembly.RuntimeError();
    942        },
    943      },
    944    }
    945  ).exports.f(),
    946  42
    947 );
    948 
    949 // Test uncatchable JS exceptions (OOM & stack overflow).
    950 {
    951  let f = wasmEvalText(
    952    `(module
    953       (import "m" "foreign" (func $foreign))
    954       (func (export "f") (result)
    955         try
    956           (call $foreign)
    957         catch_all
    958         end))`,
    959    {
    960      m: {
    961        foreign() {
    962          throwOutOfMemory();
    963        },
    964      },
    965    }
    966  ).exports.f;
    967 
    968  var thrownVal;
    969  try {
    970    f();
    971  } catch (exn) {
    972    thrownVal = exn;
    973  }
    974 
    975  assertEq(thrownVal, "out of memory");
    976 }
    977 
    978 assertErrorMessage(
    979  () =>
    980    wasmEvalText(
    981      `(module
    982       (import "m" "foreign" (func $foreign))
    983       (func (export "f")
    984         try
    985           (call $foreign)
    986         catch_all
    987         end))`,
    988      {
    989        m: {
    990          foreign: function foreign() {
    991            foreign();
    992          },
    993        },
    994      }
    995    ).exports.f(),
    996  Error,
    997  "too much recursion"
    998 );
    999 
   1000 // Test all implemented instructions in a single module.
   1001 {
   1002  let divFunctypeInline =
   1003      `(param $numerator i32) (param $denominator i32) (result i32)`;
   1004 
   1005  let safediv = wasmEvalText(
   1006    `(module
   1007       (tag $divexn (param i32 i32))
   1008       (tag $notThrownExn (param i32))
   1009       (func $throwingdiv ${divFunctypeInline}
   1010          (local.get $numerator)
   1011          (local.get $denominator)
   1012          (if (param i32 i32) (result i32)
   1013            (i32.eqz (local.get $denominator))
   1014            (then
   1015              try (param i32 i32)
   1016                (throw $divexn)
   1017              delegate 0
   1018              (i32.const 9))
   1019            (else
   1020              i32.div_u)))
   1021       (func $safediv (export "safediv") ${divFunctypeInline}
   1022          (local.get $numerator)
   1023          (local.get $denominator)
   1024          try (param i32 i32) (result i32)
   1025              (call $throwingdiv)
   1026          catch $notThrownExn
   1027          catch $divexn
   1028            i32.add
   1029          catch_all
   1030            (i32.const 44)
   1031          end
   1032        ))`
   1033  ).exports.safediv;
   1034 
   1035  assertEq(safediv(6, 3), 2);
   1036  assertEq(safediv(6, 0), 6);
   1037 }
   1038 
   1039 // Test simple rethrow.
   1040 assertEq(
   1041  wasmEvalText(
   1042    `(module
   1043       (type (func))
   1044       (tag $exn (type 0))
   1045       (func (export "f") (result i32)
   1046         try (result i32)
   1047           try
   1048             throw $exn
   1049           catch $exn
   1050             rethrow 0
   1051           end
   1052           i32.const 1
   1053         catch $exn
   1054           i32.const 27
   1055         end))`
   1056  ).exports.f(),
   1057  27
   1058 );
   1059 
   1060 assertEq(
   1061  wasmEvalText(
   1062    `(module
   1063       (type (func))
   1064       (tag $exn (type 0))
   1065       (func (export "f") (result i32)
   1066         try (result i32)
   1067           try
   1068             throw $exn
   1069           catch_all
   1070             rethrow 0
   1071           end
   1072           i32.const 1
   1073         catch $exn
   1074           i32.const 27
   1075         end))`
   1076  ).exports.f(),
   1077  27
   1078 );
   1079 
   1080 // Test rethrows in nested blocks.
   1081 assertEq(
   1082  wasmEvalText(
   1083    `(module
   1084       (type (func))
   1085       (tag $exn (type 0))
   1086       (func (export "f") (result i32)
   1087         try (result i32)
   1088           try
   1089             throw $exn
   1090           catch $exn
   1091             block
   1092               rethrow 1
   1093             end
   1094           end
   1095           i32.const 1
   1096         catch $exn
   1097           i32.const 27
   1098         end))`
   1099  ).exports.f(),
   1100  27
   1101 );
   1102 
   1103 assertEq(
   1104  wasmEvalText(
   1105    `(module
   1106       (type (func))
   1107       (tag $exn (type 0))
   1108       (func (export "f") (result i32)
   1109         try (result i32)
   1110           try
   1111             throw $exn
   1112           catch_all
   1113             block
   1114               rethrow 1
   1115             end
   1116           end
   1117           i32.const 1
   1118         catch $exn
   1119           i32.const 27
   1120         end))`
   1121  ).exports.f(),
   1122  27
   1123 );
   1124 
   1125 assertEq(
   1126  wasmEvalText(
   1127    `(module
   1128       (type (func))
   1129       (tag $exn1 (type 0))
   1130       (tag $exn2 (type 0))
   1131       (func (export "f") (result i32)
   1132         try (result i32)
   1133           try
   1134             throw $exn1
   1135           catch $exn1
   1136             try
   1137               throw $exn2
   1138             catch $exn2
   1139               rethrow 1
   1140             end
   1141           end
   1142           i32.const 0
   1143         catch $exn1
   1144           i32.const 1
   1145         catch $exn2
   1146           i32.const 2
   1147         end))`
   1148  ).exports.f(),
   1149  1
   1150 );
   1151 
   1152 assertEq(
   1153  wasmEvalText(
   1154    `(module
   1155       (type (func))
   1156       (tag $exn1 (type 0))
   1157       (tag $exn2 (type 0))
   1158       (func (export "f") (result i32)
   1159         try (result i32)
   1160           try
   1161             throw $exn1
   1162           catch $exn1
   1163             try
   1164               throw $exn2
   1165             catch_all
   1166               rethrow 1
   1167             end
   1168           end
   1169           i32.const 0
   1170         catch $exn1
   1171           i32.const 1
   1172         catch $exn2
   1173           i32.const 2
   1174         end))`
   1175  ).exports.f(),
   1176  1
   1177 );
   1178 
   1179 // Test that rethrow makes the rest of the block dead code.
   1180 assertEq(
   1181  wasmEvalText(
   1182    `(module
   1183       (tag (param i32))
   1184       (func (export "f") (result i32)
   1185         try (result i32)
   1186           (i32.const 1)
   1187         catch 0
   1188           (rethrow 0)
   1189           (i32.const 2)
   1190         end
   1191       ))`
   1192  ).exports.f(),
   1193  1
   1194 );
   1195 
   1196 assertEq(
   1197  wasmEvalText(
   1198    `(module
   1199       (tag (param i32))
   1200       (func (export "f") (result i32)
   1201         try (result i32)
   1202           try
   1203             (i32.const 13)
   1204             (throw 0)
   1205            catch 0
   1206              (rethrow 0)
   1207            end
   1208           (unreachable)
   1209         catch 0
   1210         end
   1211       ))`
   1212  ).exports.f(),
   1213  13
   1214 );
   1215 
   1216 assertEq(
   1217  wasmEvalText(
   1218    `(module
   1219       (tag)
   1220       (func (export "f") (result i32)
   1221         try (result i32)
   1222           try
   1223             (throw 0)
   1224           catch 0
   1225             (i32.const 4)
   1226             (rethrow 0)
   1227           end
   1228           (unreachable)
   1229         catch 0
   1230            (i32.const 13)
   1231         end
   1232       ))`
   1233  ).exports.f(),
   1234  13
   1235 );
   1236 
   1237 assertEq(
   1238  wasmEvalText(
   1239    `(module
   1240       (tag (param i32))
   1241       (func (export "f") (result i32)
   1242         try (result i32)
   1243           try
   1244             (i32.const 13)
   1245             (throw 0)
   1246           catch 0
   1247             (i32.const 111)
   1248             (rethrow 0)
   1249           end
   1250           (i32.const 222)
   1251         catch 0
   1252       end
   1253     ))`
   1254  ).exports.f(),
   1255  13
   1256 );
   1257 
   1258 // Test try-delegate blocks.
   1259 
   1260 // Dead delegate to caller
   1261 assertEq(
   1262  wasmEvalText(
   1263    `(module
   1264       (tag $exn (param))
   1265       (func (export "f") (result i32)
   1266         i32.const 1
   1267         br 0
   1268         try
   1269           throw $exn
   1270         delegate 0))`
   1271  ).exports.f(),
   1272  1
   1273 );
   1274 
   1275 // Nested try-delegate.
   1276 assertEq(
   1277  wasmEvalText(
   1278    `(module
   1279       (tag $exn (param))
   1280       (func (export "f") (result i32)
   1281         try (result i32)
   1282           try
   1283             try
   1284               throw $exn
   1285             delegate 0
   1286           end
   1287           i32.const 0
   1288         catch $exn
   1289           i32.const 1
   1290         end))`
   1291  ).exports.f(),
   1292  1
   1293 );
   1294 
   1295 // Non-throwing and breaking try-delegate.
   1296 assertEq(
   1297  wasmEvalText(
   1298    `(module
   1299       (tag $exn (param))
   1300       (func (export "f") (result i32)
   1301         try (result i32)
   1302           i32.const 1
   1303           br 0
   1304         delegate 0))`
   1305    ).exports.f(),
   1306    1
   1307 );
   1308 
   1309 assertEq(
   1310  wasmEvalText(
   1311    `(module
   1312       (tag $exn (param))
   1313       (func (export "f") (result i32)
   1314         try (result i32)
   1315           i32.const 1
   1316           return
   1317         delegate 0))`
   1318    ).exports.f(),
   1319    1
   1320  );
   1321 
   1322 // More nested try-delegate.
   1323 assertEq(
   1324    wasmEvalText(
   1325      `(module
   1326       (type (func (param i32)))
   1327       (tag $exn (type 0))
   1328       (func (export "f") (result i32)
   1329         try (result i32)
   1330           try
   1331             i32.const 42
   1332             throw $exn
   1333           delegate 0
   1334           i32.const 0
   1335         catch $exn
   1336           i32.const 1
   1337           i32.add
   1338         end))`
   1339  ).exports.f(),
   1340  43
   1341 );
   1342 
   1343 assertEq(
   1344  wasmEvalText(
   1345    `(module
   1346       (type (func (param i32)))
   1347       (tag $exn (type 0))
   1348       (func (export "f") (result i32)
   1349         try (result i32)
   1350           try (result i32)
   1351             try
   1352               i32.const 42
   1353               throw $exn
   1354             delegate 1
   1355             i32.const 0
   1356           catch $exn
   1357             i32.const 1
   1358             i32.add
   1359           end
   1360         catch $exn
   1361           i32.const 2
   1362           i32.add
   1363         end))`
   1364  ).exports.f(),
   1365  44
   1366 );
   1367 
   1368 assertEq(
   1369  wasmEvalText(
   1370    `(module
   1371       (type (func (param i32)))
   1372       (tag $exn (type 0))
   1373       (func (export "f") (result i32)
   1374         try (result i32)
   1375           try (result i32)
   1376             try (result i32)
   1377               try
   1378                 i32.const 42
   1379                 throw $exn
   1380               delegate 1
   1381               i32.const 0
   1382             catch $exn
   1383               i32.const 1
   1384               i32.add
   1385             end
   1386           delegate 0
   1387         catch $exn
   1388           i32.const 2
   1389           i32.add
   1390         end))`
   1391  ).exports.f(),
   1392  44
   1393 );
   1394 
   1395 assertEq(
   1396  wasmEvalText(
   1397    `(module
   1398       (tag $exn (param))
   1399       (func $g (param i32) (result i32) (i32.const 42))
   1400       (func (export "f") (result i32)
   1401         try (result i32)
   1402           try $t
   1403             block (result i32)
   1404               (i32.const 4)
   1405               (call $g)
   1406               try
   1407                 throw $exn
   1408               delegate $t
   1409             end
   1410             drop
   1411           end
   1412           i32.const 0
   1413         catch_all
   1414           i32.const 1
   1415         end))`
   1416  ).exports.f(),
   1417  1
   1418 );
   1419 
   1420 // Test delegation to function body and blocks.
   1421 
   1422 // Non-throwing.
   1423 assertEq(
   1424  wasmEvalText(
   1425    `(module
   1426       (tag $exn (param))
   1427       (func (export "f") (result i32)
   1428         try (result i32)
   1429           i32.const 1
   1430         delegate 0))`
   1431  ).exports.f(),
   1432  1
   1433 );
   1434 
   1435 // Block target.
   1436 assertEq(
   1437  wasmEvalText(
   1438    `(module
   1439       (tag $exn (param i32))
   1440       (func (export "f") (result i32)
   1441         try (result i32)
   1442           block
   1443             try
   1444               i32.const 1
   1445               throw $exn
   1446             delegate 0
   1447           end
   1448           i32.const 0
   1449         catch $exn
   1450         end))`
   1451  ).exports.f(),
   1452  1
   1453 );
   1454 
   1455 // Catch target.
   1456 assertEq(
   1457  wasmEvalText(
   1458    `(module
   1459       (tag $exn (param))
   1460       (func (export "f") (result i32)
   1461         try (result i32)
   1462           try
   1463             throw $exn
   1464           catch $exn
   1465             try
   1466               throw $exn
   1467             delegate 0
   1468           end
   1469           i32.const 0
   1470         catch_all
   1471           i32.const 1
   1472         end))`
   1473  ).exports.f(),
   1474  1
   1475 );
   1476 
   1477 // Target function body.
   1478 assertEq(
   1479  wasmEvalText(
   1480    `(module
   1481       (type (func (param i32)))
   1482       (tag $exn (type 0))
   1483       (func (export "f") (result i32)
   1484         try (result i32)
   1485           call $g
   1486         catch $exn
   1487         end)
   1488       (func $g (result i32)
   1489         try (result i32)
   1490           try
   1491             i32.const 42
   1492             throw $exn
   1493           delegate 1
   1494           i32.const 0
   1495         catch $exn
   1496           i32.const 1
   1497           i32.add
   1498         end))`
   1499  ).exports.f(),
   1500  42
   1501 );
   1502 
   1503 // Try-delegate from inside a loop.
   1504 assertEq(
   1505  wasmEvalText(
   1506    `(module
   1507       (tag $exn)
   1508       ;; For the purpose of this test, the params below should be increasing.
   1509       (func (export "f") (param $depth_to_throw_exn i32)
   1510                          (param $maximum_loop_iterations i32)
   1511                          (result i32)
   1512                          (local $loop_countdown i32)
   1513                          ;; Counts how many times the loop was started.
   1514                          (local $loop_verifier i32)
   1515         ;; The loop is counting down.
   1516         (local.get $maximum_loop_iterations)
   1517         (local.set $loop_countdown)
   1518         try $catch_exn (result i32)
   1519           try
   1520             (loop $loop
   1521               ;; Counts how many times the loop was started.
   1522               (local.set $loop_verifier
   1523                          (i32.add (i32.const 1)
   1524                                   (local.get $loop_verifier)))
   1525               (if (i32.eqz (local.get $loop_countdown))
   1526                 (then (return (i32.const 440)))
   1527                 (else
   1528                   try $rethrow_label
   1529                     (if (i32.eq (local.get $depth_to_throw_exn)
   1530                                 (local.get $loop_countdown))
   1531                         (then (throw $exn))
   1532                         (else
   1533                           (local.set $loop_countdown
   1534                                      (i32.sub (local.get $loop_countdown)
   1535                                               (i32.const 1)))))
   1536                   catch $exn try
   1537                               (rethrow $rethrow_label)
   1538                              delegate $catch_exn
   1539                   end
   1540                 ))
   1541               (br $loop))
   1542             catch_all unreachable
   1543             end
   1544             (i32.const 2000)
   1545         catch_all (i32.const 10000)
   1546         end
   1547         (i32.add (local.get $loop_verifier))))`
   1548  ).exports.f(3, 5),
   1549  10003
   1550 );