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