dsa算法(27完)
2015-07-24 11:56
253 查看
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() << "
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() << "
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() << "
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项目中,它是这个项目的基础。
相关文章推荐
- Java finalize方法使用
- 关于大型网站技术演进的思考(八)--存储的瓶颈终篇(8)
- 关于大型网站技术演进的思考(九)--网站静态化处理--总述(1)
- Iterator Pattern
- 指针
- 2015/7/21 操作糟糕的一天,低卖高买
- Mybatis与spring项目中遇到的奇怪的问题:Loaded JDBC driver: com.mysql.jdbc.Driver
- 关于大型网站技术演进的思考(七)--存储的瓶颈(7)
- 二维数组
- WPF 流文档
- 简单正则表达式练习
- 进程与线程的区别
- 红米手机加载echarts出现图表重复问题,华为手机加载echarts禁用动画后不显示问题
- 数据库设计中一个矛盾:数据库外键,用还是不用
- php5.3.*编译出现make: *** [ext/gd/libgd/gd_compat.lo] Error 1的解决方法
- linux key
- postgresql PL/pgsql语法介绍
- 关于大型网站技术演进的思考(六)--存储的瓶颈(6)
- 《深入理解LLVM》第一章 LLVM简介
- VS2010 + Win7+ IIS7.5 开发调试ASP实战