/* * 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" #define STRINGIFY_DEBUG 0 #if STRINGIFY_DEBUG #define DBG(statement) statement #else #define DBG(statement) #endif #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 inline void StringifyWalker::doWalkModule(Module* module) { ModuleUtils::iterDefinedFunctions( *module, [&](Function* func) { this->walkFunction(func); }); } template inline void StringifyWalker::doWalkFunction(Function* func) { addUniqueSymbol(SeparatorReason::makeFuncStart(func)); Super::walk(func->body); addUniqueSymbol(SeparatorReason::makeEnd()); while (!controlFlowQueue.empty()) { dequeueControlFlow(); } } template inline void StringifyWalker::scan(SubType* self, Expression** currp) { Expression* curr = *currp; if (Properties::isControlFlowStructure(curr)) { self->controlFlowQueue.push(curr); DBG(std::cerr << "controlFlowQueue.push: " << ShallowExpression{curr} << ", " << curr << "\n"); 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 void StringifyWalker::dequeueControlFlow() { auto& queue = controlFlowQueue; Expression* curr = queue.front(); queue.pop(); DBG(std::cerr << "controlFlowQueue.pop: " << ShallowExpression{curr} << ", " << curr << "\n"); // TODO: Issue #5796, Make a ControlChildIterator switch (curr->_id) { case Expression::Id::BlockId: { auto* block = curr->cast(); addUniqueSymbol(SeparatorReason::makeBlockStart(block)); for (auto& child : block->list) { Super::walk(child); } addUniqueSymbol(SeparatorReason::makeEnd()); break; } case Expression::Id::IfId: { auto* iff = curr->cast(); addUniqueSymbol(SeparatorReason::makeIfStart(iff)); Super::walk(iff->ifTrue); if (iff->ifFalse) { addUniqueSymbol(SeparatorReason::makeElseStart()); Super::walk(iff->ifFalse); } addUniqueSymbol(SeparatorReason::makeEnd()); break; } case Expression::Id::TryId: { auto* tryy = curr->cast(); addUniqueSymbol(SeparatorReason::makeTryBodyStart()); Super::walk(tryy->body); addUniqueSymbol(SeparatorReason::makeEnd()); for (auto& child : tryy->catchBodies) { addUniqueSymbol(SeparatorReason::makeTryCatchStart()); Super::walk(child); addUniqueSymbol(SeparatorReason::makeEnd()); } break; } case Expression::Id::LoopId: { auto* loop = curr->cast(); addUniqueSymbol(SeparatorReason::makeLoopStart(loop)); Super::walk(loop->body); addUniqueSymbol(SeparatorReason::makeEnd()); break; } default: { assert(Properties::isControlFlowStructure(curr)); WASM_UNREACHABLE("unexpected expression"); } } } template void StringifyWalker::doVisitExpression(SubType* self, Expression** currp) { Expression* curr = *currp; self->visit(curr); } template inline void StringifyWalker::addUniqueSymbol(SeparatorReason reason) { // 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::addUniqueSymbol != // &SubType::addUniqueSymbol); auto self = static_cast(this); self->addUniqueSymbol(reason); } } // namespace wasm #endif // wasm_passes_stringify_walker_impl_h