1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 // This is clang plugin used by gcmole tool. See README for more details. 29 30 #include "clang/AST/AST.h" 31 #include "clang/AST/ASTConsumer.h" 32 #include "clang/AST/Mangle.h" 33 #include "clang/AST/RecursiveASTVisitor.h" 34 #include "clang/AST/StmtVisitor.h" 35 #include "clang/Frontend/FrontendPluginRegistry.h" 36 #include "clang/Frontend/CompilerInstance.h" 37 #include "llvm/Support/raw_ostream.h" 38 39 #include <bitset> 40 #include <fstream> 41 #include <iostream> 42 #include <map> 43 #include <set> 44 #include <stack> 45 46 namespace { 47 48 typedef std::string MangledName; 49 typedef std::set<MangledName> CalleesSet; 50 51 static bool GetMangledName(clang::MangleContext* ctx, 52 const clang::NamedDecl* decl, 53 MangledName* result) { 54 if (!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 67 static bool InV8Namespace(const clang::NamedDecl* decl) { 68 return decl->getQualifiedNameAsString().compare(0, 4, "v8::") == 0; 69 } 70 71 72 static std::string EXTERNAL("EXTERNAL"); 73 static std::string STATE_TAG("enum v8::internal::StateTag"); 74 75 static bool IsExternalVMState(const clang::ValueDecl* var) { 76 const clang::EnumConstantDecl* enum_constant = 77 dyn_cast<clang::EnumConstantDecl>(var); 78 if (enum_constant != NULL && enum_constant->getNameAsString() == EXTERNAL) { 79 clang::QualType type = enum_constant->getType(); 80 return (type.getAsString() == STATE_TAG); 81 } 82 83 return false; 84 } 85 86 87 struct Resolver { 88 explicit Resolver(clang::ASTContext& ctx) 89 : ctx_(ctx), decl_ctx_(ctx.getTranslationUnitDecl()) { 90 } 91 92 Resolver(clang::ASTContext& ctx, clang::DeclContext* decl_ctx) 93 : ctx_(ctx), decl_ctx_(decl_ctx) { 94 } 95 96 clang::DeclarationName ResolveName(const char* n) { 97 clang::IdentifierInfo* ident = &ctx_.Idents.get(n); 98 return ctx_.DeclarationNames.getIdentifier(ident); 99 } 100 101 Resolver ResolveNamespace(const char* n) { 102 return Resolver(ctx_, Resolve<clang::NamespaceDecl>(n)); 103 } 104 105 template<typename T> 106 T* Resolve(const char* n) { 107 if (decl_ctx_ == NULL) return NULL; 108 109 clang::DeclContext::lookup_result result = 110 decl_ctx_->lookup(ResolveName(n)); 111 112 clang::DeclContext::lookup_iterator end = result.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: 130 explicit CalleesPrinter(clang::MangleContext* ctx) : ctx_(ctx) { 131 } 132 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 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 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 162 bool Analyzed(const MangledName& name) { 163 return callgraph_[name] != NULL; 164 } 165 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 176 void LeaveScope() { 177 scopes_.pop(); 178 } 179 180 void AddCallee(const MangledName& name) { 181 if (!scopes_.empty()) scopes_.top()->insert(name); 182 } 183 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: 211 explicit FunctionDeclarationFinder(clang::Diagnostic& d, 212 clang::SourceManager& sm, 213 const std::vector<std::string>& args) 214 : d_(d), sm_(sm) { } 215 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 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 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 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: 280 bool hasGC() { return (effect_ & kCausesGC) != 0; } 281 void setGC() { effect_ |= kCausesGC; } 282 283 bool hasRawDef() { return (effect_ & kRawDef) != 0; } 284 void setRawDef() { effect_ |= kRawDef; } 285 286 bool hasRawUse() { return (effect_ & kRawUse) != 0; } 287 void setRawUse() { effect_ |= kRawUse; } 288 289 static ExprEffect None() { return ExprEffect(kNoEffect, NULL); } 290 static ExprEffect NoneWithEnv(Environment* env) { 291 return ExprEffect(kNoEffect, env); 292 } 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 299 Environment* env() { 300 return reinterpret_cast<Environment*>(effect_ & ~kAllEffects); 301 } 302 303 static ExprEffect GC() { 304 return ExprEffect(kCausesGC, NULL); 305 } 306 307 private: 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: 322 Environment() { } 323 324 static Environment Unreachable() { 325 Environment env; 326 env.live_.set(); 327 return env; 328 } 329 330 static Environment Merge(const Environment& l, 331 const Environment& r) { 332 return Environment(l, r); 333 } 334 335 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 343 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 349 bool Equal(const Environment& env) { 350 return live_ == env.live_; 351 } 352 353 Environment Define(const std::string& name) const { 354 return Environment(*this, SymbolToCode(name)); 355 } 356 357 void MDefine(const std::string& name) { 358 live_.set(SymbolToCode(name)); 359 } 360 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 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 384 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 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: 407 Environment(const Environment& l, const Environment& r) 408 : live_(l.live_ & r.live_) { 409 } 410 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: 429 CallProps() : env_(NULL) { } 430 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 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 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 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 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 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: 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 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 643 DECL_VISIT_EXPR(CXXThisExpr) { 644 return Use(expr, expr->getType(), THIS, env); 645 } 646 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 653 DECL_VISIT_EXPR(ArraySubscriptExpr) { 654 clang::Expr* exprs[2] = {expr->getBase(), expr->getIdx()}; 655 return Par(expr, 2, exprs, env); 656 } 657 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 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 696 DECL_VISIT_EXPR(CXXBindTemporaryExpr) { 697 return VisitExpr(expr->getSubExpr(), env); 698 } 699 700 DECL_VISIT_EXPR(CXXConstructExpr) { 701 return VisitArguments<>(expr, env); 702 } 703 704 DECL_VISIT_EXPR(CXXDefaultArgExpr) { 705 return VisitExpr(expr->getExpr(), env); 706 } 707 708 DECL_VISIT_EXPR(CXXDeleteExpr) { 709 return VisitExpr(expr->getArgument(), env); 710 } 711 712 DECL_VISIT_EXPR(CXXNewExpr) { 713 return Par(expr, 714 expr->getNumConstructorArgs(), 715 expr->getConstructorArgs(), 716 env); 717 } 718 719 DECL_VISIT_EXPR(ExprWithCleanups) { 720 return VisitExpr(expr->getSubExpr(), env); 721 } 722 723 DECL_VISIT_EXPR(CXXThrowExpr) { 724 return VisitExpr(expr->getSubExpr(), env); 725 } 726 727 DECL_VISIT_EXPR(InitListExpr) { 728 return Seq(expr, expr->getNumInits(), expr->getInits(), env); 729 } 730 731 DECL_VISIT_EXPR(MemberExpr) { 732 return VisitExpr(expr->getBase(), env); 733 } 734 735 DECL_VISIT_EXPR(OpaqueValueExpr) { 736 return VisitExpr(expr->getSourceExpr(), env); 737 } 738 739 DECL_VISIT_EXPR(ParenExpr) { 740 return VisitExpr(expr->getSubExpr(), env); 741 } 742 743 DECL_VISIT_EXPR(ParenListExpr) { 744 return Par(expr, expr->getNumExprs(), expr->getExprs(), env); 745 } 746 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 763 DECL_VISIT_EXPR(CastExpr) { 764 return VisitExpr(expr->getSubExpr(), env); 765 } 766 767 DECL_VISIT_EXPR(DeclRefExpr) { 768 return Use(expr, expr->getDecl(), env); 769 } 770 771 DECL_VISIT_EXPR(BlockDeclRefExpr) { 772 return Use(expr, expr->getDecl(), env); 773 } 774 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 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 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 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> 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> 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 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 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: 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 941 ~Block() { 942 owner_->LeaveBlock(parent_); 943 } 944 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 951 bool changed() { 952 if (changed_) { 953 changed_ = false; 954 return true; 955 } 956 return false; 957 } 958 959 const Environment& in() { 960 return in_; 961 } 962 963 const Environment& out() { 964 return out_; 965 } 966 967 void MergeOut(const Environment& env) { 968 out_ = Environment::Merge(out_, env); 969 } 970 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 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 984 void Loop(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) { 985 Seq(a, b, c); 986 MergeIn(out()); 987 } 988 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 1004 DECL_VISIT_STMT(BreakStmt) { 1005 block_->MergeOut(env); 1006 return Environment::Unreachable(); 1007 } 1008 1009 DECL_VISIT_STMT(ContinueStmt) { 1010 block_->MergeIn(env); 1011 return Environment::Unreachable(); 1012 } 1013 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 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 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 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 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 1058 DECL_VISIT_STMT(SwitchStmt) { 1059 Block block (env, this); 1060 block.Seq(stmt->getCond(), stmt->getBody()); 1061 return block.out(); 1062 } 1063 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 1070 DECL_VISIT_STMT(DefaultStmt) { 1071 Environment in = Environment::Merge(env, block_->in()); 1072 return VisitStmt(stmt->getSubStmt(), in); 1073 } 1074 1075 DECL_VISIT_STMT(ReturnStmt) { 1076 VisitExpr(stmt->getRetValue(), env); 1077 return Environment::Unreachable(); 1078 } 1079 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 1093 bool IsDerivedFrom(clang::CXXRecordDecl* record, 1094 clang::CXXRecordDecl* base) { 1095 return (record == base) || record->isDerivedFrom(base); 1096 } 1097 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 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 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 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 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 1169 Block* EnterBlock(Block* block) { 1170 Block* parent = block_; 1171 block_ = block; 1172 return parent; 1173 } 1174 1175 void LeaveBlock(Block* block) { 1176 block_ = block; 1177 } 1178 1179 private: 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: 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 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 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: 1265 clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &CI, 1266 llvm::StringRef InFile) { 1267 return new ConsumerType(CI.getDiagnostics(), CI.getSourceManager(), args_); 1268 } 1269 1270 bool ParseArgs(const clang::CompilerInstance &CI, 1271 const std::vector<std::string>& args) { 1272 args_ = args; 1273 return true; 1274 } 1275 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