Hi klimek,
Refactor VariantMatcher::MatcherOps to reduce the amount of generated code.
- Use a manually generated vtable instead of virtual method.
- Make some code type agnostic and move it to the cpp file.
- Return a void* instead of storing the object in MatcherOps. The
caller already knows the real type.
This change reduces the number of symbols generated in Registry.cpp by
~18% and the compilation time (in non-release mode) by ~20%.
http://reviews.llvm.org/D5124
Files:
include/clang/ASTMatchers/ASTMatchersInternal.h
include/clang/ASTMatchers/Dynamic/VariantValue.h
lib/ASTMatchers/ASTMatchersInternal.cpp
lib/ASTMatchers/Dynamic/VariantValue.cpp
Index: include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchersInternal.h
+++ include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -372,9 +372,9 @@
/// This method verifies that the underlying matcher in \c Other can process
/// nodes of types T.
template <typename T> bool canConvertTo() const {
- return getSupportedKind().isBaseOf(
- ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+ return canConvertTo(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
}
+ bool canConvertTo(ast_type_traits::ASTNodeKind To) const;
/// \brief Construct a \c Matcher<T> interface around the dynamic matcher.
///
@@ -460,16 +460,8 @@
/// \brief Specialization of the conversion functions for QualType.
///
-/// These specializations provide the Matcher<Type>->Matcher<QualType>
+/// This specialization provides the Matcher<Type>->Matcher<QualType>
/// conversion that the static API does.
-template <> inline bool DynTypedMatcher::canConvertTo<QualType>() const {
- const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind();
- return SourceKind.isSame(
- ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) ||
- SourceKind.isSame(
- ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>());
-}
-
template <>
inline Matcher<QualType> DynTypedMatcher::convertTo<QualType>() const {
assert(canConvertTo<QualType>());
Index: include/clang/ASTMatchers/Dynamic/VariantValue.h
===================================================================
--- include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -90,16 +90,36 @@
/// - hasTypedMatcher<T>()/getTypedMatcher<T>(): These calls will determine if
/// the underlying matcher(s) can unambiguously return a Matcher<T>.
class VariantMatcher {
+ /// \brief VTable used for type specific logic.
+ struct UntypedOps {
+ /// \brief Constructs a typed matcher from \p M.
+ /// Returns a Matcher<T>* as a void*.
+ void *(*ConstructFrom)(const DynTypedMatcher &M);
+ /// \brief Constructs a variadic typed matcher from \p M.
+ /// Returns a Matcher<T>* as a void*.
+ void *(*ConstructVariadicOperator)(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<DynTypedMatcher> M);
+ /// \brief Constructs a DynTypedMatcher out of \p M.
+ /// \p M is a Matcher<T>* as a void* and will be deleted by this function.
+ DynTypedMatcher (*DynamicConstructFromConsume)(void *M);
+ ast_type_traits::ASTNodeKind NodeKind;
+ };
+
/// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher.
class MatcherOps {
public:
- virtual ~MatcherOps();
- virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
- bool &IsExactMatch) const = 0;
- virtual void constructFrom(const DynTypedMatcher &Matcher) = 0;
- virtual void constructVariadicOperator(
+ MatcherOps(const UntypedOps &Ops) : Ops(Ops) {}
+
+ bool canConstructFrom(const DynTypedMatcher &Matcher,
+ bool &IsExactMatch) const;
+ void *constructFrom(const DynTypedMatcher &Matcher);
+ void *constructVariadicOperator(
ast_matchers::internal::VariadicOperatorFunction Func,
- ArrayRef<VariantMatcher> InnerMatchers) = 0;
+ ArrayRef<VariantMatcher> InnerMatchers);
+
+ private:
+ const UntypedOps Ops;
};
/// \brief Payload interface to be specialized by each matcher type.
@@ -110,7 +130,7 @@
virtual ~Payload();
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
virtual std::string getTypeAsString() const = 0;
- virtual void makeTypedMatcher(MatcherOps &Ops) const = 0;
+ virtual void* makeTypedMatcher(MatcherOps &Ops) const = 0;
virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
unsigned *Specificity) const = 0;
};
@@ -158,9 +178,10 @@
/// that can, the result would be ambiguous and false is returned.
template <class T>
bool hasTypedMatcher() const {
- TypedMatcherOps<T> Ops;
- if (Value) Value->makeTypedMatcher(Ops);
- return Ops.hasMatcher();
+ auto *M = maybeGetTypedMatcher<T>();
+ bool Result = M != nullptr;
+ delete M;
+ return Result;
}
/// \brief Determines if the contained matcher can be converted to \p Kind.
@@ -182,10 +203,11 @@
/// Asserts that \c hasTypedMatcher<T>() is true.
template <class T>
ast_matchers::internal::Matcher<T> getTypedMatcher() const {
- TypedMatcherOps<T> Ops;
- Value->makeTypedMatcher(Ops);
- assert(Ops.hasMatcher() && "hasTypedMatcher<T>() == false");
- return Ops.matcher();
+ auto *M = maybeGetTypedMatcher<T>();
+ assert(M != nullptr && "hasTypedMatcher<T>() == false");
+ auto Result = *M;
+ delete M;
+ return Result;
}
/// \brief String representation of the type of the value.
@@ -197,51 +219,49 @@
private:
explicit VariantMatcher(Payload *Value) : Value(Value) {}
+ template <typename T> struct TypedOps;
+
+ template <class T>
+ ast_matchers::internal::Matcher<T>* maybeGetTypedMatcher() const {
+ if (!Value) return nullptr;
+ MatcherOps Ops((TypedOps<T>()));
+ return static_cast<ast_matchers::internal::Matcher<T> *>(
+ Value->makeTypedMatcher(Ops));
+ }
+
class SinglePayload;
class PolymorphicPayload;
class VariadicOpPayload;
- template <typename T>
- class TypedMatcherOps : public MatcherOps {
- public:
- typedef ast_matchers::internal::Matcher<T> MatcherT;
-
- virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
- bool &IsExactMatch) const {
- IsExactMatch = Matcher.getSupportedKind().isSame(
- ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
- return Matcher.canConvertTo<T>();
- }
+ IntrusiveRefCntPtr<const Payload> Value;
+};
- virtual void constructFrom(const DynTypedMatcher& Matcher) {
- Out.reset(new MatcherT(Matcher.convertTo<T>()));
- }
+template <typename T>
+struct VariantMatcher::TypedOps : VariantMatcher::UntypedOps {
+ TypedOps()
+ : UntypedOps{&constructFrom, &constructVariadicOperator,
+ &dynamicConstructFromConsume,
+ ast_type_traits::ASTNodeKind::getFromNodeKind<T>()} {}
+ typedef ast_matchers::internal::Matcher<T> MatcherT;
- virtual void constructVariadicOperator(
- ast_matchers::internal::VariadicOperatorFunction Func,
- ArrayRef<VariantMatcher> InnerMatchers) {
- std::vector<DynTypedMatcher> DynMatchers;
- for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
- // Abort if any of the inner matchers can't be converted to
- // Matcher<T>.
- if (!InnerMatchers[i].hasTypedMatcher<T>()) {
- return;
- }
- DynMatchers.push_back(InnerMatchers[i].getTypedMatcher<T>());
- }
- Out.reset(new MatcherT(
- new ast_matchers::internal::VariadicOperatorMatcherInterface<T>(
- Func, DynMatchers)));
- }
-
- bool hasMatcher() const { return Out.get() != nullptr; }
- const MatcherT &matcher() const { return *Out; }
+ static void* constructFrom(const DynTypedMatcher &Matcher) {
+ return new MatcherT(Matcher.convertTo<T>());
+ }
- private:
- std::unique_ptr<MatcherT> Out;
- };
+ static DynTypedMatcher dynamicConstructFromConsume(void *M) {
+ MatcherT *TypedM = static_cast<MatcherT *>(M);
+ DynTypedMatcher Out = *TypedM;
+ delete TypedM;
+ return Out;
+ }
- IntrusiveRefCntPtr<const Payload> Value;
+ static void* constructVariadicOperator(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<DynTypedMatcher> InnerMatchers) {
+ return new MatcherT(
+ new ast_matchers::internal::VariadicOperatorMatcherInterface<T>(
+ Func, InnerMatchers));
+ }
};
/// \brief Variant value class.
Index: lib/ASTMatchers/ASTMatchersInternal.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchersInternal.cpp
+++ lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -26,6 +26,16 @@
}
}
+bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const {
+ const auto SourceKind = getSupportedKind();
+ auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>();
+ auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>();
+ if (To.isSame(QualKind)) {
+ return SourceKind.isSame(TypeKind) || SourceKind.isSame(QualKind);
+ }
+ return SourceKind.isBaseOf(To);
+}
+
DynTypedMatcher::MatcherStorage::~MatcherStorage() {}
void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
Index: lib/ASTMatchers/Dynamic/VariantValue.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -49,7 +49,35 @@
return true;
}
-VariantMatcher::MatcherOps::~MatcherOps() {}
+bool
+VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher,
+ bool &IsExactMatch) const {
+ IsExactMatch = Matcher.getSupportedKind().isSame(Ops.NodeKind);
+ return Matcher.canConvertTo(Ops.NodeKind);
+}
+
+void *
+VariantMatcher::MatcherOps::constructFrom(const DynTypedMatcher &Matcher) {
+ return Ops.ConstructFrom(Matcher);
+}
+
+void *VariantMatcher::MatcherOps::constructVariadicOperator(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> InnerMatchers) {
+ std::vector<DynTypedMatcher> DynMatchers;
+ for (const auto &InnerMatcher : InnerMatchers) {
+ // Abort if any of the inner matchers can't be converted to
+ // Matcher<T>.
+ if (!InnerMatcher.Value)
+ return nullptr;
+ void* Inner = InnerMatcher.Value->makeTypedMatcher(*this);
+ if (!Inner)
+ return nullptr;
+ DynMatchers.push_back(Ops.DynamicConstructFromConsume(Inner));
+ }
+ return Ops.ConstructVariadicOperator(Func, DynMatchers);
+}
+
VariantMatcher::Payload::~Payload() {}
class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
@@ -65,10 +93,11 @@
.str();
}
- void makeTypedMatcher(MatcherOps &Ops) const override {
+ void* makeTypedMatcher(MatcherOps &Ops) const override {
bool Ignore;
if (Ops.canConstructFrom(Matcher, Ignore))
- Ops.constructFrom(Matcher);
+ return Ops.constructFrom(Matcher);
+ return nullptr;
}
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
@@ -104,7 +133,7 @@
return (Twine("Matcher<") + Inner + ">").str();
}
- void makeTypedMatcher(MatcherOps &Ops) const override {
+ void* makeTypedMatcher(MatcherOps &Ops) const override {
bool FoundIsExact = false;
const DynTypedMatcher *Found = nullptr;
int NumFound = 0;
@@ -124,7 +153,8 @@
}
// We only succeed if we found exactly one, or if we found an exact match.
if (Found && (FoundIsExact || NumFound == 1))
- Ops.constructFrom(*Found);
+ return Ops.constructFrom(*Found);
+ return nullptr;
}
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
@@ -165,8 +195,8 @@
return Inner;
}
- void makeTypedMatcher(MatcherOps &Ops) const override {
- Ops.constructVariadicOperator(Func, Args);
+ void* makeTypedMatcher(MatcherOps &Ops) const override {
+ return Ops.constructVariadicOperator(Func, Args);
}
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits