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 #include "clang/AST/Attr.h" | 8 #include "clang/AST/Attr.h" |
9 | 9 |
10 using namespace clang; | 10 using namespace clang; |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 it != base_paths_->end(); | 106 it != base_paths_->end(); |
107 ++it) { | 107 ++it) { |
108 const CXXBasePathElement& elem = (*it)[it->size() - 1]; | 108 const CXXBasePathElement& elem = (*it)[it->size() - 1]; |
109 CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); | 109 CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); |
110 if (Config::IsGCFinalizedBase(base->getName())) | 110 if (Config::IsGCFinalizedBase(base->getName())) |
111 return true; | 111 return true; |
112 } | 112 } |
113 return false; | 113 return false; |
114 } | 114 } |
115 | 115 |
| 116 // A mixin has not yet been "mixed in" if its only GC base is the mixin base. |
| 117 bool RecordInfo::IsUnmixedGCMixin() { |
| 118 if (!IsGCDerived() || base_paths_->begin() == base_paths_->end()) |
| 119 return false; |
| 120 // Get the last element of the first path. |
| 121 CXXBasePaths::paths_iterator it = base_paths_->begin(); |
| 122 const CXXBasePathElement& elem = (*it)[it->size() - 1]; |
| 123 CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); |
| 124 // If it is not a mixin base we are done. |
| 125 if (!Config::IsGCMixinBase(base->getName())) |
| 126 return false; |
| 127 // Otherwise, this is unmixed if there are no other paths to GC bases. |
| 128 return ++it == base_paths_->end(); |
| 129 } |
| 130 |
116 // Test if a record is allocated on the managed heap. | 131 // Test if a record is allocated on the managed heap. |
117 bool RecordInfo::IsGCAllocated() { | 132 bool RecordInfo::IsGCAllocated() { |
118 return IsGCDerived() || IsHeapAllocatedCollection(); | 133 return IsGCDerived() || IsHeapAllocatedCollection(); |
119 } | 134 } |
120 | 135 |
121 static bool IsAnnotated(Decl* decl, const string& anno) { | 136 static bool IsAnnotated(Decl* decl, const string& anno) { |
122 AnnotateAttr* attr = decl->getAttr<AnnotateAttr>(); | 137 AnnotateAttr* attr = decl->getAttr<AnnotateAttr>(); |
123 return attr && (attr->getAnnotation() == anno); | 138 return attr && (attr->getAnnotation() == anno); |
124 } | 139 } |
125 | 140 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { | 179 for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { |
165 if (it->second.info()->InheritsNonPureTrace()) | 180 if (it->second.info()->InheritsNonPureTrace()) |
166 return true; | 181 return true; |
167 } | 182 } |
168 return false; | 183 return false; |
169 } | 184 } |
170 | 185 |
171 RecordInfo::Bases* RecordInfo::CollectBases() { | 186 RecordInfo::Bases* RecordInfo::CollectBases() { |
172 // Compute the collection locally to avoid inconsistent states. | 187 // Compute the collection locally to avoid inconsistent states. |
173 Bases* bases = new Bases; | 188 Bases* bases = new Bases; |
| 189 if (!record_->hasDefinition()) |
| 190 return bases; |
174 for (CXXRecordDecl::base_class_iterator it = record_->bases_begin(); | 191 for (CXXRecordDecl::base_class_iterator it = record_->bases_begin(); |
175 it != record_->bases_end(); | 192 it != record_->bases_end(); |
176 ++it) { | 193 ++it) { |
177 if (CXXRecordDecl* base = it->getType()->getAsCXXRecordDecl()) { | 194 const CXXBaseSpecifier& spec = *it; |
178 RecordInfo* info = cache_->Lookup(base); | 195 RecordInfo* info = cache_->Lookup(spec.getType()); |
179 TracingStatus status = info->InheritsNonPureTrace() | 196 if (!info) |
180 ? TracingStatus::Needed() | 197 continue; |
181 : TracingStatus::Unneeded(); | 198 CXXRecordDecl* base = info->record(); |
182 bases->insert(std::make_pair(base, BasePoint(info, status))); | 199 TracingStatus status = info->InheritsNonPureTrace() |
183 } | 200 ? TracingStatus::Needed() |
| 201 : TracingStatus::Unneeded(); |
| 202 bases->insert(std::make_pair(base, BasePoint(spec, info, status))); |
184 } | 203 } |
185 return bases; | 204 return bases; |
186 } | 205 } |
187 | 206 |
188 RecordInfo::Fields& RecordInfo::GetFields() { | 207 RecordInfo::Fields& RecordInfo::GetFields() { |
189 if (!fields_) | 208 if (!fields_) |
190 fields_ = CollectFields(); | 209 fields_ = CollectFields(); |
191 return *fields_; | 210 return *fields_; |
192 } | 211 } |
193 | 212 |
194 RecordInfo::Fields* RecordInfo::CollectFields() { | 213 RecordInfo::Fields* RecordInfo::CollectFields() { |
195 // Compute the collection locally to avoid inconsistent states. | 214 // Compute the collection locally to avoid inconsistent states. |
196 Fields* fields = new Fields; | 215 Fields* fields = new Fields; |
| 216 if (!record_->hasDefinition()) |
| 217 return fields; |
197 TracingStatus fields_status = TracingStatus::Unneeded(); | 218 TracingStatus fields_status = TracingStatus::Unneeded(); |
198 for (RecordDecl::field_iterator it = record_->field_begin(); | 219 for (RecordDecl::field_iterator it = record_->field_begin(); |
199 it != record_->field_end(); | 220 it != record_->field_end(); |
200 ++it) { | 221 ++it) { |
201 FieldDecl* field = *it; | 222 FieldDecl* field = *it; |
202 // Ignore fields annotated with the NO_TRACE_CHECKING macro. | 223 // Ignore fields annotated with the NO_TRACE_CHECKING macro. |
203 if (IsAnnotated(field, "blink_no_trace_checking")) | 224 if (IsAnnotated(field, "blink_no_trace_checking")) |
204 continue; | 225 continue; |
205 if (Edge* edge = CreateEdge(field->getType().getTypePtrOrNull())) { | 226 if (Edge* edge = CreateEdge(field->getType().getTypePtrOrNull())) { |
206 fields->insert(std::make_pair(field, FieldPoint(field, edge))); | 227 fields->insert(std::make_pair(field, FieldPoint(field, edge))); |
(...skipping 27 matching lines...) Expand all Loading... |
234 trace_method_ = traceAfterDispatch; | 255 trace_method_ = traceAfterDispatch; |
235 trace_dispatch_method_ = trace; | 256 trace_dispatch_method_ = trace; |
236 } else { | 257 } else { |
237 // TODO: Can we never have a dispatch method called trace without the same | 258 // TODO: Can we never have a dispatch method called trace without the same |
238 // class defining a traceAfterDispatch method? | 259 // class defining a traceAfterDispatch method? |
239 trace_method_ = trace; | 260 trace_method_ = trace; |
240 trace_dispatch_method_ = 0; | 261 trace_dispatch_method_ = 0; |
241 } | 262 } |
242 } | 263 } |
243 | 264 |
| 265 // TODO: Add classes with a finalize() method that specialize FinalizerTrait. |
| 266 bool RecordInfo::NeedsFinalization() { |
| 267 return record_->hasNonTrivialDestructor(); |
| 268 } |
| 269 |
244 // A class needs tracing if: | 270 // A class needs tracing if: |
245 // - it is allocated on the managed heap, | 271 // - it is allocated on the managed heap, |
246 // - it defines a trace method (of the proper signature), or | 272 // - it is derived from a class that needs tracing, or |
247 // - it contains fields that need tracing. | 273 // - it contains fields that need tracing. |
| 274 // TODO: Defining NeedsTracing based on whether a class defines a trace method |
| 275 // (of the proper signature) over approximates too much. The use of transition |
| 276 // types causes some classes to have trace methods without them needing to be |
| 277 // traced. |
248 TracingStatus RecordInfo::NeedsTracing(Edge::NeedsTracingOption option) { | 278 TracingStatus RecordInfo::NeedsTracing(Edge::NeedsTracingOption option) { |
249 if (IsGCAllocated() || GetTraceMethod()) | 279 if (IsGCAllocated()) |
250 return TracingStatus::Needed(); | 280 return TracingStatus::Needed(); |
251 | 281 |
| 282 for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { |
| 283 if (it->second.info()->NeedsTracing(option).IsNeeded()) |
| 284 return TracingStatus::Needed(); |
| 285 } |
| 286 |
252 if (option == Edge::kRecursive) | 287 if (option == Edge::kRecursive) |
253 GetFields(); | 288 GetFields(); |
254 | 289 |
255 return fields_need_tracing_; | 290 return fields_need_tracing_; |
256 } | 291 } |
257 | 292 |
258 Edge* RecordInfo::CreateEdge(const Type* type) { | 293 Edge* RecordInfo::CreateEdge(const Type* type) { |
259 if (!type) { | 294 if (!type) { |
260 return 0; | 295 return 0; |
261 } | 296 } |
262 | 297 |
263 if (type->isPointerType()) { | 298 if (type->isPointerType()) { |
264 if (Edge* ptr = CreateEdge(type->getPointeeType().getTypePtrOrNull())) | 299 if (Edge* ptr = CreateEdge(type->getPointeeType().getTypePtrOrNull())) |
265 return new RawPtr(ptr); | 300 return new RawPtr(ptr); |
266 return 0; | 301 return 0; |
267 } | 302 } |
268 | 303 |
269 CXXRecordDecl* record = type->getAsCXXRecordDecl(); | 304 RecordInfo* info = cache_->Lookup(type); |
270 | 305 |
271 // If the type is neither a pointer or a C++ record we ignore it. | 306 // If the type is neither a pointer or a C++ record we ignore it. |
272 if (!record) { | 307 if (!info) { |
273 return 0; | 308 return 0; |
274 } | 309 } |
275 | 310 |
276 RecordInfo* info = cache_->Lookup(record); | |
277 | |
278 TemplateArgs args; | 311 TemplateArgs args; |
279 | 312 |
280 if (Config::IsRawPtr(info->name()) && info->GetTemplateArgs(1, &args)) { | 313 if (Config::IsRawPtr(info->name()) && info->GetTemplateArgs(1, &args)) { |
281 if (Edge* ptr = CreateEdge(args[0])) | 314 if (Edge* ptr = CreateEdge(args[0])) |
282 return new RawPtr(ptr); | 315 return new RawPtr(ptr); |
283 return 0; | 316 return 0; |
284 } | 317 } |
285 | 318 |
286 if (Config::IsRefPtr(info->name()) && info->GetTemplateArgs(1, &args)) { | 319 if (Config::IsRefPtr(info->name()) && info->GetTemplateArgs(1, &args)) { |
287 if (Edge* ptr = CreateEdge(args[0])) | 320 if (Edge* ptr = CreateEdge(args[0])) |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 return 0; | 354 return 0; |
322 } | 355 } |
323 | 356 |
324 if (Config::IsGCCollection(info->name()) || | 357 if (Config::IsGCCollection(info->name()) || |
325 Config::IsWTFCollection(info->name())) { | 358 Config::IsWTFCollection(info->name())) { |
326 bool is_root = Config::IsPersistentGCCollection(info->name()); | 359 bool is_root = Config::IsPersistentGCCollection(info->name()); |
327 bool on_heap = is_root || info->IsHeapAllocatedCollection(); | 360 bool on_heap = is_root || info->IsHeapAllocatedCollection(); |
328 size_t count = Config::CollectionDimension(info->name()); | 361 size_t count = Config::CollectionDimension(info->name()); |
329 if (!info->GetTemplateArgs(count, &args)) | 362 if (!info->GetTemplateArgs(count, &args)) |
330 return 0; | 363 return 0; |
331 Collection* edge = new Collection(on_heap, is_root); | 364 Collection* edge = new Collection(info, on_heap, is_root); |
332 for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) { | 365 for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) { |
333 if (Edge* member = CreateEdge(*it)) { | 366 if (Edge* member = CreateEdge(*it)) { |
334 edge->members().push_back(member); | 367 edge->members().push_back(member); |
335 } else { | 368 } else { |
336 // We failed to create an edge so abort the entire edge construction. | 369 // We failed to create an edge so abort the entire edge construction. |
337 delete edge; // Will delete the already allocated members. | 370 delete edge; // Will delete the already allocated members. |
338 return 0; | 371 return 0; |
339 } | 372 } |
340 } | 373 } |
341 return edge; | 374 return edge; |
342 } | 375 } |
343 | 376 |
344 return new Value(info); | 377 return new Value(info); |
345 } | 378 } |
OLD | NEW |