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