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 "CheckFieldsVisitor.h"
      6 
      7 #include <cassert>
      8 
      9 #include "BlinkGCPluginOptions.h"
     10 #include "RecordInfo.h"
     11 
     12 CheckFieldsVisitor::CheckFieldsVisitor()
     13     : current_(0),
     14       stack_allocated_host_(false) {
     15 }
     16 
     17 CheckFieldsVisitor::Errors& CheckFieldsVisitor::invalid_fields() {
     18   return invalid_fields_;
     19 }
     20 
     21 bool CheckFieldsVisitor::ContainsInvalidFields(RecordInfo* info) {
     22   stack_allocated_host_ = info->IsStackAllocated();
     23   managed_host_ = stack_allocated_host_ ||
     24                   info->IsGCAllocated() ||
     25                   info->IsNonNewable() ||
     26                   info->IsOnlyPlacementNewable();
     27   for (RecordInfo::Fields::iterator it = info->GetFields().begin();
     28        it != info->GetFields().end();
     29        ++it) {
     30     context().clear();
     31     current_ = &it->second;
     32     current_->edge()->Accept(this);
     33   }
     34   return !invalid_fields_.empty();
     35 }
     36 
     37 void CheckFieldsVisitor::AtMember(Member* edge) {
     38   if (managed_host_)
     39     return;
     40   // A member is allowed to appear in the context of a root.
     41   for (Context::iterator it = context().begin();
     42        it != context().end();
     43        ++it) {
     44     if ((*it)->Kind() == Edge::kRoot)
     45       return;
     46   }
     47   invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged));
     48 }
     49 
     50 void CheckFieldsVisitor::AtIterator(Iterator* edge) {
     51   if (!managed_host_)
     52     return;
     53 
     54   if (edge->IsUnsafe())
     55     invalid_fields_.push_back(std::make_pair(current_, kIteratorToGCManaged));
     56 }
     57 
     58 void CheckFieldsVisitor::AtValue(Value* edge) {
     59   // TODO: what should we do to check unions?
     60   if (edge->value()->record()->isUnion())
     61     return;
     62 
     63   if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) {
     64     invalid_fields_.push_back(std::make_pair(current_, kPtrFromHeapToStack));
     65     return;
     66   }
     67 
     68   if (!Parent() &&
     69       edge->value()->IsGCDerived() &&
     70       !edge->value()->IsGCMixin()) {
     71     invalid_fields_.push_back(std::make_pair(current_, kGCDerivedPartObject));
     72     return;
     73   }
     74 
     75   // If in a stack allocated context, be fairly insistent that T in Member<T>
     76   // is GC allocated, as stack allocated objects do not have a trace()
     77   // that separately verifies the validity of Member<T>.
     78   //
     79   // Notice that an error is only reported if T's definition is in scope;
     80   // we do not require that it must be brought into scope as that would
     81   // prevent declarations of mutually dependent class types.
     82   //
     83   // (Note: Member<>'s constructor will at run-time verify that the
     84   // pointer it wraps is indeed heap allocated.)
     85   if (stack_allocated_host_ && Parent() && Parent()->IsMember() &&
     86       edge->value()->HasDefinition() && !edge->value()->IsGCAllocated()) {
     87     invalid_fields_.push_back(std::make_pair(current_,
     88                                              kMemberToGCUnmanaged));
     89     return;
     90   }
     91 
     92   if (!Parent() || !edge->value()->IsGCAllocated())
     93     return;
     94 
     95   // Disallow  OwnPtr<T>, RefPtr<T> and T* to stack-allocated types.
     96   if (Parent()->IsOwnPtr() ||
     97       Parent()->IsUniquePtr() ||
     98       Parent()->IsRefPtr() ||
     99       (stack_allocated_host_ && Parent()->IsRawPtr())) {
    100     invalid_fields_.push_back(std::make_pair(
    101         current_, InvalidSmartPtr(Parent())));
    102     return;
    103   }
    104   if (Parent()->IsRawPtr()) {
    105     RawPtr* rawPtr = static_cast<RawPtr*>(Parent());
    106     Error error = rawPtr->HasReferenceType() ?
    107         kReferencePtrToGCManaged : kRawPtrToGCManaged;
    108     invalid_fields_.push_back(std::make_pair(current_, error));
    109   }
    110 }
    111 
    112 void CheckFieldsVisitor::AtCollection(Collection* edge) {
    113   if (edge->on_heap() && Parent() && Parent()->IsOwnPtr())
    114     invalid_fields_.push_back(std::make_pair(current_, kOwnPtrToGCManaged));
    115   if (edge->on_heap() && Parent() && Parent()->IsUniquePtr())
    116     invalid_fields_.push_back(std::make_pair(current_, kUniquePtrToGCManaged));
    117 }
    118 
    119 CheckFieldsVisitor::Error CheckFieldsVisitor::InvalidSmartPtr(Edge* ptr) {
    120   if (ptr->IsRawPtr()) {
    121     if (static_cast<RawPtr*>(ptr)->HasReferenceType())
    122       return kReferencePtrToGCManaged;
    123     else
    124       return kRawPtrToGCManaged;
    125   }
    126   if (ptr->IsRefPtr())
    127     return kRefPtrToGCManaged;
    128   if (ptr->IsOwnPtr())
    129     return kOwnPtrToGCManaged;
    130   if (ptr->IsUniquePtr())
    131     return kUniquePtrToGCManaged;
    132   assert(false && "Unknown smart pointer kind");
    133 }
    134