Home | History | Annotate | Download | only in blink_gc_plugin
      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
      3 // found in the LICENSE file.
      4 
      5 // This file provides a wrapper for CXXRecordDecl that accumulates GC related
      6 // information about a class. Accumulated information is memoized and the info
      7 // objects are stored in a RecordCache.
      8 
      9 #ifndef TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_
     10 #define TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_
     11 
     12 #include <map>
     13 #include <vector>
     14 
     15 #include "Edge.h"
     16 
     17 #include "clang/AST/AST.h"
     18 #include "clang/AST/CXXInheritance.h"
     19 #include "clang/Frontend/CompilerInstance.h"
     20 
     21 class RecordCache;
     22 
     23 // A potentially tracable and/or lifetime affecting point in the object graph.
     24 class GraphPoint {
     25  public:
     26   GraphPoint() : traced_(false) {}
     27   virtual ~GraphPoint() {}
     28   void MarkTraced() { traced_ = true; }
     29   bool IsProperlyTraced() { return traced_ || !NeedsTracing().IsNeeded(); }
     30   bool IsInproperlyTraced() { return traced_ && NeedsTracing().IsIllegal(); }
     31   virtual const TracingStatus NeedsTracing() = 0;
     32 
     33  private:
     34   bool traced_;
     35 };
     36 
     37 class BasePoint : public GraphPoint {
     38  public:
     39   BasePoint(const clang::CXXBaseSpecifier& spec,
     40             RecordInfo* info,
     41             const TracingStatus& status)
     42       : spec_(spec), info_(info), status_(status) {}
     43   const TracingStatus NeedsTracing() { return status_; }
     44   const clang::CXXBaseSpecifier& spec() { return spec_; }
     45   RecordInfo* info() { return info_; }
     46 
     47  private:
     48   const clang::CXXBaseSpecifier& spec_;
     49   RecordInfo* info_;
     50   TracingStatus status_;
     51 };
     52 
     53 class FieldPoint : public GraphPoint {
     54  public:
     55   FieldPoint(clang::FieldDecl* field, Edge* edge)
     56       : field_(field), edge_(edge) {}
     57   const TracingStatus NeedsTracing() {
     58     return edge_->NeedsTracing(Edge::kRecursive);
     59   }
     60   clang::FieldDecl* field() { return field_; }
     61   Edge* edge() { return edge_; }
     62 
     63  private:
     64   clang::FieldDecl* field_;
     65   Edge* edge_;
     66 
     67   friend class RecordCache;
     68   void deleteEdge() { delete edge_; }
     69 };
     70 
     71 // Wrapper class to lazily collect information about a C++ record.
     72 class RecordInfo {
     73  public:
     74   typedef std::vector<std::pair<clang::CXXRecordDecl*, BasePoint>> Bases;
     75 
     76   struct FieldDeclCmp {
     77     bool operator()(clang::FieldDecl* a, clang::FieldDecl *b) const {
     78       return a->getLocStart() < b->getLocStart();
     79     }
     80   };
     81   typedef std::map<clang::FieldDecl*, FieldPoint, FieldDeclCmp> Fields;
     82 
     83   typedef std::vector<const clang::Type*> TemplateArgs;
     84 
     85   ~RecordInfo();
     86 
     87   clang::CXXRecordDecl* record() const { return record_; }
     88   const std::string& name() const { return name_; }
     89   Fields& GetFields();
     90   Bases& GetBases();
     91   clang::CXXMethodDecl* GetTraceMethod();
     92   clang::CXXMethodDecl* GetTraceDispatchMethod();
     93   clang::CXXMethodDecl* GetFinalizeDispatchMethod();
     94 
     95   bool GetTemplateArgs(size_t count, TemplateArgs* output_args);
     96 
     97   bool IsHeapAllocatedCollection();
     98   bool IsGCDerived();
     99   bool IsGCAllocated();
    100   bool IsGCFinalized();
    101   bool IsGCMixin();
    102   bool IsStackAllocated();
    103   bool IsNonNewable();
    104   bool IsOnlyPlacementNewable();
    105   bool IsEagerlyFinalized();
    106 
    107   bool HasDefinition();
    108 
    109   clang::CXXMethodDecl* DeclaresNewOperator();
    110 
    111   bool RequiresTraceMethod();
    112   bool NeedsFinalization();
    113   bool DeclaresGCMixinMethods();
    114   bool DeclaresLocalTraceMethod();
    115   TracingStatus NeedsTracing(Edge::NeedsTracingOption);
    116   clang::CXXMethodDecl* InheritsNonVirtualTrace();
    117   bool IsConsideredAbstract();
    118 
    119   static clang::CXXRecordDecl* GetDependentTemplatedDecl(const clang::Type&);
    120 
    121  private:
    122   RecordInfo(clang::CXXRecordDecl* record, RecordCache* cache);
    123 
    124   void walkBases();
    125 
    126   Fields* CollectFields();
    127   Bases* CollectBases();
    128   void DetermineTracingMethods();
    129   bool InheritsTrace();
    130 
    131   Edge* CreateEdge(const clang::Type* type);
    132 
    133   RecordCache* cache_;
    134   clang::CXXRecordDecl* record_;
    135   const std::string name_;
    136   TracingStatus fields_need_tracing_;
    137   Bases* bases_;
    138   Fields* fields_;
    139 
    140   enum CachedBool { kFalse = 0, kTrue = 1, kNotComputed = 2 };
    141   CachedBool is_stack_allocated_;
    142   CachedBool is_non_newable_;
    143   CachedBool is_only_placement_newable_;
    144   CachedBool does_need_finalization_;
    145   CachedBool has_gc_mixin_methods_;
    146   CachedBool is_declaring_local_trace_;
    147   CachedBool is_eagerly_finalized_;
    148 
    149   bool determined_trace_methods_;
    150   clang::CXXMethodDecl* trace_method_;
    151   clang::CXXMethodDecl* trace_dispatch_method_;
    152   clang::CXXMethodDecl* finalize_dispatch_method_;
    153 
    154   bool is_gc_derived_;
    155 
    156   std::vector<std::string> gc_base_names_;
    157 
    158   friend class RecordCache;
    159 };
    160 
    161 class RecordCache {
    162  public:
    163   RecordCache(clang::CompilerInstance& instance)
    164     : instance_(instance)
    165   {
    166   }
    167 
    168   RecordInfo* Lookup(clang::CXXRecordDecl* record);
    169 
    170   RecordInfo* Lookup(const clang::CXXRecordDecl* record) {
    171     return Lookup(const_cast<clang::CXXRecordDecl*>(record));
    172   }
    173 
    174   RecordInfo* Lookup(clang::DeclContext* decl) {
    175     return Lookup(clang::dyn_cast<clang::CXXRecordDecl>(decl));
    176   }
    177 
    178   RecordInfo* Lookup(const clang::Type* type) {
    179     return Lookup(type->getAsCXXRecordDecl());
    180   }
    181 
    182   RecordInfo* Lookup(const clang::QualType& type) {
    183     return Lookup(type.getTypePtr());
    184   }
    185 
    186   ~RecordCache() {
    187     for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) {
    188       if (!it->second.fields_)
    189         continue;
    190       for (RecordInfo::Fields::iterator fit = it->second.fields_->begin();
    191         fit != it->second.fields_->end();
    192         ++fit) {
    193         fit->second.deleteEdge();
    194       }
    195     }
    196   }
    197 
    198   clang::CompilerInstance& instance() const { return instance_; }
    199 
    200  private:
    201   clang::CompilerInstance& instance_;
    202 
    203   typedef std::map<clang::CXXRecordDecl*, RecordInfo> Cache;
    204   Cache cache_;
    205 };
    206 
    207 #endif  // TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_
    208