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