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