Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: tools/gcmole/gcmole.cc

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

Powered by Google App Engine
This is Rietveld 408576698