blob: e856773c9f832304c27b3b8deb4dc05962e982c6 [file] [log] [blame] [edit]
/*
* Copyright 2023 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 "stringify-walker.h"
#ifndef wasm_passes_stringify_walker_impl_h
#define wasm_passes_stringify_walker_impl_h
namespace wasm {
// This walker supplies its own doWalkModule because it does not make sense to
// walk anything besides defined functions.
template<typename SubType>
inline void StringifyWalker<SubType>::doWalkModule(Module* module) {
ModuleUtils::iterDefinedFunctions(
*module, [&](Function* func) { this->walkFunction(func); });
}
template<typename SubType>
inline void StringifyWalker<SubType>::doWalkFunction(Function* func) {
walk(func->body);
/*
* We add a unique symbol after walking the function body to separate the
* string generated from visiting the function body as a single unit from the
* subsequent strings that will be generated from visiting the sub-expressions
* of the function body. If we did not add this unique symbol and a program
* had two functions with the same instructions, we would incorrectly create a
* new function with the instructions repeated twice.
*
* It might be helpful to think of the function body as a block that needs to
* be separated from subsequent instructions.
*/
addUniqueSymbol();
}
template<typename SubType>
inline void StringifyWalker<SubType>::walk(Expression* curr) {
Super::walk(curr);
do {
addUniqueSymbol();
dequeueControlFlow();
} while (!controlFlowQueue.empty());
}
template<typename SubType>
inline void StringifyWalker<SubType>::scan(SubType* self, Expression** currp) {
Expression* curr = *currp;
if (Properties::isControlFlowStructure(curr)) {
self->controlFlowQueue.push(currp);
self->pushTask(doVisitExpression, currp);
// The if-condition is a value child consumed by the if control flow, which
// makes the if-condition a true sibling rather than part of its contents in
// the binary format
for (auto*& child : ValueChildIterator(curr)) {
Super::scan(self, &child);
}
} else {
Super::scan(self, currp);
}
}
// This dequeueControlFlow is responsible for visiting the children expressions
// of control flow.
template<typename SubType> void StringifyWalker<SubType>::dequeueControlFlow() {
auto& queue = controlFlowQueue;
if (queue.empty()) {
return;
}
Expression** currp = queue.front();
queue.pop();
Expression* curr = *currp;
// TODO: Issue #5796, Make a ControlChildIterator
switch (curr->_id) {
case Expression::Id::BlockId: {
auto* block = curr->cast<Block>();
for (auto& child : block->list) {
Super::walk(child);
}
break;
}
case Expression::Id::IfId: {
auto* iff = curr->cast<If>();
Super::walk(iff->ifTrue);
if (iff->ifFalse) {
addUniqueSymbol();
Super::walk(iff->ifFalse);
}
break;
}
case Expression::Id::TryId: {
auto* tryy = curr->cast<Try>();
Super::walk(tryy->body);
for (auto& child : tryy->catchBodies) {
addUniqueSymbol();
Super::walk(child);
}
break;
}
case Expression::Id::LoopId: {
auto* loop = curr->cast<Loop>();
Super::walk(loop->body);
break;
}
default: {
assert(Properties::isControlFlowStructure(curr));
WASM_UNREACHABLE("unexpected expression");
}
}
}
template<typename SubType>
void StringifyWalker<SubType>::doVisitExpression(SubType* self,
Expression** currp) {
Expression* curr = *currp;
self->visit(curr);
}
template<typename SubType>
inline void StringifyWalker<SubType>::addUniqueSymbol() {
// TODO: Add the following static_assert when the compilers running our GitHub
// actions are updated enough to know that this is a constant condition:
// static_assert(&StringifyWalker<SubType>::addUniqueSymbol !=
// &SubType::addUniqueSymbol);
auto self = static_cast<SubType*>(this);
self->addUniqueSymbol();
}
} // namespace wasm
#endif // wasm_passes_stringify_walker_impl_h