| Index: tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp
|
| diff --git a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0ed953fccf92e57197fcb7cc54a99bff36b8a675
|
| --- /dev/null
|
| +++ b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp
|
| @@ -0,0 +1,152 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "CheckFieldsVisitor.h"
|
| +
|
| +#include <cassert>
|
| +
|
| +#include "BlinkGCPluginOptions.h"
|
| +#include "RecordInfo.h"
|
| +
|
| +CheckFieldsVisitor::CheckFieldsVisitor(const BlinkGCPluginOptions& options)
|
| + : options_(options),
|
| + current_(0),
|
| + stack_allocated_host_(false) {
|
| +}
|
| +
|
| +CheckFieldsVisitor::Errors& CheckFieldsVisitor::invalid_fields() {
|
| + return invalid_fields_;
|
| +}
|
| +
|
| +bool CheckFieldsVisitor::ContainsInvalidFields(RecordInfo* info) {
|
| + stack_allocated_host_ = info->IsStackAllocated();
|
| + managed_host_ = stack_allocated_host_ ||
|
| + info->IsGCAllocated() ||
|
| + info->IsNonNewable() ||
|
| + info->IsOnlyPlacementNewable();
|
| + for (RecordInfo::Fields::iterator it = info->GetFields().begin();
|
| + it != info->GetFields().end();
|
| + ++it) {
|
| + context().clear();
|
| + current_ = &it->second;
|
| + current_->edge()->Accept(this);
|
| + }
|
| + return !invalid_fields_.empty();
|
| +}
|
| +
|
| +void CheckFieldsVisitor::AtMember(Member* edge) {
|
| + if (managed_host_)
|
| + return;
|
| + // A member is allowed to appear in the context of a root.
|
| + for (Context::iterator it = context().begin();
|
| + it != context().end();
|
| + ++it) {
|
| + if ((*it)->Kind() == Edge::kRoot)
|
| + return;
|
| + }
|
| + invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged));
|
| +}
|
| +
|
| +void CheckFieldsVisitor::AtValue(Value* edge) {
|
| + // TODO: what should we do to check unions?
|
| + if (edge->value()->record()->isUnion())
|
| + return;
|
| +
|
| + if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) {
|
| + invalid_fields_.push_back(std::make_pair(current_, kPtrFromHeapToStack));
|
| + return;
|
| + }
|
| +
|
| + if (!Parent() &&
|
| + edge->value()->IsGCDerived() &&
|
| + !edge->value()->IsGCMixin()) {
|
| + invalid_fields_.push_back(std::make_pair(current_, kGCDerivedPartObject));
|
| + return;
|
| + }
|
| +
|
| + // If in a stack allocated context, be fairly insistent that T in Member<T>
|
| + // is GC allocated, as stack allocated objects do not have a trace()
|
| + // that separately verifies the validity of Member<T>.
|
| + //
|
| + // Notice that an error is only reported if T's definition is in scope;
|
| + // we do not require that it must be brought into scope as that would
|
| + // prevent declarations of mutually dependent class types.
|
| + //
|
| + // (Note: Member<>'s constructor will at run-time verify that the
|
| + // pointer it wraps is indeed heap allocated.)
|
| + if (stack_allocated_host_ && Parent() && Parent()->IsMember() &&
|
| + edge->value()->HasDefinition() && !edge->value()->IsGCAllocated()) {
|
| + invalid_fields_.push_back(std::make_pair(current_,
|
| + kMemberToGCUnmanaged));
|
| + return;
|
| + }
|
| +
|
| + if (!Parent() || !edge->value()->IsGCAllocated())
|
| + return;
|
| +
|
| + // In transition mode, disallow OwnPtr<T>, RawPtr<T> to GC allocated T's,
|
| + // also disallow T* in stack-allocated types.
|
| + if (options_.enable_oilpan) {
|
| + if (Parent()->IsOwnPtr() ||
|
| + Parent()->IsRawPtrClass() ||
|
| + (stack_allocated_host_ && Parent()->IsRawPtr())) {
|
| + invalid_fields_.push_back(std::make_pair(
|
| + current_, InvalidSmartPtr(Parent())));
|
| + return;
|
| + }
|
| + if (options_.warn_raw_ptr && Parent()->IsRawPtr()) {
|
| + if (static_cast<RawPtr*>(Parent())->HasReferenceType()) {
|
| + invalid_fields_.push_back(std::make_pair(
|
| + current_, kReferencePtrToGCManagedWarning));
|
| + } else {
|
| + invalid_fields_.push_back(std::make_pair(
|
| + current_, kRawPtrToGCManagedWarning));
|
| + }
|
| + }
|
| + return;
|
| + }
|
| +
|
| + if (Parent()->IsRawPtr() || Parent()->IsRefPtr() || Parent()->IsOwnPtr()) {
|
| + invalid_fields_.push_back(std::make_pair(
|
| + current_, InvalidSmartPtr(Parent())));
|
| + return;
|
| + }
|
| +}
|
| +
|
| +void CheckFieldsVisitor::AtCollection(Collection* edge) {
|
| + if (edge->on_heap() && Parent() && Parent()->IsOwnPtr())
|
| + invalid_fields_.push_back(std::make_pair(current_, kOwnPtrToGCManaged));
|
| +}
|
| +
|
| +bool CheckFieldsVisitor::IsWarning(Error error) {
|
| + if (error == kRawPtrToGCManagedWarning)
|
| + return true;
|
| + if (error == kReferencePtrToGCManagedWarning)
|
| + return true;
|
| + return false;
|
| +}
|
| +
|
| +bool CheckFieldsVisitor::IsRawPtrError(Error error) {
|
| + return (error == kRawPtrToGCManaged ||
|
| + error == kRawPtrToGCManagedWarning);
|
| +}
|
| +
|
| +bool CheckFieldsVisitor::IsReferencePtrError(Error error) {
|
| + return (error == kReferencePtrToGCManaged ||
|
| + error == kReferencePtrToGCManagedWarning);
|
| +}
|
| +
|
| +CheckFieldsVisitor::Error CheckFieldsVisitor::InvalidSmartPtr(Edge* ptr) {
|
| + if (ptr->IsRawPtr()) {
|
| + if (static_cast<RawPtr*>(ptr)->HasReferenceType())
|
| + return kReferencePtrToGCManaged;
|
| + else
|
| + return kRawPtrToGCManaged;
|
| + }
|
| + if (ptr->IsRefPtr())
|
| + return kRefPtrToGCManaged;
|
| + if (ptr->IsOwnPtr())
|
| + return kOwnPtrToGCManaged;
|
| + assert(false && "Unknown smart pointer kind");
|
| +}
|
|
|