| 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 |