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
CheckFieldsVisitor()12 CheckFieldsVisitor::CheckFieldsVisitor()
13 : current_(0),
14 stack_allocated_host_(false) {
15 }
16
invalid_fields()17 CheckFieldsVisitor::Errors& CheckFieldsVisitor::invalid_fields() {
18 return invalid_fields_;
19 }
20
ContainsInvalidFields(RecordInfo * info)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
AtMember(Member * edge)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
AtIterator(Iterator * edge)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
AtValue(Value * edge)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
AtCollection(Collection * edge)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
InvalidSmartPtr(Edge * ptr)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