Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / v8 / tools / gcmole / gcmole.cc
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
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
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
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 {
88   explicit Resolver(clang::ASTContext& ctx)
89       : ctx_(ctx), decl_ctx_(ctx.getTranslationUnitDecl()) {
90   }
91
92   Resolver(clang::ASTContext& ctx, clang::DeclContext* decl_ctx)
93       : ctx_(ctx), decl_ctx_(decl_ctx) {
94   }
95
96   clang::DeclarationName ResolveName(const char* n) {
97     clang::IdentifierInfo* ident = &ctx_.Idents.get(n);
98     return ctx_.DeclarationNames.getIdentifier(ident);
99   }
100
101   Resolver ResolveNamespace(const char* n) {
102     return Resolver(ctx_, Resolve<clang::NamespaceDecl>(n));
103   }
104
105   template<typename T>
106   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:
129   explicit CalleesPrinter(clang::MangleContext* ctx) : ctx_(ctx) {
130   }
131
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
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
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
161   bool Analyzed(const MangledName& name) {
162     return callgraph_[name] != NULL;
163   }
164
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
175   void LeaveScope() {
176     scopes_.pop();
177   }
178
179   void AddCallee(const MangledName& name) {
180     if (!scopes_.empty()) scopes_.top()->insert(name);
181   }
182
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:
210   explicit FunctionDeclarationFinder(clang::DiagnosticsEngine& d,
211                                      clang::SourceManager& sm,
212                                      const std::vector<std::string>& args)
213       : d_(d), sm_(sm) {}
214
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
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
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
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:
279   bool hasGC() { return (effect_ & kCausesGC) != 0; }
280   void setGC() { effect_ |= kCausesGC; }
281
282   bool hasRawDef() { return (effect_ & kRawDef) != 0; }
283   void setRawDef() { effect_ |= kRawDef; }
284
285   bool hasRawUse() { return (effect_ & kRawUse) != 0; }
286   void setRawUse() { effect_ |= kRawUse; }
287
288   static ExprEffect None() { return ExprEffect(kNoEffect, NULL); }
289   static ExprEffect NoneWithEnv(Environment* env) {
290     return ExprEffect(kNoEffect, env);
291   }
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
298   Environment* env() {
299     return reinterpret_cast<Environment*>(effect_ & ~kAllEffects);
300   }
301
302   static ExprEffect GC() {
303     return ExprEffect(kCausesGC, NULL);
304   }
305
306  private:
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:
321   Environment() { }
322
323   static Environment Unreachable() {
324     Environment env;
325     env.live_.set();
326     return env;
327   }
328
329   static Environment Merge(const Environment& l,
330                            const Environment& r) {
331     return Environment(l, r);
332   }
333
334   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
342   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
348   bool Equal(const Environment& env) {
349     return live_ == env.live_;
350   }
351
352   Environment Define(const std::string& name) const {
353     return Environment(*this, SymbolToCode(name));
354   }
355
356   void MDefine(const std::string& name) {
357     live_.set(SymbolToCode(name));
358   }
359
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
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
383   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
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:
406   Environment(const Environment& l, const Environment& r)
407       : live_(l.live_ & r.live_) {
408   }
409
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:
428   CallProps() : env_(NULL) { }
429
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
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
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
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
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
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:
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
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
635   DECL_VISIT_EXPR(CXXThisExpr) {
636     return Use(expr, expr->getType(), THIS, env);
637   }
638
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
645   DECL_VISIT_EXPR(ArraySubscriptExpr) {
646     clang::Expr* exprs[2] = {expr->getBase(), expr->getIdx()};
647     return Par(expr, 2, exprs, env);
648   }
649
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
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
685   DECL_VISIT_EXPR(CXXBindTemporaryExpr) {
686     return VisitExpr(expr->getSubExpr(), env);
687   }
688
689   DECL_VISIT_EXPR(CXXConstructExpr) {
690     return VisitArguments<>(expr, env);
691   }
692
693   DECL_VISIT_EXPR(CXXDefaultArgExpr) {
694     return VisitExpr(expr->getExpr(), env);
695   }
696
697   DECL_VISIT_EXPR(CXXDeleteExpr) {
698     return VisitExpr(expr->getArgument(), env);
699   }
700
701   DECL_VISIT_EXPR(CXXNewExpr) { return VisitExpr(expr->getInitializer(), env); }
702
703   DECL_VISIT_EXPR(ExprWithCleanups) {
704     return VisitExpr(expr->getSubExpr(), env);
705   }
706
707   DECL_VISIT_EXPR(CXXThrowExpr) {
708     return VisitExpr(expr->getSubExpr(), env);
709   }
710
711   DECL_VISIT_EXPR(InitListExpr) {
712     return Seq(expr, expr->getNumInits(), expr->getInits(), env);
713   }
714
715   DECL_VISIT_EXPR(MemberExpr) {
716     return VisitExpr(expr->getBase(), env);
717   }
718
719   DECL_VISIT_EXPR(OpaqueValueExpr) {
720     return VisitExpr(expr->getSourceExpr(), env);
721   }
722
723   DECL_VISIT_EXPR(ParenExpr) {
724     return VisitExpr(expr->getSubExpr(), env);
725   }
726
727   DECL_VISIT_EXPR(ParenListExpr) {
728     return Par(expr, expr->getNumExprs(), expr->getExprs(), env);
729   }
730
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
747   DECL_VISIT_EXPR(CastExpr) {
748     return VisitExpr(expr->getSubExpr(), env);
749   }
750
751   DECL_VISIT_EXPR(DeclRefExpr) {
752     return Use(expr, expr->getDecl(), env);
753   }
754
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
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
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
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>
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>
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
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
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:
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
922     ~Block() {
923       owner_->LeaveBlock(parent_);
924     }
925
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
932     bool changed() {
933       if (changed_) {
934         changed_ = false;
935         return true;
936       }
937       return false;
938     }
939
940     const Environment& in() {
941       return in_;
942     }
943
944     const Environment& out() {
945       return out_;
946     }
947
948     void MergeOut(const Environment& env) {
949       out_ = Environment::Merge(out_, env);
950     }
951
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
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
965     void Loop(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) {
966       Seq(a, b, c);
967       MergeIn(out());
968     }
969
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
985   DECL_VISIT_STMT(BreakStmt) {
986     block_->MergeOut(env);
987     return Environment::Unreachable();
988   }
989
990   DECL_VISIT_STMT(ContinueStmt) {
991     block_->MergeIn(env);
992     return Environment::Unreachable();
993   }
994
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
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
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
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
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
1039   DECL_VISIT_STMT(SwitchStmt) {
1040     Block block (env, this);
1041     block.Seq(stmt->getCond(), stmt->getBody());
1042     return block.out();
1043   }
1044
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
1051   DECL_VISIT_STMT(DefaultStmt) {
1052     Environment in = Environment::Merge(env, block_->in());
1053     return VisitStmt(stmt->getSubStmt(), in);
1054   }
1055
1056   DECL_VISIT_STMT(ReturnStmt) {
1057     VisitExpr(stmt->getRetValue(), env);
1058     return Environment::Unreachable();
1059   }
1060
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
1075   bool IsDerivedFrom(clang::CXXRecordDecl* record,
1076                      clang::CXXRecordDecl* base) {
1077     return (record == base) || record->isDerivedFrom(base);
1078   }
1079
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
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
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
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
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
1151   Block* EnterBlock(Block* block) {
1152     Block* parent = block_;
1153     block_ = block;
1154     return parent;
1155   }
1156
1157   void LeaveBlock(Block* block) {
1158     block_ = block;
1159   }
1160
1161  private:
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:
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
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
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:
1242   clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &CI,
1243                                         llvm::StringRef InFile) {
1244     return new ConsumerType(CI.getDiagnostics(), CI.getSourceManager(), args_);
1245   }
1246
1247   bool ParseArgs(const clang::CompilerInstance &CI,
1248                  const std::vector<std::string>& args) {
1249     args_ = args;
1250     return true;
1251   }
1252
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.");