@@ -649,7 +649,7 @@ Result BinaryReaderInterp::BeginInitExpr(FuncDesc* func) {
649649 label_stack_.clear ();
650650 func_ = func;
651651 func_->code_offset = istream_.end ();
652- Type type = func ->type .results [0 ];
652+ Type type = func_ ->type .results [0 ];
653653 CHECK_RESULT (validator_.BeginInitExpr (GetLocation (), type));
654654 // Push implicit init func label (equivalent to return).
655655 PushLabel (LabelKind::Try, Istream::kInvalidOffset , Istream::kInvalidOffset );
@@ -1068,6 +1068,11 @@ Result BinaryReaderInterp::OnEndExpr() {
10681068 HandlerDesc& desc = func_->handlers [local_label->handler_desc_index ];
10691069 desc.try_end_offset = istream_.end ();
10701070 assert (desc.catches .size () == 0 );
1071+ } else if (label_type == LabelType::TryTable) {
1072+ // TryTable blocks need a try_end_offset
1073+ Label* local_label = TopLabel ();
1074+ HandlerDesc& desc = func_->handlers [local_label->handler_desc_index ];
1075+ desc.try_end_offset = istream_.end ();
10711076 } else if (label_type == LabelType::Catch) {
10721077 istream_.EmitCatchDrop (1 );
10731078 }
@@ -1553,63 +1558,77 @@ Result BinaryReaderInterp::OnTryExpr(Type sig_type) {
15531558
15541559Result BinaryReaderInterp::OnTryTableExpr (Type sig_type,
15551560 const RawCatchVector& catches) {
1556- CHECK_RESULT (validator_.BeginTryTable (GetLocation ()));
1557-
1558- assert (false && " NYI" );
1559-
1560- // // from loop
1561- // PushLabel(LabelKind::Block, istream_.end());
1562- // return Result::Ok;
1563-
1564- // // from brtable
1565- // Index drop_count, keep_count, catch_drop_count;
1566- // istream_.Emit(Opcode::BrTable, num_targets);
1567-
1568- // for (Index i = 0; i < num_targets; ++i) {
1569- // Index depth = target_depths[i];
1570- // CHECK_RESULT(
1571- // validator_.OnBrTableTarget(GetLocation(), Var(depth,
1572- // GetLocation())));
1573- // CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count));
1574- // CHECK_RESULT(validator_.GetCatchCount(depth, &catch_drop_count));
1575- // // Emit DropKeep directly (instead of using EmitDropKeep) so the
1576- // // instruction has a fixed size. Same for CatchDrop as well.
1577- // istream_.Emit(Opcode::InterpDropKeep, drop_count, keep_count);
1578- // istream_.Emit(Opcode::InterpCatchDrop, catch_drop_count);
1579- // EmitBr(depth, 0, 0, 0);
1580- // }
1581- // CHECK_RESULT(validator_.OnBrTableTarget(
1582- // GetLocation(), Var(default_target_depth, GetLocation())));
1583- // CHECK_RESULT(
1584- // GetBrDropKeepCount(default_target_depth, &drop_count, &keep_count));
1585- // CHECK_RESULT(
1586- // validator_.GetCatchCount(default_target_depth, &catch_drop_count));
1587- // // The default case doesn't need a fixed size, since it is never jumped
1588- // / over.
1589- // istream_.EmitDropKeep(drop_count, keep_count);
1590- // istream_.Emit(Opcode::InterpCatchDrop, catch_drop_count);
1591- // EmitBr(default_target_depth, 0, 0, 0);
1592-
1593- // CHECK_RESULT(validator_.EndBrTable(GetLocation()));
1594- // return Result::Ok;
1595-
1596- // // from try
1597- // u32 exn_stack_height;
1598- // CHECK_RESULT(
1599- // validator_.GetCatchCount(label_stack_.size() - 1, &exn_stack_height));
1600- // u32 value_stack_height = validator_.type_stack_size();
1601- // CHECK_RESULT(validator_.OnTry(GetLocation(), sig_type));
1602- // // Push a label that tracks mapping of exn -> catch
1603- // PushLabel(LabelKind::Try, Istream::kInvalidOffset, Istream::kInvalidOffset,
1604- // func_->handlers.size());
1605- // func_->handlers.push_back(HandlerDesc{HandlerKind::Catch,
1606- // istream_.end(),
1607- // Istream::kInvalidOffset,
1608- // {},
1609- // {Istream::kInvalidOffset},
1610- // value_stack_height,
1611- // exn_stack_height});
1612- return Result::Error;
1561+ // we can just emit the catch handlers beforehand, so long as we skip over
1562+ // them when entering the try.
1563+ CHECK_RESULT (validator_.BeginTryTable (GetLocation (), sig_type));
1564+
1565+ u32 exn_stack_height;
1566+ CHECK_RESULT (
1567+ validator_.GetCatchCount (label_stack_.size () - 1 , &exn_stack_height));
1568+ // NOTE: *NOT* GetLocalCount. we don't count the parameters, as they're not
1569+ // part of the frame.
1570+ u32 value_stack_height = validator_.type_stack_size () + local_count_;
1571+
1572+ HandlerDesc desc = HandlerDesc{HandlerKind::Catch,
1573+ Istream::kInvalidOffset ,
1574+ Istream::kInvalidOffset ,
1575+ {},
1576+ {Istream::kInvalidOffset },
1577+ value_stack_height,
1578+ exn_stack_height};
1579+
1580+ istream_.Emit (Opcode::Br);
1581+ auto offset = istream_.EmitFixupU32 ();
1582+
1583+ bool has_catch_all = false ;
1584+ for (const auto & raw_catch : catches) {
1585+ TableCatch catch_;
1586+ catch_.kind = raw_catch.kind ;
1587+ catch_.tag = Var (raw_catch.tag , GetLocation ());
1588+ catch_.target = Var (raw_catch.depth , GetLocation ());
1589+ CHECK_RESULT (validator_.OnTryTableCatch (GetLocation (), catch_));
1590+ // stop emitting handlers after catch_all - but we must still validate the
1591+ // handlers we don't emit
1592+ if (has_catch_all) {
1593+ continue ;
1594+ }
1595+ if (catch_.IsCatchAll ()) {
1596+ has_catch_all = true ;
1597+ desc.catch_all_ref = catch_.IsRef ();
1598+ desc.catch_all_offset = istream_.end ();
1599+ } else {
1600+ desc.catches .push_back (CatchDesc{raw_catch.tag , istream_.end (), catch_.IsRef ()});
1601+ }
1602+ // we can't use GetBrDropKeepCount because we're not in a real block.
1603+ SharedValidator::Label* vlabel;
1604+ CHECK_RESULT (validator_.GetLabel (raw_catch.depth , &vlabel));
1605+ // we keep the exception's results.
1606+ // (this has already been validated, above)
1607+ Index keep_count = vlabel->br_types ().size ();
1608+ // we drop everything between the current block and the br target.
1609+ // (we have already taken the TryTable block parameters into account, in
1610+ // BeginTryTable)
1611+ Index drop_count = validator_.type_stack_size () - vlabel->type_stack_limit ;
1612+ Index catch_drop_count;
1613+ // we use the regular catch count
1614+ CHECK_RESULT (validator_.GetCatchCount (raw_catch.depth , &catch_drop_count));
1615+ // but increment, as we are semantically in a catch
1616+ catch_drop_count++;
1617+ EmitBr (raw_catch.depth , drop_count, keep_count, catch_drop_count);
1618+ }
1619+
1620+ CHECK_RESULT (validator_.EndTryTable (GetLocation (), sig_type));
1621+
1622+ desc.try_start_offset = istream_.end ();
1623+
1624+ // as usual, the label is pushed after the catch handlers
1625+ PushLabel (LabelKind::Try, Istream::kInvalidOffset , Istream::kInvalidOffset ,
1626+ func_->handlers .size ());
1627+ func_->handlers .push_back (std::move (desc));
1628+
1629+ istream_.ResolveFixupU32 (offset);
1630+
1631+ return Result::Ok;
16131632}
16141633
16151634Result BinaryReaderInterp::OnCatchExpr (Index tag_index) {
0 commit comments