@@ -266,6 +266,7 @@ class CWriter {
266
266
bool IsTopLabelUsed () const ;
267
267
void PopLabel ();
268
268
269
+ static constexpr bool AreInitializersAlwaysNull (Type);
269
270
static constexpr char MangleType (Type);
270
271
static constexpr char MangleField (ModuleFieldType);
271
272
static std::string MangleTypes (const TypeVector&);
@@ -483,10 +484,12 @@ class CWriter {
483
484
void Write (const AtomicRmwExpr& expr);
484
485
void Write (const AtomicRmwCmpxchgExpr& expr);
485
486
486
- size_t BeginTry (const TryExpr& tryexpr );
487
+ size_t BeginTry (const Block& block );
487
488
void WriteTryCatch (const TryExpr& tryexpr);
488
489
void WriteTryDelegate (const TryExpr& tryexpr);
490
+ void Write (const TryTableExpr& try_table_expr);
489
491
void Write (const Catch& c);
492
+ void Write (const TableCatch& c);
490
493
void WriteThrow ();
491
494
492
495
void PushTryCatch (const std::string& name);
@@ -635,6 +638,19 @@ void CWriter::PopLabel() {
635
638
label_stack_.pop_back ();
636
639
}
637
640
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
+
638
654
// static
639
655
constexpr char CWriter::MangleType (Type type) {
640
656
// clang-format off
@@ -646,6 +662,7 @@ constexpr char CWriter::MangleType(Type type) {
646
662
case Type::V128: return ' o' ;
647
663
case Type::FuncRef: return ' r' ;
648
664
case Type::ExternRef: return ' e' ;
665
+ case Type::ExnRef: return ' x' ;
649
666
default :
650
667
WABT_UNREACHABLE;
651
668
}
@@ -1218,6 +1235,7 @@ const char* CWriter::GetCTypeName(const Type& type) {
1218
1235
case Type::V128: return " v128" ;
1219
1236
case Type::FuncRef: return " wasm_rt_funcref_t" ;
1220
1237
case Type::ExternRef: return " wasm_rt_externref_t" ;
1238
+ case Type::ExnRef: return " wasm_rt_exnref_t" ;
1221
1239
default :
1222
1240
WABT_UNREACHABLE;
1223
1241
}
@@ -1238,6 +1256,7 @@ void CWriter::Write(TypeEnum type) {
1238
1256
case Type::V128: Write (" WASM_RT_V128" ); break ;
1239
1257
case Type::FuncRef: Write (" WASM_RT_FUNCREF" ); break ;
1240
1258
case Type::ExternRef: Write (" WASM_RT_EXTERNREF" ); break ;
1259
+ case Type::ExnRef: Write (" WASM_RT_EXNREF" ); break ;
1241
1260
default :
1242
1261
WABT_UNREACHABLE;
1243
1262
}
@@ -2301,9 +2320,8 @@ void CWriter::WriteElemInitializerDecls() {
2301
2320
continue ;
2302
2321
}
2303
2322
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
2307
2325
continue ;
2308
2326
}
2309
2327
@@ -2373,9 +2391,8 @@ void CWriter::WriteElemInitializers() {
2373
2391
continue ;
2374
2392
}
2375
2393
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
2379
2396
continue ;
2380
2397
}
2381
2398
@@ -2476,15 +2493,15 @@ void CWriter::WriteElemInitializers() {
2476
2493
void CWriter::WriteElemTableInit (bool active_initialization,
2477
2494
const ElemSegment* src_segment,
2478
2495
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 );
2481
2498
assert (dst_table->elem_type == src_segment->elem_type );
2482
2499
2483
2500
Write (GetReferenceTypeName (dst_table->elem_type ), " _table_init(" ,
2484
2501
ExternalInstancePtr (ModuleFieldType::Table, dst_table->name ), " , " );
2485
2502
2486
2503
// 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
2488
2505
if (dst_table->elem_type == Type::FuncRef) {
2489
2506
if (src_segment->elem_exprs .empty ()) {
2490
2507
Write (" NULL, " );
@@ -3125,7 +3142,7 @@ void CWriter::WriteVarsByType(const Vars& vars,
3125
3142
const ToDo& todo,
3126
3143
bool setjmp_safe) {
3127
3144
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 }) {
3129
3146
Index var_index = 0 ;
3130
3147
size_t count = 0 ;
3131
3148
for (const auto & var : vars) {
@@ -3269,7 +3286,7 @@ void CWriter::WriteLocals(const std::vector<std::string>& index_to_name) {
3269
3286
func_->local_types , [](auto x) { return x; },
3270
3287
[&](Index local_index, Type local_type) {
3271
3288
Write (DefineParamName (index_to_name[num_params + local_index]), " = " );
3272
- if (local_type == Type::FuncRef || local_type == Type::ExternRef ) {
3289
+ if (local_type. IsRef () ) {
3273
3290
Write (GetReferenceNullValue (local_type));
3274
3291
} else if (local_type == Type::V128) {
3275
3292
Write (" simde_wasm_i64x2_make(0, 0)" );
@@ -3301,27 +3318,27 @@ void CWriter::Write(const Block& block) {
3301
3318
PushTypes (block.decl .sig .result_types );
3302
3319
}
3303
3320
3304
- size_t CWriter::BeginTry (const TryExpr& tryexpr ) {
3321
+ size_t CWriter::BeginTry (const Block& block ) {
3305
3322
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 );
3308
3325
Write (" WASM_RT_UNWIND_TARGET *" , tlabel,
3309
3326
" _outer_target = wasm_rt_get_unwind_target();" , Newline ());
3310
3327
Write (" WASM_RT_UNWIND_TARGET " , tlabel, " _unwind_target;" , Newline ());
3311
3328
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 ());
3314
3331
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 );
3317
3334
Write (" wasm_rt_set_unwind_target(&" , tlabel, " _unwind_target);" , Newline ());
3318
3335
PushTryCatch (tlabel);
3319
- Write (tryexpr. block .exprs );
3336
+ Write (block.exprs );
3320
3337
ResetTypeStack (mark);
3321
3338
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 */
3323
3340
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 );
3325
3342
assert (label_stack_.back ().label_type == LabelType::Try);
3326
3343
label_stack_.back ().label_type = LabelType::Catch;
3327
3344
if (try_catch_stack_.back ().used ) {
@@ -3332,7 +3349,7 @@ size_t CWriter::BeginTry(const TryExpr& tryexpr) {
3332
3349
}
3333
3350
3334
3351
void CWriter::WriteTryCatch (const TryExpr& tryexpr) {
3335
- const size_t mark = BeginTry (tryexpr);
3352
+ const size_t mark = BeginTry (tryexpr. block );
3336
3353
3337
3354
/* exception has been thrown -- do we catch it? */
3338
3355
@@ -3430,7 +3447,7 @@ void CWriter::PopTryCatch() {
3430
3447
}
3431
3448
3432
3449
void CWriter::WriteTryDelegate (const TryExpr& tryexpr) {
3433
- const size_t mark = BeginTry (tryexpr);
3450
+ const size_t mark = BeginTry (tryexpr. block );
3434
3451
3435
3452
/* exception has been thrown -- where do we delegate it? */
3436
3453
@@ -3477,6 +3494,85 @@ void CWriter::WriteTryDelegate(const TryExpr& tryexpr) {
3477
3494
PushTypes (tryexpr.block .decl .sig .result_types );
3478
3495
}
3479
3496
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
+
3480
3576
void CWriter::Write (const ExprList& exprs) {
3481
3577
for (const Expr& expr : exprs) {
3482
3578
switch (expr.type ()) {
@@ -3879,6 +3975,10 @@ void CWriter::Write(const ExprList& exprs) {
3879
3975
" == " , GetReferenceNullValue (Type::ExternRef), " );" ,
3880
3976
Newline ());
3881
3977
break ;
3978
+ case Type::ExnRef:
3979
+ Write (StackVar (0 , Type::I32), " = (" , StackVar (0 ), " .tag == NULL" ,
3980
+ " );" , Newline ());
3981
+ break ;
3882
3982
default :
3883
3983
WABT_UNREACHABLE;
3884
3984
}
@@ -3995,7 +4095,19 @@ void CWriter::Write(const ExprList& exprs) {
3995
4095
}
3996
4096
3997
4097
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
+ }
3999
4111
4000
4112
case ExprType::Rethrow: {
4001
4113
const RethrowExpr* rethrow = cast<RethrowExpr>(&expr);
@@ -4022,6 +4134,15 @@ void CWriter::Write(const ExprList& exprs) {
4022
4134
}
4023
4135
} break ;
4024
4136
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
+
4025
4146
case ExprType::AtomicLoad: {
4026
4147
Write (*cast<AtomicLoadExpr>(&expr));
4027
4148
break ;
@@ -4146,8 +4267,6 @@ void CWriter::Write(const ExprList& exprs) {
4146
4267
case ExprType::AtomicWait:
4147
4268
case ExprType::AtomicNotify:
4148
4269
case ExprType::CallRef:
4149
- case ExprType::ThrowRef:
4150
- case ExprType::TryTable:
4151
4270
UNIMPLEMENTED (" ..." );
4152
4271
break ;
4153
4272
}
@@ -5998,6 +6117,8 @@ const char* CWriter::GetReferenceTypeName(const Type& type) {
5998
6117
return " funcref" ;
5999
6118
case Type::ExternRef:
6000
6119
return " externref" ;
6120
+ case Type::ExnRef:
6121
+ return " exnref" ;
6001
6122
default :
6002
6123
WABT_UNREACHABLE;
6003
6124
}
@@ -6010,6 +6131,8 @@ const char* CWriter::GetReferenceNullValue(const Type& type) {
6010
6131
return " wasm_rt_funcref_null_value" ;
6011
6132
case Type::ExternRef:
6012
6133
return " wasm_rt_externref_null_value" ;
6134
+ case Type::ExnRef:
6135
+ return " wasm_rt_exnref_null_value" ;
6013
6136
default :
6014
6137
WABT_UNREACHABLE;
6015
6138
}
0 commit comments