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* GetTraceWrappersMethod();
     93   clang::CXXMethodDecl* GetTraceDispatchMethod();
     94   clang::CXXMethodDecl* GetFinalizeDispatchMethod();
     95 
     96   bool GetTemplateArgs(size_t count, TemplateArgs* output_args);
     97 
     98   bool IsHeapAllocatedCollection();
     99   bool IsGCDerived();
    100   bool IsGCAllocated();
    101   bool IsGCFinalized();
    102   bool IsGCMixin();
    103   bool IsStackAllocated();
    104   bool IsNonNewable();
    105   bool IsOnlyPlacementNewable();
    106   bool IsEagerlyFinalized();
    107 
    108   bool HasDefinition();
    109 
    110   clang::CXXMethodDecl* DeclaresNewOperator();
    111 
    112   bool RequiresTraceMethod();
    113   bool NeedsFinalization();
    114   bool DeclaresGCMixinMethods();
    115   bool DeclaresLocalTraceMethod();
    116   TracingStatus NeedsTracing(Edge::NeedsTracingOption);
    117   clang::CXXMethodDecl* InheritsNonVirtualTrace();
    118   bool IsConsideredAbstract();
    119 
    120   static clang::CXXRecordDecl* GetDependentTemplatedDecl(const clang::Type&);
    121 
    122  private:
    123   RecordInfo(clang::CXXRecordDecl* record, RecordCache* cache);
    124 
    125   void walkBases();
    126 
    127   Fields* CollectFields();
    128   Bases* CollectBases();
    129   void DetermineTracingMethods();
    130   bool InheritsTrace();
    131 
    132   Edge* CreateEdge(const clang::Type* type);
    133   Edge* CreateEdgeFromOriginalType(const clang::Type* type);
    134 
    135   bool HasOptionalFinalizer();
    136 
    137   RecordCache* cache_;
    138   clang::CXXRecordDecl* record_;
    139   const std::string name_;
    140   TracingStatus fields_need_tracing_;
    141   Bases* bases_;
    142   Fields* fields_;
    143 
    144   enum CachedBool { kFalse = 0, kTrue = 1, kNotComputed = 2 };
    145   CachedBool is_stack_allocated_;
    146   CachedBool is_non_newable_;
    147   CachedBool is_only_placement_newable_;
    148   CachedBool does_need_finalization_;
    149   CachedBool has_gc_mixin_methods_;
    150   CachedBool is_declaring_local_trace_;
    151   CachedBool is_eagerly_finalized_;
    152 
    153   bool determined_trace_methods_;
    154   clang::CXXMethodDecl* trace_method_;
    155   clang::CXXMethodDecl* trace_dispatch_method_;
    156   clang::CXXMethodDecl* finalize_dispatch_method_;
    157 
    158   bool is_gc_derived_;
    159 
    160   std::vector<std::string> gc_base_names_;
    161 
    162   friend class RecordCache;
    163 };
    164 
    165 class RecordCache {
    166  public:
    167   RecordCache(clang::CompilerInstance& instance)
    168     : instance_(instance)
    169   {
    170   }
    171 
    172   RecordInfo* Lookup(clang::CXXRecordDecl* record);
    173 
    174   RecordInfo* Lookup(const clang::CXXRecordDecl* record) {
    175     return Lookup(const_cast<clang::CXXRecordDecl*>(record));
    176   }
    177 
    178   RecordInfo* Lookup(clang::DeclContext* decl) {
    179     return Lookup(clang::dyn_cast<clang::CXXRecordDecl>(decl));
    180   }
    181 
    182   RecordInfo* Lookup(const clang::Type* type) {
    183     return Lookup(type->getAsCXXRecordDecl());
    184   }
    185 
    186   RecordInfo* Lookup(const clang::QualType& type) {
    187     return Lookup(type.getTypePtr());
    188   }
    189 
    190   ~RecordCache() {
    191     for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) {
    192       if (!it->second.fields_)
    193         continue;
    194       for (RecordInfo::Fields::iterator fit = it->second.fields_->begin();
    195         fit != it->second.fields_->end();
    196         ++fit) {
    197         fit->second.deleteEdge();
    198       }
    199     }
    200   }
    201 
    202   clang::CompilerInstance& instance() const { return instance_; }
    203 
    204  private:
    205   clang::CompilerInstance& instance_;
    206 
    207   typedef std::map<clang::CXXRecordDecl*, RecordInfo> Cache;
    208   Cache cache_;
    209 };
    210 
    211 #endif  // TOOLS_BLINK_GC_PLUGIN_RECORD_INFO_H_
    212