/* * Copyright 2021 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 "parsing.h" #include "ir/branch-utils.h" #include "support/small_set.h" namespace wasm { void ParseException::dump(std::ostream& o) const { Colors::magenta(o); o << "["; Colors::red(o); o << "parse exception: "; Colors::green(o); o << text; if (line != size_t(-1)) { Colors::normal(o); o << " (at " << line << ":" << col << ")"; } Colors::magenta(o); o << "]"; Colors::normal(o); } // UniqueNameMapper Name UniqueNameMapper::getPrefixedName(Name prefix) { if (reverseLabelMapping.find(prefix) == reverseLabelMapping.end()) { return prefix; } // make sure to return a unique name not already on the stack while (1) { Name ret = prefix.toString() + std::to_string(otherIndex++); if (reverseLabelMapping.find(ret) == reverseLabelMapping.end()) { return ret; } } } Name UniqueNameMapper::pushLabelName(Name sName) { Name name = getPrefixedName(sName); labelStack.push_back(name); labelMappings[sName].push_back(name); reverseLabelMapping[name] = sName; return name; } void UniqueNameMapper::popLabelName(Name name) { assert(labelStack.back() == name); labelStack.pop_back(); labelMappings[reverseLabelMapping[name]].pop_back(); } Name UniqueNameMapper::sourceToUnique(Name sName) { // DELEGATE_CALLER_TARGET is a fake target used to denote delegating to the // caller. We do not need to modify it, as it has no definitions, only uses. if (sName == DELEGATE_CALLER_TARGET) { return DELEGATE_CALLER_TARGET; } if (labelMappings.find(sName) == labelMappings.end()) { throw ParseException("bad label in sourceToUnique: " + sName.toString()); } if (labelMappings[sName].empty()) { throw ParseException("use of popped label in sourceToUnique: " + sName.toString()); } return labelMappings[sName].back(); } Name UniqueNameMapper::uniqueToSource(Name name) { if (reverseLabelMapping.find(name) == reverseLabelMapping.end()) { throw ParseException("label mismatch in uniqueToSource"); } return reverseLabelMapping[name]; } void UniqueNameMapper::clear() { labelStack.clear(); labelMappings.clear(); reverseLabelMapping.clear(); } namespace { struct DuplicateNameScanner : public PostWalker> { // Whether things are ok. If not, we need to fix things up. bool ok = true; // It is rare to have many nested names in general, so track the seen names // as we go in an efficient way. SmallUnorderedSet seen; void visitExpression(Expression* curr) { BranchUtils::operateOnScopeNameDefs(curr, [&](Name& name) { if (!name.is()) { return; } // TODO: This could be done in a single insert operation that checks // whether we actually inserted, if we improved // SmallSetBase::insert to return a value like std::set does. if (seen.count(name)) { // A name has been defined more than once; we'll need to fix that. ok = false; } else { seen.insert(name); } }); } }; } // anonymous namespace void UniqueNameMapper::uniquify(Expression* curr) { // First, scan the code to see if anything needs to be fixed up, since in the // common case nothing needs fixing, and we can verify that very quickly. DuplicateNameScanner scanner; scanner.walk(curr); if (scanner.ok) { return; } struct Walker : public ControlFlowWalker> { UniqueNameMapper mapper; static void doPreVisitControlFlow(Walker* self, Expression** currp) { BranchUtils::operateOnScopeNameDefs(*currp, [&](Name& name) { if (name.is()) { name = self->mapper.pushLabelName(name); } }); } static void doPostVisitControlFlow(Walker* self, Expression** currp) { BranchUtils::operateOnScopeNameDefs(*currp, [&](Name& name) { if (name.is()) { self->mapper.popLabelName(name); } }); } void visitExpression(Expression* curr) { BranchUtils::operateOnScopeNameUses(curr, [&](Name& name) { if (name.is()) { name = mapper.sourceToUnique(name); } }); } } walker; walker.walk(curr); } } // namespace wasm