| 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 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 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 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."); |
| OLD | NEW |