| 1668 | } |
| 1669 | |
| 1670 | Result BinaryReaderInterp::OnTryTableExpr(Type sig_type, |
| 1671 | const CatchClauseVector& catches) { |
| 1672 | // we can just emit the catch handlers beforehand, so long as we skip over |
| 1673 | // them when entering the try. |
| 1674 | CHECK_RESULT(validator_.BeginTryTable(GetLocation(), sig_type)); |
| 1675 | |
| 1676 | u32 exn_stack_height; |
| 1677 | CHECK_RESULT( |
| 1678 | validator_.GetCatchCount(label_stack_.size() - 1, &exn_stack_height)); |
| 1679 | // NOTE: *NOT* GetLocalCount. we don't count the parameters, as they're not |
| 1680 | // part of the frame. |
| 1681 | u32 value_stack_height = validator_.type_stack_size() + local_count_; |
| 1682 | |
| 1683 | HandlerDesc desc = |
| 1684 | HandlerDesc{HandlerKind::Catch, Istream::kInvalidOffset, |
| 1685 | Istream::kInvalidOffset, {}, |
| 1686 | {Istream::kInvalidOffset}, value_stack_height, |
| 1687 | exn_stack_height}; |
| 1688 | |
| 1689 | istream_.Emit(Opcode::Br); |
| 1690 | auto offset = istream_.EmitFixupU32(); |
| 1691 | |
| 1692 | bool has_catch_all = false; |
| 1693 | for (const auto& raw_catch : catches) { |
| 1694 | TableCatch catch_; |
| 1695 | catch_.kind = raw_catch.kind; |
| 1696 | catch_.tag = Var(raw_catch.tag, GetLocation()); |
| 1697 | catch_.target = Var(raw_catch.depth, GetLocation()); |
| 1698 | CHECK_RESULT(validator_.OnTryTableCatch(GetLocation(), catch_)); |
| 1699 | // stop emitting handlers after catch_all - but we must still validate the |
| 1700 | // handlers we don't emit |
| 1701 | if (has_catch_all) { |
| 1702 | continue; |
| 1703 | } |
| 1704 | if (catch_.IsCatchAll()) { |
| 1705 | has_catch_all = true; |
| 1706 | desc.catch_all_ref = catch_.IsRef(); |
| 1707 | desc.catch_all_offset = istream_.end(); |
| 1708 | } else { |
| 1709 | desc.catches.push_back( |
| 1710 | CatchDesc{raw_catch.tag, istream_.end(), catch_.IsRef()}); |
| 1711 | } |
| 1712 | // we can't use GetBrDropKeepCount because we're not in a real block. |
| 1713 | SharedValidator::Label* vlabel; |
| 1714 | CHECK_RESULT(validator_.GetLabel(raw_catch.depth, &vlabel)); |
| 1715 | // we keep the exception's results. |
| 1716 | // (this has already been validated, above) |
| 1717 | Index keep_count = vlabel->br_types().size(); |
| 1718 | // we drop everything between the current block and the br target. |
| 1719 | // (we have already taken the TryTable block parameters into account, in |
| 1720 | // BeginTryTable) |
| 1721 | Index drop_count = validator_.type_stack_size() - vlabel->type_stack_limit; |
| 1722 | Index catch_drop_count; |
| 1723 | // we use the regular catch count |
| 1724 | CHECK_RESULT(validator_.GetCatchCount(raw_catch.depth, &catch_drop_count)); |
| 1725 | // but increment, as we are semantically in a catch |
| 1726 | catch_drop_count++; |
| 1727 | EmitBr(raw_catch.depth, drop_count, keep_count, catch_drop_count); |
nothing calls this directly
no test coverage detected