/* * Copyright 2016 WebAssembly Community Group participants * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "wasm.h" #include "wasm-traversal.h" #include "ast_utils.h" namespace wasm { struct TypeSeeker : public PostWalker> { Expression* target; // look for this one Name targetName; std::vector types; TypeSeeker(Expression* target, Name targetName) : target(target), targetName(targetName) { Expression* temp = target; walk(temp); } void visitBreak(Break* curr) { if (curr->name == targetName) { types.push_back(curr->value ? curr->value->type : none); } } void visitSwitch(Switch* curr) { for (auto name : curr->targets) { if (name == targetName) types.push_back(curr->value ? curr->value->type : none); } if (curr->default_ == targetName) types.push_back(curr->value ? curr->value->type : none); } void visitBlock(Block* curr) { if (curr == target) { if (curr->list.size() > 0) { types.push_back(curr->list.back()->type); } else { types.push_back(none); } } else if (curr->name == targetName) { types.clear(); // ignore all breaks til now, they were captured by someone with the same name } } void visitLoop(Loop* curr) { if (curr == target) { types.push_back(curr->body->type); } else if (curr->in == targetName || curr->out == targetName) { types.clear(); // ignore all breaks til now, they were captured by someone with the same name } } }; static WasmType mergeTypes(std::vector& types) { WasmType type = unreachable; for (auto other : types) { // once none, stop. it then indicates a poison value, that must not be consumed // and ignore unreachable if (type != none) { if (other == none) { type = none; } else if (other != unreachable) { if (type == unreachable) { type = other; } else if (type != other) { type = none; // poison value, we saw multiple types; this should not be consumed } } } } return type; } void Block::finalize() { if (!name.is()) { // nothing branches here, so this is easy if (list.size() > 0) { type = list.back()->type; } else { type = unreachable; } return; } TypeSeeker seeker(this, this->name); type = mergeTypes(seeker.types); } void Loop::finalize() { if (!out.is()) { type = body->type; return; } TypeSeeker seeker(this, this->out); type = mergeTypes(seeker.types); } } // namespace wasm