0

Reland "heap: Fix clang plugin handling of cppgc library types"

This is a reland of 3d3cb2f878

Original change's description:
> heap: Fix clang plugin handling of cppgc library types
>
> Bug: 1056170
> Change-Id: I8a056a9a44e6b482e6d96df8c486b6d134fed46e
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2976400
> Commit-Queue: Omer Katz <omerkatz@chromium.org>
> Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#894876}

Bug: 1056170
Change-Id: Ibcfe9064edaa739badebffc3701b863f5cc359d2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2982560
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Omer Katz <omerkatz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#896116}
This commit is contained in:
Omer Katz
2021-06-25 17:53:20 +00:00
committed by Chromium LUCI CQ
parent 193ef7d462
commit 91fb9e97f6
5 changed files with 141 additions and 79 deletions

@ -14,6 +14,7 @@
#include <cassert>
#include "RecordInfo.h"
#include "clang/AST/AST.h"
#include "clang/AST/Attr.h"
@ -35,28 +36,78 @@ extern const char kConstReverseIteratorName[];
extern const char kReverseIteratorName[];
class Config {
private:
// Checks that the namespace matches the expected namespace and that the type
// takes at least |expected_minimum_arg_count| template arguments. If both
// requirements are fulfilled, populates |args| with the first
// |expected_minimum_arg_count| template arguments. Verifying only the minimum
// expected argument keeps the plugin resistant to changes in the type
// definitions (to some extent)
static bool VerifyNamespaceAndArgCount(std::string expected_ns_name,
int expected_minimum_arg_count,
llvm::StringRef ns_name,
RecordInfo* info,
RecordInfo::TemplateArgs* args) {
return (ns_name == expected_ns_name) &&
info->GetTemplateArgs(expected_minimum_arg_count, args);
}
public:
static bool IsMember(llvm::StringRef name) {
return name == "Member";
static bool IsMember(llvm::StringRef name,
llvm::StringRef ns_name,
RecordInfo* info,
RecordInfo::TemplateArgs* args) {
if (name == "Member") {
return VerifyNamespaceAndArgCount("blink", 1, ns_name, info, args);
}
if (name == "BasicMember") {
if (!VerifyNamespaceAndArgCount("cppgc", 2, ns_name, info, args))
return false;
return (*args)[1]->getAsRecordDecl()->getName() == "StrongMemberTag";
}
return false;
}
static bool IsWeakMember(llvm::StringRef name) {
return name == "WeakMember";
static bool IsWeakMember(llvm::StringRef name,
llvm::StringRef ns_name,
RecordInfo* info,
RecordInfo::TemplateArgs* args) {
if (name == "WeakMember") {
return VerifyNamespaceAndArgCount("blink", 1, ns_name, info, args);
}
if (name == "BasicMember") {
if (!VerifyNamespaceAndArgCount("cppgc", 2, ns_name, info, args))
return false;
return (*args)[1]->getAsRecordDecl()->getName() == "WeakMemberTag";
}
return false;
}
static bool IsMemberHandle(llvm::StringRef name) {
return IsMember(name) ||
IsWeakMember(name);
static bool IsPersistent(llvm::StringRef name,
llvm::StringRef ns_name,
RecordInfo* info,
RecordInfo::TemplateArgs* args) {
if ((name == "Persistent") || (name == "WeakPersistent")) {
return VerifyNamespaceAndArgCount("blink", 1, ns_name, info, args);
}
if (name == "BasicPersistent") {
return VerifyNamespaceAndArgCount("cppgc", 1, ns_name, info, args);
}
return false;
}
static bool IsPersistent(llvm::StringRef name) {
return name == "Persistent" ||
name == "WeakPersistent" ;
}
static bool IsCrossThreadPersistent(llvm::StringRef name) {
return name == "CrossThreadPersistent" ||
name == "CrossThreadWeakPersistent" ;
static bool IsCrossThreadPersistent(llvm::StringRef name,
llvm::StringRef ns_name,
RecordInfo* info,
RecordInfo::TemplateArgs* args) {
if ((name == "CrossThreadPersistent") ||
(name == "CrossThreadWeakPersistent")) {
return VerifyNamespaceAndArgCount("blink", 1, ns_name, info, args);
}
if (name == "BasicCrossThreadPersistent") {
return VerifyNamespaceAndArgCount("cppgc", 1, ns_name, info, args);
}
return false;
}
static bool IsRefPtr(llvm::StringRef name) { return name == "scoped_refptr"; }
@ -71,8 +122,12 @@ class Config {
return name == "unique_ptr";
}
static bool IsTraceWrapperV8Reference(llvm::StringRef name) {
return name == "TraceWrapperV8Reference";
static bool IsTraceWrapperV8Reference(llvm::StringRef name,
llvm::StringRef ns_name,
RecordInfo* info,
RecordInfo::TemplateArgs* args) {
return name == "TraceWrapperV8Reference" &&
VerifyNamespaceAndArgCount("blink", 1, ns_name, info, args);
}
static bool IsWTFCollection(llvm::StringRef name) {

@ -686,33 +686,32 @@ Edge* RecordInfo::CreateEdge(const Type* type) {
return 0;
}
if (Config::IsMember(info->name()) && info->GetTemplateArgs(1, &args)) {
if (Edge* ptr = CreateEdge(args[0]))
// Find top-level namespace.
NamespaceDecl* ns = dyn_cast<NamespaceDecl>(info->record()->getDeclContext());
if (ns) {
while (NamespaceDecl* outer_ns =
dyn_cast<NamespaceDecl>(ns->getDeclContext())) {
ns = outer_ns;
}
}
auto ns_name = ns ? ns->getName() : "";
if (Config::IsMember(info->name(), ns_name, info, &args)) {
if (Edge* ptr = CreateEdge(args[0])) {
return new Member(ptr);
}
return 0;
}
if (Config::IsWeakMember(info->name()) && info->GetTemplateArgs(1, &args)) {
if (Config::IsWeakMember(info->name(), ns_name, info, &args)) {
if (Edge* ptr = CreateEdge(args[0]))
return new WeakMember(ptr);
return 0;
}
bool is_persistent = Config::IsPersistent(info->name());
if (is_persistent || Config::IsCrossThreadPersistent(info->name())) {
// Persistent might refer to v8::Persistent, so check the name space.
// TODO: Consider using a more canonical identification than names.
NamespaceDecl* ns =
dyn_cast<NamespaceDecl>(info->record()->getDeclContext());
// Find outer-most namespace.
while (NamespaceDecl* outer_ns =
dyn_cast<NamespaceDecl>(ns->getDeclContext())) {
ns = outer_ns;
}
if (!ns || (ns->getName() != "blink") && (ns->getName() != "cppgc"))
return 0;
if (!info->GetTemplateArgs(1, &args))
return 0;
bool is_persistent = Config::IsPersistent(info->name(), ns_name, info, &args);
if (is_persistent ||
Config::IsCrossThreadPersistent(info->name(), ns_name, info, &args)) {
if (Edge* ptr = CreateEdge(args[0])) {
if (is_persistent)
return new Persistent(ptr);
@ -739,8 +738,7 @@ Edge* RecordInfo::CreateEdge(const Type* type) {
return edge;
}
if (Config::IsTraceWrapperV8Reference(info->name()) &&
info->GetTemplateArgs(1, &args)) {
if (Config::IsTraceWrapperV8Reference(info->name(), ns_name, info, &args)) {
if (Edge* ptr = CreateEdge(args[0]))
return new TraceWrapperV8Reference(ptr);
return 0;

@ -196,6 +196,44 @@ class Visitor {
namespace internal {
class GarbageCollectedBase {};
class StrongMemberTag;
class WeakMemberTag;
class MemberBase {};
template <typename T, typename Tag>
class BasicMember : public MemberBase {
public:
operator T*() const { return 0; }
T* operator->() const { return 0; }
bool operator!() const { return false; }
};
class StrongPersistentPolicy;
class WeakPersistentPolicy;
class PersistentBase {};
template <typename T, typename Tag>
class BasicPersistent : public PersistentBase {
public:
operator T*() const { return 0; }
T* operator->() const { return 0; }
bool operator!() const { return false; }
};
class StrongCrossThreadPersistentPolicy;
class WeakCrossThreadPersistentPolicy;
template <typename T, typename Tag>
class BasicCrossThreadPersistent : public PersistentBase {
public:
operator T*() const { return 0; }
T* operator->() const { return 0; }
bool operator!() const { return false; }
};
} // namespace internal
template <typename T>
@ -209,54 +247,25 @@ class GarbageCollectedMixin : public internal::GarbageCollectedBase {
};
template <typename T>
class Member {
public:
operator T*() const { return 0; }
T* operator->() const { return 0; }
bool operator!() const { return false; }
};
using Member = internal::BasicMember<T, internal::StrongMemberTag>;
template <typename T>
using WeakMember = internal::BasicMember<T, internal::WeakMemberTag>;
template <typename T>
class WeakMember {
public:
operator T*() const { return 0; }
T* operator->() const { return 0; }
bool operator!() const { return false; }
};
using Persistent =
internal::BasicPersistent<T, internal::StrongPersistentPolicy>;
template <typename T>
class Persistent {
public:
operator T*() const { return 0; }
T* operator->() const { return 0; }
bool operator!() const { return false; }
};
template <typename T>
class WeakPersistent {
public:
operator T*() const { return 0; }
T* operator->() const { return 0; }
bool operator!() const { return false; }
};
using WeakPersistent =
internal::BasicPersistent<T, internal::WeakPersistentPolicy>;
namespace subtle {
template <typename T>
class CrossThreadPersistent {
public:
operator T*() const { return 0; }
T* operator->() const { return 0; }
bool operator!() const { return false; }
};
using CrossThreadPersistent = internal::
BasicCrossThreadPersistent<T, internal::StrongCrossThreadPersistentPolicy>;
template <typename T>
class CrossThreadWeakPersistent {
public:
operator T*() const { return 0; }
T* operator->() const { return 0; }
bool operator!() const { return false; }
};
using CrossThreadWeakPersistent = internal::
BasicCrossThreadPersistent<T, internal::WeakCrossThreadPersistentPolicy>;
} // namespace subtle

@ -23,7 +23,7 @@ class DerivedHeapObject2 : public HeapObject {
./stack_allocated.h:44:3: warning: [blink-gc] Garbage collected class 'DerivedHeapObject2' is not permitted to override its new operator.
STACK_ALLOCATED();
^
./heap/stubs.h:362:3: note: expanded from macro 'STACK_ALLOCATED'
./heap/stubs.h:371:3: note: expanded from macro 'STACK_ALLOCATED'
__attribute__((annotate("blink_stack_allocated"))) \
^
In file included from stack_allocated.cpp:5:

@ -1,4 +1,4 @@
trace_if_needed.cpp:9:1: warning: [blink-gc] Class 'TemplatedObject<cppgc::Member<blink::HeapObject>>' has untraced fields that require tracing.
trace_if_needed.cpp:9:1: warning: [blink-gc] Class 'TemplatedObject<cppgc::internal::BasicMember<blink::HeapObject, cppgc::internal::StrongMemberTag>>' has untraced fields that require tracing.
template <typename T>
^
./trace_if_needed.h:21:5: note: [blink-gc] Untraced field 'm_two' declared here: