1 //===--- WebAssemblyExceptionInfo.cpp - Exception Infomation --------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief This file implements WebAssemblyException information analysis.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "WebAssemblyExceptionInfo.h"
16 #include "WebAssemblyUtilities.h"
17 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
18 #include "llvm/ADT/PostOrderIterator.h"
19 #include "llvm/CodeGen/MachineDominanceFrontier.h"
20 #include "llvm/CodeGen/MachineDominators.h"
21 
22 using namespace llvm;
23 
24 #define DEBUG_TYPE "wasm-exception-info"
25 
26 char WebAssemblyExceptionInfo::ID = 0;
27 
28 INITIALIZE_PASS_BEGIN(WebAssemblyExceptionInfo, DEBUG_TYPE,
29                       "WebAssembly Exception Information", true, true)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)30 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
31 INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier)
32 INITIALIZE_PASS_END(WebAssemblyExceptionInfo, DEBUG_TYPE,
33                     "WebAssembly Exception Information", true, true)
34 
35 bool WebAssemblyExceptionInfo::runOnMachineFunction(MachineFunction &F) {
36   releaseMemory();
37   auto &MDT = getAnalysis<MachineDominatorTree>();
38   auto &MDF = getAnalysis<MachineDominanceFrontier>();
39   recalculate(MDT, MDF);
40   return false;
41 }
42 
recalculate(MachineDominatorTree & MDT,const MachineDominanceFrontier & MDF)43 void WebAssemblyExceptionInfo::recalculate(
44     MachineDominatorTree &MDT, const MachineDominanceFrontier &MDF) {
45   // Postorder traversal of the dominator tree.
46   SmallVector<WebAssemblyException *, 8> Exceptions;
47   for (auto DomNode : post_order(&MDT)) {
48     MachineBasicBlock *EHPad = DomNode->getBlock();
49     if (!EHPad->isEHPad())
50       continue;
51     // We group catch & catch-all terminate pads together, so skip the second
52     // one
53     if (WebAssembly::isCatchAllTerminatePad(*EHPad))
54       continue;
55     auto *WE = new WebAssemblyException(EHPad);
56     discoverAndMapException(WE, MDT, MDF);
57     Exceptions.push_back(WE);
58   }
59 
60   // Add BBs to exceptions
61   for (auto DomNode : post_order(&MDT)) {
62     MachineBasicBlock *MBB = DomNode->getBlock();
63     WebAssemblyException *WE = getExceptionFor(MBB);
64     for (; WE; WE = WE->getParentException())
65       WE->addBlock(MBB);
66   }
67 
68   // Add subexceptions to exceptions
69   for (auto *WE : Exceptions) {
70     if (WE->getParentException())
71       WE->getParentException()->getSubExceptions().push_back(WE);
72     else
73       addTopLevelException(WE);
74   }
75 
76   // For convenience, Blocks and SubExceptions are inserted in postorder.
77   // Reverse the lists.
78   for (auto *WE : Exceptions) {
79     WE->reverseBlock();
80     std::reverse(WE->getSubExceptions().begin(), WE->getSubExceptions().end());
81   }
82 }
83 
releaseMemory()84 void WebAssemblyExceptionInfo::releaseMemory() {
85   BBMap.clear();
86   DeleteContainerPointers(TopLevelExceptions);
87   TopLevelExceptions.clear();
88 }
89 
getAnalysisUsage(AnalysisUsage & AU) const90 void WebAssemblyExceptionInfo::getAnalysisUsage(AnalysisUsage &AU) const {
91   AU.setPreservesAll();
92   AU.addRequired<MachineDominatorTree>();
93   AU.addRequired<MachineDominanceFrontier>();
94   MachineFunctionPass::getAnalysisUsage(AU);
95 }
96 
discoverAndMapException(WebAssemblyException * WE,const MachineDominatorTree & MDT,const MachineDominanceFrontier & MDF)97 void WebAssemblyExceptionInfo::discoverAndMapException(
98     WebAssemblyException *WE, const MachineDominatorTree &MDT,
99     const MachineDominanceFrontier &MDF) {
100   unsigned NumBlocks = 0;
101   unsigned NumSubExceptions = 0;
102 
103   // Map blocks that belong to a catchpad / cleanuppad
104   MachineBasicBlock *EHPad = WE->getEHPad();
105 
106   // We group catch & catch-all terminate pads together within an exception
107   if (WebAssembly::isCatchTerminatePad(*EHPad)) {
108     assert(EHPad->succ_size() == 1 &&
109            "Catch terminate pad has more than one successors");
110     changeExceptionFor(EHPad, WE);
111     changeExceptionFor(*(EHPad->succ_begin()), WE);
112     return;
113   }
114 
115   SmallVector<MachineBasicBlock *, 8> WL;
116   WL.push_back(EHPad);
117   while (!WL.empty()) {
118     MachineBasicBlock *MBB = WL.pop_back_val();
119 
120     // Find its outermost discovered exception. If this is a discovered block,
121     // check if it is already discovered to be a subexception of this exception.
122     WebAssemblyException *SubE = getOutermostException(MBB);
123     if (SubE) {
124       if (SubE != WE) {
125         // Discover a subexception of this exception.
126         SubE->setParentException(WE);
127         ++NumSubExceptions;
128         NumBlocks += SubE->getBlocksVector().capacity();
129         // All blocks that belong to this subexception have been already
130         // discovered. Skip all of them. Add the subexception's landing pad's
131         // dominance frontier to the worklist.
132         for (auto &Frontier : MDF.find(SubE->getEHPad())->second)
133           if (MDT.dominates(EHPad, Frontier))
134             WL.push_back(Frontier);
135       }
136       continue;
137     }
138 
139     // This is an undiscovered block. Map it to the current exception.
140     changeExceptionFor(MBB, WE);
141     ++NumBlocks;
142 
143     // Add successors dominated by the current BB to the worklist.
144     for (auto *Succ : MBB->successors())
145       if (MDT.dominates(EHPad, Succ))
146         WL.push_back(Succ);
147   }
148 
149   WE->getSubExceptions().reserve(NumSubExceptions);
150   WE->reserveBlocks(NumBlocks);
151 }
152 
153 WebAssemblyException *
getOutermostException(MachineBasicBlock * MBB) const154 WebAssemblyExceptionInfo::getOutermostException(MachineBasicBlock *MBB) const {
155   WebAssemblyException *WE = getExceptionFor(MBB);
156   if (WE) {
157     while (WebAssemblyException *Parent = WE->getParentException())
158       WE = Parent;
159   }
160   return WE;
161 }
162 
print(raw_ostream & OS,unsigned Depth) const163 void WebAssemblyException::print(raw_ostream &OS, unsigned Depth) const {
164   OS.indent(Depth * 2) << "Exception at depth " << getExceptionDepth()
165                        << " containing: ";
166 
167   for (unsigned I = 0; I < getBlocks().size(); ++I) {
168     MachineBasicBlock *MBB = getBlocks()[I];
169     if (I)
170       OS << ", ";
171     OS << "%bb." << MBB->getNumber();
172     if (const auto *BB = MBB->getBasicBlock())
173       if (BB->hasName())
174         OS << "." << BB->getName();
175 
176     if (getEHPad() == MBB)
177       OS << " (landing-pad)";
178   }
179   OS << "\n";
180 
181   for (auto &SubE : SubExceptions)
182     SubE->print(OS, Depth + 2);
183 }
184 
185 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const186 LLVM_DUMP_METHOD void WebAssemblyException::dump() const { print(dbgs()); }
187 #endif
188 
operator <<(raw_ostream & OS,const WebAssemblyException & WE)189 raw_ostream &operator<<(raw_ostream &OS, const WebAssemblyException &WE) {
190   WE.print(OS);
191   return OS;
192 }
193 
print(raw_ostream & OS,const Module *) const194 void WebAssemblyExceptionInfo::print(raw_ostream &OS, const Module *) const {
195   for (auto *WE : TopLevelExceptions)
196     WE->print(OS);
197 }
198