1.3.11. TDDataStructures与EQTDDataStructures遍
自顶向下阶段非常类似于自底向上阶段。BU阶段已经识别了调用图,因此TD阶段可以使用Tarjan的算法直接遍历调用图的SCC。它不需要像BU阶段那样“重新访问”SCC。注意到在BU阶段可能仅部分访问某些SCC,因此TD阶段负责简并这些图。
总体来说,TD阶段仅在4方面与BU阶段不同:首先,TD阶段不会把一个SCC标记为未访问:它使用由BU阶段发现并记录的调用边。其次,TD阶段以逆后序,而不是后序,访问由BU遍历得到的调用图的SCC。第三,TD遍把每个函数图内联入其调用的函数(而不是相反),并且它是直接把一个调用者的图内联入其所有的潜在的被调用者(不需要“延迟”这个内联操作,因为每个调用点的潜在被调用者是已知的)。最后的差别是,如果一个函数的所有调用者已经被分析识别出来,就把形参节点标记为完整。比如,任何外部函数不能访问的函数。类似的,全局变量可能被标记为完整,除非它们可以被外部函数访问。一个函数或全局对象是外部可见的,如果它没有内部链接性(比如,没有标记为static的C对象),或者在main的图中,该全局对象存在一个没有标记为完整的节点。
1.3.11.1. 确定外部可访问的函数
TDDataStructures作为独立的遍运行时,77行的useEQBU被设置为false,这时它只依赖于BUDataStructures的结果。但当运行EQTDDataStructures遍时,useEQBU被设置为true,则TDDataStructures依赖于EquivBUDataStructures的结果。注意在对init的调用中,倒数第2个参数是true(copyGlobalAuxCalls),在拷贝DSGraph时,还将拷贝AuxFunctionCalls的内容(它现在保存了还未解析的函数调用)。
75 bool TDDataStructures::runOnModule(Module&M) {
76
77 init(useEQBU? &getAnalysis<EquivBUDataStructures>()
78 : &getAnalysis<BUDataStructures>(),
79 true, true, true, false);
80 // Figure outwhich functions must not mark their arguments complete because
81 // they areaccessible outside this compilation unit. Currently, these
82 // arguments arefunctions which are reachable by incomplete or external
83 // nodes in theglobals graph.
84 constDSScalarMap &GGSM = GlobalsGraph->getScalarMap();
85 DenseSet<DSNode*> Visited;
86 for(DSScalarMap::global_iterator I=GGSM.global_begin(), E=GGSM.global_end();
87 I != E; ++I) {
88 DSNode *N =GGSM.find(*I)->second.getNode();
89 if (N->isIncompleteNode() ||N->isExternalNode())
90 markReachableFunctionsExternallyAccessible(N,Visited);
91 }
92
93 // Loop overunresolved call nodes. Any functionspassed into (but not
94 // returned!) fromunresolvable call nodes may be invoked outside of the
95 // currentmodule.
96 for(DSGraph::afc_iterator I = GlobalsGraph->afc_begin(),
97 E = GlobalsGraph->afc_end(); I !=E; ++I)
98 for(unsigned arg = 0, e = I->getNumPtrArgs(); arg != e; ++arg)
99 markReachableFunctionsExternallyAccessible(I->getPtrArg(arg).getNode(),
100 Visited);
101 Visited.clear();
DSGraph中的ScalarMap保存了该函数所援引的对象,而其中的GlobalSet只保存全局对象,而ValMap则保存所有对象(实际上是Value与DSNodeHandle的对)。上面86行的循环就是遍历全局图的GlobalSet,88行的find则返回DSNodeHandle指向的ValMap中的DSNode——对象在函数图里的节点。如果这个节点是不完整或是外部的,则调用下面的函数。而96行的循环则是遍历AuxFunctionCalls,并对每个指针参数调用同样的函数。
51 void TDDataStructures::markReachableFunctionsExternallyAccessible(DSNode*N,
52 DenseSet<DSNode*> &Visited) {
53 if (!N || Visited.count(N)) return;
54 Visited.insert(N);
55
56 // Handle thisnode
57 {
58 N->addFullFunctionSet(ExternallyCallable);
59 }
60
61 for(DSNode::edge_iterator ii = N->edge_begin(),
62 ee = N->edge_end(); ii != ee;++ii)
63 if (!ii->second.isNull()) {
64 DSNodeHandle &NH = ii->second;
65 DSNode * NN = NH.getNode();
66 NN->addFullFunctionSet(ExternallyCallable);
67 markReachableFunctionsExternallyAccessible(NN,Visited);
68 }
69 }
这里ExternallyCallable记录的是外部可调用函数。在DSA的设计中,从不完整或外部节点可访问的函数都被视为外部可访问的。另外,作为参数传递给未解析的函数的函数也可能是外部可访问的。除此之外,定义在当前编译单元中的函数,如果不是定义为内部或私有,也是外部可访问的。
TDDataStructures::runOnModule(续)
103 // Clear Aux ofGlobals Graph to be refilled in later by post-TD unresolved
104 // functions
105 GlobalsGraph->getAuxFunctionCalls().clear();
106
107 // Functionswithout internal linkage are definitely externally callable!
108 for(Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
109 if (!I->isDeclaration() &&!I->hasInternalLinkage() && !I->hasPrivateLinkage())
110 ExternallyCallable.insert(I);
111
112 // Debug code toprint the functions that are externally callable
113 #if 0
114 for (Module::iterator I = M.begin(), E =M.end(); I != E; ++I)
115 if (ExternallyCallable.count(I)) {
116 errs() << "ExternallyCallable:" << I->getNameStr() << "\n";
117 }
118 #endif
1.3.11.2. 确定调用函数的后序遍历序
接下来,ComputePostOrder计算指定函数中函数调用的后序遍历次序,以这个次序在PostOrder中保存函数的DSGraph。
TDDataStructures::runOnModule(续)
120 // We want totraverse the call graph in reverse post-order. To do this, we
121 // calculate apost-order traversal, then reverse it.
122 DenseSet<DSGraph*> VisitedGraph;
123 std::vector<DSGraph*> PostOrder;
124
125 {TIME_REGION(XXX, "td:Computepostorder");
126
127 // Calculatetop-down from main...
128 if (Function *F =M.getFunction("main"))
129 ComputePostOrder(*F,VisitedGraph, PostOrder);
130
131 // Next calculatethe graphs for each unreachable function...
132 for(Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
133 if (!I->isDeclaration())
134 ComputePostOrder(*I,VisitedGraph, PostOrder);
135
136 VisitedGraph.clear(); // Releasememory!
137 }
ComputePostOrder对函数的处理次序依然是先main,后其他函数。同样对于直接调用函数,直接进行递归。
187 void TDDataStructures::ComputePostOrder(const Function &F,
188 DenseSet<DSGraph*> &Visited,
189 std::vector<DSGraph*> &PostOrder) {
190 if (F.isDeclaration()) return;
191 DSGraph* G = getOrCreateGraph(&F);
192 if (!Visited.insert(G).second) return;
193
194 // Recursivelytraverse all of the callee graphs.
195 svset<constFunction*> Callees;
196
197 // Go through allof the callsites in this graph and find all callees
198 // Here we'retrying to capture all possible callees so that we can ensure
199 // each functionhas all possible callers inlined into it.
200 for(DSGraph::fc_iterator CI = G->fc_begin(), E = G->fc_end();
201 CI != E; ++CI) {
202 // Direct callsare easy, no reason to look at DSCallGraph
203 // or anythingto do with SCC's
204 if (CI->isDirectCall()) {
205 ComputePostOrder(*CI->getCalleeFunc(),Visited, PostOrder);
206 }
207 else {
208 // Otherwise,ask the DSCallGraph for the full set of possible
209 // calleesfor this callsite.
210 // Thisincludes all members of the SCC's of those callees,
211 // and wellas others in F's SCC, since we must assume
212 // anyindirect call might be intra-SCC.
213 callgraph.addFullFunctionSet(CI->getCallSite(),Callees);
214 }
215 }
216
217 for(svset<const Function*>::iterator I =Callees.begin(),
218 E = Callees.end(); I != E; ++I)
219 ComputePostOrder(**I, Visited, PostOrder);
220
221 PostOrder.push_back(G);
222 }
对于间接调用的函数,通过addFullFunctionSet收集候选函数。下面265行遍历callgraph的ActualCallees容器中与指定CallSite关联的函数(Function)。对于某一特定的函数,如果它属于某个调用链SCC,把这个SCC的所有成员加入Set(如果它不属于某个SCC,267行的scc_begin会返回与scc_end相同的迭代器)。对于该CallSite所在的函数(270行的F1),同样向Set加入其所在SCC的成员,如果存在这样的SCC。因为我们假定间接调用都可能是SCC的任何部分。
261 void DSCallGraph::addFullFunctionSet(llvm::CallSiteCS,
262 svset<const llvm::Function*> &Set) const {
263 DSCallGraph::callee_iterator csi =callee_begin(CS),
264 cse = callee_end(CS);
265 while(csi !=cse) {
266 constFunction *F = *csi;
267 Set.insert(scc_begin(F), scc_end(F));
268 ++csi;
269 }
270 constFunction *F1 = CS.getInstruction()->getParent()->getParent();
271 F1 = sccLeader(&*F1);
272 Set.insert(scc_begin(F1), scc_end(F1));
273 }
接着在TDDataStructures::ComputePostOrder的217行对这些收集到的间接被调用函数进行递归。221行就是后序遍历的标志。
1.3.11.3. 向被调用者内联调用者
现在在PostOrder中,调用链最底层的被调用函数出现在容器头部,最顶层的则出现在容器的底部,因此143行对InlineCallersIntoGraph的调用从最顶层的(被)调用函数开始。这样对调用图的访问就是逆后序的。
TDDataStructures::runOnModule(续)
139 {TIME_REGION(XXX,"td:Inline stuff");
140
141 // Visit each ofthe graphs in reverse post-order now!
142 while(!PostOrder.empty()) {
143 InlineCallersIntoGraph(PostOrder.back());
144 PostOrder.pop_back();
145 }
146 }
这个函数用到一个新的数据类型:CallerCallEdge。336~338行的注释已经解释了这个结构的作用。
335 struct CallerCallEdge {
336 DSGraph *CallerGraph; // Thegraph of the caller function.
337 constDSCallSite *CS; // The actual call site.
338 constFunction *CalledFunction; // The actual function being called.
339
340 CallerCallEdge(DSGraph *G, const DSCallSite *cs, constFunction *CF)
341 : CallerGraph(G), CS(cs),CalledFunction(CF) {}
342
343 bool operator<(const CallerCallEdge &RHS) const {
344 returnCallerGraph < RHS.CallerGraph ||
345 (CallerGraph == RHS.CallerGraph&& CS < RHS.CS);
346 }
347 };
下面231行的CallerEdges的定义是std::map<DSGraph*, std::vector<CallerCallEdge> >,它是TDDataStructures的成员。DSG如果在CallerEdges中有记录,这个记录是它的调用者添加的(参考函数的后半段),230~235行取出这个记录。使用CallerCallEdge定义的比较操作符,238行的sort以调用者图的地址排序相关的CallerCallEdge项(这样同一个调用函数用产生的CallerCallEdge项会集合在一起,便于循环处理)。
226 void TDDataStructures::InlineCallersIntoGraph(DSGraph*DSG) {
227 // Inline callergraphs into this graph. First step, getthe list of call
228 // sites thatcall into this graph.
229 std::vector<CallerCallEdge>EdgesFromCaller;
230 std::map<DSGraph*,std::vector<CallerCallEdge> >::iterator
231 CEI = CallerEdges.find(DSG);
232 if (CEI != CallerEdges.end()) {
233 std::swap(CEI->second, EdgesFromCaller);
234 CallerEdges.erase(CEI);
235 }
236
237 // Sort thecaller sites to provide a by-caller-graph ordering.
238 std::sort(EdgesFromCaller.begin(),EdgesFromCaller.end());
239
240
241 // Mergeinformation from the globals graph into this graph. FIXME: This is
242 // stupid. Instead of us cloning information from the GGinto this graph,
243 // then havingRemoveDeadNodes clone it back, we should do all of this as a
244 // post-pass overall of the graphs. We need to takecloning out of
245 //removeDeadNodes and gut removeDeadNodes at the same time first though. :(
246 cloneGlobalsInto(DSG,DSGraph::DontCloneCallNodes |
247 DSGraph::DontCloneAuxCallNodes);
248
249 DEBUG(errs() << "[TD] Inliningcallers into '"
250 << DSG->getFunctionNames()<< "'\n");
251
252 DSG->maskIncompleteMarkers();
253 // Iterativelyinline caller graphs into this graph.
254 while(!EdgesFromCaller.empty()) {
255 DSGraph* CallerGraph =EdgesFromCaller.back().CallerGraph;
256
257 // Iteratethrough all of the call sites of this graph, cloning and merging
258 // any nodesrequired by the call.
259 ReachabilityCloner RC(DSG, CallerGraph,
260 DSGraph::DontCloneCallNodes |
261 DSGraph::DontCloneAuxCallNodes);
262
263 // Inline all callsites from this caller graph.
264 do {
265 constDSCallSite &CS = *EdgesFromCaller.back().CS;
266 constFunction &CF = *EdgesFromCaller.back().CalledFunction;
267 DEBUG(errs() << " [TD] Inlining graph into Fn '"
268 << CF.getName().str() << "'from ");
269 if(CallerGraph->getReturnNodes().empty()) {
270 DEBUG(errs() << "SYNTHESIZEDINDIRECT GRAPH");
271 } else {
272 DEBUG(errs() << "Fn '"<< CS.getCallSite().getInstruction()->
273 getParent()->getParent()->getName().str()<< "'");
274 }
275 DEBUG(errs() << ": "<< CF.getFunctionType()->getNumParams()
276 << " args\n");
277
278 // Get theformal argument and return nodes for the called function and
279 // merge themwith the cloned subgraph.
280 DSCallSite T1 =DSG->getCallSiteForArguments(CF);
281 RC.mergeCallSite(T1, CS);
282 ++NumTDInlines;
283
284 EdgesFromCaller.pop_back();
285 } while(!EdgesFromCaller.empty() &&
286 EdgesFromCaller.back().CallerGraph== CallerGraph);
287 }
252行清除所有节点的不完整标记。顶层调用函数不会进入230~235及254~287行。其他函数则根据CallerEdges的记录,把其调用者中调用点信息简并入自己的图。接着,297行的DSG是InlineCallersIntoGraph要处理的DSGraph,retnodes_begin返回ReturnNodes的首迭代器(ReturnNodes的类型是std::map<constFunction*, DSNodeHandle>,它记录函数的返回值。在BU遍中,在向调用者内联被调用者时,被调用者的返回值将被加入调用者的这个容器)。如果这个DSGraph所代表的函数(经过了内联,所代表的函数可以是多个)之一是外部可调用的,在300行isExternallyCallable被置为true。
TDDataStructures::InlineCallersIntoGraph(续)
291 // Next, now thatthis graph is finalized, we need to recompute the
292 // incompletenessmarkers for this graph and remove unreachable nodes.
293
294 // If any of thefunctions is externally callable, treat everything in its
295 // SCC asexternally callable.
296 bool isExternallyCallable = false;
297 for(DSGraph::retnodes_iterator I = DSG->retnodes_begin(),
298 E = DSG->retnodes_end(); I != E;++I)
299 if (ExternallyCallable.count(I->first)){
300 isExternallyCallable = true;
301 break;
302 }
303
304 // Recompute theIncomplete markers. Depends on whetherargs are complete
305 unsigned IncFlags =DSGraph::IgnoreFormalArgs;
306 IncFlags |= DSGraph::IgnoreGlobals |DSGraph::MarkVAStart;
307 DSG->markIncompleteNodes(IncFlags);
308
309 // If this graphcontains functions that are externally callable, now is the time to mark
310 // theirarguments and return values as external. At this point TD is inlining all caller information,
311 // and that meansExternal callers too.
312 unsigned ExtFlags = isExternallyCallable ?
313 DSGraph::MarkFormalsExternal: DSGraph::DontMarkFormalsExternal;
314 DSG->computeExternalFlags(ExtFlags);
315 DSG->computeIntPtrFlags();
316
317 cloneIntoGlobals(DSG,DSGraph::DontCloneCallNodes |
318 DSGraph::DontCloneAuxCallNodes);
319 //
320 // Delete deadnodes. Treat globals that areunreachable as dead also.
321 //
322 // FIXME:
323 // Do not delete unreachable globals as thecomment describes. For its
324 // alignment checks on the results of loadinstructions, SAFECode must be
325 // able to find the DSNode of both the result ofthe load as well as the
326 // pointer dereferenced by the load. If we remove unreachable globals, then
327 // if the dereferenced pointer is a global, itsDSNode will not reachable
328 // from the local graph's scalar map, and chaosensues.
329 //
330 // So, for now, just remove dead nodes but leavethe globals alone.
331 //
332 DSG->removeDeadNodes(0);
因为在前面252行已经把所有节点的未完成标记去掉了,在307行重现计算这些节点的未完成标记。根据IncFlags内容,markIncompleteNodes只把AuxFunctionCalls容器内的节点、可变参数节点标记为不完整。而314行的computeExternalFlags,则根据函数是否外部可访问,把函数的指针参数、返回值、可变参数标记为外部。317行将函数图中的全局对象节点克隆、简并入全局图(此时全局图中的全局对象节点是标记为完成的)。332行的removeDeadNodes在前一版是有参数DSGraph::RemoveUnreachableGlobals的,当前版本把这个参数去掉,原因322行的注释解释了。
TDDataStructures::InlineCallersIntoGraph(续)
334 // We are donewith computing the current TD Graph! Finally, before we can
335 // finishprocessing this function, we figure out which functions it calls and
336 // records thesecall graph edges, so that we have them when we process the
337 // callee graphs.
338 if (DSG->fc_begin() == DSG->fc_end()) return;
339
340 // Loop over allthe call sites and all the callees at each call site, and add
341 // edges to theCallerEdges structure for each callee.
342 for(DSGraph::fc_iterator CI = DSG->fc_begin(), E = DSG->fc_end();
343 CI != E; ++CI) {
344
345 // Handle directcalls efficiently.
346 if (CI->isDirectCall()) {
347 if(!CI->getCalleeFunc()->isDeclaration() &&
348 !DSG->getReturnNodes().count(CI->getCalleeFunc()))
349 CallerEdges[getOrCreateGraph(CI->getCalleeFunc())]
350 .push_back(CallerCallEdge(DSG,&*CI, CI->getCalleeFunc()));
351 continue;
352 }
353
354 svset<constFunction*> AllCallees;
355 std::vector<constFunction*> Callees;
356
357 // Get the listof callees
358 callgraph.addFullFunctionSet(CI->getCallSite(),AllCallees);
359
360 // Filter allnon-declarations, and calls within this DSGraph
361 for(svset<const Function*>::iterator I =AllCallees.begin(),
362 E = AllCallees.end(); I != E; ++I) {
363 constFunction *F = *I;
364 if (!F->isDeclaration() &&getDSGraph(**I) != DSG)
365 Callees.push_back(F);
366 }
367 AllCallees.clear();
368
369 // If there isexactly one callee from this call site, remember the edge in
370 // CallerEdges.
371 if (Callees.size() == 1) {
372 constFunction * Callee = Callees[0];
373 CallerEdges[getOrCreateGraph(Callee)]
374 .push_back(CallerCallEdge(DSG,&*CI, Callee));
375 }
376 if (Callees.size() <= 1) continue;
377
378 // Otherwise,there are multiple callees from this call site, so it must be
379 // an indirectcall. Chances are that there will beother call sites with
380 // this set oftargets. If so, we don't want to do M*Ninlining operations,
381 // so we buildup a new, private, graph that represents the calls of all
382 // calls tothis set of functions.
383
384 std::map<std::vector<const Function*>, DSGraph*>::iteratorIndCallRecI =
385 IndCallMap.lower_bound(Callees);
386
387 // If wealready have this graph, recycle it.
388 if (IndCallRecI != IndCallMap.end()&& IndCallRecI->first == Callees) {
389 DEBUG(errs() << " [TD] *** Reuse of indcall graph for "<< Callees.size()
390 << " callees!\n");
391 DSGraph * IndCallGraph =IndCallRecI->second;
392 assert(IndCallGraph->getFunctionCalls().size()== 1);
393
394 // Merge thecall into the CS already in the IndCallGraph
395 ReachabilityCloner RC(IndCallGraph, DSG,0);
396 RC.mergeCallSite(IndCallGraph->getFunctionCalls().front(),*CI);
DSGraph的fc_begin及fc_end返回容器FunctionCalls的首尾迭代器,FunctionCalls记录了在该函数中进行的函数调用。上面这段代码的目的是找出当前函数调用的函数,并使CallerEdges记录之。对于直接调用(346行条件),如果被调用的函数有定义,且不在当前函数图中,把它记录在CallerEdges里。对于间接调用,在358行首先获取所有可能的被调用函数,在364行过滤掉没有定义或者在当前函数图中调用的函数。如果被调用函数的个数只是1(371行),那么直接把它记录在CallerEdges里。而如果被调用函数的个数多于1个,而且如果这些被调用函数已经处理过了(比如,另一个调用这些函数的调用点,这样它们会被记录在IndCallMap中),那么已经存在一个内联后的图,在396行把这些函数调用简并入这个图(这样避免在InlineCallersIntoGraph开头的更耗时的内联操作)。注意392行断言检查IndCallMap的完整性是否被破坏。
1036 void ReachabilityCloner::mergeCallSite(DSCallSite&DestCS,
1037 const DSCallSite &SrcCS) {
1038 merge(DestCS.getRetVal(),SrcCS.getRetVal());
1039 merge(DestCS.getVAVal(),SrcCS.getVAVal());
1040 unsigned MinArgs = DestCS.getNumPtrArgs();
1041 if (SrcCS.getNumPtrArgs() < MinArgs)MinArgs = SrcCS.getNumPtrArgs();
1042
1043 for (unsigneda = 0; a != MinArgs; ++a)
1044 merge(DestCS.getPtrArg(a),SrcCS.getPtrArg(a));
1045
1046 for (unsigneda = MinArgs, e = SrcCS.getNumPtrArgs(); a != e; ++a) {
1047 // If a callsite passes more params, ignore the extra params.
1048 // If thecalled function is varargs, merge the extra params, with
1049 // the varargsnode.
1050 if(DestCS.getVAVal() != NULL) {
1051 merge(DestCS.getVAVal(),SrcCS.getPtrArg(a));
1052 }
1053 }
1054
1055 for (unsigneda = MinArgs, e = DestCS.getNumPtrArgs(); a!=e; ++a) {
1056 // If a callsite passes less explicit params, than the function needs
1057 // But passesparams through a varargs node, merge those in.
1058 if(SrcCS.getVAVal() != NULL) {
1059 merge(DestCS.getPtrArg(a),SrcCS.getVAVal());
1060 }
1061 }
1062 }
对于调用点来说,可以看到就是返回值、各种参数,因此简并意味着处理返回值、指针参数以及可变参数。
接下来处理个数多于1个且尚未处理的被调用函数。这种情况下,399行首先创建一个新的DSGraph实例,注意在这个实例中FunctionCalls是空的,而且不包含任何DSNode节点(因为它的目的就是携带CallSite对象)。407行向这个DSGraph加入唯一的一个DSCallSite对象,并在410行加入IndCallMap(这是前面392行断言的依据)。最后,针对每个被调用函数,在CallerEdges中记录下IndCallGraph(携带CallSite信息的图,即代表调用函数),对应的DSCallSite(似乎不需要),被调用函数(以被调用函数图为键值)。
TDDataStructures::InlineCallersIntoGraph(续)
397 } else {
398 // Otherwise,create a new DSGraph to represent this.
399 DSGraph* IndCallGraph = new DSGraph(DSG->getGlobalECs(),
400 DSG->getDataLayout(), *TypeSS);
401
402 // Clone overthe call into the new DSGraph
403 ReachabilityCloner RC(IndCallGraph, DSG,0);
404 DSCallSite ClonedCS = RC.cloneCallSite(*CI);
405
406 // Add thecloned CS to the graph, as if it were an original call.
407 IndCallGraph->getFunctionCalls().push_back(ClonedCS);
408
409 // Save thisgraph for use later, should we need it.
410 IndCallRecI =IndCallMap.insert(IndCallRecI,
411 std::make_pair(Callees, IndCallGraph));
412
413 //Additionally, make sure that each of the callees inlines this graph
414 // exactlyonce.
415 DSCallSite *NCS =&IndCallGraph->getFunctionCalls().front();
416 for(unsigned i = 0, e = Callees.size(); i != e; ++i) {
417 DSGraph* CalleeGraph = getDSGraph(*Callees[i]);
418 if (CalleeGraph != DSG)
419 CallerEdges[CalleeGraph].push_back(CallerCallEdge(IndCallGraph, NCS,
420 Callees[i]));
421 }
422 }
423 }
424 }
在处理了所有的函数调用后,IndCallMap,ExternallyCallable的内容不再需要,回收其中的资源。接下来重现计算全局图的各种标记,注意这里不再重现计算完整性标记,因为全局图节点的完整性计算在BUDataStructure及CompleteDataStructure遍中就完成了。同样,函数图的完整性计算在InlineCallersIntoGraph中已经完成。最后,恢复调用图。
TDDataStructures::runOnModule(续)
148 // Free theIndCallMap.
149 while(!IndCallMap.empty()) {
150 deleteIndCallMap.begin()->second;
151 IndCallMap.erase(IndCallMap.begin());
152 }
153
154 formGlobalECs();
155
156 ExternallyCallable.clear();
157 GlobalsGraph->removeTriviallyDeadNodes();
158 GlobalsGraph->computeExternalFlags(DSGraph::DontMarkFormalsExternal);
159 GlobalsGraph->computeIntPtrFlags();
160
161 // Make sure eachgraph has updated external information about globals
162 // in the globalsgraph.
163 VisitedGraph.clear();
164 for(Module::iterator F = M.begin(); F != M.end(); ++F) {
165 if (!(F->isDeclaration())){
166 DSGraph *Graph = getOrCreateGraph(F);
167 if (!VisitedGraph.insert(Graph).second) continue;
168
169 cloneGlobalsInto(Graph,DSGraph::DontCloneCallNodes |
170 DSGraph::DontCloneAuxCallNodes);
171
172 Graph->computeExternalFlags(DSGraph::DontMarkFormalsExternal);
173 Graph->computeIntPtrFlags();
174 // Clean upuninteresting nodes
175 Graph->removeDeadNodes(0);
176
177 }
178 }
179
180 // CBU containsthe correct call graph.
181 // Restore it, sothat subsequent passes and clients can get it.
182 restoreCorrectCallGraph();
183 return false;
184 }
至此,TDDataStructures及EQTDDataStructures遍的处理全部完成。从DSA分析的结果出发,Chris在论文中提到了其在别名分析及自动池分配(automatic pool allocation)的应用。Poolalloc对此也做了延伸及扩展。Poolalloc目前被应用到SafeCode项目中,它是这个项目的基础。