Home | History | Annotate | Download | only in blink_gc_plugin
      1 // Copyright 2015 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 #include "CheckFinalizerVisitor.h"
      6 
      7 using namespace clang;
      8 
      9 namespace {
     10 
     11 // Simple visitor to determine if the content of a field might be collected
     12 // during finalization.
     13 class MightBeCollectedVisitor : public EdgeVisitor {
     14  public:
     15   explicit MightBeCollectedVisitor(bool is_eagerly_finalized);
     16 
     17   bool might_be_collected() const;
     18   bool as_eagerly_finalized() const;
     19 
     20   void VisitMember(Member* edge) override;
     21   void VisitCollection(Collection* edge) override;
     22 
     23  private:
     24   bool might_be_collected_;
     25   bool is_eagerly_finalized_;
     26   bool as_eagerly_finalized_;
     27 };
     28 
     29 MightBeCollectedVisitor::MightBeCollectedVisitor(bool is_eagerly_finalized)
     30     : might_be_collected_(false),
     31       is_eagerly_finalized_(is_eagerly_finalized),
     32       as_eagerly_finalized_(false) {
     33 }
     34 
     35 bool MightBeCollectedVisitor::might_be_collected() const {
     36   return might_be_collected_;
     37 }
     38 
     39 bool MightBeCollectedVisitor::as_eagerly_finalized() const {
     40   return as_eagerly_finalized_;
     41 }
     42 
     43 void MightBeCollectedVisitor::VisitMember(Member* edge) {
     44   if (is_eagerly_finalized_) {
     45     if (edge->ptr()->IsValue()) {
     46       Value* member = static_cast<Value*>(edge->ptr());
     47       if (member->value()->IsEagerlyFinalized()) {
     48         might_be_collected_ = true;
     49         as_eagerly_finalized_ = true;
     50       }
     51     }
     52     return;
     53   }
     54   might_be_collected_ = true;
     55 }
     56 
     57 void MightBeCollectedVisitor::VisitCollection(Collection* edge) {
     58   if (edge->on_heap() && !is_eagerly_finalized_) {
     59     might_be_collected_ = !edge->is_root();
     60   } else {
     61     edge->AcceptMembers(this);
     62   }
     63 }
     64 
     65 }  // namespace
     66 
     67 CheckFinalizerVisitor::CheckFinalizerVisitor(RecordCache* cache,
     68                                              bool is_eagerly_finalized)
     69     : blacklist_context_(false),
     70       cache_(cache),
     71       is_eagerly_finalized_(is_eagerly_finalized) {
     72 }
     73 
     74 CheckFinalizerVisitor::Errors& CheckFinalizerVisitor::finalized_fields() {
     75   return finalized_fields_;
     76 }
     77 
     78 bool CheckFinalizerVisitor::WalkUpFromCXXOperatorCallExpr(
     79     CXXOperatorCallExpr* expr) {
     80   // Only continue the walk-up if the operator is a blacklisted one.
     81   switch (expr->getOperator()) {
     82     case OO_Arrow:
     83     case OO_Subscript:
     84       this->WalkUpFromCallExpr(expr);
     85       return true;
     86     default:
     87       return true;
     88   }
     89 }
     90 
     91 bool CheckFinalizerVisitor::WalkUpFromCallExpr(CallExpr* expr) {
     92   // We consider all non-operator calls to be blacklisted contexts.
     93   bool prev_blacklist_context = blacklist_context_;
     94   blacklist_context_ = true;
     95   for (size_t i = 0; i < expr->getNumArgs(); ++i)
     96     this->TraverseStmt(expr->getArg(i));
     97   blacklist_context_ = prev_blacklist_context;
     98   return true;
     99 }
    100 
    101 bool CheckFinalizerVisitor::VisitMemberExpr(MemberExpr* member) {
    102   FieldDecl* field = dyn_cast<FieldDecl>(member->getMemberDecl());
    103   if (!field)
    104     return true;
    105 
    106   RecordInfo* info = cache_->Lookup(field->getParent());
    107   if (!info)
    108     return true;
    109 
    110   RecordInfo::Fields::iterator it = info->GetFields().find(field);
    111   if (it == info->GetFields().end())
    112     return true;
    113 
    114   if (seen_members_.find(member) != seen_members_.end())
    115     return true;
    116 
    117   bool as_eagerly_finalized = false;
    118   if (blacklist_context_ &&
    119       MightBeCollected(&it->second, &as_eagerly_finalized)) {
    120     finalized_fields_.push_back(
    121         Error(member, as_eagerly_finalized, &it->second));
    122     seen_members_.insert(member);
    123   }
    124   return true;
    125 }
    126 
    127 bool CheckFinalizerVisitor::MightBeCollected(FieldPoint* point,
    128                                              bool* as_eagerly_finalized) {
    129   MightBeCollectedVisitor visitor(is_eagerly_finalized_);
    130   point->edge()->Accept(&visitor);
    131   *as_eagerly_finalized = visitor.as_eagerly_finalized();
    132   return visitor.might_be_collected();
    133 }
    134