@@ -99,7 +99,7 @@ struct CFGWalker : public PostWalker<SubType, VisitorType> {
99
99
// that can reach catch blocks (each item is assumed to be able to reach any
100
100
// of the catches, although that could be improved perhaps).
101
101
std::vector<std::vector<BasicBlock*>> throwingInstsStack;
102
- // stack of 'Try' expressions corresponding to throwingInstsStack.
102
+ // stack of 'Try'/'TryTable' expressions corresponding to throwingInstsStack.
103
103
std::vector<Expression*> tryStack;
104
104
// A stack for each try, where each entry is a list of blocks, one for each
105
105
// catch, used during processing. We start by assigning the start blocks to
@@ -254,11 +254,11 @@ struct CFGWalker : public PostWalker<SubType, VisitorType> {
254
254
}
255
255
256
256
static void doEndThrowingInst (SubType* self, Expression** currp) {
257
- // If the innermost try does not have a catch_all clause, an exception
258
- // thrown can be caught by any of its outer catch block. And if that outer
259
- // try-catch also does not have a catch_all, this continues until we
260
- // encounter a try-catch_all. Create a link to all those possible catch
261
- // unwind destinations.
257
+ // If the innermost try/try_table does not have a catch_all clause, an
258
+ // exception thrown can be caught by any of its outer catch block. And if
259
+ // that outer try/try_table also does not have a catch_all, this continues
260
+ // until we encounter a try/try_table -catch_all. Create a link to all those
261
+ // possible catch unwind destinations.
262
262
// TODO This can be more precise for `throw`s if we compare tag types and
263
263
// create links to outer catch BBs only when the exception is not caught.
264
264
// TODO This can also be more precise if we analyze the structure of nested
@@ -281,36 +281,47 @@ struct CFGWalker : public PostWalker<SubType, VisitorType> {
281
281
// end
282
282
assert (self->tryStack .size () == self->throwingInstsStack .size ());
283
283
for (int i = self->throwingInstsStack .size () - 1 ; i >= 0 ;) {
284
- auto * tryy = self->tryStack [i]->template cast <Try>();
285
- if (tryy->isDelegate ()) {
286
- // If this delegates to the caller, there is no possibility that this
287
- // instruction can throw to outer catches.
288
- if (tryy->delegateTarget == DELEGATE_CALLER_TARGET) {
289
- break ;
290
- }
291
- // If this delegates to an outer try, we skip catches between this try
292
- // and the target try.
293
- [[maybe_unused]] bool found = false ;
294
- for (int j = i - 1 ; j >= 0 ; j--) {
295
- if (self->tryStack [j]->template cast <Try>()->name ==
296
- tryy->delegateTarget ) {
297
- i = j;
298
- found = true ;
284
+ if (auto * tryy = self->tryStack [i]->template dynCast <Try>()) {
285
+ if (tryy->isDelegate ()) {
286
+ // If this delegates to the caller, there is no possibility that this
287
+ // instruction can throw to outer catches.
288
+ if (tryy->delegateTarget == DELEGATE_CALLER_TARGET) {
299
289
break ;
300
290
}
291
+ // If this delegates to an outer try, we skip catches between this try
292
+ // and the target try.
293
+ [[maybe_unused]] bool found = false ;
294
+ for (int j = i - 1 ; j >= 0 ; j--) {
295
+ if (self->tryStack [j]->template cast <Try>()->name ==
296
+ tryy->delegateTarget ) {
297
+ i = j;
298
+ found = true ;
299
+ break ;
300
+ }
301
+ }
302
+ assert (found);
303
+ continue ;
301
304
}
302
- assert (found);
303
- continue ;
304
305
}
305
306
306
307
// Exception thrown. Note outselves so that we will create a link to each
307
- // catch within the try when we get there.
308
+ // catch within the try / each destination block within the try_table when
309
+ // we get there.
308
310
self->throwingInstsStack [i].push_back (self->currBasicBlock );
309
311
310
- // If this try has catch_all, there is no possibility that this
311
- // instruction can throw to outer catches. Stop here.
312
- if (tryy->hasCatchAll ()) {
313
- break ;
312
+ if (auto * tryy = self->tryStack [i]->template dynCast <Try>()) {
313
+ // If this try has catch_all, there is no possibility that this
314
+ // instruction can throw to outer catches. Stop here.
315
+ if (tryy->hasCatchAll ()) {
316
+ break ;
317
+ }
318
+ } else if (auto * tryTable =
319
+ self->tryStack [i]->template dynCast <TryTable>()) {
320
+ if (tryTable->hasCatchAll ()) {
321
+ break ;
322
+ }
323
+ } else {
324
+ WASM_UNREACHABLE (" invalid throwingInstsStack item" );
314
325
}
315
326
i--;
316
327
}
@@ -411,6 +422,28 @@ struct CFGWalker : public PostWalker<SubType, VisitorType> {
411
422
self->startUnreachableBlock ();
412
423
}
413
424
425
+ static void doStartTryTable (SubType* self, Expression** currp) {
426
+ auto * curr = (*currp)->cast <TryTable>();
427
+ self->throwingInstsStack .emplace_back ();
428
+ self->tryStack .push_back (curr);
429
+ }
430
+
431
+ static void doEndTryTable (SubType* self, Expression** currp) {
432
+ auto * curr = (*currp)->cast <TryTable>();
433
+
434
+ auto catchTargets = BranchUtils::getUniqueTargets (curr);
435
+ // Add catch destinations to the targets.
436
+ for (auto target : catchTargets) {
437
+ auto & preds = self->throwingInstsStack .back ();
438
+ for (auto * pred : preds) {
439
+ self->branches [target].push_back (pred);
440
+ }
441
+ }
442
+
443
+ self->throwingInstsStack .pop_back ();
444
+ self->tryStack .pop_back ();
445
+ }
446
+
414
447
static bool isReturnCall (Expression* curr) {
415
448
switch (curr->_id ) {
416
449
case Expression::Id::CallId:
@@ -478,8 +511,13 @@ struct CFGWalker : public PostWalker<SubType, VisitorType> {
478
511
self->pushTask (SubType::doStartTry, currp);
479
512
return ; // don't do anything else
480
513
}
514
+ case Expression::Id::TryTableId: {
515
+ self->pushTask (SubType::doEndTryTable, currp);
516
+ break ;
517
+ }
481
518
case Expression::Id::ThrowId:
482
- case Expression::Id::RethrowId: {
519
+ case Expression::Id::RethrowId:
520
+ case Expression::Id::ThrowRefId: {
483
521
self->pushTask (SubType::doEndThrow, currp);
484
522
break ;
485
523
}
@@ -499,6 +537,10 @@ struct CFGWalker : public PostWalker<SubType, VisitorType> {
499
537
self->pushTask (SubType::doStartLoop, currp);
500
538
break ;
501
539
}
540
+ case Expression::Id::TryTableId: {
541
+ self->pushTask (SubType::doStartTryTable, currp);
542
+ break ;
543
+ }
502
544
default : {}
503
545
}
504
546
}
0 commit comments