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   Edge* CreateEdgeFromOriginalType(const clang::Type* type);
    133 
    134   RecordCache* cache_;
    135   clang::CXXRecordDecl* record_;
    136   const std::string name_;
    137   TracingStatus fields_need_tracing_;
    138   Bases* bases_;
    139   Fields* fields_;
    140 
    141   enum CachedBool { kFalse = 0, kTrue = 1, kNotComputed = 2 };
    142   CachedBool is_stack_allocated_;
    143   CachedBool is_non_newable_;
    144   CachedBool is_only_placement_newable_;
    145   CachedBool does_need_finalization_;
    146   CachedBool has_gc_mixin_methods_;
    147   CachedBool is_declaring_local_trace_;
    148   CachedBool is_eagerly_finalized_;
    149 
    150   bool determined_trace_methods_;
    151   clang::CXXMethodDecl* trace_method_;
    152   clang::CXXMethodDecl* trace_dispatch_method_;
    153   clang::CXXMethodDecl* finalize_dispatch_method_;
    154 
    155   bool is_gc_derived_;
    156 
    157   std::vector<std::string> gc_base_names_;
    158 
    159   friend class RecordCache;
    160 };
    161 
    162 class RecordCache {
    163  public:
    164   RecordCache(clang::CompilerInstance& instance)
    165     : instance_(instance)
    166   {
    167   }
    168 
    169   RecordInfo* Lookup(clang::CXXRecordDecl* record);
    170 
    171   RecordInfo* Lookup(const clang::CXXRecordDecl* record) {
    172     return Lookup(const_cast<clang::CXXRecordDecl*>(record));
    173   }
    174 
    175   RecordInfo* Lookup(clang::DeclContext* decl) {
    176     return Lookup(clang::dyn_cast<clang::CXXRecordDecl>(decl));
    177   }
    178 
    179   RecordInfo* Lookup(const clang::Type* type) {
    180     return Lookup(type->getAsCXXRecordDecl());
    181   }
    182 
    183   RecordInfo* Lookup(const clang::QualType& type) {
    184     return Lookup(type.getTypePtr());
    185   }
    186 
    187   ~RecordCache() {
    188     for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) {
    189       if (!it->second.fields_)
    190         continue;
    191       for (RecordInfo::Fields::iterator fit = it->second.fields_->begin();
    192         fit != it->second.fields_->end();
    193         ++fit) {
    194         fit->second.deleteEdge();
    195       }
    196     }
    197   }
    198 
    199   clang::CompilerInstance& instance() const { return instance_; }
    200 
    201  private:
    202   clang::CompilerInstance& instance_;
    203 
    204   typedef std::map<clang::CXXRecordDecl*, RecordInfo> Cache;
    205   Cache cache_;
    206 };
    207 
    208 #endif  // TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_
    209