Commit 1f34a19f authored by Anton Bikineev's avatar Anton Bikineev Committed by Commit Bot

Reland "blink_gc_plugin: Disallow Members for stack-allocated types"

Members in stack allocated types issue redundant write-barriers. This CL
provided an option --no-members-in-gc-allocated, which prohibits use of
them.

Bug: 1021889
Change-Id: Iae010f6a3154ba54963fafddc888b45a42b56698
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2015167Reviewed-by: default avatarAnton Bikineev <bikineev@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Commit-Queue: Anton Bikineev <bikineev@chromium.org>
Cr-Commit-Position: refs/heads/master@{#734398}
parent 1d33fc6f
...@@ -33,6 +33,8 @@ class BlinkGCPluginAction : public PluginASTAction { ...@@ -33,6 +33,8 @@ class BlinkGCPluginAction : public PluginASTAction {
for (const auto& arg : args) { for (const auto& arg : args) {
if (arg == "dump-graph") { if (arg == "dump-graph") {
options_.dump_graph = true; options_.dump_graph = true;
} else if (arg == "no-members-in-stack-allocated") {
options_.no_members_in_stack_allocated = true;
} else if (arg == "enable-weak-members-in-unmanaged-classes") { } else if (arg == "enable-weak-members-in-unmanaged-classes") {
options_.enable_weak_members_in_unmanaged_classes = true; options_.enable_weak_members_in_unmanaged_classes = true;
} else if (arg == "no-gc-finalized" || arg == "warn-unneeded-finalizer") { } else if (arg == "no-gc-finalized" || arg == "warn-unneeded-finalizer") {
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
struct BlinkGCPluginOptions { struct BlinkGCPluginOptions {
bool dump_graph = false; bool dump_graph = false;
// If |true|, disallow Member types in stack allocated classes.
bool no_members_in_stack_allocated = false;
// Member<T> fields are only permitted in managed classes, // Member<T> fields are only permitted in managed classes,
// something CheckFieldsVisitor verifies, issuing errors if // something CheckFieldsVisitor verifies, issuing errors if
// found in unmanaged classes. WeakMember<T> should be treated // found in unmanaged classes. WeakMember<T> should be treated
......
...@@ -78,6 +78,19 @@ void CheckFieldsVisitor::AtValue(Value* edge) { ...@@ -78,6 +78,19 @@ void CheckFieldsVisitor::AtValue(Value* edge) {
return; return;
} }
if (options_.no_members_in_stack_allocated) {
// Members/WeakMembers are prohibited if the host is stack allocated, but
// heap collections with Members are okay.
if (stack_allocated_host_ && Parent() &&
(Parent()->IsMember() || Parent()->IsWeakMember())) {
if (!GrandParent() || !GrandParent()->IsCollection()) {
invalid_fields_.push_back(
std::make_pair(current_, kMemberInStackAllocated));
return;
}
}
}
// If in a stack allocated context, be fairly insistent that T in Member<T> // 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() // is GC allocated, as stack allocated objects do not have a trace()
// that separately verifies the validity of Member<T>. // that separately verifies the validity of Member<T>.
...@@ -88,25 +101,24 @@ void CheckFieldsVisitor::AtValue(Value* edge) { ...@@ -88,25 +101,24 @@ void CheckFieldsVisitor::AtValue(Value* edge) {
// //
// (Note: Member<>'s constructor will at run-time verify that the // (Note: Member<>'s constructor will at run-time verify that the
// pointer it wraps is indeed heap allocated.) // pointer it wraps is indeed heap allocated.)
if (stack_allocated_host_ && Parent() && Parent()->IsMember() && if (stack_allocated_host_ && Parent() &&
(Parent()->IsMember() || Parent()->IsWeakMember()) &&
edge->value()->HasDefinition() && !edge->value()->IsGCAllocated()) { edge->value()->HasDefinition() && !edge->value()->IsGCAllocated()) {
invalid_fields_.push_back(std::make_pair(current_, invalid_fields_.push_back(std::make_pair(current_, kMemberToGCUnmanaged));
kMemberToGCUnmanaged));
return; return;
} }
if (!Parent() || !edge->value()->IsGCAllocated()) if (!Parent() || !edge->value()->IsGCAllocated())
return; return;
// Disallow unique_ptr<T>, RefPtr<T> and T* to stack-allocated types. // Disallow unique_ptr<T>, RefPtr<T>.
if (Parent()->IsUniquePtr() || if (Parent()->IsUniquePtr() || Parent()->IsRefPtr()) {
Parent()->IsRefPtr() ||
(stack_allocated_host_ && Parent()->IsRawPtr())) {
invalid_fields_.push_back(std::make_pair( invalid_fields_.push_back(std::make_pair(
current_, InvalidSmartPtr(Parent()))); current_, InvalidSmartPtr(Parent())));
return; return;
} }
if (Parent()->IsRawPtr()) { if (Parent()->IsRawPtr() &&
!(stack_allocated_host_ && options_.no_members_in_stack_allocated)) {
RawPtr* rawPtr = static_cast<RawPtr*>(Parent()); RawPtr* rawPtr = static_cast<RawPtr*>(Parent());
Error error = rawPtr->HasReferenceType() ? Error error = rawPtr->HasReferenceType() ?
kReferencePtrToGCManaged : kRawPtrToGCManaged; kReferencePtrToGCManaged : kRawPtrToGCManaged;
...@@ -120,12 +132,6 @@ void CheckFieldsVisitor::AtCollection(Collection* edge) { ...@@ -120,12 +132,6 @@ void CheckFieldsVisitor::AtCollection(Collection* edge) {
} }
CheckFieldsVisitor::Error CheckFieldsVisitor::InvalidSmartPtr(Edge* ptr) { CheckFieldsVisitor::Error CheckFieldsVisitor::InvalidSmartPtr(Edge* ptr) {
if (ptr->IsRawPtr()) {
if (static_cast<RawPtr*>(ptr)->HasReferenceType())
return kReferencePtrToGCManaged;
else
return kRawPtrToGCManaged;
}
if (ptr->IsRefPtr()) if (ptr->IsRefPtr())
return kRefPtrToGCManaged; return kRefPtrToGCManaged;
if (ptr->IsUniquePtr()) if (ptr->IsUniquePtr())
......
...@@ -30,6 +30,7 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor { ...@@ -30,6 +30,7 @@ class CheckFieldsVisitor : public RecursiveEdgeVisitor {
kPtrFromHeapToStack, kPtrFromHeapToStack,
kGCDerivedPartObject, kGCDerivedPartObject,
kIteratorToGCManaged, kIteratorToGCManaged,
kMemberInStackAllocated,
}; };
using Errors = std::vector<std::pair<FieldPoint*, Error>>; using Errors = std::vector<std::pair<FieldPoint*, Error>>;
......
...@@ -130,6 +130,10 @@ const char kTraceMethodOfStackAllocatedParentNote[] = ...@@ -130,6 +130,10 @@ const char kTraceMethodOfStackAllocatedParentNote[] =
"[blink-gc] The stack allocated class %0 provides an unnecessary " "[blink-gc] The stack allocated class %0 provides an unnecessary "
"trace method:"; "trace method:";
const char kMemberInStackAllocated[] =
"[blink-gc] Member field %0 in stack allocated class declared here (use "
"raw pointer or reference instead):";
const char kUniquePtrUsedWithGC[] = const char kUniquePtrUsedWithGC[] =
"[blink-gc] Disallowed use of %0 found; %1 is a garbage-collected type. " "[blink-gc] Disallowed use of %0 found; %1 is a garbage-collected type. "
"std::unique_ptr cannot hold garbage-collected objects."; "std::unique_ptr cannot hold garbage-collected objects.";
...@@ -203,6 +207,8 @@ DiagnosticsReporter::DiagnosticsReporter( ...@@ -203,6 +207,8 @@ DiagnosticsReporter::DiagnosticsReporter(
getErrorLevel(), kIteratorToGCManagedCollectionNote); getErrorLevel(), kIteratorToGCManagedCollectionNote);
diag_trace_method_of_stack_allocated_parent_ = diagnostic_.getCustomDiagID( diag_trace_method_of_stack_allocated_parent_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kTraceMethodOfStackAllocatedParentNote); getErrorLevel(), kTraceMethodOfStackAllocatedParentNote);
diag_member_in_stack_allocated_class_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kMemberInStackAllocated);
// Register note messages. // Register note messages.
diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID( diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID(
...@@ -334,6 +340,8 @@ void DiagnosticsReporter::ClassContainsInvalidFields( ...@@ -334,6 +340,8 @@ void DiagnosticsReporter::ClassContainsInvalidFields(
note = diag_part_object_to_gc_derived_class_note_; note = diag_part_object_to_gc_derived_class_note_;
} else if (error.second == CheckFieldsVisitor::kIteratorToGCManaged) { } else if (error.second == CheckFieldsVisitor::kIteratorToGCManaged) {
note = diag_iterator_to_gc_managed_collection_note_; note = diag_iterator_to_gc_managed_collection_note_;
} else if (error.second == CheckFieldsVisitor::kMemberInStackAllocated) {
note = diag_member_in_stack_allocated_class_;
} else { } else {
llvm_unreachable("Unknown field error."); llvm_unreachable("Unknown field error.");
} }
......
...@@ -139,6 +139,7 @@ class DiagnosticsReporter { ...@@ -139,6 +139,7 @@ class DiagnosticsReporter {
unsigned diag_manual_dispatch_method_note_; unsigned diag_manual_dispatch_method_note_;
unsigned diag_iterator_to_gc_managed_collection_note_; unsigned diag_iterator_to_gc_managed_collection_note_;
unsigned diag_trace_method_of_stack_allocated_parent_; unsigned diag_trace_method_of_stack_allocated_parent_;
unsigned diag_member_in_stack_allocated_class_;
unsigned diag_unique_ptr_used_with_gc_; unsigned diag_unique_ptr_used_with_gc_;
unsigned diag_optional_used_with_gc_; unsigned diag_optional_used_with_gc_;
......
...@@ -63,6 +63,9 @@ class RecursiveEdgeVisitor : public EdgeVisitor { ...@@ -63,6 +63,9 @@ class RecursiveEdgeVisitor : public EdgeVisitor {
typedef std::deque<Edge*> Context; typedef std::deque<Edge*> Context;
Context& context() { return context_; } Context& context() { return context_; }
Edge* Parent() { return context_.empty() ? 0 : context_.front(); } Edge* Parent() { return context_.empty() ? 0 : context_.front(); }
Edge* GrandParent() {
return Parent() ? (context_.size() > 1 ? context_[1] : nullptr) : nullptr;
}
void Enter(Edge* e) { return context_.push_front(e); } void Enter(Edge* e) { return context_.push_front(e); }
void Leave() { context_.pop_front(); } void Leave() { context_.pop_front(); }
......
...@@ -23,8 +23,7 @@ private: ...@@ -23,8 +23,7 @@ private:
class StackObject { class StackObject {
STACK_ALLOCATED(); STACK_ALLOCATED();
private: private:
Member<HeapObject> m_obj; // OK HeapObject* m_obj; // OK
Member<OffHeapObject> m_memberOff; // NOT OK
HeapVector<Member<OffHeapObject>> m_heapVectorMemberOff; // NOT OK HeapVector<Member<OffHeapObject>> m_heapVectorMemberOff; // NOT OK
}; };
......
...@@ -11,10 +11,10 @@ class OffHeapObject { ...@@ -11,10 +11,10 @@ class OffHeapObject {
./member_in_offheap_class.h:23:1: warning: [blink-gc] Class 'StackObject' contains invalid fields. ./member_in_offheap_class.h:23:1: warning: [blink-gc] Class 'StackObject' contains invalid fields.
class StackObject { class StackObject {
^ ^
./member_in_offheap_class.h:27:5: note: [blink-gc] Member field 'm_memberOff' to non-GC managed class declared here: ./member_in_offheap_class.h:26:5: note: [blink-gc] Raw pointer field 'm_obj' to a GC managed class declared here:
Member<OffHeapObject> m_memberOff; // NOT OK HeapObject* m_obj; // OK
^ ^
./member_in_offheap_class.h:28:5: note: [blink-gc] Member field 'm_heapVectorMemberOff' to non-GC managed class declared here: ./member_in_offheap_class.h:27:5: note: [blink-gc] Member field 'm_heapVectorMemberOff' to non-GC managed class declared here:
HeapVector<Member<OffHeapObject>> m_heapVectorMemberOff; // NOT OK HeapVector<Member<OffHeapObject>> m_heapVectorMemberOff; // NOT OK
^ ^
2 warnings generated. 2 warnings generated.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment