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