1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 // This is clang plugin used by gcmole tool. See README for more details.
29 
30 #include "clang/AST/AST.h"
31 #include "clang/AST/ASTConsumer.h"
32 #include "clang/AST/Mangle.h"
33 #include "clang/AST/RecursiveASTVisitor.h"
34 #include "clang/AST/StmtVisitor.h"
35 #include "clang/Frontend/FrontendPluginRegistry.h"
36 #include "clang/Frontend/CompilerInstance.h"
37 #include "llvm/Support/raw_ostream.h"
38 
39 #include <bitset>
40 #include <fstream>
41 #include <iostream>
42 #include <map>
43 #include <set>
44 #include <stack>
45 
46 namespace {
47 
48 typedef std::string MangledName;
49 typedef std::set<MangledName> CalleesSet;
50 
GetMangledName(clang::MangleContext * ctx,const clang::NamedDecl * decl,MangledName * result)51 static bool GetMangledName(clang::MangleContext* ctx,
52                            const clang::NamedDecl* decl,
53                            MangledName* result) {
54   if (!llvm::isa<clang::CXXConstructorDecl>(decl) &&
55       !llvm::isa<clang::CXXDestructorDecl>(decl)) {
56     llvm::SmallVector<char, 512> output;
57     llvm::raw_svector_ostream out(output);
58     ctx->mangleName(decl, out);
59     *result = out.str().str();
60     return true;
61   }
62 
63   return false;
64 }
65 
66 
InV8Namespace(const clang::NamedDecl * decl)67 static bool InV8Namespace(const clang::NamedDecl* decl) {
68   return decl->getQualifiedNameAsString().compare(0, 4, "v8::") == 0;
69 }
70 
71 
72 static std::string EXTERNAL("EXTERNAL");
73 static std::string STATE_TAG("enum v8::internal::StateTag");
74 
IsExternalVMState(const clang::ValueDecl * var)75 static bool IsExternalVMState(const clang::ValueDecl* var) {
76   const clang::EnumConstantDecl* enum_constant =
77       llvm::dyn_cast<clang::EnumConstantDecl>(var);
78   if (enum_constant != NULL && enum_constant->getNameAsString() == EXTERNAL) {
79     clang::QualType type = enum_constant->getType();
80     return (type.getAsString() == STATE_TAG);
81   }
82 
83   return false;
84 }
85 
86 
87 struct Resolver {
Resolver__anond932a49f0111::Resolver88   explicit Resolver(clang::ASTContext& ctx)
89       : ctx_(ctx), decl_ctx_(ctx.getTranslationUnitDecl()) {
90   }
91 
Resolver__anond932a49f0111::Resolver92   Resolver(clang::ASTContext& ctx, clang::DeclContext* decl_ctx)
93       : ctx_(ctx), decl_ctx_(decl_ctx) {
94   }
95 
ResolveName__anond932a49f0111::Resolver96   clang::DeclarationName ResolveName(const char* n) {
97     clang::IdentifierInfo* ident = &ctx_.Idents.get(n);
98     return ctx_.DeclarationNames.getIdentifier(ident);
99   }
100 
ResolveNamespace__anond932a49f0111::Resolver101   Resolver ResolveNamespace(const char* n) {
102     return Resolver(ctx_, Resolve<clang::NamespaceDecl>(n));
103   }
104 
105   template<typename T>
Resolve__anond932a49f0111::Resolver106   T* Resolve(const char* n) {
107     if (decl_ctx_ == NULL) return NULL;
108 
109     clang::DeclContext::lookup_result result =
110         decl_ctx_->lookup(ResolveName(n));
111 
112     clang::DeclContext::lookup_iterator end = result.end();
113     for (clang::DeclContext::lookup_iterator i = result.begin(); i != end;
114          i++) {
115       if (llvm::isa<T>(*i)) return llvm::cast<T>(*i);
116     }
117 
118     return NULL;
119   }
120 
121  private:
122   clang::ASTContext& ctx_;
123   clang::DeclContext* decl_ctx_;
124 };
125 
126 
127 class CalleesPrinter : public clang::RecursiveASTVisitor<CalleesPrinter> {
128  public:
CalleesPrinter(clang::MangleContext * ctx)129   explicit CalleesPrinter(clang::MangleContext* ctx) : ctx_(ctx) {
130   }
131 
VisitCallExpr(clang::CallExpr * expr)132   virtual bool VisitCallExpr(clang::CallExpr* expr) {
133     const clang::FunctionDecl* callee = expr->getDirectCallee();
134     if (callee != NULL) AnalyzeFunction(callee);
135     return true;
136   }
137 
VisitDeclRefExpr(clang::DeclRefExpr * expr)138   virtual bool VisitDeclRefExpr(clang::DeclRefExpr* expr) {
139     // If function mentions EXTERNAL VMState add artificial garbage collection
140     // mark.
141     if (IsExternalVMState(expr->getDecl())) AddCallee("CollectGarbage");
142     return true;
143   }
144 
AnalyzeFunction(const clang::FunctionDecl * f)145   void AnalyzeFunction(const clang::FunctionDecl* f) {
146     MangledName name;
147     if (InV8Namespace(f) && GetMangledName(ctx_, f, &name)) {
148       AddCallee(name);
149 
150       const clang::FunctionDecl* body = NULL;
151       if (f->hasBody(body) && !Analyzed(name)) {
152         EnterScope(name);
153         TraverseStmt(body->getBody());
154         LeaveScope();
155       }
156     }
157   }
158 
159   typedef std::map<MangledName, CalleesSet* > Callgraph;
160 
Analyzed(const MangledName & name)161   bool Analyzed(const MangledName& name) {
162     return callgraph_[name] != NULL;
163   }
164 
EnterScope(const MangledName & name)165   void EnterScope(const MangledName& name) {
166     CalleesSet* callees = callgraph_[name];
167 
168     if (callees == NULL) {
169       callgraph_[name] = callees = new CalleesSet();
170     }
171 
172     scopes_.push(callees);
173   }
174 
LeaveScope()175   void LeaveScope() {
176     scopes_.pop();
177   }
178 
AddCallee(const MangledName & name)179   void AddCallee(const MangledName& name) {
180     if (!scopes_.empty()) scopes_.top()->insert(name);
181   }
182 
PrintCallGraph()183   void PrintCallGraph() {
184     for (Callgraph::const_iterator i = callgraph_.begin(), e = callgraph_.end();
185          i != e;
186          ++i) {
187       std::cout << i->first << "\n";
188 
189       CalleesSet* callees = i->second;
190       for (CalleesSet::const_iterator j = callees->begin(), e = callees->end();
191            j != e;
192            ++j) {
193         std::cout << "\t" << *j << "\n";
194       }
195     }
196   }
197 
198  private:
199   clang::MangleContext* ctx_;
200 
201   std::stack<CalleesSet* > scopes_;
202   Callgraph callgraph_;
203 };
204 
205 
206 class FunctionDeclarationFinder
207     : public clang::ASTConsumer,
208       public clang::RecursiveASTVisitor<FunctionDeclarationFinder> {
209  public:
FunctionDeclarationFinder(clang::DiagnosticsEngine & d,clang::SourceManager & sm,const std::vector<std::string> & args)210   explicit FunctionDeclarationFinder(clang::DiagnosticsEngine& d,
211                                      clang::SourceManager& sm,
212                                      const std::vector<std::string>& args)
213       : d_(d), sm_(sm) {}
214 
HandleTranslationUnit(clang::ASTContext & ctx)215   virtual void HandleTranslationUnit(clang::ASTContext &ctx) {
216     mangle_context_ = clang::ItaniumMangleContext::create(ctx, d_);
217     callees_printer_ = new CalleesPrinter(mangle_context_);
218 
219     TraverseDecl(ctx.getTranslationUnitDecl());
220 
221     callees_printer_->PrintCallGraph();
222   }
223 
VisitFunctionDecl(clang::FunctionDecl * decl)224   virtual bool VisitFunctionDecl(clang::FunctionDecl* decl) {
225     callees_printer_->AnalyzeFunction(decl);
226     return true;
227   }
228 
229  private:
230   clang::DiagnosticsEngine& d_;
231   clang::SourceManager& sm_;
232   clang::MangleContext* mangle_context_;
233 
234   CalleesPrinter* callees_printer_;
235 };
236 
237 
238 static bool loaded = false;
239 static CalleesSet gc_suspects;
240 
241 
LoadGCSuspects()242 static void LoadGCSuspects() {
243   if (loaded) return;
244 
245   std::ifstream fin("gcsuspects");
246   std::string s;
247 
248   while (fin >> s) gc_suspects.insert(s);
249 
250   loaded = true;
251 }
252 
253 
KnownToCauseGC(clang::MangleContext * ctx,const clang::FunctionDecl * decl)254 static bool KnownToCauseGC(clang::MangleContext* ctx,
255                            const clang::FunctionDecl* decl) {
256   LoadGCSuspects();
257 
258   if (!InV8Namespace(decl)) return false;
259 
260   MangledName name;
261   if (GetMangledName(ctx, decl, &name)) {
262     return gc_suspects.find(name) != gc_suspects.end();
263   }
264 
265   return false;
266 }
267 
268 
269 static const int kNoEffect = 0;
270 static const int kCausesGC = 1;
271 static const int kRawDef = 2;
272 static const int kRawUse = 4;
273 static const int kAllEffects = kCausesGC | kRawDef | kRawUse;
274 
275 class Environment;
276 
277 class ExprEffect {
278  public:
hasGC()279   bool hasGC() { return (effect_ & kCausesGC) != 0; }
setGC()280   void setGC() { effect_ |= kCausesGC; }
281 
hasRawDef()282   bool hasRawDef() { return (effect_ & kRawDef) != 0; }
setRawDef()283   void setRawDef() { effect_ |= kRawDef; }
284 
hasRawUse()285   bool hasRawUse() { return (effect_ & kRawUse) != 0; }
setRawUse()286   void setRawUse() { effect_ |= kRawUse; }
287 
None()288   static ExprEffect None() { return ExprEffect(kNoEffect, NULL); }
NoneWithEnv(Environment * env)289   static ExprEffect NoneWithEnv(Environment* env) {
290     return ExprEffect(kNoEffect, env);
291   }
RawUse()292   static ExprEffect RawUse() { return ExprEffect(kRawUse, NULL); }
293 
294   static ExprEffect Merge(ExprEffect a, ExprEffect b);
295   static ExprEffect MergeSeq(ExprEffect a, ExprEffect b);
296   ExprEffect Define(const std::string& name);
297 
env()298   Environment* env() {
299     return reinterpret_cast<Environment*>(effect_ & ~kAllEffects);
300   }
301 
GC()302   static ExprEffect GC() {
303     return ExprEffect(kCausesGC, NULL);
304   }
305 
306  private:
ExprEffect(int effect,Environment * env)307   ExprEffect(int effect, Environment* env)
308       : effect_((effect & kAllEffects) |
309                 reinterpret_cast<intptr_t>(env)) { }
310 
311   intptr_t effect_;
312 };
313 
314 
315 const std::string BAD_EXPR_MSG("Possible problem with evaluation order.");
316 const std::string DEAD_VAR_MSG("Possibly dead variable.");
317 
318 
319 class Environment {
320  public:
Environment()321   Environment() { }
322 
Unreachable()323   static Environment Unreachable() {
324     Environment env;
325     env.live_.set();
326     return env;
327   }
328 
Merge(const Environment & l,const Environment & r)329   static Environment Merge(const Environment& l,
330                            const Environment& r) {
331     return Environment(l, r);
332   }
333 
ApplyEffect(ExprEffect effect) const334   Environment ApplyEffect(ExprEffect effect) const {
335     Environment out = effect.hasGC() ? Environment() : Environment(*this);
336     if (effect.env() != NULL) out.live_ |= effect.env()->live_;
337     return out;
338   }
339 
340   typedef std::map<std::string, int> SymbolTable;
341 
IsAlive(const std::string & name) const342   bool IsAlive(const std::string& name) const {
343     SymbolTable::iterator code = symbol_table_.find(name);
344     if (code == symbol_table_.end()) return false;
345     return live_[code->second];
346   }
347 
Equal(const Environment & env)348   bool Equal(const Environment& env) {
349     return live_ == env.live_;
350   }
351 
Define(const std::string & name) const352   Environment Define(const std::string& name) const {
353     return Environment(*this, SymbolToCode(name));
354   }
355 
MDefine(const std::string & name)356   void MDefine(const std::string& name) {
357     live_.set(SymbolToCode(name));
358   }
359 
SymbolToCode(const std::string & name)360   static int SymbolToCode(const std::string& name) {
361     SymbolTable::iterator code = symbol_table_.find(name);
362 
363     if (code == symbol_table_.end()) {
364       int new_code = symbol_table_.size();
365       symbol_table_.insert(std::make_pair(name, new_code));
366       return new_code;
367     }
368 
369     return code->second;
370   }
371 
ClearSymbolTable()372   static void ClearSymbolTable() {
373     std::vector<Environment*>::iterator end = envs_.end();
374     for (std::vector<Environment*>::iterator i = envs_.begin();
375          i != end;
376          ++i) {
377       delete *i;
378     }
379     envs_.clear();
380     symbol_table_.clear();
381   }
382 
Print() const383   void Print() const {
384     bool comma = false;
385     std::cout << "{";
386     SymbolTable::iterator end = symbol_table_.end();
387     for (SymbolTable::iterator i = symbol_table_.begin();
388          i != end;
389          ++i) {
390       if (live_[i->second]) {
391         if (comma) std::cout << ", ";
392         std::cout << i->first;
393         comma = true;
394       }
395     }
396     std::cout << "}";
397   }
398 
Allocate(const Environment & env)399   static Environment* Allocate(const Environment& env) {
400     Environment* allocated_env = new Environment(env);
401     envs_.push_back(allocated_env);
402     return allocated_env;
403   }
404 
405  private:
Environment(const Environment & l,const Environment & r)406   Environment(const Environment& l, const Environment& r)
407       : live_(l.live_ & r.live_) {
408   }
409 
Environment(const Environment & l,int code)410   Environment(const Environment& l, int code)
411       : live_(l.live_) {
412     live_.set(code);
413   }
414 
415   static SymbolTable symbol_table_;
416   static std::vector<Environment* > envs_;
417 
418   static const int kMaxNumberOfLocals = 256;
419   std::bitset<kMaxNumberOfLocals> live_;
420 
421   friend class ExprEffect;
422   friend class CallProps;
423 };
424 
425 
426 class CallProps {
427  public:
CallProps()428   CallProps() : env_(NULL) { }
429 
SetEffect(int arg,ExprEffect in)430   void SetEffect(int arg, ExprEffect in) {
431     if (in.hasGC()) gc_.set(arg);
432     if (in.hasRawDef()) raw_def_.set(arg);
433     if (in.hasRawUse()) raw_use_.set(arg);
434     if (in.env() != NULL) {
435       if (env_ == NULL) env_ = in.env();
436       env_->live_ |= in.env()->live_;
437     }
438   }
439 
ComputeCumulativeEffect(bool result_is_raw)440   ExprEffect ComputeCumulativeEffect(bool result_is_raw) {
441     ExprEffect out = ExprEffect::NoneWithEnv(env_);
442     if (gc_.any()) out.setGC();
443     if (raw_use_.any()) out.setRawUse();
444     if (result_is_raw) out.setRawDef();
445     return out;
446   }
447 
IsSafe()448   bool IsSafe() {
449     if (!gc_.any()) return true;
450     std::bitset<kMaxNumberOfArguments> raw = (raw_def_ | raw_use_);
451     if (!raw.any()) return true;
452     return gc_.count() == 1 && !((raw ^ gc_).any());
453   }
454 
455  private:
456   static const int kMaxNumberOfArguments = 64;
457   std::bitset<kMaxNumberOfArguments> raw_def_;
458   std::bitset<kMaxNumberOfArguments> raw_use_;
459   std::bitset<kMaxNumberOfArguments> gc_;
460   Environment* env_;
461 };
462 
463 
464 Environment::SymbolTable Environment::symbol_table_;
465 std::vector<Environment* > Environment::envs_;
466 
467 
Merge(ExprEffect a,ExprEffect b)468 ExprEffect ExprEffect::Merge(ExprEffect a, ExprEffect b) {
469   Environment* a_env = a.env();
470   Environment* b_env = b.env();
471   Environment* out = NULL;
472   if (a_env != NULL && b_env != NULL) {
473     out = Environment::Allocate(*a_env);
474     out->live_ &= b_env->live_;
475   }
476   return ExprEffect(a.effect_ | b.effect_, out);
477 }
478 
479 
MergeSeq(ExprEffect a,ExprEffect b)480 ExprEffect ExprEffect::MergeSeq(ExprEffect a, ExprEffect b) {
481   Environment* a_env = b.hasGC() ? NULL : a.env();
482   Environment* b_env = b.env();
483   Environment* out = (b_env == NULL) ? a_env : b_env;
484   if (a_env != NULL && b_env != NULL) {
485     out = Environment::Allocate(*b_env);
486     out->live_ |= a_env->live_;
487   }
488   return ExprEffect(a.effect_ | b.effect_, out);
489 }
490 
491 
Define(const std::string & name)492 ExprEffect ExprEffect::Define(const std::string& name) {
493   Environment* e = env();
494   if (e == NULL) {
495     e = Environment::Allocate(Environment());
496   }
497   e->MDefine(name);
498   return ExprEffect(effect_, e);
499 }
500 
501 
502 static std::string THIS ("this");
503 
504 
505 class FunctionAnalyzer {
506  public:
FunctionAnalyzer(clang::MangleContext * ctx,clang::DeclarationName handle_decl_name,clang::CXXRecordDecl * object_decl,clang::CXXRecordDecl * smi_decl,clang::DiagnosticsEngine & d,clang::SourceManager & sm,bool dead_vars_analysis)507   FunctionAnalyzer(clang::MangleContext* ctx,
508                    clang::DeclarationName handle_decl_name,
509                    clang::CXXRecordDecl* object_decl,
510                    clang::CXXRecordDecl* smi_decl, clang::DiagnosticsEngine& d,
511                    clang::SourceManager& sm, bool dead_vars_analysis)
512       : ctx_(ctx),
513         handle_decl_name_(handle_decl_name),
514         object_decl_(object_decl),
515         smi_decl_(smi_decl),
516         d_(d),
517         sm_(sm),
518         block_(NULL),
519         dead_vars_analysis_(dead_vars_analysis) {}
520 
521 
522   // --------------------------------------------------------------------------
523   // Expressions
524   // --------------------------------------------------------------------------
525 
VisitExpr(clang::Expr * expr,const Environment & env)526   ExprEffect VisitExpr(clang::Expr* expr, const Environment& env) {
527 #define VISIT(type)                                                         \
528   do {                                                                      \
529     clang::type* concrete_expr = llvm::dyn_cast_or_null<clang::type>(expr); \
530     if (concrete_expr != NULL) {                                            \
531       return Visit##type(concrete_expr, env);                               \
532     }                                                                       \
533   } while (0);
534 
535     VISIT(AbstractConditionalOperator);
536     VISIT(AddrLabelExpr);
537     VISIT(ArraySubscriptExpr);
538     VISIT(BinaryOperator);
539     VISIT(BlockExpr);
540     VISIT(CallExpr);
541     VISIT(CastExpr);
542     VISIT(CharacterLiteral);
543     VISIT(ChooseExpr);
544     VISIT(CompoundLiteralExpr);
545     VISIT(CXXBindTemporaryExpr);
546     VISIT(CXXBoolLiteralExpr);
547     VISIT(CXXConstructExpr);
548     VISIT(CXXDefaultArgExpr);
549     VISIT(CXXDeleteExpr);
550     VISIT(CXXDependentScopeMemberExpr);
551     VISIT(CXXNewExpr);
552     VISIT(CXXNoexceptExpr);
553     VISIT(CXXNullPtrLiteralExpr);
554     VISIT(CXXPseudoDestructorExpr);
555     VISIT(CXXScalarValueInitExpr);
556     VISIT(CXXThisExpr);
557     VISIT(CXXThrowExpr);
558     VISIT(CXXTypeidExpr);
559     VISIT(CXXUnresolvedConstructExpr);
560     VISIT(CXXUuidofExpr);
561     VISIT(DeclRefExpr);
562     VISIT(DependentScopeDeclRefExpr);
563     VISIT(DesignatedInitExpr);
564     VISIT(ExprWithCleanups);
565     VISIT(ExtVectorElementExpr);
566     VISIT(FloatingLiteral);
567     VISIT(GNUNullExpr);
568     VISIT(ImaginaryLiteral);
569     VISIT(ImplicitValueInitExpr);
570     VISIT(InitListExpr);
571     VISIT(IntegerLiteral);
572     VISIT(MemberExpr);
573     VISIT(OffsetOfExpr);
574     VISIT(OpaqueValueExpr);
575     VISIT(OverloadExpr);
576     VISIT(PackExpansionExpr);
577     VISIT(ParenExpr);
578     VISIT(ParenListExpr);
579     VISIT(PredefinedExpr);
580     VISIT(ShuffleVectorExpr);
581     VISIT(SizeOfPackExpr);
582     VISIT(StmtExpr);
583     VISIT(StringLiteral);
584     VISIT(SubstNonTypeTemplateParmPackExpr);
585     VISIT(TypeTraitExpr);
586     VISIT(UnaryOperator);
587     VISIT(VAArgExpr);
588 #undef VISIT
589 
590     return ExprEffect::None();
591   }
592 
593 #define DECL_VISIT_EXPR(type)                                           \
594   ExprEffect Visit##type (clang::type* expr, const Environment& env)
595 
596 #define IGNORE_EXPR(type)                                               \
597   ExprEffect Visit##type (clang::type* expr, const Environment& env) {  \
598     return ExprEffect::None();                                          \
599   }
600 
601   IGNORE_EXPR(AddrLabelExpr);
602   IGNORE_EXPR(BlockExpr);
603   IGNORE_EXPR(CharacterLiteral);
604   IGNORE_EXPR(ChooseExpr);
605   IGNORE_EXPR(CompoundLiteralExpr);
606   IGNORE_EXPR(CXXBoolLiteralExpr);
607   IGNORE_EXPR(CXXDependentScopeMemberExpr);
608   IGNORE_EXPR(CXXNullPtrLiteralExpr);
609   IGNORE_EXPR(CXXPseudoDestructorExpr);
610   IGNORE_EXPR(CXXScalarValueInitExpr);
611   IGNORE_EXPR(CXXNoexceptExpr);
612   IGNORE_EXPR(CXXTypeidExpr);
613   IGNORE_EXPR(CXXUnresolvedConstructExpr);
614   IGNORE_EXPR(CXXUuidofExpr);
615   IGNORE_EXPR(DependentScopeDeclRefExpr);
616   IGNORE_EXPR(DesignatedInitExpr);
617   IGNORE_EXPR(ExtVectorElementExpr);
618   IGNORE_EXPR(FloatingLiteral);
619   IGNORE_EXPR(ImaginaryLiteral);
620   IGNORE_EXPR(IntegerLiteral);
621   IGNORE_EXPR(OffsetOfExpr);
622   IGNORE_EXPR(ImplicitValueInitExpr);
623   IGNORE_EXPR(PackExpansionExpr);
624   IGNORE_EXPR(PredefinedExpr);
625   IGNORE_EXPR(ShuffleVectorExpr);
626   IGNORE_EXPR(SizeOfPackExpr);
627   IGNORE_EXPR(StmtExpr);
628   IGNORE_EXPR(StringLiteral);
629   IGNORE_EXPR(SubstNonTypeTemplateParmPackExpr);
630   IGNORE_EXPR(TypeTraitExpr);
631   IGNORE_EXPR(VAArgExpr);
632   IGNORE_EXPR(GNUNullExpr);
633   IGNORE_EXPR(OverloadExpr);
634 
DECL_VISIT_EXPR(CXXThisExpr)635   DECL_VISIT_EXPR(CXXThisExpr) {
636     return Use(expr, expr->getType(), THIS, env);
637   }
638 
DECL_VISIT_EXPR(AbstractConditionalOperator)639   DECL_VISIT_EXPR(AbstractConditionalOperator) {
640     Environment after_cond = env.ApplyEffect(VisitExpr(expr->getCond(), env));
641     return ExprEffect::Merge(VisitExpr(expr->getTrueExpr(), after_cond),
642                              VisitExpr(expr->getFalseExpr(), after_cond));
643   }
644 
DECL_VISIT_EXPR(ArraySubscriptExpr)645   DECL_VISIT_EXPR(ArraySubscriptExpr) {
646     clang::Expr* exprs[2] = {expr->getBase(), expr->getIdx()};
647     return Par(expr, 2, exprs, env);
648   }
649 
IsRawPointerVar(clang::Expr * expr,std::string * var_name)650   bool IsRawPointerVar(clang::Expr* expr, std::string* var_name) {
651     if (llvm::isa<clang::DeclRefExpr>(expr)) {
652       *var_name =
653           llvm::cast<clang::DeclRefExpr>(expr)->getDecl()->getNameAsString();
654       return true;
655     }
656     return false;
657   }
658 
DECL_VISIT_EXPR(BinaryOperator)659   DECL_VISIT_EXPR(BinaryOperator) {
660     clang::Expr* lhs = expr->getLHS();
661     clang::Expr* rhs = expr->getRHS();
662     clang::Expr* exprs[2] = {lhs, rhs};
663 
664     switch (expr->getOpcode()) {
665       case clang::BO_Comma:
666         return Seq(expr, 2, exprs, env);
667 
668       case clang::BO_LAnd:
669       case clang::BO_LOr:
670         return ExprEffect::Merge(VisitExpr(lhs, env), VisitExpr(rhs, env));
671 
672       case clang::BO_Assign: {
673         std::string var_name;
674         if (IsRawPointerVar(lhs, &var_name)) {
675           return VisitExpr(rhs, env).Define(var_name);
676         }
677         return Par(expr, 2, exprs, env);
678       }
679 
680       default:
681         return Par(expr, 2, exprs, env);
682     }
683   }
684 
DECL_VISIT_EXPR(CXXBindTemporaryExpr)685   DECL_VISIT_EXPR(CXXBindTemporaryExpr) {
686     return VisitExpr(expr->getSubExpr(), env);
687   }
688 
DECL_VISIT_EXPR(CXXConstructExpr)689   DECL_VISIT_EXPR(CXXConstructExpr) {
690     return VisitArguments<>(expr, env);
691   }
692 
DECL_VISIT_EXPR(CXXDefaultArgExpr)693   DECL_VISIT_EXPR(CXXDefaultArgExpr) {
694     return VisitExpr(expr->getExpr(), env);
695   }
696 
DECL_VISIT_EXPR(CXXDeleteExpr)697   DECL_VISIT_EXPR(CXXDeleteExpr) {
698     return VisitExpr(expr->getArgument(), env);
699   }
700 
DECL_VISIT_EXPR(CXXNewExpr)701   DECL_VISIT_EXPR(CXXNewExpr) { return VisitExpr(expr->getInitializer(), env); }
702 
DECL_VISIT_EXPR(ExprWithCleanups)703   DECL_VISIT_EXPR(ExprWithCleanups) {
704     return VisitExpr(expr->getSubExpr(), env);
705   }
706 
DECL_VISIT_EXPR(CXXThrowExpr)707   DECL_VISIT_EXPR(CXXThrowExpr) {
708     return VisitExpr(expr->getSubExpr(), env);
709   }
710 
DECL_VISIT_EXPR(InitListExpr)711   DECL_VISIT_EXPR(InitListExpr) {
712     return Seq(expr, expr->getNumInits(), expr->getInits(), env);
713   }
714 
DECL_VISIT_EXPR(MemberExpr)715   DECL_VISIT_EXPR(MemberExpr) {
716     return VisitExpr(expr->getBase(), env);
717   }
718 
DECL_VISIT_EXPR(OpaqueValueExpr)719   DECL_VISIT_EXPR(OpaqueValueExpr) {
720     return VisitExpr(expr->getSourceExpr(), env);
721   }
722 
DECL_VISIT_EXPR(ParenExpr)723   DECL_VISIT_EXPR(ParenExpr) {
724     return VisitExpr(expr->getSubExpr(), env);
725   }
726 
DECL_VISIT_EXPR(ParenListExpr)727   DECL_VISIT_EXPR(ParenListExpr) {
728     return Par(expr, expr->getNumExprs(), expr->getExprs(), env);
729   }
730 
DECL_VISIT_EXPR(UnaryOperator)731   DECL_VISIT_EXPR(UnaryOperator) {
732     // TODO We are treating all expressions that look like &raw_pointer_var
733     //      as definitions of raw_pointer_var. This should be changed to
734     //      recognize less generic pattern:
735     //
736     //         if (maybe_object->ToObject(&obj)) return maybe_object;
737     //
738     if (expr->getOpcode() == clang::UO_AddrOf) {
739       std::string var_name;
740       if (IsRawPointerVar(expr->getSubExpr(), &var_name)) {
741         return ExprEffect::None().Define(var_name);
742       }
743     }
744     return VisitExpr(expr->getSubExpr(), env);
745   }
746 
DECL_VISIT_EXPR(CastExpr)747   DECL_VISIT_EXPR(CastExpr) {
748     return VisitExpr(expr->getSubExpr(), env);
749   }
750 
DECL_VISIT_EXPR(DeclRefExpr)751   DECL_VISIT_EXPR(DeclRefExpr) {
752     return Use(expr, expr->getDecl(), env);
753   }
754 
Par(clang::Expr * parent,int n,clang::Expr ** exprs,const Environment & env)755   ExprEffect Par(clang::Expr* parent,
756                  int n,
757                  clang::Expr** exprs,
758                  const Environment& env) {
759     CallProps props;
760 
761     for (int i = 0; i < n; ++i) {
762       props.SetEffect(i, VisitExpr(exprs[i], env));
763     }
764 
765     if (!props.IsSafe()) ReportUnsafe(parent, BAD_EXPR_MSG);
766 
767     return props.ComputeCumulativeEffect(IsRawPointerType(parent->getType()));
768   }
769 
Seq(clang::Stmt * parent,int n,clang::Expr ** exprs,const Environment & env)770   ExprEffect Seq(clang::Stmt* parent,
771                  int n,
772                  clang::Expr** exprs,
773                  const Environment& env) {
774     ExprEffect out = ExprEffect::None();
775     Environment out_env = env;
776     for (int i = 0; i < n; ++i) {
777       out = ExprEffect::MergeSeq(out, VisitExpr(exprs[i], out_env));
778       out_env = out_env.ApplyEffect(out);
779     }
780     return out;
781   }
782 
Use(const clang::Expr * parent,const clang::QualType & var_type,const std::string & var_name,const Environment & env)783   ExprEffect Use(const clang::Expr* parent,
784                  const clang::QualType& var_type,
785                  const std::string& var_name,
786                  const Environment& env) {
787     if (IsRawPointerType(var_type)) {
788       if (!env.IsAlive(var_name) && dead_vars_analysis_) {
789         ReportUnsafe(parent, DEAD_VAR_MSG);
790       }
791       return ExprEffect::RawUse();
792     }
793     return ExprEffect::None();
794   }
795 
Use(const clang::Expr * parent,const clang::ValueDecl * var,const Environment & env)796   ExprEffect Use(const clang::Expr* parent,
797                  const clang::ValueDecl* var,
798                  const Environment& env) {
799     if (IsExternalVMState(var)) {
800       return ExprEffect::GC();
801     }
802     return Use(parent, var->getType(), var->getNameAsString(), env);
803   }
804 
805 
806   template<typename ExprType>
VisitArguments(ExprType * call,const Environment & env)807   ExprEffect VisitArguments(ExprType* call, const Environment& env) {
808     CallProps props;
809     VisitArguments<>(call, &props, env);
810     if (!props.IsSafe()) ReportUnsafe(call, BAD_EXPR_MSG);
811     return props.ComputeCumulativeEffect(IsRawPointerType(call->getType()));
812   }
813 
814   template<typename ExprType>
VisitArguments(ExprType * call,CallProps * props,const Environment & env)815   void VisitArguments(ExprType* call,
816                       CallProps* props,
817                       const Environment& env) {
818     for (unsigned arg = 0; arg < call->getNumArgs(); arg++) {
819       props->SetEffect(arg + 1, VisitExpr(call->getArg(arg), env));
820     }
821   }
822 
823 
VisitCallExpr(clang::CallExpr * call,const Environment & env)824   ExprEffect VisitCallExpr(clang::CallExpr* call,
825                            const Environment& env) {
826     CallProps props;
827 
828     clang::CXXMemberCallExpr* memcall =
829         llvm::dyn_cast_or_null<clang::CXXMemberCallExpr>(call);
830     if (memcall != NULL) {
831       clang::Expr* receiver = memcall->getImplicitObjectArgument();
832       props.SetEffect(0, VisitExpr(receiver, env));
833     }
834 
835     VisitArguments<>(call, &props, env);
836 
837     if (!props.IsSafe()) ReportUnsafe(call, BAD_EXPR_MSG);
838 
839     ExprEffect out =
840         props.ComputeCumulativeEffect(IsRawPointerType(call->getType()));
841 
842     clang::FunctionDecl* callee = call->getDirectCallee();
843     if ((callee != NULL) && KnownToCauseGC(ctx_, callee)) {
844       out.setGC();
845     }
846 
847     return out;
848   }
849 
850   // --------------------------------------------------------------------------
851   // Statements
852   // --------------------------------------------------------------------------
853 
VisitStmt(clang::Stmt * stmt,const Environment & env)854   Environment VisitStmt(clang::Stmt* stmt, const Environment& env) {
855 #define VISIT(type)                                                         \
856   do {                                                                      \
857     clang::type* concrete_stmt = llvm::dyn_cast_or_null<clang::type>(stmt); \
858     if (concrete_stmt != NULL) {                                            \
859       return Visit##type(concrete_stmt, env);                               \
860     }                                                                       \
861   } while (0);
862 
863     if (clang::Expr* expr = llvm::dyn_cast_or_null<clang::Expr>(stmt)) {
864       return env.ApplyEffect(VisitExpr(expr, env));
865     }
866 
867     VISIT(AsmStmt);
868     VISIT(BreakStmt);
869     VISIT(CompoundStmt);
870     VISIT(ContinueStmt);
871     VISIT(CXXCatchStmt);
872     VISIT(CXXTryStmt);
873     VISIT(DeclStmt);
874     VISIT(DoStmt);
875     VISIT(ForStmt);
876     VISIT(GotoStmt);
877     VISIT(IfStmt);
878     VISIT(IndirectGotoStmt);
879     VISIT(LabelStmt);
880     VISIT(NullStmt);
881     VISIT(ReturnStmt);
882     VISIT(CaseStmt);
883     VISIT(DefaultStmt);
884     VISIT(SwitchStmt);
885     VISIT(WhileStmt);
886 #undef VISIT
887 
888     return env;
889   }
890 
891 #define DECL_VISIT_STMT(type)                                           \
892   Environment Visit##type (clang::type* stmt, const Environment& env)
893 
894 #define IGNORE_STMT(type)                                               \
895   Environment Visit##type (clang::type* stmt, const Environment& env) { \
896     return env;                                                         \
897   }
898 
899   IGNORE_STMT(IndirectGotoStmt);
900   IGNORE_STMT(NullStmt);
901   IGNORE_STMT(AsmStmt);
902 
903   // We are ignoring control flow for simplicity.
904   IGNORE_STMT(GotoStmt);
905   IGNORE_STMT(LabelStmt);
906 
907   // We are ignoring try/catch because V8 does not use them.
908   IGNORE_STMT(CXXCatchStmt);
909   IGNORE_STMT(CXXTryStmt);
910 
911   class Block {
912    public:
Block(const Environment & in,FunctionAnalyzer * owner)913     Block(const Environment& in,
914           FunctionAnalyzer* owner)
915         : in_(in),
916           out_(Environment::Unreachable()),
917           changed_(false),
918           owner_(owner) {
919       parent_ = owner_->EnterBlock(this);
920     }
921 
~Block()922     ~Block() {
923       owner_->LeaveBlock(parent_);
924     }
925 
MergeIn(const Environment & env)926     void MergeIn(const Environment& env) {
927       Environment old_in = in_;
928       in_ = Environment::Merge(in_, env);
929       changed_ = !old_in.Equal(in_);
930     }
931 
changed()932     bool changed() {
933       if (changed_) {
934         changed_ = false;
935         return true;
936       }
937       return false;
938     }
939 
in()940     const Environment& in() {
941       return in_;
942     }
943 
out()944     const Environment& out() {
945       return out_;
946     }
947 
MergeOut(const Environment & env)948     void MergeOut(const Environment& env) {
949       out_ = Environment::Merge(out_, env);
950     }
951 
Seq(clang::Stmt * a,clang::Stmt * b,clang::Stmt * c)952     void Seq(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) {
953       Environment a_out = owner_->VisitStmt(a, in());
954       Environment b_out = owner_->VisitStmt(b, a_out);
955       Environment c_out = owner_->VisitStmt(c, b_out);
956       MergeOut(c_out);
957     }
958 
Seq(clang::Stmt * a,clang::Stmt * b)959     void Seq(clang::Stmt* a, clang::Stmt* b) {
960       Environment a_out = owner_->VisitStmt(a, in());
961       Environment b_out = owner_->VisitStmt(b, a_out);
962       MergeOut(b_out);
963     }
964 
Loop(clang::Stmt * a,clang::Stmt * b,clang::Stmt * c)965     void Loop(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) {
966       Seq(a, b, c);
967       MergeIn(out());
968     }
969 
Loop(clang::Stmt * a,clang::Stmt * b)970     void Loop(clang::Stmt* a, clang::Stmt* b) {
971       Seq(a, b);
972       MergeIn(out());
973     }
974 
975 
976    private:
977     Environment in_;
978     Environment out_;
979     bool changed_;
980     FunctionAnalyzer* owner_;
981     Block* parent_;
982   };
983 
984 
DECL_VISIT_STMT(BreakStmt)985   DECL_VISIT_STMT(BreakStmt) {
986     block_->MergeOut(env);
987     return Environment::Unreachable();
988   }
989 
DECL_VISIT_STMT(ContinueStmt)990   DECL_VISIT_STMT(ContinueStmt) {
991     block_->MergeIn(env);
992     return Environment::Unreachable();
993   }
994 
DECL_VISIT_STMT(CompoundStmt)995   DECL_VISIT_STMT(CompoundStmt) {
996     Environment out = env;
997     clang::CompoundStmt::body_iterator end = stmt->body_end();
998     for (clang::CompoundStmt::body_iterator s = stmt->body_begin();
999          s != end;
1000          ++s) {
1001       out = VisitStmt(*s, out);
1002     }
1003     return out;
1004   }
1005 
DECL_VISIT_STMT(WhileStmt)1006   DECL_VISIT_STMT(WhileStmt) {
1007     Block block (env, this);
1008     do {
1009       block.Loop(stmt->getCond(), stmt->getBody());
1010     } while (block.changed());
1011     return block.out();
1012   }
1013 
DECL_VISIT_STMT(DoStmt)1014   DECL_VISIT_STMT(DoStmt) {
1015     Block block (env, this);
1016     do {
1017       block.Loop(stmt->getBody(), stmt->getCond());
1018     } while (block.changed());
1019     return block.out();
1020   }
1021 
DECL_VISIT_STMT(ForStmt)1022   DECL_VISIT_STMT(ForStmt) {
1023     Block block (VisitStmt(stmt->getInit(), env), this);
1024     do {
1025       block.Loop(stmt->getCond(),
1026                  stmt->getBody(),
1027                  stmt->getInc());
1028     } while (block.changed());
1029     return block.out();
1030   }
1031 
DECL_VISIT_STMT(IfStmt)1032   DECL_VISIT_STMT(IfStmt) {
1033     Environment cond_out = VisitStmt(stmt->getCond(), env);
1034     Environment then_out = VisitStmt(stmt->getThen(), cond_out);
1035     Environment else_out = VisitStmt(stmt->getElse(), cond_out);
1036     return Environment::Merge(then_out, else_out);
1037   }
1038 
DECL_VISIT_STMT(SwitchStmt)1039   DECL_VISIT_STMT(SwitchStmt) {
1040     Block block (env, this);
1041     block.Seq(stmt->getCond(), stmt->getBody());
1042     return block.out();
1043   }
1044 
DECL_VISIT_STMT(CaseStmt)1045   DECL_VISIT_STMT(CaseStmt) {
1046     Environment in = Environment::Merge(env, block_->in());
1047     Environment after_lhs = VisitStmt(stmt->getLHS(), in);
1048     return VisitStmt(stmt->getSubStmt(), after_lhs);
1049   }
1050 
DECL_VISIT_STMT(DefaultStmt)1051   DECL_VISIT_STMT(DefaultStmt) {
1052     Environment in = Environment::Merge(env, block_->in());
1053     return VisitStmt(stmt->getSubStmt(), in);
1054   }
1055 
DECL_VISIT_STMT(ReturnStmt)1056   DECL_VISIT_STMT(ReturnStmt) {
1057     VisitExpr(stmt->getRetValue(), env);
1058     return Environment::Unreachable();
1059   }
1060 
ToTagType(const clang::Type * t)1061   const clang::TagType* ToTagType(const clang::Type* t) {
1062     if (t == NULL) {
1063       return NULL;
1064     } else if (llvm::isa<clang::TagType>(t)) {
1065       return llvm::cast<clang::TagType>(t);
1066     } else if (llvm::isa<clang::SubstTemplateTypeParmType>(t)) {
1067       return ToTagType(llvm::cast<clang::SubstTemplateTypeParmType>(t)
1068                            ->getReplacementType()
1069                            .getTypePtr());
1070     } else {
1071       return NULL;
1072     }
1073   }
1074 
IsDerivedFrom(clang::CXXRecordDecl * record,clang::CXXRecordDecl * base)1075   bool IsDerivedFrom(clang::CXXRecordDecl* record,
1076                      clang::CXXRecordDecl* base) {
1077     return (record == base) || record->isDerivedFrom(base);
1078   }
1079 
IsRawPointerType(clang::QualType qtype)1080   bool IsRawPointerType(clang::QualType qtype) {
1081     const clang::PointerType* type =
1082         llvm::dyn_cast_or_null<clang::PointerType>(qtype.getTypePtrOrNull());
1083     if (type == NULL) return false;
1084 
1085     const clang::TagType* pointee =
1086         ToTagType(type->getPointeeType().getTypePtr());
1087     if (pointee == NULL) return false;
1088 
1089     clang::CXXRecordDecl* record =
1090         llvm::dyn_cast_or_null<clang::CXXRecordDecl>(pointee->getDecl());
1091     if (record == NULL) return false;
1092 
1093     if (!InV8Namespace(record)) return false;
1094 
1095     if (!record->hasDefinition()) return false;
1096 
1097     record = record->getDefinition();
1098 
1099     return IsDerivedFrom(record, object_decl_) &&
1100         !IsDerivedFrom(record, smi_decl_);
1101   }
1102 
VisitDecl(clang::Decl * decl,const Environment & env)1103   Environment VisitDecl(clang::Decl* decl, const Environment& env) {
1104     if (clang::VarDecl* var = llvm::dyn_cast<clang::VarDecl>(decl)) {
1105       Environment out = var->hasInit() ? VisitStmt(var->getInit(), env) : env;
1106 
1107       if (IsRawPointerType(var->getType())) {
1108         out = out.Define(var->getNameAsString());
1109       }
1110 
1111       return out;
1112     }
1113     // TODO: handle other declarations?
1114     return env;
1115   }
1116 
DECL_VISIT_STMT(DeclStmt)1117   DECL_VISIT_STMT(DeclStmt) {
1118     Environment out = env;
1119     clang::DeclStmt::decl_iterator end = stmt->decl_end();
1120     for (clang::DeclStmt::decl_iterator decl = stmt->decl_begin();
1121          decl != end;
1122          ++decl) {
1123       out = VisitDecl(*decl, out);
1124     }
1125     return out;
1126   }
1127 
1128 
DefineParameters(const clang::FunctionDecl * f,Environment * env)1129   void DefineParameters(const clang::FunctionDecl* f,
1130                         Environment* env) {
1131     env->MDefine(THIS);
1132     clang::FunctionDecl::param_const_iterator end = f->param_end();
1133     for (clang::FunctionDecl::param_const_iterator p = f->param_begin();
1134          p != end;
1135          ++p) {
1136       env->MDefine((*p)->getNameAsString());
1137     }
1138   }
1139 
1140 
AnalyzeFunction(const clang::FunctionDecl * f)1141   void AnalyzeFunction(const clang::FunctionDecl* f) {
1142     const clang::FunctionDecl* body = NULL;
1143     if (f->hasBody(body)) {
1144       Environment env;
1145       DefineParameters(body, &env);
1146       VisitStmt(body->getBody(), env);
1147       Environment::ClearSymbolTable();
1148     }
1149   }
1150 
EnterBlock(Block * block)1151   Block* EnterBlock(Block* block) {
1152     Block* parent = block_;
1153     block_ = block;
1154     return parent;
1155   }
1156 
LeaveBlock(Block * block)1157   void LeaveBlock(Block* block) {
1158     block_ = block;
1159   }
1160 
1161  private:
ReportUnsafe(const clang::Expr * expr,const std::string & msg)1162   void ReportUnsafe(const clang::Expr* expr, const std::string& msg) {
1163     d_.Report(clang::FullSourceLoc(expr->getExprLoc(), sm_),
1164               d_.getCustomDiagID(clang::DiagnosticsEngine::Warning, "%0"))
1165         << msg;
1166   }
1167 
1168 
1169   clang::MangleContext* ctx_;
1170   clang::DeclarationName handle_decl_name_;
1171   clang::CXXRecordDecl* object_decl_;
1172   clang::CXXRecordDecl* smi_decl_;
1173 
1174   clang::DiagnosticsEngine& d_;
1175   clang::SourceManager& sm_;
1176 
1177   Block* block_;
1178   bool dead_vars_analysis_;
1179 };
1180 
1181 
1182 class ProblemsFinder : public clang::ASTConsumer,
1183                        public clang::RecursiveASTVisitor<ProblemsFinder> {
1184  public:
ProblemsFinder(clang::DiagnosticsEngine & d,clang::SourceManager & sm,const std::vector<std::string> & args)1185   ProblemsFinder(clang::DiagnosticsEngine& d, clang::SourceManager& sm,
1186                  const std::vector<std::string>& args)
1187       : d_(d), sm_(sm), dead_vars_analysis_(false) {
1188     for (unsigned i = 0; i < args.size(); ++i) {
1189       if (args[i] == "--dead-vars") {
1190         dead_vars_analysis_ = true;
1191       }
1192     }
1193   }
1194 
HandleTranslationUnit(clang::ASTContext & ctx)1195   virtual void HandleTranslationUnit(clang::ASTContext &ctx) {
1196     Resolver r(ctx);
1197 
1198     clang::CXXRecordDecl* object_decl =
1199         r.ResolveNamespace("v8").ResolveNamespace("internal").
1200             Resolve<clang::CXXRecordDecl>("Object");
1201 
1202     clang::CXXRecordDecl* smi_decl =
1203         r.ResolveNamespace("v8").ResolveNamespace("internal").
1204             Resolve<clang::CXXRecordDecl>("Smi");
1205 
1206     if (object_decl != NULL) object_decl = object_decl->getDefinition();
1207 
1208     if (smi_decl != NULL) smi_decl = smi_decl->getDefinition();
1209 
1210     if (object_decl != NULL && smi_decl != NULL) {
1211       function_analyzer_ = new FunctionAnalyzer(
1212           clang::ItaniumMangleContext::create(ctx, d_), r.ResolveName("Handle"),
1213           object_decl, smi_decl, d_, sm_, dead_vars_analysis_);
1214       TraverseDecl(ctx.getTranslationUnitDecl());
1215     } else {
1216       if (object_decl == NULL) {
1217         llvm::errs() << "Failed to resolve v8::internal::Object\n";
1218       }
1219       if (smi_decl == NULL) {
1220         llvm::errs() << "Failed to resolve v8::internal::Smi\n";
1221       }
1222     }
1223   }
1224 
VisitFunctionDecl(clang::FunctionDecl * decl)1225   virtual bool VisitFunctionDecl(clang::FunctionDecl* decl) {
1226     function_analyzer_->AnalyzeFunction(decl);
1227     return true;
1228   }
1229 
1230  private:
1231   clang::DiagnosticsEngine& d_;
1232   clang::SourceManager& sm_;
1233   bool dead_vars_analysis_;
1234 
1235   FunctionAnalyzer* function_analyzer_;
1236 };
1237 
1238 
1239 template<typename ConsumerType>
1240 class Action : public clang::PluginASTAction {
1241  protected:
CreateASTConsumer(clang::CompilerInstance & CI,llvm::StringRef InFile)1242   clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &CI,
1243                                         llvm::StringRef InFile) {
1244     return new ConsumerType(CI.getDiagnostics(), CI.getSourceManager(), args_);
1245   }
1246 
ParseArgs(const clang::CompilerInstance & CI,const std::vector<std::string> & args)1247   bool ParseArgs(const clang::CompilerInstance &CI,
1248                  const std::vector<std::string>& args) {
1249     args_ = args;
1250     return true;
1251   }
1252 
PrintHelp(llvm::raw_ostream & ros)1253   void PrintHelp(llvm::raw_ostream& ros) {
1254   }
1255  private:
1256   std::vector<std::string> args_;
1257 };
1258 
1259 
1260 }
1261 
1262 static clang::FrontendPluginRegistry::Add<Action<ProblemsFinder> >
1263 FindProblems("find-problems", "Find GC-unsafe places.");
1264 
1265 static clang::FrontendPluginRegistry::Add<
1266   Action<FunctionDeclarationFinder> >
1267 DumpCallees("dump-callees", "Dump callees for each function.");
1268