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