summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm')
-rw-r--r--src/wasm/wasm-binary.cpp23
-rw-r--r--src/wasm/wasm-s-parser.cpp29
-rw-r--r--src/wasm/wasm-stack.cpp2
-rw-r--r--src/wasm/wasm-validator.cpp36
4 files changed, 39 insertions, 51 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index c6ed1dcfb..b843aad03 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -3475,12 +3475,12 @@ Name WasmBinaryBuilder::getExceptionTargetName(int32_t offset) {
}
size_t index = breakStack.size() - 1 - offset;
if (index > breakStack.size()) {
- throwError("bad delegate index (high)");
+ throwError("bad try index (high)");
}
- BYN_TRACE("delegate target " << breakStack[index].name << std::endl);
+ BYN_TRACE("exception target " << breakStack[index].name << std::endl);
auto& ret = breakStack[index];
- // if the delegate is in literally unreachable code, then we will not emit it
- // anyhow, so do not note that the target has delegate to it
+ // if the delegate/rethrow is in literally unreachable code, then we will not
+ // emit it anyhow, so do not note that the target has a reference to it
if (!willBeIgnored) {
exceptionTargetNames.insert(ret.name);
}
@@ -5835,11 +5835,12 @@ void WasmBinaryBuilder::visitTryOrTryInBlock(Expression*& out) {
curr->delegateTarget = getExceptionTargetName(getU32LEB());
}
- // For simplicity, we make try's labels only can be targeted by delegates, and
- // delegates can only target try's labels. (If they target blocks or loops, it
- // is a validation failure.) Because we create an inner block within each try
- // and catch body, if any delegate targets those inner blocks, we should make
- // them target the try's label instead.
+ // For simplicity, we ensure that try's labels can only be targeted by
+ // delegates and rethrows, and delegates/rethrows can only target try's
+ // labels. (If they target blocks or loops, it is a validation failure.)
+ // Because we create an inner block within each try and catch body, if any
+ // delegate/rethrow targets those inner blocks, we should make them target the
+ // try's label instead.
curr->name = getNextLabel();
if (auto* block = curr->body->dynCast<Block>()) {
if (block->name.is()) {
@@ -5936,7 +5937,9 @@ void WasmBinaryBuilder::visitThrow(Throw* curr) {
void WasmBinaryBuilder::visitRethrow(Rethrow* curr) {
BYN_TRACE("zz node: Rethrow\n");
- curr->depth = getU32LEB();
+ curr->target = getExceptionTargetName(getU32LEB());
+ // This special target is valid only for delegates
+ assert(curr->target != DELEGATE_CALLER_TARGET);
curr->finalize();
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 0ff4bfb9f..13b76801b 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2067,8 +2067,8 @@ Expression* SExpressionWasmBuilder::makeTry(Element& s) {
// We create a different name for the wrapping block, because try's name can
// be used by internal delegates
block->name = nameMapper.pushLabelName(sName);
- // For simplicity, try's name canonly be targeted by delegates. Make the
- // branches target the new wrapping block instead.
+ // For simplicity, try's name can only be targeted by delegates and
+ // rethrows. Make the branches target the new wrapping block instead.
BranchUtils::replaceBranchTargets(ret, ret->name, block->name);
block->list.push_back(ret);
nameMapper.popLabelName(block->name);
@@ -2078,29 +2078,6 @@ Expression* SExpressionWasmBuilder::makeTry(Element& s) {
return ret;
}
-Expression*
-SExpressionWasmBuilder::makeTryOrCatchBody(Element& s, Type type, bool isTry) {
- if (isTry && !elementStartsWith(s, "do")) {
- throw ParseException("invalid try do clause", s.line, s.col);
- }
- if (!isTry && !elementStartsWith(s, "catch") &&
- !elementStartsWith(s, "catch_all")) {
- throw ParseException("invalid catch clause", s.line, s.col);
- }
- if (s.size() == 1) { // (do) / (catch) / (catch_all) without instructions
- return makeNop();
- }
- auto ret = allocator.alloc<Block>();
- for (size_t i = 1; i < s.size(); i++) {
- ret->list.push_back(parseExpression(s[i]));
- }
- if (ret->list.size() == 1) {
- return ret->list[0];
- }
- ret->finalize(type);
- return ret;
-}
-
Expression* SExpressionWasmBuilder::makeThrow(Element& s) {
auto ret = allocator.alloc<Throw>();
Index i = 1;
@@ -2118,7 +2095,7 @@ Expression* SExpressionWasmBuilder::makeThrow(Element& s) {
Expression* SExpressionWasmBuilder::makeRethrow(Element& s) {
auto ret = allocator.alloc<Rethrow>();
- ret->depth = atoi(s[1]->str().c_str());
+ ret->target = getLabel(*s[1], LabelType::Exception);
ret->finalize();
return ret;
}
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index d36c2386c..b6c0392ca 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -1936,7 +1936,7 @@ void BinaryInstWriter::visitThrow(Throw* curr) {
}
void BinaryInstWriter::visitRethrow(Rethrow* curr) {
- o << int8_t(BinaryConsts::Rethrow) << U32LEB(curr->depth);
+ o << int8_t(BinaryConsts::Rethrow) << U32LEB(getBreakIndex(curr->target));
}
void BinaryInstWriter::visitNop(Nop* curr) { o << int8_t(BinaryConsts::Nop); }
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 736d669fb..6bcdb0e7c 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -236,7 +236,8 @@ struct FunctionValidator : public WalkerPass<PostWalker<FunctionValidator>> {
};
std::unordered_map<Name, BreakInfo> breakInfos;
- std::unordered_set<Name> exceptionTargetNames;
+ std::unordered_set<Name> delegateTargetNames;
+ std::unordered_set<Name> rethrowTargetNames;
std::set<Type> returnTypes; // types used in returns
@@ -280,7 +281,7 @@ public:
static void visitPreTry(FunctionValidator* self, Expression** currp) {
auto* curr = (*currp)->cast<Try>();
if (curr->name.is()) {
- self->exceptionTargetNames.insert(curr->name);
+ self->delegateTargetNames.insert(curr->name);
}
}
@@ -300,7 +301,8 @@ public:
static void visitPreCatch(FunctionValidator* self, Expression** currp) {
auto* curr = (*currp)->cast<Try>();
if (curr->name.is()) {
- self->exceptionTargetNames.erase(curr->name);
+ self->delegateTargetNames.erase(curr->name);
+ self->rethrowTargetNames.insert(curr->name);
}
}
@@ -376,7 +378,8 @@ public:
void visitRefIs(RefIs* curr);
void visitRefFunc(RefFunc* curr);
void visitRefEq(RefEq* curr);
- void noteException(Name name, Expression* curr);
+ void noteDelegate(Name name, Expression* curr);
+ void noteRethrow(Name name, Expression* curr);
void visitTry(Try* curr);
void visitThrow(Throw* curr);
void visitRethrow(Rethrow* curr);
@@ -2073,14 +2076,20 @@ void FunctionValidator::visitRefEq(RefEq* curr) {
"ref.eq's right argument should be a subtype of eqref");
}
-void FunctionValidator::noteException(Name name, Expression* curr) {
+void FunctionValidator::noteDelegate(Name name, Expression* curr) {
if (name != DELEGATE_CALLER_TARGET) {
- shouldBeTrue(exceptionTargetNames.find(name) != exceptionTargetNames.end(),
+ shouldBeTrue(delegateTargetNames.count(name) != 0,
curr,
"all delegate targets must be valid");
}
}
+void FunctionValidator::noteRethrow(Name name, Expression* curr) {
+ shouldBeTrue(rethrowTargetNames.count(name) != 0,
+ curr,
+ "all rethrow targets must be valid");
+}
+
void FunctionValidator::visitTry(Try* curr) {
shouldBeTrue(getModule()->features.hasExceptionHandling(),
curr,
@@ -2122,8 +2131,10 @@ void FunctionValidator::visitTry(Try* curr) {
"try should have either catches or a delegate");
if (curr->isDelegate()) {
- noteException(curr->delegateTarget, curr);
+ noteDelegate(curr->delegateTarget, curr);
}
+
+ rethrowTargetNames.erase(curr->name);
}
void FunctionValidator::visitThrow(Throw* curr) {
@@ -2167,8 +2178,7 @@ void FunctionValidator::visitRethrow(Rethrow* curr) {
Type(Type::unreachable),
curr,
"rethrow's type must be unreachable");
- // TODO Validate the depth field. The current LLVM toolchain only generates
- // depth 0 for C++ support.
+ noteRethrow(curr->target, curr);
}
void FunctionValidator::visitTupleMake(TupleMake* curr) {
@@ -2531,11 +2541,9 @@ void FunctionValidator::visitFunction(Function* curr) {
"function result must match, if function has returns");
}
- shouldBeTrue(
- breakInfos.empty(), curr->body, "all named break targets must exist");
- shouldBeTrue(exceptionTargetNames.empty(),
- curr->body,
- "all named delegate targets must exist");
+ assert(breakInfos.empty());
+ assert(delegateTargetNames.empty());
+ assert(rethrowTargetNames.empty());
returnTypes.clear();
labelNames.clear();
// validate optional local names