1 //===--- WebAssemblyExceptionInfo.cpp - Exception Infomation --------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// \brief This file implements WebAssemblyException information analysis. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "WebAssemblyExceptionInfo.h" 15 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 16 #include "WebAssemblyUtilities.h" 17 #include "llvm/ADT/PostOrderIterator.h" 18 #include "llvm/CodeGen/MachineDominanceFrontier.h" 19 #include "llvm/CodeGen/MachineDominators.h" 20 #include "llvm/CodeGen/WasmEHFuncInfo.h" 21 #include "llvm/InitializePasses.h" 22 23 using namespace llvm; 24 25 #define DEBUG_TYPE "wasm-exception-info" 26 27 char WebAssemblyExceptionInfo::ID = 0; 28 29 INITIALIZE_PASS_BEGIN(WebAssemblyExceptionInfo, DEBUG_TYPE, 30 "WebAssembly Exception Information", true, true) 31 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) 32 INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier) 33 INITIALIZE_PASS_END(WebAssemblyExceptionInfo, DEBUG_TYPE, 34 "WebAssembly Exception Information", true, true) 35 36 bool WebAssemblyExceptionInfo::runOnMachineFunction(MachineFunction &MF) { 37 LLVM_DEBUG(dbgs() << "********** Exception Info Calculation **********\n" 38 "********** Function: " 39 << MF.getName() << '\n'); 40 releaseMemory(); 41 auto &MDT = getAnalysis<MachineDominatorTree>(); 42 auto &MDF = getAnalysis<MachineDominanceFrontier>(); 43 recalculate(MF, MDT, MDF); 44 return false; 45 } 46 47 void WebAssemblyExceptionInfo::recalculate( 48 MachineFunction &MF, MachineDominatorTree &MDT, 49 const MachineDominanceFrontier &MDF) { 50 // Postorder traversal of the dominator tree. 51 SmallVector<std::unique_ptr<WebAssemblyException>, 8> Exceptions; 52 for (auto DomNode : post_order(&MDT)) { 53 MachineBasicBlock *EHPad = DomNode->getBlock(); 54 if (!EHPad->isEHPad()) 55 continue; 56 auto WE = std::make_unique<WebAssemblyException>(EHPad); 57 discoverAndMapException(WE.get(), MDT, MDF); 58 Exceptions.push_back(std::move(WE)); 59 } 60 61 // WasmEHFuncInfo contains a map of <catchpad, its next unwind destination>, 62 // which means, if an exception is not caught by the catchpad, it should end 63 // up in the next unwind destination stored in this data structure. (It is 64 // written as catchswitch's 'unwind' destination in ll files.) The below is an 65 // intuitive example of their relationship in C++ code: 66 // try { 67 // try { 68 // } catch (int) { // catchpad 69 // ... // this catch (int) { ... } is grouped as an exception 70 // } 71 // } catch (...) { // next unwind destination 72 // } 73 // (The example is try-catches for illustration purpose, but the unwind 74 // destination can be also a cleanuppad generated by destructor calls.) So the 75 // unwind destination is in the outside of the catchpad's exception. 76 // 77 // We group exceptions in this analysis simply by including all BBs dominated 78 // by an EH pad. But in case the EH pad's unwind destination does not have any 79 // children outside of the exception, that unwind destination ends up also 80 // being dominated by the EH pad and included in the exception, which is not 81 // semantically correct, because it unwinds/rethrows into an inner scope. 82 // 83 // Here we extract those unwind destinations from their (incorrect) parent 84 // exception. Note that the unwind destinations may not be an immediate 85 // children of the parent exception, so we have to traverse the parent chain. 86 const auto *EHInfo = MF.getWasmEHFuncInfo(); 87 for (auto &MBB : MF) { 88 if (!MBB.isEHPad()) 89 continue; 90 auto *EHPad = &MBB; 91 if (!EHInfo->hasUnwindDest(EHPad)) 92 continue; 93 auto *UnwindDest = EHInfo->getUnwindDest(EHPad); 94 auto *WE = getExceptionFor(EHPad); 95 auto *UnwindDestWE = getExceptionFor(UnwindDest); 96 if (WE->contains(UnwindDestWE)) { 97 if (WE->getParentException()) 98 UnwindDestWE->setParentException(WE->getParentException()); 99 else 100 UnwindDestWE->setParentException(nullptr); 101 } 102 } 103 104 // Add BBs to exceptions 105 for (auto DomNode : post_order(&MDT)) { 106 MachineBasicBlock *MBB = DomNode->getBlock(); 107 WebAssemblyException *WE = getExceptionFor(MBB); 108 for (; WE; WE = WE->getParentException()) 109 WE->addBlock(MBB); 110 } 111 112 SmallVector<WebAssemblyException*, 8> ExceptionPointers; 113 ExceptionPointers.reserve(Exceptions.size()); 114 115 // Add subexceptions to exceptions 116 for (auto &WE : Exceptions) { 117 ExceptionPointers.push_back(WE.get()); 118 if (WE->getParentException()) 119 WE->getParentException()->getSubExceptions().push_back(std::move(WE)); 120 else 121 addTopLevelException(std::move(WE)); 122 } 123 124 // For convenience, Blocks and SubExceptions are inserted in postorder. 125 // Reverse the lists. 126 for (auto *WE : ExceptionPointers) { 127 WE->reverseBlock(); 128 std::reverse(WE->getSubExceptions().begin(), WE->getSubExceptions().end()); 129 } 130 } 131 132 void WebAssemblyExceptionInfo::releaseMemory() { 133 BBMap.clear(); 134 TopLevelExceptions.clear(); 135 } 136 137 void WebAssemblyExceptionInfo::getAnalysisUsage(AnalysisUsage &AU) const { 138 AU.setPreservesAll(); 139 AU.addRequired<MachineDominatorTree>(); 140 AU.addRequired<MachineDominanceFrontier>(); 141 MachineFunctionPass::getAnalysisUsage(AU); 142 } 143 144 void WebAssemblyExceptionInfo::discoverAndMapException( 145 WebAssemblyException *WE, const MachineDominatorTree &MDT, 146 const MachineDominanceFrontier &MDF) { 147 unsigned NumBlocks = 0; 148 unsigned NumSubExceptions = 0; 149 150 // Map blocks that belong to a catchpad / cleanuppad 151 MachineBasicBlock *EHPad = WE->getEHPad(); 152 SmallVector<MachineBasicBlock *, 8> WL; 153 WL.push_back(EHPad); 154 while (!WL.empty()) { 155 MachineBasicBlock *MBB = WL.pop_back_val(); 156 157 // Find its outermost discovered exception. If this is a discovered block, 158 // check if it is already discovered to be a subexception of this exception. 159 WebAssemblyException *SubE = getOutermostException(MBB); 160 if (SubE) { 161 if (SubE != WE) { 162 // Discover a subexception of this exception. 163 SubE->setParentException(WE); 164 ++NumSubExceptions; 165 NumBlocks += SubE->getBlocksVector().capacity(); 166 // All blocks that belong to this subexception have been already 167 // discovered. Skip all of them. Add the subexception's landing pad's 168 // dominance frontier to the worklist. 169 for (auto &Frontier : MDF.find(SubE->getEHPad())->second) 170 if (MDT.dominates(EHPad, Frontier)) 171 WL.push_back(Frontier); 172 } 173 continue; 174 } 175 176 // This is an undiscovered block. Map it to the current exception. 177 changeExceptionFor(MBB, WE); 178 ++NumBlocks; 179 180 // Add successors dominated by the current BB to the worklist. 181 for (auto *Succ : MBB->successors()) 182 if (MDT.dominates(EHPad, Succ)) 183 WL.push_back(Succ); 184 } 185 186 WE->getSubExceptions().reserve(NumSubExceptions); 187 WE->reserveBlocks(NumBlocks); 188 } 189 190 WebAssemblyException * 191 WebAssemblyExceptionInfo::getOutermostException(MachineBasicBlock *MBB) const { 192 WebAssemblyException *WE = getExceptionFor(MBB); 193 if (WE) { 194 while (WebAssemblyException *Parent = WE->getParentException()) 195 WE = Parent; 196 } 197 return WE; 198 } 199 200 void WebAssemblyException::print(raw_ostream &OS, unsigned Depth) const { 201 OS.indent(Depth * 2) << "Exception at depth " << getExceptionDepth() 202 << " containing: "; 203 204 for (unsigned I = 0; I < getBlocks().size(); ++I) { 205 MachineBasicBlock *MBB = getBlocks()[I]; 206 if (I) 207 OS << ", "; 208 OS << "%bb." << MBB->getNumber(); 209 if (const auto *BB = MBB->getBasicBlock()) 210 if (BB->hasName()) 211 OS << "." << BB->getName(); 212 213 if (getEHPad() == MBB) 214 OS << " (landing-pad)"; 215 } 216 OS << "\n"; 217 218 for (auto &SubE : SubExceptions) 219 SubE->print(OS, Depth + 2); 220 } 221 222 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 223 LLVM_DUMP_METHOD void WebAssemblyException::dump() const { print(dbgs()); } 224 #endif 225 226 raw_ostream &operator<<(raw_ostream &OS, const WebAssemblyException &WE) { 227 WE.print(OS); 228 return OS; 229 } 230 231 void WebAssemblyExceptionInfo::print(raw_ostream &OS, const Module *) const { 232 for (auto &WE : TopLevelExceptions) 233 WE->print(OS); 234 } 235