@@ -241,7 +241,10 @@ class BinaryReaderInterp : public BinaryReaderNop {
241241 Result OnTableInitExpr (Index segment_index, Index table_index) override ;
242242 Result OnTernaryExpr (Opcode opcode) override ;
243243 Result OnThrowExpr (Index tag_index) override ;
244+ Result OnThrowRefExpr () override ;
244245 Result OnTryExpr (Type sig_type) override ;
246+ Result OnTryTableExpr (Type sig_type,
247+ const CatchClauseVector& catches) override ;
245248 Result OnUnreachableExpr () override ;
246249 Result EndFunctionBody (Index index) override ;
247250 Result OnSimdLaneOpExpr (Opcode opcode, uint64_t value) override ;
@@ -1072,6 +1075,11 @@ Result BinaryReaderInterp::OnEndExpr() {
10721075 HandlerDesc& desc = func_->handlers [local_label->handler_desc_index ];
10731076 desc.try_end_offset = istream_.end ();
10741077 assert (desc.catches .size () == 0 );
1078+ } else if (label_type == LabelType::TryTable) {
1079+ // TryTable blocks need a try_end_offset
1080+ Label* local_label = TopLabel ();
1081+ HandlerDesc& desc = func_->handlers [local_label->handler_desc_index ];
1082+ desc.try_end_offset = istream_.end ();
10751083 } else if (label_type == LabelType::Catch) {
10761084 istream_.EmitCatchDrop (1 );
10771085 }
@@ -1518,6 +1526,12 @@ Result BinaryReaderInterp::OnThrowExpr(Index tag_index) {
15181526 return Result::Ok;
15191527}
15201528
1529+ Result BinaryReaderInterp::OnThrowRefExpr () {
1530+ CHECK_RESULT (validator_.OnThrowRef (GetLocation ()));
1531+ istream_.Emit (Opcode::ThrowRef);
1532+ return Result::Ok;
1533+ }
1534+
15211535Result BinaryReaderInterp::OnRethrowExpr (Index depth) {
15221536 Index catch_depth;
15231537 CHECK_RESULT (validator_.OnRethrow (GetLocation (), Var (depth, GetLocation ())));
@@ -1549,6 +1563,80 @@ Result BinaryReaderInterp::OnTryExpr(Type sig_type) {
15491563 return Result::Ok;
15501564}
15511565
1566+ Result BinaryReaderInterp::OnTryTableExpr (Type sig_type,
1567+ const CatchClauseVector& catches) {
1568+ // we can just emit the catch handlers beforehand, so long as we skip over
1569+ // them when entering the try.
1570+ CHECK_RESULT (validator_.BeginTryTable (GetLocation (), sig_type));
1571+
1572+ u32 exn_stack_height;
1573+ CHECK_RESULT (
1574+ validator_.GetCatchCount (label_stack_.size () - 1 , &exn_stack_height));
1575+ // NOTE: *NOT* GetLocalCount. we don't count the parameters, as they're not
1576+ // part of the frame.
1577+ u32 value_stack_height = validator_.type_stack_size () + local_count_;
1578+
1579+ HandlerDesc desc =
1580+ HandlerDesc{HandlerKind::Catch, Istream::kInvalidOffset ,
1581+ Istream::kInvalidOffset , {},
1582+ {Istream::kInvalidOffset }, value_stack_height,
1583+ exn_stack_height};
1584+
1585+ istream_.Emit (Opcode::Br);
1586+ auto offset = istream_.EmitFixupU32 ();
1587+
1588+ bool has_catch_all = false ;
1589+ for (const auto & raw_catch : catches) {
1590+ TableCatch catch_;
1591+ catch_.kind = raw_catch.kind ;
1592+ catch_.tag = Var (raw_catch.tag , GetLocation ());
1593+ catch_.target = Var (raw_catch.depth , GetLocation ());
1594+ CHECK_RESULT (validator_.OnTryTableCatch (GetLocation (), catch_));
1595+ // stop emitting handlers after catch_all - but we must still validate the
1596+ // handlers we don't emit
1597+ if (has_catch_all) {
1598+ continue ;
1599+ }
1600+ if (catch_.IsCatchAll ()) {
1601+ has_catch_all = true ;
1602+ desc.catch_all_ref = catch_.IsRef ();
1603+ desc.catch_all_offset = istream_.end ();
1604+ } else {
1605+ desc.catches .push_back (
1606+ CatchDesc{raw_catch.tag , istream_.end (), catch_.IsRef ()});
1607+ }
1608+ // we can't use GetBrDropKeepCount because we're not in a real block.
1609+ SharedValidator::Label* vlabel;
1610+ CHECK_RESULT (validator_.GetLabel (raw_catch.depth , &vlabel));
1611+ // we keep the exception's results.
1612+ // (this has already been validated, above)
1613+ Index keep_count = vlabel->br_types ().size ();
1614+ // we drop everything between the current block and the br target.
1615+ // (we have already taken the TryTable block parameters into account, in
1616+ // BeginTryTable)
1617+ Index drop_count = validator_.type_stack_size () - vlabel->type_stack_limit ;
1618+ Index catch_drop_count;
1619+ // we use the regular catch count
1620+ CHECK_RESULT (validator_.GetCatchCount (raw_catch.depth , &catch_drop_count));
1621+ // but increment, as we are semantically in a catch
1622+ catch_drop_count++;
1623+ EmitBr (raw_catch.depth , drop_count, keep_count, catch_drop_count);
1624+ }
1625+
1626+ CHECK_RESULT (validator_.EndTryTable (GetLocation (), sig_type));
1627+
1628+ desc.try_start_offset = istream_.end ();
1629+
1630+ // as usual, the label is pushed after the catch handlers
1631+ PushLabel (LabelKind::Try, Istream::kInvalidOffset , Istream::kInvalidOffset ,
1632+ func_->handlers .size ());
1633+ func_->handlers .push_back (std::move (desc));
1634+
1635+ istream_.ResolveFixupU32 (offset);
1636+
1637+ return Result::Ok;
1638+ }
1639+
15521640Result BinaryReaderInterp::OnCatchExpr (Index tag_index) {
15531641 CHECK_RESULT (
15541642 validator_.OnCatch (GetLocation (), Var (tag_index, GetLocation ()), false ));
0 commit comments