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

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

Issue 6812002: Add GCMole to the repository. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 // This is clang plugin used by gcmole tool. See README for more details.
29
30 #include "clang/AST/AST.h"
31 #include "clang/AST/ASTConsumer.h"
32 #include "clang/AST/Mangle.h"
33 #include "clang/AST/RecursiveASTVisitor.h"
34 #include "clang/AST/StmtVisitor.h"
35 #include "clang/Frontend/FrontendPluginRegistry.h"
36 #include "clang/Frontend/CompilerInstance.h"
37 #include "llvm/Support/raw_ostream.h"
38
39 #include <bitset>
40 #include <fstream>
41 #include <iostream>
42 #include <map>
43 #include <set>
44 #include <stack>
45
46 namespace {
47
48 typedef std::string MangledName;
49 typedef std::set<MangledName> CalleesSet;
50
51 static bool GetMangledName(clang::MangleContext* ctx,
52 const clang::NamedDecl* decl,
53 MangledName* result) {
54 if (!isa<clang::CXXConstructorDecl>(decl) &&
55 !isa<clang::CXXDestructorDecl>(decl)) {
56 llvm::SmallVector<char, 512> output;
57 llvm::raw_svector_ostream out(output);
58 ctx->mangleName(decl, out);
59 *result = out.str().str();
60 return true;
61 }
62
63 return false;
64 }
65
66
67 static bool InV8Namespace(const clang::NamedDecl* decl) {
68 return decl->getQualifiedNameAsString().compare(0, 4, "v8::") == 0;
69 }
70
71
72 class CalleesPrinter : public clang::RecursiveASTVisitor<CalleesPrinter> {
73 public:
74 explicit CalleesPrinter(clang::MangleContext* ctx) : ctx_(ctx) {
75 }
76
77 virtual bool VisitCallExpr(clang::CallExpr* expr) {
78 const clang::FunctionDecl* callee = expr->getDirectCallee();
79 if (callee != NULL) AnalyzeFunction(callee);
80 return true;
81 }
82
83 void AnalyzeFunction(const clang::FunctionDecl* f) {
84 MangledName name;
85 if (InV8Namespace(f) && GetMangledName(ctx_, f, &name)) {
86 AddCallee(name);
87
88 const clang::FunctionDecl* body = NULL;
89 if (f->hasBody(body) && !Analyzed(name)) {
90 EnterScope(name);
91 TraverseStmt(body->getBody());
92 LeaveScope();
93 }
94 }
95 }
96
97 typedef std::map<MangledName, CalleesSet* > Callgraph;
98
99 bool Analyzed(const MangledName& name) {
100 return callgraph_[name] != NULL;
101 }
102
103 void EnterScope(const MangledName& name) {
104 CalleesSet* callees = callgraph_[name];
105
106 if (callees == NULL) {
107 callgraph_[name] = callees = new CalleesSet();
108 }
109
110 scopes_.push(callees);
111 }
112
113 void LeaveScope() {
114 scopes_.pop();
115 }
116
117 void AddCallee(const MangledName& name) {
118 if (!scopes_.empty()) scopes_.top()->insert(name);
119 }
120
121 void PrintCallGraph() {
122 for (Callgraph::const_iterator i = callgraph_.begin(), e = callgraph_.end();
123 i != e;
124 ++i) {
125 std::cout << i->first << "\n";
126
127 CalleesSet* callees = i->second;
128 for (CalleesSet::const_iterator j = callees->begin(), e = callees->end();
129 j != e;
130 ++j) {
131 std::cout << "\t" << *j << "\n";
132 }
133 }
134 }
135
136 private:
137 clang::MangleContext* ctx_;
138
139 std::stack<CalleesSet* > scopes_;
140 Callgraph callgraph_;
141 };
142
143 class FunctionDeclarationFinder
144 : public clang::ASTConsumer,
145 public clang::RecursiveASTVisitor<FunctionDeclarationFinder> {
146 public:
147 explicit FunctionDeclarationFinder(clang::Diagnostic& d,
148 clang::SourceManager& sm)
149 : d_(d), sm_(sm) { }
150
151 virtual void HandleTranslationUnit(clang::ASTContext &ctx) {
152 mangle_context_ = clang::createItaniumMangleContext(ctx, d_);
153 callees_printer_ = new CalleesPrinter(mangle_context_);
154
155 TraverseDecl(ctx.getTranslationUnitDecl());
156
157 callees_printer_->PrintCallGraph();
158 }
159
160 virtual bool VisitFunctionDecl(clang::FunctionDecl* decl) {
161 callees_printer_->AnalyzeFunction(decl);
162 return true;
163 }
164
165 private:
166 clang::Diagnostic& d_;
167 clang::SourceManager& sm_;
168 clang::MangleContext* mangle_context_;
169
170 CalleesPrinter* callees_printer_;
171 };
172
173
174 static bool loaded = false;
175 static CalleesSet gc_suspects;
176
177
178 static void LoadGCSuspects() {
179 if (loaded) return;
180
181 std::ifstream fin("gcsuspects");
182 std::string s;
183
184 while (fin >> s) gc_suspects.insert(s);
185
186 loaded = true;
187 }
188
189
190 static bool KnownToCauseGC(clang::MangleContext* ctx,
191 const clang::FunctionDecl* decl) {
192 LoadGCSuspects();
193
194 if (!InV8Namespace(decl)) return false;
195
196 MangledName name;
197 if (GetMangledName(ctx, decl, &name)) {
198 return gc_suspects.find(name) != gc_suspects.end();
199 }
200
201 return false;
202 }
203
204 static bool IsHandleType(const clang::DeclarationName& handleDeclName,
205 const clang::QualType& qtype) {
206 const clang::Type* canonical_type =
207 qtype.getTypePtr()->getCanonicalTypeUnqualified().getTypePtr();
208
209 if (const clang::TemplateSpecializationType* type =
210 canonical_type->getAs<clang::TemplateSpecializationType>()) {
211 if (clang::TemplateDecl* decl =
212 type->getTemplateName().getAsTemplateDecl()) {
213 if (decl->getTemplatedDecl()->getDeclName() == handleDeclName) return true ;
Søren Thygesen Gjesse 2011/04/07 08:20:28 Long line.
214 }
215 } else if (const clang::RecordType* type =
216 canonical_type->getAs<clang::RecordType>()) {
217 if (const clang::ClassTemplateSpecializationDecl* t =
218 dyn_cast<clang::ClassTemplateSpecializationDecl>(type->getDecl())) {
219 if (t->getSpecializedTemplate()->getDeclName() == handleDeclName) {
220 return true;
221 }
222 }
223 }
224
225 return false;
226 }
227
228
229 class ExpressionClassifier :
230 public clang::RecursiveASTVisitor<ExpressionClassifier> {
231 public:
232 ExpressionClassifier(clang::DeclarationName handleDeclName,
233 clang::MangleContext* ctx,
234 clang::CXXRecordDecl* objectDecl)
235 : handleDeclName_(handleDeclName),
236 ctx_(ctx),
237 objectDecl_(objectDecl) {
238 }
239
240 bool IsBadExpression(clang::Expr* expr) {
241 has_derefs_ = has_gc_ = false;
242 TraverseStmt(expr);
243 return has_derefs_ && has_gc_;
244 }
245
246 bool IsBadCallSite(clang::Expr* expr) {
247 if (isa<clang::CallExpr>(expr)) {
248 clang::CallExpr* call = cast<clang::CallExpr>(expr);
249
250 MarkGCSuspectAsArgument(call);
251 MarkHandleDereferenceAsArgument(call);
252
253 return derefs_.any() &&
254 ((gc_.count() > 1) || (gc_.any() && (gc_ ^ derefs_).any()));
255 }
256 return false;
257 }
258
259 virtual bool VisitExpr(clang::Expr* expr) {
260 has_derefs_ = has_derefs_ || IsRawPointerType(expr);
261 return !has_gc_ || !has_derefs_;
262 }
263
264 virtual bool VisitCallExpr(clang::CallExpr* expr) {
265 has_gc_ = has_gc_ || CanCauseGC(expr);
266 return !has_gc_ || !has_derefs_;
267 }
268 private:
269 void MarkHandleDereferenceAsArgument(clang::CallExpr* call) {
270 derefs_.reset();
271
272 if (clang::CXXMemberCallExpr* memcall =
273 dyn_cast<clang::CXXMemberCallExpr>(call)) {
274 if (ManipulatesRawPointers(memcall->getImplicitObjectArgument())) {
275 derefs_.set(0);
276 }
277 }
278
279 for (unsigned arg = 0; arg < call->getNumArgs(); arg++) {
280 if (ManipulatesRawPointers(call->getArg(arg))) derefs_.set(arg + 1);
281 }
282 }
283
284 void MarkGCSuspectAsArgument(clang::CallExpr* call) {
285 gc_.reset();
286
287 clang::CXXMemberCallExpr* memcall =
288 dyn_cast_or_null<clang::CXXMemberCallExpr>(call);
289 if (memcall != NULL && CanCauseGC(memcall->getImplicitObjectArgument())) {
290 gc_.set(0);
291 }
292
293 for (unsigned arg = 0; arg < call->getNumArgs(); arg++) {
294 if (CanCauseGC(call->getArg(arg))) gc_.set(arg + 1);
295 }
296 }
297
298 const clang::TagType* ToTagType(const clang::Type* t) {
299 if (t == NULL) {
300 return NULL;
301 } else if (isa<clang::TagType>(t)) {
302 return cast<clang::TagType>(t);
303 } else if (isa<clang::SubstTemplateTypeParmType>(t)) {
304 return ToTagType(cast<clang::SubstTemplateTypeParmType>(t)->
305 getReplacementType().getTypePtr());
306 } else {
307 return NULL;
308 }
309 }
310
311 bool IsRawPointerType(clang::Expr* expr) {
312 clang::QualType result = expr->getType();
313
314 const clang::PointerType* type =
315 dyn_cast_or_null<clang::PointerType>(expr->getType().getTypePtr());
316 if (type == NULL) return false;
317
318 const clang::TagType* pointee =
319 ToTagType(type->getPointeeType().getTypePtr());
320 if (pointee == NULL) return false;
321
322 clang::CXXRecordDecl* record =
323 dyn_cast_or_null<clang::CXXRecordDecl>(pointee->getDecl());
324 if (record == NULL) return false;
325
326 return InV8Namespace(record) &&
327 record->hasDefinition() &&
328 ((record == objectDecl_) || record->isDerivedFrom(objectDecl_));
329 }
330
331 bool IsHandleDereference(clang::Expr* expr) {
332 if (expr == NULL) {
333 return false;
334 } else if (isa<clang::UnaryOperator>(expr)) {
335 clang::UnaryOperator* unop = cast<clang::UnaryOperator>(expr);
336 return unop->getOpcode() == clang::UO_Deref &&
337 IsHandleType(handleDeclName_, unop->getSubExpr()->getType());
338 } else if (isa<clang::CXXOperatorCallExpr>(expr)) {
339 clang::CXXOperatorCallExpr* op = cast<clang::CXXOperatorCallExpr>(expr);
340 return (op->getOperator() == clang::OO_Star ||
341 op->getOperator() == clang::OO_Arrow) &&
342 IsHandleType(handleDeclName_, op->getArg(0)->getType());
343 } else {
344 return false;
345 }
346 }
347
348 bool CanCauseGC(clang::Expr* expr) {
349 if (expr == NULL) return false;
350
351 has_gc_ = false;
352 has_derefs_ = true;
353 TraverseStmt(expr);
354 return has_gc_;
355 }
356
357 bool ManipulatesRawPointers(clang::Expr* expr) {
358 if (expr == NULL) return false;
359
360 has_gc_ = true;
361 has_derefs_ = false;
362 TraverseStmt(expr);
363 return has_derefs_;
364 }
365
366 bool CanCauseGC(const clang::CallExpr* call) {
367 const clang::FunctionDecl* fn = call->getDirectCallee();
368 return (fn != NULL) && KnownToCauseGC(ctx_, fn);
369 }
370
371 // For generic expression classification.
372 bool has_derefs_;
373 bool has_gc_;
374
375 // For callsite classification.
376 static const int kMaxNumberOfArguments = 64;
377 std::bitset<kMaxNumberOfArguments> derefs_;
378 std::bitset<kMaxNumberOfArguments> gc_;
379
380 clang::DeclarationName handleDeclName_;
381 clang::MangleContext* ctx_;
382 clang::CXXRecordDecl* objectDecl_;
383 };
384
385 const std::string BAD_EXPRESSION_MSG("Possible problem with evaluation order.");
386
387 class ExpressionsFinder : public clang::ASTConsumer,
388 public clang::RecursiveASTVisitor<ExpressionsFinder> {
389 public:
390 explicit ExpressionsFinder(clang::Diagnostic& d, clang::SourceManager& sm)
391 : d_(d), sm_(sm) { }
392
393 struct Resolver {
394 explicit Resolver(clang::ASTContext& ctx)
395 : ctx_(ctx), decl_ctx_(ctx.getTranslationUnitDecl()) {
396 }
397
398 Resolver(clang::ASTContext& ctx, clang::DeclContext* decl_ctx)
399 : ctx_(ctx), decl_ctx_(decl_ctx) {
400 }
401
402 clang::DeclarationName ResolveName(const char* n) {
403 clang::IdentifierInfo* ident = &ctx_.Idents.get(n);
404 return ctx_.DeclarationNames.getIdentifier(ident);
405 }
406
407 Resolver ResolveNamespace(const char* n) {
408 return Resolver(ctx_, Resolve<clang::NamespaceDecl>(n));
409 }
410
411 template<typename T>
412 T* Resolve(const char* n) {
413 if (decl_ctx_ == NULL) return NULL;
414
415 clang::DeclContext::lookup_result result =
416 decl_ctx_->lookup(ResolveName(n));
417
418 for (clang::DeclContext::lookup_iterator i = result.first,
419 e = result.second;
420 i != e;
421 i++) {
422 if (isa<T>(*i)) return cast<T>(*i);
423 }
424
425 return NULL;
426 }
427
428 private:
429 clang::ASTContext& ctx_;
430 clang::DeclContext* decl_ctx_;
431 };
432
433 virtual void HandleTranslationUnit(clang::ASTContext &ctx) {
434 Resolver r(ctx);
435
436 clang::CXXRecordDecl* objectDecl =
437 r.ResolveNamespace("v8").ResolveNamespace("internal").
438 Resolve<clang::CXXRecordDecl>("Object");
439
440 if (objectDecl != NULL) {
441 expression_classifier_ =
442 new ExpressionClassifier(r.ResolveName("Handle"),
443 clang::createItaniumMangleContext(ctx, d_),
444 objectDecl);
445 TraverseDecl(ctx.getTranslationUnitDecl());
446 } else {
447 std::cerr << "Failed to resolve v8::internal::Object" << std::endl;
448 }
449 }
450
451 virtual bool VisitExpr(clang::Expr* expr) {
452 if ( expression_classifier_->IsBadCallSite(expr) ) {
453 d_.Report(clang::FullSourceLoc(expr->getExprLoc(), sm_),
454 d_.getCustomDiagID(clang::Diagnostic::Warning,
455 BAD_EXPRESSION_MSG));
456 }
457
458 return true;
459 }
460
461 private:
462 clang::Diagnostic& d_;
463 clang::SourceManager& sm_;
464
465 ExpressionClassifier* expression_classifier_;
466 };
467
468
469 template<typename ConsumerType>
470 class Action : public clang::PluginASTAction {
471 protected:
472 clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &CI,
473 llvm::StringRef InFile) {
474 return new ConsumerType(CI.getDiagnostics(), CI.getSourceManager());
475 }
476
477 bool ParseArgs(const clang::CompilerInstance &CI,
478 const std::vector<std::string>& args) {
479 return true;
480 }
481
482 void PrintHelp(llvm::raw_ostream& ros) { }
483 };
484
485 }
486
487 static clang::FrontendPluginRegistry::Add<Action<ExpressionsFinder> >
488 FindProblems("find-problems", "Find possible problems with evaluations order.");
489
490 static clang::FrontendPluginRegistry::Add<Action<FunctionDeclarationFinder> >
491 DumpCallees("dump-callees", "Dump callees for each function.");
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698