blob: 0ed953fccf92e57197fcb7cc54a99bff36b8a675 [file] [log] [blame]
// 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");
}