diff options
Diffstat (limited to 'src/wasm/wasm-validator.cpp')
-rw-r--r-- | src/wasm/wasm-validator.cpp | 103 |
1 files changed, 23 insertions, 80 deletions
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 057243fd3..80b7eb874 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -209,21 +209,7 @@ struct FunctionValidator : public WalkerPass<PostWalker<FunctionValidator>> { FunctionValidator(ValidationInfo* info) : info(*info) {} - struct BreakInfo { - enum { UnsetArity = Index(-1), PoisonArity = Index(-2) }; - - Type type; - Index arity; - BreakInfo() : arity(UnsetArity) {} - BreakInfo(Type type, Index arity) : type(type), arity(arity) {} - - bool hasBeenSet() { - // Compare to the impossible value. - return arity != UnsetArity; - } - }; - - std::unordered_map<Name, BreakInfo> breakInfos; + std::unordered_map<Name, std::unordered_set<Type>> breakTypes; std::unordered_set<Name> delegateTargetNames; std::unordered_set<Name> rethrowTargetNames; @@ -248,7 +234,7 @@ public: static void visitPreBlock(FunctionValidator* self, Expression** currp) { auto* curr = (*currp)->cast<Block>(); if (curr->name.is()) { - self->breakInfos[curr->name]; + self->breakTypes[curr->name]; } } @@ -259,7 +245,7 @@ public: static void visitPreLoop(FunctionValidator* self, Expression** currp) { auto* curr = (*currp)->cast<Loop>(); if (curr->name.is()) { - self->breakInfos[curr->name]; + self->breakTypes[curr->name]; } } @@ -533,49 +519,17 @@ void FunctionValidator::visitBlock(Block* curr) { // if we are break'ed to, then the value must be right for us if (curr->name.is()) { noteLabelName(curr->name); - auto iter = breakInfos.find(curr->name); - assert(iter != breakInfos.end()); // we set it ourselves - auto& info = iter->second; - if (info.hasBeenSet()) { - if (curr->type.isConcrete()) { - shouldBeTrue(info.arity != 0, - curr, - "break arities must be > 0 if block has a value"); - } else { - shouldBeTrue(info.arity == 0, - curr, - "break arities must be 0 if block has no value"); - } + auto iter = breakTypes.find(curr->name); + assert(iter != breakTypes.end()); // we set it ourselves + for (Type breakType : iter->second) { // none or unreachable means a poison value that we should ignore - if // consumed, it will error - if (info.type.isConcrete() && curr->type.isConcrete()) { - shouldBeSubType( - info.type, - curr->type, - curr, - "block+breaks must have right type if breaks return a value"); - } - if (curr->type.isConcrete() && info.arity && - info.type != Type::unreachable) { - shouldBeSubType( - info.type, - curr->type, - curr, - "block+breaks must have right type if breaks have arity"); - } - shouldBeTrue( - info.arity != BreakInfo::PoisonArity, curr, "break arities must match"); - if (curr->list.size() > 0) { - auto last = curr->list.back()->type; - if (last == Type::none) { - shouldBeTrue(info.arity == Index(0), - curr, - "if block ends with a none, breaks cannot send a value " - "of any type"); - } - } + shouldBeSubType(breakType, + curr->type, + curr, + "break type must be a subtype of the target block type"); } - breakInfos.erase(iter); + breakTypes.erase(iter); } switch (getFunction()->profile) { case IRProfile::Normal: @@ -679,14 +633,15 @@ void FunctionValidator::validatePoppyBlockElements(Block* curr) { void FunctionValidator::visitLoop(Loop* curr) { if (curr->name.is()) { noteLabelName(curr->name); - auto iter = breakInfos.find(curr->name); - assert(iter != breakInfos.end()); // we set it ourselves - auto& info = iter->second; - if (info.hasBeenSet()) { - shouldBeEqual( - info.arity, Index(0), curr, "breaks to a loop cannot pass a value"); + auto iter = breakTypes.find(curr->name); + assert(iter != breakTypes.end()); // we set it ourselves + for (Type breakType : iter->second) { + shouldBeEqual(breakType, + Type(Type::none), + curr, + "breaks to a loop cannot pass a value"); } - breakInfos.erase(iter); + breakTypes.erase(iter); } if (curr->type == Type::none) { shouldBeFalse(curr->body->type.isConcrete(), @@ -775,24 +730,12 @@ void FunctionValidator::noteBreak(Name name, } void FunctionValidator::noteBreak(Name name, Type valueType, Expression* curr) { - Index arity = 0; - if (valueType != Type::none) { - arity = 1; - } - auto iter = breakInfos.find(name); + auto iter = breakTypes.find(name); if (!shouldBeTrue( - iter != breakInfos.end(), curr, "all break targets must be valid")) { + iter != breakTypes.end(), curr, "all break targets must be valid")) { return; } - auto& info = iter->second; - if (!info.hasBeenSet()) { - info = BreakInfo(valueType, arity); - } else { - info.type = Type::getLeastUpperBound(info.type, valueType); - if (arity != info.arity) { - info.arity = BreakInfo::PoisonArity; - } - } + iter->second.insert(valueType); } void FunctionValidator::visitBreak(Break* curr) { @@ -2518,7 +2461,7 @@ void FunctionValidator::visitFunction(Function* curr) { "function result must match, if function has returns"); } - assert(breakInfos.empty()); + assert(breakTypes.empty()); assert(delegateTargetNames.empty()); assert(rethrowTargetNames.empty()); returnTypes.clear(); |