Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 for (clang::DeclContext::lookup_iterator i = result.first, | |
| 98 e = result.second; | |
|
Mads Ager (chromium)
2011/05/16 06:10:27
How about extracting result.second before the loop
| |
| 99 i != e; | |
| 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 Loading... | |
| 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 Loading... | |
| 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 for (std::vector<Environment*>::iterator i = envs_.begin(), | |
| 349 end = envs_.end(); | |
| 350 i != end; | |
|
Mads Ager (chromium)
2011/05/16 06:10:27
Move envs_.end() here to make code more readable?
| |
| 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 for (SymbolTable::iterator i = symbol_table_.begin(), | |
| 362 end = symbol_table_.end(); | |
| 363 i != end; | |
|
Mads Ager (chromium)
2011/05/16 06:10:27
Ditto. Also multiple places below.
| |
| 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 handleDeclName, | |
| 484 clang::CXXRecordDecl* objectDecl, | |
| 485 clang::CXXRecordDecl* smiDecl, | |
| 486 clang::Diagnostic& d, | |
| 487 clang::SourceManager& sm, | |
| 488 bool dead_vars_analysis) | |
| 489 : ctx_(ctx), | |
| 490 handleDeclName_(handleDeclName), | |
| 491 objectDecl_(objectDecl), | |
| 492 smiDecl_(smiDecl), | |
| 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); \ | |
|
Mads Ager (chromium)
2011/05/16 06:10:27
Placement of '*'.
| |
| 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) | |
|
Mads Ager (chromium)
2011/05/16 06:10:27
Is there a reason for the '*' placement here and i
| |
| 883 | |
| 884 #define IGNORE_STMT(type) \ | |
| 885 Environment Visit##type (clang::type * stmt, const Environment& env) { \ | |
|
Mads Ager (chromium)
2011/05/16 06:10:27
If you place the '*' differently the '\' aligns wi
| |
| 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), out_(Environment::Unreachable()), changed_(false), owner_(own er) { | |
|
Mads Ager (chromium)
2011/05/16 06:10:27
Long line.
| |
| 906 parent_ = owner_->EnterBlock(this); | |
| 907 } | |
| 908 | |
| 909 ~Block() { | |
| 910 owner_->LeaveBlock(parent_); | |
| 911 } | |
| 912 | |
| 913 void MergeIn(const Environment& env) { | |
| 914 Environment old_in = in_; | |
| 915 in_ = Environment::Merge(in_, env); | |
| 916 changed_ = !old_in.Equal(in_); | |
| 917 } | |
| 918 | |
| 919 bool changed() { | |
| 920 if (changed_) { | |
| 921 changed_ = false; | |
| 215 return true; | 922 return true; |
| 216 } | 923 } |
| 217 } | 924 return false; |
| 218 } else if (const clang::RecordType* type = | 925 } |
| 219 canonical_type->getAs<clang::RecordType>()) { | 926 |
| 220 if (const clang::ClassTemplateSpecializationDecl* t = | 927 const Environment& in() { |
| 221 dyn_cast<clang::ClassTemplateSpecializationDecl>(type->getDecl())) { | 928 return in_; |
| 222 if (t->getSpecializedTemplate()->getDeclName() == handleDeclName) { | 929 } |
| 223 return true; | 930 |
| 224 } | 931 const Environment& out() { |
| 225 } | 932 return out_; |
| 226 } | 933 } |
| 227 | 934 |
| 228 return false; | 935 void MergeOut(const Environment& env) { |
| 229 } | 936 out_ = Environment::Merge(out_, env); |
| 230 | 937 } |
| 231 | 938 |
| 232 class ExpressionClassifier : | 939 void Seq(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) { |
| 233 public clang::RecursiveASTVisitor<ExpressionClassifier> { | 940 Environment a_out = owner_->VisitStmt(a, in()); |
| 234 public: | 941 Environment b_out = owner_->VisitStmt(b, a_out); |
| 235 ExpressionClassifier(clang::DeclarationName handleDeclName, | 942 Environment c_out = owner_->VisitStmt(c, b_out); |
| 236 clang::MangleContext* ctx, | 943 MergeOut(c_out); |
| 237 clang::CXXRecordDecl* objectDecl) | 944 } |
| 238 : handleDeclName_(handleDeclName), | 945 |
| 239 ctx_(ctx), | 946 void Seq(clang::Stmt* a, clang::Stmt* b) { |
| 240 objectDecl_(objectDecl) { | 947 Environment a_out = owner_->VisitStmt(a, in()); |
| 241 } | 948 Environment b_out = owner_->VisitStmt(b, a_out); |
| 242 | 949 MergeOut(b_out); |
| 243 bool IsBadExpression(clang::Expr* expr) { | 950 } |
| 244 has_derefs_ = has_gc_ = false; | 951 |
| 245 TraverseStmt(expr); | 952 void Loop(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) { |
| 246 return has_derefs_ && has_gc_; | 953 Seq(a, b, c); |
| 247 } | 954 MergeIn(out()); |
| 248 | 955 } |
| 249 bool IsBadCallSite(clang::Expr* expr) { | 956 |
| 250 if (isa<clang::CallExpr>(expr)) { | 957 void Loop(clang::Stmt* a, clang::Stmt* b) { |
| 251 clang::CallExpr* call = cast<clang::CallExpr>(expr); | 958 Seq(a, b); |
| 252 | 959 MergeIn(out()); |
| 253 MarkGCSuspectAsArgument(call); | 960 } |
| 254 MarkHandleDereferenceAsArgument(call); | 961 |
| 255 | 962 |
| 256 return derefs_.any() && | 963 private: |
| 257 ((gc_.count() > 1) || (gc_.any() && (gc_ ^ derefs_).any())); | 964 Environment in_; |
| 258 } | 965 Environment out_; |
| 259 return false; | 966 bool changed_; |
| 260 } | 967 FunctionAnalyzer* owner_; |
| 261 | 968 Block* parent_; |
| 262 virtual bool VisitExpr(clang::Expr* expr) { | 969 }; |
| 263 has_derefs_ = has_derefs_ || IsRawPointerType(expr); | 970 |
| 264 return !has_gc_ || !has_derefs_; | 971 |
| 265 } | 972 DECL_VISIT_STMT(BreakStmt) { |
| 266 | 973 block_->MergeOut(env); |
| 267 virtual bool VisitCallExpr(clang::CallExpr* expr) { | 974 return Environment::Unreachable(); |
| 268 has_gc_ = has_gc_ || CanCauseGC(expr); | 975 } |
| 269 return !has_gc_ || !has_derefs_; | 976 |
| 270 } | 977 DECL_VISIT_STMT(ContinueStmt) { |
| 271 private: | 978 block_->MergeIn(env); |
| 272 void MarkHandleDereferenceAsArgument(clang::CallExpr* call) { | 979 return Environment::Unreachable(); |
| 273 derefs_.reset(); | 980 } |
| 274 | 981 |
| 275 if (clang::CXXMemberCallExpr* memcall = | 982 DECL_VISIT_STMT(CompoundStmt) { |
| 276 dyn_cast<clang::CXXMemberCallExpr>(call)) { | 983 Environment out = env; |
| 277 if (ManipulatesRawPointers(memcall->getImplicitObjectArgument())) { | 984 for (clang::CompoundStmt::body_iterator s = stmt->body_begin(), |
| 278 derefs_.set(0); | 985 end = stmt->body_end(); |
| 279 } | 986 s != end; |
| 280 } | 987 ++s) { |
| 281 | 988 out = VisitStmt(*s, out); |
| 282 for (unsigned arg = 0; arg < call->getNumArgs(); arg++) { | 989 } |
| 283 if (ManipulatesRawPointers(call->getArg(arg))) derefs_.set(arg + 1); | 990 return out; |
| 284 } | 991 } |
| 285 } | 992 |
| 286 | 993 DECL_VISIT_STMT(WhileStmt) { |
| 287 void MarkGCSuspectAsArgument(clang::CallExpr* call) { | 994 Block block (env, this); |
| 288 gc_.reset(); | 995 do { |
| 289 | 996 block.Loop(stmt->getCond(), stmt->getBody()); |
| 290 clang::CXXMemberCallExpr* memcall = | 997 } while (block.changed()); |
| 291 dyn_cast_or_null<clang::CXXMemberCallExpr>(call); | 998 return block.out(); |
| 292 if (memcall != NULL && CanCauseGC(memcall->getImplicitObjectArgument())) { | 999 } |
| 293 gc_.set(0); | 1000 |
| 294 } | 1001 DECL_VISIT_STMT(DoStmt) { |
| 295 | 1002 Block block (env, this); |
| 296 for (unsigned arg = 0; arg < call->getNumArgs(); arg++) { | 1003 do { |
| 297 if (CanCauseGC(call->getArg(arg))) gc_.set(arg + 1); | 1004 block.Loop(stmt->getBody(), stmt->getCond()); |
| 298 } | 1005 } while (block.changed()); |
| 1006 return block.out(); | |
| 1007 } | |
| 1008 | |
| 1009 DECL_VISIT_STMT(ForStmt) { | |
| 1010 Block block (VisitStmt(stmt->getInit(), env), this); | |
| 1011 do { | |
| 1012 block.Loop(stmt->getCond(), | |
|
Mads Ager (chromium)
2011/05/16 06:10:27
Shouldn't this be Loop(Cond, Body, Inc)?
| |
| 1013 stmt->getInc(), | |
| 1014 stmt->getBody()); | |
| 1015 } while (block.changed()); | |
| 1016 return block.out(); | |
| 1017 } | |
| 1018 | |
| 1019 DECL_VISIT_STMT(IfStmt) { | |
| 1020 Environment cond_out = VisitStmt(stmt->getCond(), env); | |
| 1021 Environment then_out = VisitStmt(stmt->getThen(), cond_out); | |
| 1022 Environment else_out = VisitStmt(stmt->getElse(), cond_out); | |
| 1023 return Environment::Merge(then_out, else_out); | |
| 1024 } | |
| 1025 | |
| 1026 DECL_VISIT_STMT(SwitchStmt) { | |
| 1027 Block block (env, this); | |
| 1028 block.Seq(stmt->getCond(), stmt->getBody()); | |
| 1029 return block.out(); | |
| 1030 } | |
| 1031 | |
| 1032 DECL_VISIT_STMT(CaseStmt) { | |
| 1033 Environment in = Environment::Merge(env, block_->in()); | |
| 1034 Environment after_lhs = VisitStmt(stmt->getLHS(), in); | |
| 1035 return VisitStmt(stmt->getSubStmt(), after_lhs); | |
| 1036 } | |
| 1037 | |
| 1038 DECL_VISIT_STMT(DefaultStmt) { | |
| 1039 Environment in = Environment::Merge(env, block_->in()); | |
| 1040 return VisitStmt(stmt->getSubStmt(), in); | |
| 1041 } | |
| 1042 | |
| 1043 DECL_VISIT_STMT(ReturnStmt) { | |
| 1044 VisitExpr(stmt->getRetValue(), env); | |
| 1045 return Environment::Unreachable(); | |
| 299 } | 1046 } |
| 300 | 1047 |
| 301 const clang::TagType* ToTagType(const clang::Type* t) { | 1048 const clang::TagType* ToTagType(const clang::Type* t) { |
| 302 if (t == NULL) { | 1049 if (t == NULL) { |
| 303 return NULL; | 1050 return NULL; |
| 304 } else if (isa<clang::TagType>(t)) { | 1051 } else if (isa<clang::TagType>(t)) { |
| 305 return cast<clang::TagType>(t); | 1052 return cast<clang::TagType>(t); |
| 306 } else if (isa<clang::SubstTemplateTypeParmType>(t)) { | 1053 } else if (isa<clang::SubstTemplateTypeParmType>(t)) { |
| 307 return ToTagType(cast<clang::SubstTemplateTypeParmType>(t)-> | 1054 return ToTagType(cast<clang::SubstTemplateTypeParmType>(t)-> |
| 308 getReplacementType().getTypePtr()); | 1055 getReplacementType().getTypePtr()); |
| 309 } else { | 1056 } else { |
| 310 return NULL; | 1057 return NULL; |
| 311 } | 1058 } |
| 312 } | 1059 } |
| 313 | 1060 |
| 314 bool IsRawPointerType(clang::Expr* expr) { | 1061 bool IsDerivedFrom(clang::CXXRecordDecl* record, |
| 315 clang::QualType result = expr->getType(); | 1062 clang::CXXRecordDecl* base) { |
| 1063 return (record == base) || record->isDerivedFrom(base); | |
| 1064 } | |
| 316 | 1065 |
| 1066 bool IsRawPointerType(clang::QualType qtype) { | |
| 317 const clang::PointerType* type = | 1067 const clang::PointerType* type = |
| 318 dyn_cast_or_null<clang::PointerType>(expr->getType().getTypePtr()); | 1068 dyn_cast_or_null<clang::PointerType>(qtype.getTypePtrOrNull()); |
| 319 if (type == NULL) return false; | 1069 if (type == NULL) return false; |
| 320 | 1070 |
| 321 const clang::TagType* pointee = | 1071 const clang::TagType* pointee = |
| 322 ToTagType(type->getPointeeType().getTypePtr()); | 1072 ToTagType(type->getPointeeType().getTypePtr()); |
| 323 if (pointee == NULL) return false; | 1073 if (pointee == NULL) return false; |
| 324 | 1074 |
| 325 clang::CXXRecordDecl* record = | 1075 clang::CXXRecordDecl* record = |
| 326 dyn_cast_or_null<clang::CXXRecordDecl>(pointee->getDecl()); | 1076 dyn_cast_or_null<clang::CXXRecordDecl>(pointee->getDecl()); |
| 327 if (record == NULL) return false; | 1077 if (record == NULL) return false; |
| 328 | 1078 |
| 329 return InV8Namespace(record) && | 1079 if (!InV8Namespace(record)) return false; |
| 330 record->hasDefinition() && | 1080 |
| 331 ((record == objectDecl_) || record->isDerivedFrom(objectDecl_)); | 1081 if (!record->hasDefinition()) return false; |
| 1082 | |
| 1083 record = record->getDefinition(); | |
| 1084 | |
| 1085 return IsDerivedFrom(record, objectDecl_) && | |
| 1086 !IsDerivedFrom(record, smiDecl_); | |
| 332 } | 1087 } |
| 333 | 1088 |
| 334 bool IsHandleDereference(clang::Expr* expr) { | 1089 Environment VisitDecl(clang::Decl* decl, const Environment& env) { |
| 335 if (expr == NULL) { | 1090 if (clang::VarDecl* var = dyn_cast<clang::VarDecl>(decl)) { |
| 336 return false; | 1091 Environment out = var->hasInit() ? VisitStmt(var->getInit(), env) : env; |
| 337 } else if (isa<clang::UnaryOperator>(expr)) { | 1092 |
| 338 clang::UnaryOperator* unop = cast<clang::UnaryOperator>(expr); | 1093 if (IsRawPointerType(var->getType())) { |
| 339 return unop->getOpcode() == clang::UO_Deref && | 1094 out = out.Define(var->getNameAsString()); |
| 340 IsHandleType(handleDeclName_, unop->getSubExpr()->getType()); | 1095 } |
| 341 } else if (isa<clang::CXXOperatorCallExpr>(expr)) { | 1096 |
| 342 clang::CXXOperatorCallExpr* op = cast<clang::CXXOperatorCallExpr>(expr); | 1097 return out; |
| 343 return (op->getOperator() == clang::OO_Star || | 1098 } |
| 344 op->getOperator() == clang::OO_Arrow) && | 1099 // TODO: handle other declarations? |
| 345 IsHandleType(handleDeclName_, op->getArg(0)->getType()); | 1100 return env; |
| 346 } else { | 1101 } |
| 347 return false; | 1102 |
| 1103 DECL_VISIT_STMT(DeclStmt) { | |
| 1104 Environment out = env; | |
| 1105 for (clang::DeclStmt::decl_iterator decl = stmt->decl_begin(), | |
| 1106 end = stmt->decl_end(); | |
| 1107 decl != end; | |
| 1108 ++decl) { | |
| 1109 out = VisitDecl(*decl, out); | |
| 1110 } | |
| 1111 return out; | |
| 1112 } | |
| 1113 | |
| 1114 | |
| 1115 void DefineParameters(const clang::FunctionDecl* f, | |
| 1116 Environment* env) { | |
| 1117 env->MDefine(THIS); | |
| 1118 for (clang::FunctionDecl::param_const_iterator p = f->param_begin(), | |
| 1119 end = f->param_end(); | |
| 1120 p != end; | |
| 1121 ++p) { | |
| 1122 env->MDefine((*p)->getNameAsString()); | |
| 348 } | 1123 } |
| 349 } | 1124 } |
| 350 | 1125 |
| 351 bool CanCauseGC(clang::Expr* expr) { | |
| 352 if (expr == NULL) return false; | |
| 353 | 1126 |
| 354 has_gc_ = false; | 1127 void AnalyzeFunction(const clang::FunctionDecl* f) { |
| 355 has_derefs_ = true; | 1128 const clang::FunctionDecl* body = NULL; |
| 356 TraverseStmt(expr); | 1129 if (f->hasBody(body)) { |
| 357 return has_gc_; | 1130 Environment env; |
| 1131 DefineParameters(body, &env); | |
| 1132 VisitStmt(body->getBody(), env); | |
| 1133 Environment::ClearSymbolTable(); | |
| 1134 } | |
| 358 } | 1135 } |
| 359 | 1136 |
| 360 bool ManipulatesRawPointers(clang::Expr* expr) { | 1137 Block* EnterBlock(Block* block) { |
| 361 if (expr == NULL) return false; | 1138 Block* parent = block_; |
| 362 | 1139 block_ = block; |
| 363 has_gc_ = true; | 1140 return parent; |
| 364 has_derefs_ = false; | |
| 365 TraverseStmt(expr); | |
| 366 return has_derefs_; | |
| 367 } | 1141 } |
| 368 | 1142 |
| 369 bool CanCauseGC(const clang::CallExpr* call) { | 1143 void LeaveBlock(Block* block) { |
| 370 const clang::FunctionDecl* fn = call->getDirectCallee(); | 1144 block_ = block; |
| 371 return (fn != NULL) && KnownToCauseGC(ctx_, fn); | |
| 372 } | 1145 } |
| 373 | 1146 |
| 374 // For generic expression classification. | 1147 private: |
| 375 bool has_derefs_; | 1148 void ReportUnsafe(const clang::Expr* expr, const std::string& msg) { |
| 376 bool has_gc_; | 1149 d_.Report(clang::FullSourceLoc(expr->getExprLoc(), sm_), |
| 1150 d_.getCustomDiagID(clang::Diagnostic::Warning, msg)); | |
| 1151 } | |
| 377 | 1152 |
| 378 // For callsite classification. | |
| 379 static const int kMaxNumberOfArguments = 64; | |
| 380 std::bitset<kMaxNumberOfArguments> derefs_; | |
| 381 std::bitset<kMaxNumberOfArguments> gc_; | |
| 382 | 1153 |
| 1154 clang::MangleContext* ctx_; | |
| 383 clang::DeclarationName handleDeclName_; | 1155 clang::DeclarationName handleDeclName_; |
| 384 clang::MangleContext* ctx_; | |
| 385 clang::CXXRecordDecl* objectDecl_; | 1156 clang::CXXRecordDecl* objectDecl_; |
| 1157 clang::CXXRecordDecl* smiDecl_; | |
| 1158 | |
| 1159 clang::Diagnostic& d_; | |
| 1160 clang::SourceManager& sm_; | |
| 1161 | |
| 1162 Block* block_; | |
| 1163 bool dead_vars_analysis_; | |
| 386 }; | 1164 }; |
| 387 | 1165 |
| 388 const std::string BAD_EXPRESSION_MSG("Possible problem with evaluation order."); | |
| 389 | 1166 |
| 390 class ExpressionsFinder : public clang::ASTConsumer, | 1167 class ProblemsFinder : public clang::ASTConsumer, |
| 391 public clang::RecursiveASTVisitor<ExpressionsFinder> { | 1168 public clang::RecursiveASTVisitor<ProblemsFinder> { |
| 392 public: | 1169 public: |
| 393 explicit ExpressionsFinder(clang::Diagnostic& d, clang::SourceManager& sm) | 1170 ProblemsFinder(clang::Diagnostic& d, |
| 394 : d_(d), sm_(sm) { } | 1171 clang::SourceManager& sm, |
| 395 | 1172 const std::vector<std::string>& args) |
| 396 struct Resolver { | 1173 : d_(d), sm_(sm), dead_vars_analysis_(false) { |
| 397 explicit Resolver(clang::ASTContext& ctx) | 1174 for (unsigned i = 0; i < args.size(); ++i) { |
| 398 : ctx_(ctx), decl_ctx_(ctx.getTranslationUnitDecl()) { | 1175 if (args[i] == "--dead-vars") { |
| 1176 dead_vars_analysis_ = true; | |
| 1177 } | |
| 399 } | 1178 } |
| 400 | 1179 } |
| 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 | 1180 |
| 436 virtual void HandleTranslationUnit(clang::ASTContext &ctx) { | 1181 virtual void HandleTranslationUnit(clang::ASTContext &ctx) { |
| 437 Resolver r(ctx); | 1182 Resolver r(ctx); |
| 438 | 1183 |
| 439 clang::CXXRecordDecl* objectDecl = | 1184 clang::CXXRecordDecl* objectDecl = |
| 440 r.ResolveNamespace("v8").ResolveNamespace("internal"). | 1185 r.ResolveNamespace("v8").ResolveNamespace("internal"). |
| 441 Resolve<clang::CXXRecordDecl>("Object"); | 1186 Resolve<clang::CXXRecordDecl>("Object"); |
| 442 | 1187 |
| 443 if (objectDecl != NULL) { | 1188 clang::CXXRecordDecl* smiDecl = |
|
Mads Ager (chromium)
2011/05/16 06:10:27
Why the switch in naming conventions? smi_decl and
| |
| 444 expression_classifier_ = | 1189 r.ResolveNamespace("v8").ResolveNamespace("internal"). |
| 445 new ExpressionClassifier(r.ResolveName("Handle"), | 1190 Resolve<clang::CXXRecordDecl>("Smi"); |
| 446 clang::createItaniumMangleContext(ctx, d_), | 1191 |
| 447 objectDecl); | 1192 if (objectDecl != NULL) objectDecl = objectDecl->getDefinition(); |
| 1193 | |
| 1194 if (smiDecl != NULL) smiDecl = smiDecl->getDefinition(); | |
| 1195 | |
| 1196 if (objectDecl != NULL && smiDecl != NULL) { | |
| 1197 function_analyzer_ = | |
| 1198 new FunctionAnalyzer(clang::createItaniumMangleContext(ctx, d_), | |
| 1199 r.ResolveName("Handle"), | |
| 1200 objectDecl, | |
| 1201 smiDecl, | |
| 1202 d_, | |
| 1203 sm_, | |
| 1204 dead_vars_analysis_); | |
| 448 TraverseDecl(ctx.getTranslationUnitDecl()); | 1205 TraverseDecl(ctx.getTranslationUnitDecl()); |
| 449 } else { | 1206 } else { |
| 450 std::cerr << "Failed to resolve v8::internal::Object" << std::endl; | 1207 if (objectDecl == NULL) { |
| 1208 std::cerr << "Failed to resolve v8::internal::Object" << std::endl; | |
| 1209 } | |
| 1210 if (smiDecl == NULL) { | |
| 1211 std::cerr << "Failed to resolve v8::internal::Smi" << std::endl; | |
| 1212 } | |
| 451 } | 1213 } |
| 452 } | 1214 } |
| 453 | 1215 |
| 454 virtual bool VisitExpr(clang::Expr* expr) { | 1216 virtual bool VisitFunctionDecl(clang::FunctionDecl* decl) { |
| 455 if ( expression_classifier_->IsBadCallSite(expr) ) { | 1217 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; | 1218 return true; |
| 462 } | 1219 } |
| 463 | 1220 |
| 464 private: | 1221 private: |
| 465 clang::Diagnostic& d_; | 1222 clang::Diagnostic& d_; |
| 466 clang::SourceManager& sm_; | 1223 clang::SourceManager& sm_; |
| 1224 bool dead_vars_analysis_; | |
| 467 | 1225 |
| 468 ExpressionClassifier* expression_classifier_; | 1226 FunctionAnalyzer* function_analyzer_; |
| 469 }; | 1227 }; |
| 470 | 1228 |
| 471 | 1229 |
| 472 template<typename ConsumerType> | 1230 template<typename ConsumerType> |
| 473 class Action : public clang::PluginASTAction { | 1231 class Action : public clang::PluginASTAction { |
| 474 protected: | 1232 protected: |
| 475 clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &CI, | 1233 clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &CI, |
| 476 llvm::StringRef InFile) { | 1234 llvm::StringRef InFile) { |
| 477 return new ConsumerType(CI.getDiagnostics(), CI.getSourceManager()); | 1235 return new ConsumerType(CI.getDiagnostics(), CI.getSourceManager(), args_); |
| 478 } | 1236 } |
| 479 | 1237 |
| 480 bool ParseArgs(const clang::CompilerInstance &CI, | 1238 bool ParseArgs(const clang::CompilerInstance &CI, |
| 481 const std::vector<std::string>& args) { | 1239 const std::vector<std::string>& args) { |
| 1240 args_ = args; | |
| 482 return true; | 1241 return true; |
| 483 } | 1242 } |
| 484 | 1243 |
| 485 void PrintHelp(llvm::raw_ostream& ros) { } | 1244 void PrintHelp(llvm::raw_ostream& ros) { |
| 1245 } | |
| 1246 private: | |
| 1247 std::vector<std::string> args_; | |
| 486 }; | 1248 }; |
| 487 | 1249 |
| 488 | 1250 |
| 489 } | 1251 } |
| 490 | 1252 |
| 491 static clang::FrontendPluginRegistry::Add<Action<ExpressionsFinder> > | 1253 static clang::FrontendPluginRegistry::Add<Action<ProblemsFinder> > |
| 492 FindProblems("find-problems", "Find possible problems with evaluations order."); | 1254 FindProblems("find-problems", "Find GC-unsafe places."); |
| 493 | 1255 |
| 494 static clang::FrontendPluginRegistry::Add<Action<FunctionDeclarationFinder> > | 1256 static clang::FrontendPluginRegistry::Add< |
| 1257 Action<FunctionDeclarationFinder> > | |
| 495 DumpCallees("dump-callees", "Dump callees for each function."); | 1258 DumpCallees("dump-callees", "Dump callees for each function."); |
| OLD | NEW |