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
AtValue(Value * edge)50 void CheckFieldsVisitor::AtValue(Value* edge) {
51 // TODO: what should we do to check unions?
52 if (edge->value()->record()->isUnion())
53 return;
54
55 if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) {
56 invalid_fields_.push_back(std::make_pair(current_, kPtrFromHeapToStack));
57 return;
58 }
59
60 if (!Parent() &&
61 edge->value()->IsGCDerived() &&
62 !edge->value()->IsGCMixin()) {
63 invalid_fields_.push_back(std::make_pair(current_, kGCDerivedPartObject));
64 return;
65 }
66
67 // If in a stack allocated context, be fairly insistent that T in Member<T>
68 // is GC allocated, as stack allocated objects do not have a trace()
69 // that separately verifies the validity of Member<T>.
70 //
71 // Notice that an error is only reported if T's definition is in scope;
72 // we do not require that it must be brought into scope as that would
73 // prevent declarations of mutually dependent class types.
74 //
75 // (Note: Member<>'s constructor will at run-time verify that the
76 // pointer it wraps is indeed heap allocated.)
77 if (stack_allocated_host_ && Parent() && Parent()->IsMember() &&
78 edge->value()->HasDefinition() && !edge->value()->IsGCAllocated()) {
79 invalid_fields_.push_back(std::make_pair(current_,
80 kMemberToGCUnmanaged));
81 return;
82 }
83
84 if (!Parent() || !edge->value()->IsGCAllocated())
85 return;
86
87 // Disallow OwnPtr<T>, RefPtr<T> and T* to stack-allocated types.
88 if (Parent()->IsOwnPtr() ||
89 Parent()->IsUniquePtr() ||
90 Parent()->IsRefPtr() ||
91 (stack_allocated_host_ && Parent()->IsRawPtr())) {
92 invalid_fields_.push_back(std::make_pair(
93 current_, InvalidSmartPtr(Parent())));
94 return;
95 }
96 if (Parent()->IsRawPtr()) {
97 RawPtr* rawPtr = static_cast<RawPtr*>(Parent());
98 Error error = rawPtr->HasReferenceType() ?
99 kReferencePtrToGCManaged : kRawPtrToGCManaged;
100 invalid_fields_.push_back(std::make_pair(current_, error));
101 }
102 }
103
AtCollection(Collection * edge)104 void CheckFieldsVisitor::AtCollection(Collection* edge) {
105 if (edge->on_heap() && Parent() && Parent()->IsOwnPtr())
106 invalid_fields_.push_back(std::make_pair(current_, kOwnPtrToGCManaged));
107 if (edge->on_heap() && Parent() && Parent()->IsUniquePtr())
108 invalid_fields_.push_back(std::make_pair(current_, kUniquePtrToGCManaged));
109 }
110
InvalidSmartPtr(Edge * ptr)111 CheckFieldsVisitor::Error CheckFieldsVisitor::InvalidSmartPtr(Edge* ptr) {
112 if (ptr->IsRawPtr()) {
113 if (static_cast<RawPtr*>(ptr)->HasReferenceType())
114 return kReferencePtrToGCManaged;
115 else
116 return kRawPtrToGCManaged;
117 }
118 if (ptr->IsRefPtr())
119 return kRefPtrToGCManaged;
120 if (ptr->IsOwnPtr())
121 return kOwnPtrToGCManaged;
122 if (ptr->IsUniquePtr())
123 return kUniquePtrToGCManaged;
124 assert(false && "Unknown smart pointer kind");
125 }
126