15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "Config.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "RecordInfo.h"
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using namespace clang;
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using std::string;
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RecordInfo::RecordInfo(CXXRecordDecl* record, RecordCache* cache)
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : cache_(cache),
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      record_(record),
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      name_(record->getName()),
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      fields_need_tracing_(TracingStatus::Unknown()),
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      bases_(0),
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      fields_(0),
1823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      is_stack_allocated_(kNotComputed),
19effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      is_non_newable_(kNotComputed),
20effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      is_only_placement_newable_(kNotComputed),
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      does_need_finalization_(kNotComputed),
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      determined_trace_methods_(false),
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      trace_method_(0),
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      trace_dispatch_method_(0),
2523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      finalize_dispatch_method_(0),
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      is_gc_derived_(false),
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base_paths_(0) {}
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RecordInfo::~RecordInfo() {
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  delete fields_;
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  delete bases_;
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  delete base_paths_;
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Get |count| number of template arguments. Returns false if there
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// are fewer than |count| arguments or any of the arguments are not
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// of a valid Type structure. If |count| is non-positive, all
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// arguments are collected.
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool RecordInfo::GetTemplateArgs(size_t count, TemplateArgs* output_args) {
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ClassTemplateSpecializationDecl* tmpl =
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      dyn_cast<ClassTemplateSpecializationDecl>(record_);
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!tmpl)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const TemplateArgumentList& args = tmpl->getTemplateArgs();
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (args.size() < count)
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (count <= 0)
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    count = args.size();
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (unsigned i = 0; i < count; ++i) {
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TemplateArgument arg = args[i];
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (arg.getKind() == TemplateArgument::Type && !arg.getAsType().isNull()) {
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      output_args->push_back(arg.getAsType().getTypePtr());
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return false;
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Test if a record is a HeapAllocated collection.
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool RecordInfo::IsHeapAllocatedCollection() {
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!Config::IsGCCollection(name_) && !Config::IsWTFCollection(name_))
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TemplateArgs args;
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (GetTemplateArgs(0, &args)) {
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) {
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (CXXRecordDecl* decl = (*it)->getAsCXXRecordDecl())
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (decl->getName() == kHeapAllocatorName)
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          return true;
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return Config::IsGCCollection(name_);
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static bool IsGCBaseCallback(const CXXBaseSpecifier* specifier,
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             CXXBasePath& path,
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             void* data) {
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (CXXRecordDecl* record = specifier->getType()->getAsCXXRecordDecl())
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return Config::IsGCBase(record->getName());
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return false;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Test if a record is derived from a garbage collected base.
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool RecordInfo::IsGCDerived() {
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If already computed, return the known result.
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (base_paths_)
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return is_gc_derived_;
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base_paths_ = new CXXBasePaths(true, true, false);
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!record_->hasDefinition())
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The base classes are not themselves considered garbage collected objects.
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (Config::IsGCBase(name_))
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Walk the inheritance tree to find GC base classes.
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  is_gc_derived_ = record_->lookupInBases(IsGCBaseCallback, 0, *base_paths_);
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return is_gc_derived_;
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool RecordInfo::IsGCFinalized() {
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!IsGCDerived())
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (CXXBasePaths::paths_iterator it = base_paths_->begin();
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       it != base_paths_->end();
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++it) {
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const CXXBasePathElement& elem = (*it)[it->size() - 1];
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl();
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (Config::IsGCFinalizedBase(base->getName()))
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return true;
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// A GC mixin is a class that inherits from a GC mixin base and has
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// not yet been "mixed in" with another GC base class.
12123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool RecordInfo::IsGCMixin() {
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!IsGCDerived() || base_paths_->begin() == base_paths_->end())
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (CXXBasePaths::paths_iterator it = base_paths_->begin();
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu       it != base_paths_->end();
1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu       ++it) {
1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      // Get the last element of the path.
1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const CXXBasePathElement& elem = (*it)[it->size() - 1];
1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl();
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      // If it is not a mixin base we are done.
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (!Config::IsGCMixinBase(base->getName()))
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          return false;
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // This is a mixin if all GC bases are mixins.
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return true;
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Test if a record is allocated on the managed heap.
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool RecordInfo::IsGCAllocated() {
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return IsGCDerived() || IsHeapAllocatedCollection();
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)RecordInfo* RecordCache::Lookup(CXXRecordDecl* record) {
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Ignore classes annotated with the GC_PLUGIN_IGNORE macro.
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!record || Config::IsIgnoreAnnotated(record))
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Cache::iterator it = cache_.find(record);
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (it != cache_.end())
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return &it->second;
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return &cache_.insert(std::make_pair(record, RecordInfo(record, this)))
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch              .first->second;
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool RecordInfo::IsStackAllocated() {
15523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (is_stack_allocated_ == kNotComputed) {
15623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    is_stack_allocated_ = kFalse;
15723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    for (Bases::iterator it = GetBases().begin();
15823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)         it != GetBases().end();
15923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)         ++it) {
16023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (it->second.info()->IsStackAllocated()) {
16123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        is_stack_allocated_ = kTrue;
162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        return is_stack_allocated_;
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for (CXXRecordDecl::method_iterator it = record_->method_begin();
166effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         it != record_->method_end();
167effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         ++it) {
168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (it->getNameAsString() == kNewOperatorName &&
169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          it->isDeleted() &&
170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          Config::IsStackAnnotated(*it)) {
171effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        is_stack_allocated_ = kTrue;
172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        return is_stack_allocated_;
17323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      }
17423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return is_stack_allocated_;
177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool RecordInfo::IsNonNewable() {
180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (is_non_newable_ == kNotComputed) {
181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    bool deleted = false;
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    bool all_deleted = true;
18323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    for (CXXRecordDecl::method_iterator it = record_->method_begin();
18423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)         it != record_->method_end();
18523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)         ++it) {
18623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (it->getNameAsString() == kNewOperatorName) {
187effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        deleted = it->isDeleted();
188effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        all_deleted = all_deleted && deleted;
189effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
190effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
191effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    is_non_newable_ = (deleted && all_deleted) ? kTrue : kFalse;
192effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
193effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return is_non_newable_;
194effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
195effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
196effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool RecordInfo::IsOnlyPlacementNewable() {
197effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (is_only_placement_newable_ == kNotComputed) {
198effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    bool placement = false;
199effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    bool new_deleted = false;
200effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for (CXXRecordDecl::method_iterator it = record_->method_begin();
201effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         it != record_->method_end();
202effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         ++it) {
203effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (it->getNameAsString() == kNewOperatorName) {
204effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        if (it->getNumParams() == 1) {
205effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          new_deleted = it->isDeleted();
206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        } else if (it->getNumParams() == 2) {
207effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          placement = !it->isDeleted();
20823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
20923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      }
21023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
211effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    is_only_placement_newable_ = (placement && new_deleted) ? kTrue : kFalse;
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
213effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return is_only_placement_newable_;
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
216010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)CXXMethodDecl* RecordInfo::DeclaresNewOperator() {
217010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (CXXRecordDecl::method_iterator it = record_->method_begin();
218010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       it != record_->method_end();
219010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       ++it) {
220010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (it->getNameAsString() == kNewOperatorName && it->getNumParams() == 1)
221010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return *it;
222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
223010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return 0;
224010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
225010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// An object requires a tracing method if it has any fields that need tracing
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// or if it inherits from multiple bases that need tracing.
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool RecordInfo::RequiresTraceMethod() {
22923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (IsStackAllocated())
23023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  unsigned bases_with_trace = 0;
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (it->second.NeedsTracing().IsNeeded())
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ++bases_with_trace;
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (bases_with_trace > 1)
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return true;
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GetFields();
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return fields_need_tracing_.IsNeeded();
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Get the actual tracing method (ie, can be traceAfterDispatch if there is a
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// dispatch method).
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CXXMethodDecl* RecordInfo::GetTraceMethod() {
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DetermineTracingMethods();
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return trace_method_;
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Get the static trace dispatch method.
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CXXMethodDecl* RecordInfo::GetTraceDispatchMethod() {
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DetermineTracingMethods();
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return trace_dispatch_method_;
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
25523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)CXXMethodDecl* RecordInfo::GetFinalizeDispatchMethod() {
25623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  DetermineTracingMethods();
25723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return finalize_dispatch_method_;
25823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
25923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RecordInfo::Bases& RecordInfo::GetBases() {
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!bases_)
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bases_ = CollectBases();
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return *bases_;
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool RecordInfo::InheritsTrace() {
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (GetTraceMethod())
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return true;
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (it->second.info()->InheritsTrace())
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return true;
272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
27623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)CXXMethodDecl* RecordInfo::InheritsNonVirtualTrace() {
27723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (CXXMethodDecl* trace = GetTraceMethod())
27823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return trace->isVirtual() ? 0 : trace;
27923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
28023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (CXXMethodDecl* trace = it->second.info()->InheritsNonVirtualTrace())
28123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return trace;
28223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
28323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return 0;
28423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
28523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
28623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// A (non-virtual) class is considered abstract in Blink if it has
28723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// no public constructors and no create methods.
28823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool RecordInfo::IsConsideredAbstract() {
28923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (CXXRecordDecl::ctor_iterator it = record_->ctor_begin();
29023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)       it != record_->ctor_end();
29123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)       ++it) {
29223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (!it->isCopyOrMoveConstructor() && it->getAccess() == AS_public)
29323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return false;
29423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
29523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (CXXRecordDecl::method_iterator it = record_->method_begin();
29623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)       it != record_->method_end();
29723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)       ++it) {
29823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (it->getNameAsString() == kCreateName)
29923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return false;
30023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
30123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return true;
30223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
30323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RecordInfo::Bases* RecordInfo::CollectBases() {
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Compute the collection locally to avoid inconsistent states.
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Bases* bases = new Bases;
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!record_->hasDefinition())
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return bases;
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (CXXRecordDecl::base_class_iterator it = record_->bases_begin();
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != record_->bases_end();
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const CXXBaseSpecifier& spec = *it;
313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RecordInfo* info = cache_->Lookup(spec.getType());
314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!info)
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      continue;
316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    CXXRecordDecl* base = info->record();
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    TracingStatus status = info->InheritsTrace()
318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               ? TracingStatus::Needed()
319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               : TracingStatus::Unneeded();
320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bases->insert(std::make_pair(base, BasePoint(spec, info, status)));
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return bases;
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RecordInfo::Fields& RecordInfo::GetFields() {
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!fields_)
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fields_ = CollectFields();
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return *fields_;
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RecordInfo::Fields* RecordInfo::CollectFields() {
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Compute the collection locally to avoid inconsistent states.
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Fields* fields = new Fields;
334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!record_->hasDefinition())
335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return fields;
336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TracingStatus fields_status = TracingStatus::Unneeded();
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (RecordDecl::field_iterator it = record_->field_begin();
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != record_->field_end();
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    FieldDecl* field = *it;
341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Ignore fields annotated with the GC_PLUGIN_IGNORE macro.
342effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (Config::IsIgnoreAnnotated(field))
343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      continue;
344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (Edge* edge = CreateEdge(field->getType().getTypePtrOrNull())) {
345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      fields_status = fields_status.LUB(edge->NeedsTracing(Edge::kRecursive));
346effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      fields->insert(std::make_pair(field, FieldPoint(field, edge)));
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  fields_need_tracing_ = fields_status;
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return fields;
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RecordInfo::DetermineTracingMethods() {
354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (determined_trace_methods_)
355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  determined_trace_methods_ = true;
35723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (Config::IsGCBase(name_))
35823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return;
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CXXMethodDecl* trace = 0;
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CXXMethodDecl* traceAfterDispatch = 0;
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool isTraceAfterDispatch;
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (CXXRecordDecl::method_iterator it = record_->method_begin();
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != record_->method_end();
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (Config::IsTraceMethod(*it, &isTraceAfterDispatch)) {
366a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (isTraceAfterDispatch) {
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        traceAfterDispatch = *it;
368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      } else {
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        trace = *it;
370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
37123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    } else if (it->getNameAsString() == kFinalizeName) {
372effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      finalize_dispatch_method_ = *it;
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (traceAfterDispatch) {
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    trace_method_ = traceAfterDispatch;
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    trace_dispatch_method_ = trace;
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // TODO: Can we never have a dispatch method called trace without the same
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // class defining a traceAfterDispatch method?
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    trace_method_ = trace;
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    trace_dispatch_method_ = 0;
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
38423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (trace_dispatch_method_ && finalize_dispatch_method_)
38523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return;
38623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // If this class does not define dispatching methods inherit them.
38723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
38823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // TODO: Does it make sense to inherit multiple dispatch methods?
38923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (CXXMethodDecl* dispatch = it->second.info()->GetTraceDispatchMethod()) {
39023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      assert(!trace_dispatch_method_ && "Multiple trace dispatching methods");
39123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      trace_dispatch_method_ = dispatch;
39223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
39323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (CXXMethodDecl* dispatch =
394effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            it->second.info()->GetFinalizeDispatchMethod()) {
39523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      assert(!finalize_dispatch_method_ &&
39623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)             "Multiple finalize dispatching methods");
39723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      finalize_dispatch_method_ = dispatch;
39823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
39923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
402a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// TODO: Add classes with a finalize() method that specialize FinalizerTrait.
403a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool RecordInfo::NeedsFinalization() {
404116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (does_need_finalization_ == kNotComputed) {
405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Rely on hasNonTrivialDestructor(), but if the only
406116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // identifiable reason for it being true is the presence
407116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // of a safely ignorable class as a direct base,
408116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // or we're processing such an 'ignorable' class, then it does
409116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // not need finalization.
410116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    does_need_finalization_ =
411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        record_->hasNonTrivialDestructor() ? kTrue : kFalse;
412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!does_need_finalization_)
413116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return does_need_finalization_;
414116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
415116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Processing a class with a safely-ignorable destructor.
416116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    NamespaceDecl* ns =
417116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        dyn_cast<NamespaceDecl>(record_->getDeclContext());
418116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (ns && Config::HasIgnorableDestructor(ns->getName(), name_)) {
419116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      does_need_finalization_ = kFalse;
420116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return does_need_finalization_;
421116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
422116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
423116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CXXDestructorDecl* dtor = record_->getDestructor();
424116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (dtor && dtor->isUserProvided())
425116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return does_need_finalization_;
426116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (Fields::iterator it = GetFields().begin();
427116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         it != GetFields().end();
428116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         ++it) {
429116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (it->second.edge()->NeedsFinalization())
430116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        return does_need_finalization_;
431116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
432116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
433116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (Bases::iterator it = GetBases().begin();
434116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         it != GetBases().end();
435116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         ++it) {
436116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (it->second.info()->NeedsFinalization())
437116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        return does_need_finalization_;
438116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
439116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Destructor was non-trivial due to bases with destructors that
440116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // can be safely ignored. Hence, no need for finalization.
441116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    does_need_finalization_ = kFalse;
442116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
443116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return does_need_finalization_;
444a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
445a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
446a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// A class needs tracing if:
447a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// - it is allocated on the managed heap,
448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// - it is derived from a class that needs tracing, or
449a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// - it contains fields that need tracing.
450a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// TODO: Defining NeedsTracing based on whether a class defines a trace method
451a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// (of the proper signature) over approximates too much. The use of transition
452a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// types causes some classes to have trace methods without them needing to be
453a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// traced.
454a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TracingStatus RecordInfo::NeedsTracing(Edge::NeedsTracingOption option) {
455a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (IsGCAllocated())
456a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return TracingStatus::Needed();
457a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
458effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (IsStackAllocated())
459effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return TracingStatus::Unneeded();
460effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
461a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
462a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (it->second.info()->NeedsTracing(option).IsNeeded())
463a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return TracingStatus::Needed();
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
466a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (option == Edge::kRecursive)
467a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    GetFields();
468a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
469a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return fields_need_tracing_;
470a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
471a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
472a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)Edge* RecordInfo::CreateEdge(const Type* type) {
473a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!type) {
474a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
477a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (type->isPointerType()) {
478a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (Edge* ptr = CreateEdge(type->getPointeeType().getTypePtrOrNull()))
479c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return new RawPtr(ptr, false);
480a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
483a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RecordInfo* info = cache_->Lookup(type);
484a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
485a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If the type is neither a pointer or a C++ record we ignore it.
486a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!info) {
487a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
490a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TemplateArgs args;
491a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
492a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (Config::IsRawPtr(info->name()) && info->GetTemplateArgs(1, &args)) {
493a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (Edge* ptr = CreateEdge(args[0]))
494c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return new RawPtr(ptr, true);
495a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
498a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (Config::IsRefPtr(info->name()) && info->GetTemplateArgs(1, &args)) {
499a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (Edge* ptr = CreateEdge(args[0]))
500a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return new RefPtr(ptr);
501a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
504a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (Config::IsOwnPtr(info->name()) && info->GetTemplateArgs(1, &args)) {
505a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (Edge* ptr = CreateEdge(args[0]))
506a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return new OwnPtr(ptr);
507a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
508a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
510a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (Config::IsMember(info->name()) && info->GetTemplateArgs(1, &args)) {
511a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (Edge* ptr = CreateEdge(args[0]))
512a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return new Member(ptr);
513a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
514a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
516a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (Config::IsWeakMember(info->name()) && info->GetTemplateArgs(1, &args)) {
517a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (Edge* ptr = CreateEdge(args[0]))
518a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return new WeakMember(ptr);
519a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
520a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
521a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
522a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (Config::IsPersistent(info->name())) {
523a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Persistent might refer to v8::Persistent, so check the name space.
524a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // TODO: Consider using a more canonical identification than names.
525a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    NamespaceDecl* ns =
526a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        dyn_cast<NamespaceDecl>(info->record()->getDeclContext());
527116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!ns || ns->getName() != "blink")
528a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return 0;
529a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!info->GetTemplateArgs(1, &args))
530a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return 0;
531a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (Edge* ptr = CreateEdge(args[0]))
532a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return new Persistent(ptr);
533a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 0;
534a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
536a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (Config::IsGCCollection(info->name()) ||
537a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      Config::IsWTFCollection(info->name())) {
538a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool is_root = Config::IsPersistentGCCollection(info->name());
539a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool on_heap = is_root || info->IsHeapAllocatedCollection();
540a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    size_t count = Config::CollectionDimension(info->name());
541a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!info->GetTemplateArgs(count, &args))
542a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return 0;
543a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    Collection* edge = new Collection(info, on_heap, is_root);
544a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) {
545a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (Edge* member = CreateEdge(*it)) {
546a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        edge->members().push_back(member);
547a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
548010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      // TODO: Handle the case where we fail to create an edge (eg, if the
549010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      // argument is a primitive type or just not fully known yet).
550a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
551a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return edge;
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
554a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return new Value(info);
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
556