CheckFieldsVisitor.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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. #include "CheckFieldsVisitor.h"
  5. #include <cassert>
  6. #include "RecordInfo.h"
  7. #include "llvm/Support/ErrorHandling.h"
  8. CheckFieldsVisitor::CheckFieldsVisitor(const BlinkGCPluginOptions& options)
  9. : options_(options), current_(0), stack_allocated_host_(false) {}
  10. CheckFieldsVisitor::Errors& CheckFieldsVisitor::invalid_fields() {
  11. return invalid_fields_;
  12. }
  13. bool CheckFieldsVisitor::ContainsInvalidFields(RecordInfo* info) {
  14. stack_allocated_host_ = info->IsStackAllocated();
  15. managed_host_ = stack_allocated_host_ ||
  16. info->IsGCAllocated() ||
  17. info->IsNonNewable() ||
  18. info->IsOnlyPlacementNewable();
  19. for (RecordInfo::Fields::iterator it = info->GetFields().begin();
  20. it != info->GetFields().end();
  21. ++it) {
  22. context().clear();
  23. current_ = &it->second;
  24. current_->edge()->Accept(this);
  25. }
  26. return !invalid_fields_.empty();
  27. }
  28. void CheckFieldsVisitor::AtMember(Member*) {
  29. if (managed_host_)
  30. return;
  31. // A member is allowed to appear in the context of a root.
  32. for (Context::iterator it = context().begin();
  33. it != context().end();
  34. ++it) {
  35. if ((*it)->Kind() == Edge::kRoot)
  36. return;
  37. }
  38. invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged));
  39. }
  40. void CheckFieldsVisitor::AtWeakMember(WeakMember*) {
  41. // TODO(sof): remove this once crbug.com/724418's change
  42. // has safely been rolled out.
  43. if (options_.enable_weak_members_in_unmanaged_classes)
  44. return;
  45. AtMember(nullptr);
  46. }
  47. void CheckFieldsVisitor::AtIterator(Iterator* edge) {
  48. if (!managed_host_)
  49. return;
  50. if (!stack_allocated_host_ && edge->on_heap())
  51. invalid_fields_.push_back(std::make_pair(current_, kIteratorToGCManaged));
  52. }
  53. void CheckFieldsVisitor::AtValue(Value* edge) {
  54. // TODO: what should we do to check unions?
  55. if (edge->value()->record()->isUnion())
  56. return;
  57. if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) {
  58. invalid_fields_.push_back(std::make_pair(current_, kPtrFromHeapToStack));
  59. return;
  60. }
  61. if (!Parent() &&
  62. edge->value()->IsGCDerived() &&
  63. !edge->value()->IsGCMixin()) {
  64. invalid_fields_.push_back(std::make_pair(current_, kGCDerivedPartObject));
  65. return;
  66. }
  67. // Members/WeakMembers are prohibited if the host is stack allocated, but
  68. // heap collections with Members are okay.
  69. if (stack_allocated_host_ && Parent() &&
  70. (Parent()->IsMember() || Parent()->IsWeakMember())) {
  71. if (!GrandParent() || !GrandParent()->IsCollection()) {
  72. invalid_fields_.push_back(
  73. std::make_pair(current_, kMemberInStackAllocated));
  74. return;
  75. }
  76. }
  77. // If in a stack allocated context, be fairly insistent that T in Member<T>
  78. // is GC allocated, as stack allocated objects do not have a trace()
  79. // that separately verifies the validity of Member<T>.
  80. //
  81. // Notice that an error is only reported if T's definition is in scope;
  82. // we do not require that it must be brought into scope as that would
  83. // prevent declarations of mutually dependent class types.
  84. //
  85. // (Note: Member<>'s constructor will at run-time verify that the
  86. // pointer it wraps is indeed heap allocated.)
  87. if (stack_allocated_host_ && Parent() &&
  88. (Parent()->IsMember() || Parent()->IsWeakMember()) &&
  89. edge->value()->HasDefinition() && !edge->value()->IsGCAllocated()) {
  90. invalid_fields_.push_back(std::make_pair(current_, kMemberToGCUnmanaged));
  91. return;
  92. }
  93. if (!Parent() || !edge->value()->IsGCAllocated())
  94. return;
  95. // Disallow unique_ptr<T>, scoped_refptr<T>, WeakPtr<T>.
  96. if (Parent()->IsUniquePtr() || Parent()->IsRefPtr()) {
  97. invalid_fields_.push_back(std::make_pair(
  98. current_, InvalidSmartPtr(Parent())));
  99. return;
  100. }
  101. if (Parent()->IsRawPtr() && !stack_allocated_host_) {
  102. RawPtr* rawPtr = static_cast<RawPtr*>(Parent());
  103. Error error = rawPtr->HasReferenceType() ?
  104. kReferencePtrToGCManaged : kRawPtrToGCManaged;
  105. invalid_fields_.push_back(std::make_pair(current_, error));
  106. }
  107. }
  108. void CheckFieldsVisitor::AtCollection(Collection* edge) {
  109. if (edge->on_heap() && Parent() && Parent()->IsUniquePtr())
  110. invalid_fields_.push_back(std::make_pair(current_, kUniquePtrToGCManaged));
  111. }
  112. CheckFieldsVisitor::Error CheckFieldsVisitor::InvalidSmartPtr(Edge* ptr) {
  113. if (ptr->IsRefPtr())
  114. return ptr->Kind() == Edge::kStrong ? kRefPtrToGCManaged
  115. : kWeakPtrToGCManaged;
  116. if (ptr->IsUniquePtr())
  117. return kUniquePtrToGCManaged;
  118. llvm_unreachable("Unknown smart pointer kind");
  119. }