blob: 5d34da78e8a611543e1f3c839da96aa54f14fb9b [file] [log] [blame] [edit]
/*
* 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<DuplicateNameScanner,
UnifiedExpressionVisitor<DuplicateNameScanner>> {
// 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<Name, 10> 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<Walker, UnifiedExpressionVisitor<Walker>> {
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