|
47 | 47 | namespace wasm { |
48 | 48 |
|
49 | 49 | struct WasmException { |
| 50 | + // TODO: handle cross-module calls using something other than a Name here. |
50 | 51 | Name tag; |
51 | 52 | Literals values; |
52 | 53 | }; |
@@ -204,6 +205,15 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> { |
204 | 205 | return Literal(allocation, type.getHeapType()); |
205 | 206 | } |
206 | 207 |
|
| 208 | + // Same as makeGCData but for ExnData. |
| 209 | + Literal makeExnData(Name tag, const Literals& payload) { |
| 210 | + auto allocation = std::make_shared<ExnData>(tag, payload); |
| 211 | +#if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer) |
| 212 | + __lsan_ignore_object(allocation.get()); |
| 213 | +#endif |
| 214 | + return Literal(allocation); |
| 215 | + } |
| 216 | + |
207 | 217 | public: |
208 | 218 | // Indicates no limit of maxDepth or maxLoopIterations. |
209 | 219 | static const Index NO_LIMIT = 0; |
@@ -1418,7 +1428,26 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> { |
1418 | 1428 | WASM_UNREACHABLE("throw"); |
1419 | 1429 | } |
1420 | 1430 | Flow visitRethrow(Rethrow* curr) { WASM_UNREACHABLE("unimp"); } |
1421 | | - Flow visitThrowRef(ThrowRef* curr) { WASM_UNREACHABLE("unimp"); } |
| 1431 | + Flow visitThrowRef(ThrowRef* curr) { |
| 1432 | + NOTE_ENTER("ThrowRef"); |
| 1433 | + Flow flow = visit(curr->exnref); |
| 1434 | + if (flow.breaking()) { |
| 1435 | + return flow; |
| 1436 | + } |
| 1437 | + const auto& exnref = flow.getSingleValue(); |
| 1438 | + NOTE_EVAL1(exnref); |
| 1439 | + if (exnref.isNull()) { |
| 1440 | + trap("null ref"); |
| 1441 | + } |
| 1442 | + const auto& exnData = exnref.getExnData(); |
| 1443 | + WasmException exn; |
| 1444 | + exn.tag = exnData->tag; |
| 1445 | + for (auto item : exnData->payload) { |
| 1446 | + exn.values.push_back(item); |
| 1447 | + } |
| 1448 | + throwException(exn); |
| 1449 | + WASM_UNREACHABLE("throw"); |
| 1450 | + } |
1422 | 1451 | Flow visitRefI31(RefI31* curr) { |
1423 | 1452 | NOTE_ENTER("RefI31"); |
1424 | 1453 | Flow flow = visit(curr->value); |
@@ -2432,6 +2461,10 @@ class ConstantExpressionRunner : public ExpressionRunner<SubType> { |
2432 | 2461 | NOTE_ENTER("Try"); |
2433 | 2462 | return Flow(NONCONSTANT_FLOW); |
2434 | 2463 | } |
| 2464 | + Flow visitTryTable(TryTable* curr) { |
| 2465 | + NOTE_ENTER("TryTable"); |
| 2466 | + return Flow(NONCONSTANT_FLOW); |
| 2467 | + } |
2435 | 2468 | Flow visitRethrow(Rethrow* curr) { |
2436 | 2469 | NOTE_ENTER("Rethrow"); |
2437 | 2470 | return Flow(NONCONSTANT_FLOW); |
@@ -4046,6 +4079,31 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> { |
4046 | 4079 | throw; |
4047 | 4080 | } |
4048 | 4081 | } |
| 4082 | + Flow visitTryTable(TryTable* curr) { |
| 4083 | + NOTE_ENTER("TryTable"); |
| 4084 | + try { |
| 4085 | + return self()->visit(curr->body); |
| 4086 | + } catch (const WasmException& e) { |
| 4087 | + for (size_t i = 0; i < curr->catchTags.size(); i++) { |
| 4088 | + auto catchTag = curr->catchTags[i]; |
| 4089 | + if (!catchTag.is() || catchTag == e.tag) { |
| 4090 | + Flow ret; |
| 4091 | + ret.breakTo = curr->catchDests[i]; |
| 4092 | + if (catchTag.is()) { |
| 4093 | + for (auto item : e.values) { |
| 4094 | + ret.values.push_back(item); |
| 4095 | + } |
| 4096 | + } |
| 4097 | + if (curr->catchRefs[i]) { |
| 4098 | + ret.values.push_back(self()->makeExnData(e.tag, e.values)); |
| 4099 | + } |
| 4100 | + return ret; |
| 4101 | + } |
| 4102 | + } |
| 4103 | + // This exception is not caught by this try-catch. Rethrow it. |
| 4104 | + throw; |
| 4105 | + } |
| 4106 | + } |
4049 | 4107 | Flow visitRethrow(Rethrow* curr) { |
4050 | 4108 | for (int i = exceptionStack.size() - 1; i >= 0; i--) { |
4051 | 4109 | if (exceptionStack[i].second == curr->target) { |
|
0 commit comments