| // 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"); |
| } |