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 |