OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "Config.h" | 5 #include "Config.h" |
6 #include "RecordInfo.h" | 6 #include "RecordInfo.h" |
7 | 7 |
8 using namespace clang; | 8 using namespace clang; |
9 using std::string; | 9 using std::string; |
10 | 10 |
11 RecordInfo::RecordInfo(CXXRecordDecl* record, RecordCache* cache) | 11 RecordInfo::RecordInfo(CXXRecordDecl* record, RecordCache* cache) |
12 : cache_(cache), | 12 : cache_(cache), |
13 record_(record), | 13 record_(record), |
14 name_(record->getName()), | 14 name_(record->getName()), |
15 fields_need_tracing_(TracingStatus::Unknown()), | 15 fields_need_tracing_(TracingStatus::Unknown()), |
16 bases_(0), | 16 bases_(0), |
17 fields_(0), | 17 fields_(0), |
18 is_stack_allocated_(kNotComputed), | 18 is_stack_allocated_(kNotComputed), |
19 is_non_newable_(kNotComputed), | 19 is_non_newable_(kNotComputed), |
20 is_only_placement_newable_(kNotComputed), | 20 is_only_placement_newable_(kNotComputed), |
21 does_need_finalization_(kNotComputed), | 21 does_need_finalization_(kNotComputed), |
22 determined_trace_methods_(false), | 22 determined_trace_methods_(false), |
23 trace_method_(0), | 23 trace_method_(0), |
24 trace_dispatch_method_(0), | 24 trace_dispatch_method_(0), |
25 finalize_dispatch_method_(0), | 25 finalize_dispatch_method_(0), |
26 is_gc_derived_(false), | 26 is_gc_derived_(false) {} |
27 base_paths_(0) {} | |
28 | 27 |
29 RecordInfo::~RecordInfo() { | 28 RecordInfo::~RecordInfo() { |
30 delete fields_; | 29 delete fields_; |
31 delete bases_; | 30 delete bases_; |
32 delete base_paths_; | |
33 } | 31 } |
34 | 32 |
35 // Get |count| number of template arguments. Returns false if there | 33 // Get |count| number of template arguments. Returns false if there |
36 // are fewer than |count| arguments or any of the arguments are not | 34 // are fewer than |count| arguments or any of the arguments are not |
37 // of a valid Type structure. If |count| is non-positive, all | 35 // of a valid Type structure. If |count| is non-positive, all |
38 // arguments are collected. | 36 // arguments are collected. |
39 bool RecordInfo::GetTemplateArgs(size_t count, TemplateArgs* output_args) { | 37 bool RecordInfo::GetTemplateArgs(size_t count, TemplateArgs* output_args) { |
40 ClassTemplateSpecializationDecl* tmpl = | 38 ClassTemplateSpecializationDecl* tmpl = |
41 dyn_cast<ClassTemplateSpecializationDecl>(record_); | 39 dyn_cast<ClassTemplateSpecializationDecl>(record_); |
42 if (!tmpl) | 40 if (!tmpl) |
(...skipping 24 matching lines...) Expand all Loading... |
67 for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) { | 65 for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) { |
68 if (CXXRecordDecl* decl = (*it)->getAsCXXRecordDecl()) | 66 if (CXXRecordDecl* decl = (*it)->getAsCXXRecordDecl()) |
69 if (decl->getName() == kHeapAllocatorName) | 67 if (decl->getName() == kHeapAllocatorName) |
70 return true; | 68 return true; |
71 } | 69 } |
72 } | 70 } |
73 | 71 |
74 return Config::IsGCCollection(name_); | 72 return Config::IsGCCollection(name_); |
75 } | 73 } |
76 | 74 |
77 static bool IsGCBaseCallback(const CXXBaseSpecifier* specifier, | |
78 CXXBasePath& path, | |
79 void* data) { | |
80 if (CXXRecordDecl* record = specifier->getType()->getAsCXXRecordDecl()) | |
81 return Config::IsGCBase(record->getName()); | |
82 return false; | |
83 } | |
84 | |
85 // Test if a record is derived from a garbage collected base. | 75 // Test if a record is derived from a garbage collected base. |
86 bool RecordInfo::IsGCDerived() { | 76 bool RecordInfo::IsGCDerived() { |
87 // If already computed, return the known result. | 77 // If already computed, return the known result. |
88 if (base_paths_) | 78 if (gc_base_names_.size()) |
89 return is_gc_derived_; | 79 return is_gc_derived_; |
90 | 80 |
91 base_paths_ = new CXXBasePaths(true, true, false); | |
92 | |
93 if (!record_->hasDefinition()) | 81 if (!record_->hasDefinition()) |
94 return false; | 82 return false; |
95 | 83 |
96 // The base classes are not themselves considered garbage collected objects. | 84 // The base classes are not themselves considered garbage collected objects. |
97 if (Config::IsGCBase(name_)) | 85 if (Config::IsGCBase(name_)) |
98 return false; | 86 return false; |
99 | 87 |
100 // Walk the inheritance tree to find GC base classes. | 88 // Walk the inheritance tree to find GC base classes. |
101 is_gc_derived_ = record_->lookupInBases(IsGCBaseCallback, 0, *base_paths_); | 89 walkBases(); |
102 return is_gc_derived_; | 90 return is_gc_derived_; |
103 } | 91 } |
104 | 92 |
| 93 CXXRecordDecl* RecordInfo::GetDependentTemplatedDecl(const Type& type) { |
| 94 const TemplateSpecializationType* tmpl_type = |
| 95 type.getAs<TemplateSpecializationType>(); |
| 96 if (!tmpl_type) |
| 97 return 0; |
| 98 |
| 99 TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl(); |
| 100 if (!tmpl_decl) |
| 101 return 0; |
| 102 |
| 103 return dyn_cast_or_null<CXXRecordDecl>(tmpl_decl->getTemplatedDecl()); |
| 104 } |
| 105 |
| 106 void RecordInfo::walkBases() { |
| 107 // This traversal is akin to CXXRecordDecl::forallBases()'s, |
| 108 // but without stepping over dependent bases -- these might also |
| 109 // have a "GC base name", so are to be included and considered. |
| 110 SmallVector<const CXXRecordDecl*, 8> queue; |
| 111 |
| 112 const CXXRecordDecl *base_record = record(); |
| 113 while (true) { |
| 114 for (const auto& it : base_record->bases()) { |
| 115 const RecordType *type = it.getType()->getAs<RecordType>(); |
| 116 CXXRecordDecl* base; |
| 117 if (!type) |
| 118 base = GetDependentTemplatedDecl(*it.getType()); |
| 119 else { |
| 120 base = cast_or_null<CXXRecordDecl>(type->getDecl()->getDefinition()); |
| 121 if (base) |
| 122 queue.push_back(base); |
| 123 } |
| 124 if (!base) |
| 125 continue; |
| 126 |
| 127 const std::string& name = base->getName(); |
| 128 if (Config::IsGCBase(name)) { |
| 129 gc_base_names_.push_back(name); |
| 130 is_gc_derived_ = true; |
| 131 } |
| 132 } |
| 133 |
| 134 if (queue.empty()) |
| 135 break; |
| 136 base_record = queue.pop_back_val(); // not actually a queue. |
| 137 } |
| 138 } |
| 139 |
105 bool RecordInfo::IsGCFinalized() { | 140 bool RecordInfo::IsGCFinalized() { |
106 if (!IsGCDerived()) | 141 if (!IsGCDerived()) |
107 return false; | 142 return false; |
108 for (CXXBasePaths::paths_iterator it = base_paths_->begin(); | 143 for (const auto& gc_base : gc_base_names_) { |
109 it != base_paths_->end(); | 144 if (Config::IsGCFinalizedBase(gc_base)) |
110 ++it) { | |
111 const CXXBasePathElement& elem = (*it)[it->size() - 1]; | |
112 CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); | |
113 if (Config::IsGCFinalizedBase(base->getName())) | |
114 return true; | 145 return true; |
115 } | 146 } |
116 return false; | 147 return false; |
117 } | 148 } |
118 | 149 |
119 // A GC mixin is a class that inherits from a GC mixin base and has | 150 // A GC mixin is a class that inherits from a GC mixin base and has |
120 // not yet been "mixed in" with another GC base class. | 151 // not yet been "mixed in" with another GC base class. |
121 bool RecordInfo::IsGCMixin() { | 152 bool RecordInfo::IsGCMixin() { |
122 if (!IsGCDerived() || base_paths_->begin() == base_paths_->end()) | 153 if (!IsGCDerived() || !gc_base_names_.size()) |
123 return false; | 154 return false; |
124 for (CXXBasePaths::paths_iterator it = base_paths_->begin(); | 155 for (const auto& gc_base : gc_base_names_) { |
125 it != base_paths_->end(); | |
126 ++it) { | |
127 // Get the last element of the path. | |
128 const CXXBasePathElement& elem = (*it)[it->size() - 1]; | |
129 CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); | |
130 // If it is not a mixin base we are done. | 156 // If it is not a mixin base we are done. |
131 if (!Config::IsGCMixinBase(base->getName())) | 157 if (!Config::IsGCMixinBase(gc_base)) |
132 return false; | 158 return false; |
133 } | 159 } |
134 // This is a mixin if all GC bases are mixins. | 160 // This is a mixin if all GC bases are mixins. |
135 return true; | 161 return true; |
136 } | 162 } |
137 | 163 |
138 // Test if a record is allocated on the managed heap. | 164 // Test if a record is allocated on the managed heap. |
139 bool RecordInfo::IsGCAllocated() { | 165 bool RecordInfo::IsGCAllocated() { |
140 return IsGCDerived() || IsHeapAllocatedCollection(); | 166 return IsGCDerived() || IsHeapAllocatedCollection(); |
141 } | 167 } |
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 edge->members().push_back(member); | 572 edge->members().push_back(member); |
547 } | 573 } |
548 // TODO: Handle the case where we fail to create an edge (eg, if the | 574 // TODO: Handle the case where we fail to create an edge (eg, if the |
549 // argument is a primitive type or just not fully known yet). | 575 // argument is a primitive type or just not fully known yet). |
550 } | 576 } |
551 return edge; | 577 return edge; |
552 } | 578 } |
553 | 579 |
554 return new Value(info); | 580 return new Value(info); |
555 } | 581 } |
OLD | NEW |