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

Unified Diff: tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp

Issue 430213003: Blink GC plugin: Require that fields are actually traced by the visitor and identify tracing of dep… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tools/clang/blink_gc_plugin/Config.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
index 43fbcf83d5fe1ab6bb1e45edf5b44f7e3c970300..9504eecc2e38fd3ef043d161260922893fd6d7f2 100644
--- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
+++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
@@ -307,70 +307,175 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info)
: trace_(trace), info_(info) {}
- // Allow recursive traversal by using VisitMemberExpr.
bool VisitMemberExpr(MemberExpr* member) {
- // If this member expression references a field decl, mark it as traced.
- if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) {
- if (IsTemplateInstantiation(info_->record())) {
- // Pointer equality on fields does not work for template instantiations.
- // The trace method refers to fields of the template definition which
- // are different from the instantiated fields that need to be traced.
- const string& name = field->getNameAsString();
+ // In weak callbacks, consider any occurrence as a correct usage.
+ // TODO: We really want to require that isAlive is checked on manually
+ // processed weak fields.
+ if (IsWeakCallback()) {
+ if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl()))
+ FoundField(field);
+ }
+ return true;
+ }
+
+ bool VisitCallExpr(CallExpr* call) {
+ // In weak callbacks we don't check calls (see VisitMemberExpr).
+ if (IsWeakCallback())
+ return true;
+
+ // A tracing call will have either a |visitor| or a |m_field| argument.
+ // A registerWeakMembers call will have a |this| argument.
+ if (call->getNumArgs() != 1)
+ return true;
+
+ Expr* callee = call->getCallee();
+ Expr* arg = call->getArg(0);
+
+ if (CXXDependentScopeMemberExpr* expr =
+ dyn_cast<CXXDependentScopeMemberExpr>(callee)) {
+ CheckCXXDependentScopeMemberExpr(expr);
+ return true;
+ }
+
+ if (UnresolvedMemberExpr* expr = dyn_cast<UnresolvedMemberExpr>(callee)) {
+ // If we find a call to registerWeakMembers which is unresolved we
+ // unsoundly consider all weak members as traced.
+ // TODO: Find out how to validate weak member tracing for unresolved call.
+ if (expr->getMemberName().getAsString() == kRegisterWeakMembersName) {
for (RecordInfo::Fields::iterator it = info_->GetFields().begin();
it != info_->GetFields().end();
++it) {
- if (it->first->getNameAsString() == name) {
- MarkTraced(it);
- break;
- }
+ if (it->second.edge()->IsWeakMember())
+ it->second.MarkTraced();
}
- } else {
- RecordInfo::Fields::iterator it = info_->GetFields().find(field);
- if (it != info_->GetFields().end())
- MarkTraced(it);
}
+
+ QualType base = expr->getBaseType();
+ if (!base->isPointerType())
+ return true;
+ CXXRecordDecl* decl = base->getPointeeType()->getAsCXXRecordDecl();
+ if (decl)
+ CheckTraceFieldCall(expr->getMemberName().getAsString(), decl, arg);
return true;
}
- // If this is a weak callback function we only check field tracing.
+ if (CXXMemberCallExpr* expr = dyn_cast<CXXMemberCallExpr>(call)) {
+ if (CheckTraceFieldCall(expr) || CheckRegisterWeakMembers(expr))
+ return true;
+ }
+
+ CheckTraceBaseCall(call);
+ return true;
+ }
+
+ private:
+
+ // Trace calls from a templated derived class to its templated super class
+ // result in a DependentScopeMemberExpr because the concrete class depends on
+ // the instantiation of any shared template parameters. In this case we
+ // compare the type names.
+ void CheckCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr* member) {
if (IsWeakCallback())
- return true;
+ return;
- // For method calls, check tracing of bases and other special GC methods.
- if (CXXMethodDecl* fn = dyn_cast<CXXMethodDecl>(member->getMemberDecl())) {
- const string& name = fn->getNameAsString();
- // Check weak callbacks.
- if (name == kRegisterWeakMembersName) {
- if (fn->isTemplateInstantiation()) {
- const TemplateArgumentList& args =
- *fn->getTemplateSpecializationInfo()->TemplateArguments;
- // The second template argument is the callback method.
- if (args.size() > 1 &&
- args[1].getKind() == TemplateArgument::Declaration) {
- if (FunctionDecl* callback =
- dyn_cast<FunctionDecl>(args[1].getAsDecl())) {
- if (callback->hasBody()) {
- CheckTraceVisitor nested_visitor(info_);
- nested_visitor.TraverseStmt(callback->getBody());
- }
- }
- }
- }
- return true;
- }
+ // It is unknown if the member resolves to a method so we string compare.
haraken 2014/07/31 15:37:11 we string compare => we compare strings
+ if (member->getMember().getAsString() != trace_->getName())
+ return;
+
+ NestedNameSpecifier* qual = member->getQualifier();
+ if (!qual)
+ return;
+
+ const Type* type = qual->getAsType();
+ if (!type)
+ return;
+
+ const TemplateSpecializationType* tmpl_type =
+ type->getAs<TemplateSpecializationType>();
+ if (!tmpl_type)
+ return;
+
+ TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl();
+ if (!tmpl_decl)
+ return;
+
+ CXXRecordDecl* rec = dyn_cast<CXXRecordDecl>(tmpl_decl->getTemplatedDecl());
+ if (!rec)
+ return;
+
+ RecordInfo::Bases::iterator it;
+ for (it = info_->GetBases().begin(); it != info_->GetBases().end(); ++it) {
+ if (it->first->getName() == rec->getName())
+ it->second.MarkTraced();
+ }
+ }
+
+ bool CheckTraceBaseCall(CallExpr* call) {
+ MemberExpr* callee = dyn_cast<MemberExpr>(call->getCallee());
+ if (!callee)
+ return false;
+
+ FunctionDecl* fn = dyn_cast<FunctionDecl>(callee->getMemberDecl());
+ if (!fn || !Config::IsTraceMethod(fn))
+ return false;
+
+ // Currently, a manually dispatched class cannot have mixin bases (having
+ // one would add a vtable which we explicitly check against). This means
+ // that we can only make calls to a trace method of the same name. Revisit
+ // this if our mixin/vtable assumption changes.
+ if (fn->getName() != trace_->getName())
+ return false;
+
+ CXXRecordDecl* decl = 0;
+ if (callee && callee->hasQualifier()) {
+ if (const Type* type = callee->getQualifier()->getAsType())
+ decl = type->getAsCXXRecordDecl();
+ }
+ if (!decl)
+ return false;
+
+ RecordInfo::Bases::iterator it = info_->GetBases().find(decl);
+ if (it != info_->GetBases().end()) {
+ it->second.MarkTraced();
+ }
+
+ return true;
+ }
+
+ bool CheckTraceFieldCall(CXXMemberCallExpr* call) {
+ return CheckTraceFieldCall(call->getMethodDecl()->getNameAsString(),
+ call->getRecordDecl(),
+ call->getArg(0));
+ }
+
+ bool CheckTraceFieldCall(string name, CXXRecordDecl* callee, Expr* arg) {
+ if (name != kTraceName || !Config::IsVisitor(callee->getName()))
+ return false;
- // Currently, a manually dispatched class cannot have mixin bases (having
- // one would add a vtable which we explicitly check against). This means
- // that we can only make calls to a trace method of the same name. Revisit
- // this if our mixin/vtable assumption changes.
- if (Config::IsTraceMethod(fn) &&
- fn->getName() == trace_->getName() &&
- member->hasQualifier()) {
- if (const Type* type = member->getQualifier()->getAsType()) {
- if (CXXRecordDecl* decl = type->getAsCXXRecordDecl()) {
- RecordInfo::Bases::iterator it = info_->GetBases().find(decl);
- if (it != info_->GetBases().end())
- it->second.MarkTraced();
+ FindFieldVisitor finder;
+ finder.TraverseStmt(arg);
+ if (finder.field())
+ FoundField(finder.field());
+
+ return true;
+ }
+
+ bool CheckRegisterWeakMembers(CXXMemberCallExpr* call) {
+ CXXMethodDecl* fn = call->getMethodDecl();
+ if (fn->getName() != kRegisterWeakMembersName)
+ return false;
+
+ if (fn->isTemplateInstantiation()) {
+ const TemplateArgumentList& args =
+ *fn->getTemplateSpecializationInfo()->TemplateArguments;
+ // The second template argument is the callback method.
+ if (args.size() > 1 &&
+ args[1].getKind() == TemplateArgument::Declaration) {
+ if (FunctionDecl* callback =
+ dyn_cast<FunctionDecl>(args[1].getAsDecl())) {
+ if (callback->hasBody()) {
+ CheckTraceVisitor nested_visitor(info_);
+ nested_visitor.TraverseStmt(callback->getBody());
}
}
}
@@ -378,7 +483,24 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
return true;
}
- private:
+ class FindFieldVisitor : public RecursiveASTVisitor<FindFieldVisitor> {
+ public:
+ FindFieldVisitor() : member_(0), field_(0) {}
+ MemberExpr* member() const { return member_; }
+ FieldDecl* field() const { return field_; }
+ bool TraverseMemberExpr(MemberExpr* member) {
+ if (FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl())) {
+ member_ = member;
+ field_ = field;
+ return false;
+ }
+ return true;
+ }
+ private:
+ MemberExpr* member_;
+ FieldDecl* field_;
+ };
+
// Nested checking for weak callbacks.
CheckTraceVisitor(RecordInfo* info) : trace_(0), info_(info) {}
@@ -391,6 +513,27 @@ class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
it->second.MarkTraced();
}
+ void FoundField(FieldDecl* field) {
+ if (IsTemplateInstantiation(info_->record())) {
+ // Pointer equality on fields does not work for template instantiations.
+ // The trace method refers to fields of the template definition which
+ // are different from the instantiated fields that need to be traced.
+ const string& name = field->getNameAsString();
+ for (RecordInfo::Fields::iterator it = info_->GetFields().begin();
+ it != info_->GetFields().end();
+ ++it) {
+ if (it->first->getNameAsString() == name) {
+ MarkTraced(it);
+ break;
+ }
+ }
+ } else {
+ RecordInfo::Fields::iterator it = info_->GetFields().find(field);
+ if (it != info_->GetFields().end())
+ MarkTraced(it);
+ }
+ }
+
CXXMethodDecl* trace_;
RecordInfo* info_;
};
@@ -574,8 +717,7 @@ class BlinkGCPluginConsumer : public ASTConsumer {
options_(options),
json_(0) {
- // Only check structures in the blink, blink and WebKit namespaces.
- options_.checked_namespaces.insert("blink");
+ // Only check structures in the blink and WebKit namespaces.
options_.checked_namespaces.insert("blink");
options_.checked_namespaces.insert("WebKit");
« no previous file with comments | « no previous file | tools/clang/blink_gc_plugin/Config.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698