@@ -266,6 +266,7 @@ class CWriter {
266266 bool IsTopLabelUsed () const ;
267267 void PopLabel ();
268268
269+ static constexpr bool AreInitializersAlwaysNull (Type);
269270 static constexpr char MangleType (Type);
270271 static constexpr char MangleField (ModuleFieldType);
271272 static std::string MangleTypes (const TypeVector&);
@@ -483,10 +484,12 @@ class CWriter {
483484 void Write (const AtomicRmwExpr& expr);
484485 void Write (const AtomicRmwCmpxchgExpr& expr);
485486
486- size_t BeginTry (const TryExpr& tryexpr );
487+ size_t BeginTry (const Block& block );
487488 void WriteTryCatch (const TryExpr& tryexpr);
488489 void WriteTryDelegate (const TryExpr& tryexpr);
490+ void Write (const TryTableExpr& try_table_expr);
489491 void Write (const Catch& c);
492+ void Write (const TableCatch& c);
490493 void WriteThrow ();
491494
492495 void PushTryCatch (const std::string& name);
@@ -635,6 +638,19 @@ void CWriter::PopLabel() {
635638 label_stack_.pop_back ();
636639}
637640
641+ // static
642+ constexpr bool CWriter::AreInitializersAlwaysNull (Type type) {
643+ // clang-format off
644+ switch (type) {
645+ case Type::FuncRef: return false ;
646+ case Type::ExternRef: return true ;
647+ case Type::ExnRef: return true ;
648+ default :
649+ WABT_UNREACHABLE;
650+ }
651+ // clang-format on
652+ }
653+
638654// static
639655constexpr char CWriter::MangleType (Type type) {
640656 // clang-format off
@@ -646,6 +662,7 @@ constexpr char CWriter::MangleType(Type type) {
646662 case Type::V128: return ' o' ;
647663 case Type::FuncRef: return ' r' ;
648664 case Type::ExternRef: return ' e' ;
665+ case Type::ExnRef: return ' x' ;
649666 default :
650667 WABT_UNREACHABLE;
651668 }
@@ -1218,6 +1235,7 @@ const char* CWriter::GetCTypeName(const Type& type) {
12181235 case Type::V128: return " v128" ;
12191236 case Type::FuncRef: return " wasm_rt_funcref_t" ;
12201237 case Type::ExternRef: return " wasm_rt_externref_t" ;
1238+ case Type::ExnRef: return " wasm_rt_exnref_t" ;
12211239 default :
12221240 WABT_UNREACHABLE;
12231241 }
@@ -1238,6 +1256,7 @@ void CWriter::Write(TypeEnum type) {
12381256 case Type::V128: Write (" WASM_RT_V128" ); break ;
12391257 case Type::FuncRef: Write (" WASM_RT_FUNCREF" ); break ;
12401258 case Type::ExternRef: Write (" WASM_RT_EXTERNREF" ); break ;
1259+ case Type::ExnRef: Write (" WASM_RT_EXNREF" ); break ;
12411260 default :
12421261 WABT_UNREACHABLE;
12431262 }
@@ -2301,9 +2320,8 @@ void CWriter::WriteElemInitializerDecls() {
23012320 continue ;
23022321 }
23032322
2304- if (elem_segment->elem_type == Type::ExternRef) {
2305- // no need to store externref elem initializers because only
2306- // ref.null is possible
2323+ if (AreInitializersAlwaysNull (elem_segment->elem_type )) {
2324+ // no need to store these initializers because only ref.null is possible
23072325 continue ;
23082326 }
23092327
@@ -2373,9 +2391,8 @@ void CWriter::WriteElemInitializers() {
23732391 continue ;
23742392 }
23752393
2376- if (elem_segment->elem_type == Type::ExternRef) {
2377- // no need to store externref elem initializers because only
2378- // ref.null is possible
2394+ if (AreInitializersAlwaysNull (elem_segment->elem_type )) {
2395+ // no need to store these initializers because only ref.null is possible
23792396 continue ;
23802397 }
23812398
@@ -2476,15 +2493,15 @@ void CWriter::WriteElemInitializers() {
24762493void CWriter::WriteElemTableInit (bool active_initialization,
24772494 const ElemSegment* src_segment,
24782495 const Table* dst_table) {
2479- assert (dst_table->elem_type == Type::FuncRef ||
2480- dst_table->elem_type == Type::ExternRef );
2496+ assert (dst_table->elem_type . IsRef () &&
2497+ dst_table->elem_type != Type::Reference );
24812498 assert (dst_table->elem_type == src_segment->elem_type );
24822499
24832500 Write (GetReferenceTypeName (dst_table->elem_type ), " _table_init(" ,
24842501 ExternalInstancePtr (ModuleFieldType::Table, dst_table->name ), " , " );
24852502
24862503 // elem segment exprs needed only for funcref tables
2487- // because externref tables can only be initialized with ref.null
2504+ // because externref and exnref tables can only be initialized with ref.null
24882505 if (dst_table->elem_type == Type::FuncRef) {
24892506 if (src_segment->elem_exprs .empty ()) {
24902507 Write (" NULL, " );
@@ -3125,7 +3142,7 @@ void CWriter::WriteVarsByType(const Vars& vars,
31253142 const ToDo& todo,
31263143 bool setjmp_safe) {
31273144 for (Type type : {Type::I32, Type::I64, Type::F32, Type::F64, Type::V128,
3128- Type::FuncRef, Type::ExternRef}) {
3145+ Type::FuncRef, Type::ExternRef, Type::ExnRef }) {
31293146 Index var_index = 0 ;
31303147 size_t count = 0 ;
31313148 for (const auto & var : vars) {
@@ -3269,7 +3286,7 @@ void CWriter::WriteLocals(const std::vector<std::string>& index_to_name) {
32693286 func_->local_types , [](auto x) { return x; },
32703287 [&](Index local_index, Type local_type) {
32713288 Write (DefineParamName (index_to_name[num_params + local_index]), " = " );
3272- if (local_type == Type::FuncRef || local_type == Type::ExternRef ) {
3289+ if (local_type. IsRef () ) {
32733290 Write (GetReferenceNullValue (local_type));
32743291 } else if (local_type == Type::V128) {
32753292 Write (" simde_wasm_i64x2_make(0, 0)" );
@@ -3301,27 +3318,27 @@ void CWriter::Write(const Block& block) {
33013318 PushTypes (block.decl .sig .result_types );
33023319}
33033320
3304- size_t CWriter::BeginTry (const TryExpr& tryexpr ) {
3321+ size_t CWriter::BeginTry (const Block& block ) {
33053322 func_includes_.insert (" exceptions" );
3306- Write (OpenBrace ()); /* beginning of try-catch */
3307- const std::string tlabel = DefineLabelName (tryexpr. block .label );
3323+ Write (OpenBrace ()); /* beginning of try-catch or try_table */
3324+ const std::string tlabel = DefineLabelName (block.label );
33083325 Write (" WASM_RT_UNWIND_TARGET *" , tlabel,
33093326 " _outer_target = wasm_rt_get_unwind_target();" , Newline ());
33103327 Write (" WASM_RT_UNWIND_TARGET " , tlabel, " _unwind_target;" , Newline ());
33113328 Write (" if (!wasm_rt_try(" , tlabel, " _unwind_target)) " );
3312- Write (OpenBrace ()); /* beginning of try block */
3313- DropTypes (tryexpr. block .decl .GetNumParams ());
3329+ Write (OpenBrace ()); /* beginning of try or try_table block */
3330+ DropTypes (block.decl .GetNumParams ());
33143331 const size_t mark = MarkTypeStack ();
3315- PushLabel (LabelType::Try, tryexpr. block .label , tryexpr. block .decl .sig );
3316- PushTypes (tryexpr. block .decl .sig .param_types );
3332+ PushLabel (LabelType::Try, block.label , block.decl .sig );
3333+ PushTypes (block.decl .sig .param_types );
33173334 Write (" wasm_rt_set_unwind_target(&" , tlabel, " _unwind_target);" , Newline ());
33183335 PushTryCatch (tlabel);
3319- Write (tryexpr. block .exprs );
3336+ Write (block.exprs );
33203337 ResetTypeStack (mark);
33213338 Write (" wasm_rt_set_unwind_target(" , tlabel, " _outer_target);" , Newline ());
3322- Write (CloseBrace ()); /* end of try block */
3339+ Write (CloseBrace ()); /* end of try or try_table block */
33233340 Write (" else " , OpenBrace ()); /* beginning of catch blocks or delegate */
3324- assert (label_stack_.back ().name == tryexpr. block .label );
3341+ assert (label_stack_.back ().name == block.label );
33253342 assert (label_stack_.back ().label_type == LabelType::Try);
33263343 label_stack_.back ().label_type = LabelType::Catch;
33273344 if (try_catch_stack_.back ().used ) {
@@ -3332,7 +3349,7 @@ size_t CWriter::BeginTry(const TryExpr& tryexpr) {
33323349}
33333350
33343351void CWriter::WriteTryCatch (const TryExpr& tryexpr) {
3335- const size_t mark = BeginTry (tryexpr);
3352+ const size_t mark = BeginTry (tryexpr. block );
33363353
33373354 /* exception has been thrown -- do we catch it? */
33383355
@@ -3430,7 +3447,7 @@ void CWriter::PopTryCatch() {
34303447}
34313448
34323449void CWriter::WriteTryDelegate (const TryExpr& tryexpr) {
3433- const size_t mark = BeginTry (tryexpr);
3450+ const size_t mark = BeginTry (tryexpr. block );
34343451
34353452 /* exception has been thrown -- where do we delegate it? */
34363453
@@ -3477,6 +3494,85 @@ void CWriter::WriteTryDelegate(const TryExpr& tryexpr) {
34773494 PushTypes (tryexpr.block .decl .sig .result_types );
34783495}
34793496
3497+ void CWriter::Write (const TryTableExpr& try_table_expr) {
3498+ const size_t mark = BeginTry (try_table_expr.block );
3499+
3500+ /* exception has been thrown -- do we catch it? */
3501+
3502+ const LabelName tlabel = LabelName (try_table_expr.block .label );
3503+
3504+ Write (" wasm_rt_set_unwind_target(" , tlabel, " _outer_target);" , Newline ());
3505+ PopTryCatch ();
3506+
3507+ ResetTypeStack (mark);
3508+ assert (!label_stack_.empty ());
3509+ assert (label_stack_.back ().name == try_table_expr.block .label );
3510+ Write (LabelDecl (GetLocalName (try_table_expr.block .label , true )));
3511+ PopLabel ();
3512+
3513+ assert (!try_table_expr.catches .empty ());
3514+ bool has_catch_all{};
3515+ for (auto it = try_table_expr.catches .cbegin ();
3516+ it != try_table_expr.catches .cend (); ++it) {
3517+ if (it == try_table_expr.catches .cbegin ()) {
3518+ Write (Newline ());
3519+ } else {
3520+ Write (" else " );
3521+ }
3522+ ResetTypeStack (mark);
3523+ Write (*it);
3524+ if (it->IsCatchAll ()) {
3525+ has_catch_all = true ;
3526+ break ;
3527+ }
3528+ }
3529+ if (!has_catch_all) {
3530+ /* if not caught, rethrow */
3531+ Write (" else " , OpenBrace ());
3532+ WriteThrow ();
3533+ Write (CloseBrace (), Newline ());
3534+ }
3535+ Write (CloseBrace (), Newline ()); /* end of catch blocks */
3536+ Write (CloseBrace (), Newline ()); /* end of try-catch */
3537+
3538+ ResetTypeStack (mark);
3539+ PushTypes (try_table_expr.block .decl .sig .result_types );
3540+ }
3541+
3542+ void CWriter::Write (const TableCatch& c) {
3543+ if (!c.IsCatchAll ()) {
3544+ Write (" if (wasm_rt_exception_tag() == " ,
3545+ TagSymbol (module_->GetTag (c.tag )->name ), " ) " , OpenBrace ());
3546+
3547+ const Tag* tag = module_->GetTag (c.tag );
3548+ const FuncDeclaration& tag_type = tag->decl ;
3549+ const Index num_params = tag_type.GetNumParams ();
3550+ PushTypes (tag_type.sig .param_types );
3551+ if (num_params == 1 ) {
3552+ Write (" wasm_rt_memcpy(&" , StackVar (0 ), " , wasm_rt_exception(), sizeof(" ,
3553+ tag_type.GetParamType (0 ), " ));" , Newline ());
3554+ } else if (num_params > 1 ) {
3555+ Write (OpenBrace (), tag_type.sig .param_types , " tmp;" , Newline ());
3556+ Write (" wasm_rt_memcpy(&tmp, wasm_rt_exception(), sizeof(tmp));" ,
3557+ Newline ());
3558+ Unspill (tag_type.sig .param_types );
3559+ Write (CloseBrace (), Newline ());
3560+ }
3561+ }
3562+ if (c.IsRef ()) {
3563+ PushType (Type::ExnRef);
3564+ Write (StackVar (0 ), " .tag = wasm_rt_exception_tag();" , Newline ());
3565+ Write (StackVar (0 ), " .size = wasm_rt_exception_size();" , Newline ());
3566+ Write (" wasm_rt_memcpy(&" , StackVar (0 ),
3567+ " .data, wasm_rt_exception(), wasm_rt_exception_size());" , Newline ());
3568+ }
3569+
3570+ Write (GotoLabel (c.target ), Newline ());
3571+ if (!c.IsCatchAll ()) {
3572+ Write (CloseBrace ());
3573+ }
3574+ }
3575+
34803576void CWriter::Write (const ExprList& exprs) {
34813577 for (const Expr& expr : exprs) {
34823578 switch (expr.type ()) {
@@ -3879,6 +3975,10 @@ void CWriter::Write(const ExprList& exprs) {
38793975 " == " , GetReferenceNullValue (Type::ExternRef), " );" ,
38803976 Newline ());
38813977 break ;
3978+ case Type::ExnRef:
3979+ Write (StackVar (0 , Type::I32), " = (" , StackVar (0 ), " .tag == NULL" ,
3980+ " );" , Newline ());
3981+ break ;
38823982 default :
38833983 WABT_UNREACHABLE;
38843984 }
@@ -3995,7 +4095,19 @@ void CWriter::Write(const ExprList& exprs) {
39954095 }
39964096
39974097 WriteThrow ();
3998- } break ;
4098+ // Stop processing this ExprList, since the following are unreachable.
4099+ return ;
4100+ }
4101+
4102+ case ExprType::ThrowRef: {
4103+ Write (" if (" , StackVar (0 ), " .tag == NULL) { TRAP(NULL_REF); }" );
4104+ Write (" wasm_rt_load_exception(" , StackVar (0 ), " .tag, " , StackVar (0 ),
4105+ " .size, " , StackVar (0 ), " .data);" , Newline ());
4106+ DropTypes (1 );
4107+ WriteThrow ();
4108+ // Stop processing this ExprList, since the following are unreachable.
4109+ return ;
4110+ }
39994111
40004112 case ExprType::Rethrow: {
40014113 const RethrowExpr* rethrow = cast<RethrowExpr>(&expr);
@@ -4022,6 +4134,15 @@ void CWriter::Write(const ExprList& exprs) {
40224134 }
40234135 } break ;
40244136
4137+ case ExprType::TryTable: {
4138+ const TryTableExpr& try_table = *cast<TryTableExpr>(&expr);
4139+ if (try_table.catches .empty ()) {
4140+ Write (try_table.block );
4141+ } else {
4142+ Write (try_table);
4143+ }
4144+ } break ;
4145+
40254146 case ExprType::AtomicLoad: {
40264147 Write (*cast<AtomicLoadExpr>(&expr));
40274148 break ;
@@ -4146,8 +4267,6 @@ void CWriter::Write(const ExprList& exprs) {
41464267 case ExprType::AtomicWait:
41474268 case ExprType::AtomicNotify:
41484269 case ExprType::CallRef:
4149- case ExprType::ThrowRef:
4150- case ExprType::TryTable:
41514270 UNIMPLEMENTED (" ..." );
41524271 break ;
41534272 }
@@ -5998,6 +6117,8 @@ const char* CWriter::GetReferenceTypeName(const Type& type) {
59986117 return " funcref" ;
59996118 case Type::ExternRef:
60006119 return " externref" ;
6120+ case Type::ExnRef:
6121+ return " exnref" ;
60016122 default :
60026123 WABT_UNREACHABLE;
60036124 }
@@ -6010,6 +6131,8 @@ const char* CWriter::GetReferenceNullValue(const Type& type) {
60106131 return " wasm_rt_funcref_null_value" ;
60116132 case Type::ExternRef:
60126133 return " wasm_rt_externref_null_value" ;
6134+ case Type::ExnRef:
6135+ return " wasm_rt_exnref_null_value" ;
60136136 default :
60146137 WABT_UNREACHABLE;
60156138 }
0 commit comments