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