clang 24.0.0git
SerializationFormat.h
Go to the documentation of this file.
1//===- SerializationFormat.h ------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Abstract SerializationFormat interface for reading and writing
10// TUSummary and LinkUnitResolution data.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_SERIALIZATION_SERIALIZATIONFORMAT_H
15#define LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_SERIALIZATION_SERIALIZATIONFORMAT_H
16
28#include "llvm/ADT/STLFunctionalExtras.h"
29#include "llvm/ADT/StringRef.h"
30#include "llvm/Support/Error.h"
31#include "llvm/Support/Registry.h"
32
33#include <variant>
34
35namespace clang::ssaf {
36
37/// Sum type returned by \c SerializationFormat::readArtifact, used when the
38/// caller does not know up-front which kind of top-level SSAF artifact a
39/// file contains. The active alternative is decided by the file's
40/// self-describing type field.
41using Artifact = std::variant<TUSummary, LUSummary, WPASuite>;
42
43/// Lazily-deserialized counterpart of \c Artifact: the same on-disk
44/// artifacts but with their per-entity summary payloads left as opaque
45/// format-specific encodings rather than fully resolved analysis results.
46///
47/// \c StaticLibrary, \c MultiArchStaticLibrary, and
48/// \c MultiArchSharedLibrary appear only in this variant: the
49/// archiver/arch tools and the linker pass member payloads through
50/// without decoding them, so fully decoded shapes would have no consumer.
54
55/// Abstract base class for serialization formats.
57public:
58 virtual ~SerializationFormat() = default;
59
60 virtual llvm::Expected<TUSummary> readTUSummary(llvm::StringRef Path) = 0;
61
62 virtual llvm::Error writeTUSummary(const TUSummary &Summary,
63 llvm::StringRef Path) = 0;
64
66 readTUSummaryEncoding(llvm::StringRef Path) = 0;
67
68 virtual llvm::Error
70 llvm::StringRef Path) = 0;
71
72 virtual llvm::Expected<LUSummary> readLUSummary(llvm::StringRef Path) = 0;
73
74 virtual llvm::Error writeLUSummary(const LUSummary &Summary,
75 llvm::StringRef Path) = 0;
76
77 /// Generic read entry point. Inspects the file's self-describing type
78 /// field and dispatches to \c readTUSummary or \c readLUSummary
79 /// accordingly. Returns an error if the type field is missing or names
80 /// an unrecognized artifact kind.
81 virtual llvm::Expected<Artifact> readArtifact(llvm::StringRef Path) = 0;
82
83 /// Generic write entry point. Dispatches to \c writeTUSummary or
84 /// \c writeLUSummary based on the active variant alternative.
85 virtual llvm::Error writeArtifact(const Artifact &A,
86 llvm::StringRef Path) = 0;
87
88 /// Encoding-flavored counterpart of \c readArtifact. Inspects the
89 /// self-describing type field and dispatches to
90 /// \c readTUSummaryEncoding or \c readLUSummaryEncoding accordingly.
92 readArtifactEncoding(llvm::StringRef Path) = 0;
93
94 /// Encoding-flavored counterpart of \c writeArtifact. Dispatches to
95 /// \c writeTUSummaryEncoding or \c writeLUSummaryEncoding based on the
96 /// active variant alternative.
97 virtual llvm::Error writeArtifactEncoding(const ArtifactEncoding &E,
98 llvm::StringRef Path) = 0;
99
101 readLUSummaryEncoding(llvm::StringRef Path) = 0;
102
103 virtual llvm::Error
105 llvm::StringRef Path) = 0;
106
108 readStaticLibrary(llvm::StringRef Path) = 0;
109
110 virtual llvm::Error writeStaticLibrary(const StaticLibrary &S,
111 llvm::StringRef Path) = 0;
112
114 readMultiArchStaticLibrary(llvm::StringRef Path) = 0;
115
116 virtual llvm::Error
118 llvm::StringRef Path) = 0;
119
121 readMultiArchSharedLibrary(llvm::StringRef Path) = 0;
122
123 virtual llvm::Error
125 llvm::StringRef Path) = 0;
126
127 virtual llvm::Expected<WPASuite> readWPASuite(llvm::StringRef Path) = 0;
128
129 virtual llvm::Error writeWPASuite(const WPASuite &Suite,
130 llvm::StringRef Path) = 0;
131
132 /// Invokes \p Callback once for each analysis that has registered
133 /// serialization support for this format.
135 llvm::function_ref<void(llvm::StringRef Name, llvm::StringRef Desc)>
136 Callback) const = 0;
137
138protected:
139 // Helpers providing access to implementation details of basic data structures
140 // for efficient serialization/deserialization.
141
142 static EntityId makeEntityId(const size_t Index) { return EntityId(Index); }
143
144 /// Constructs an empty WPASuite. Bypasses the private default constructor
145 /// so that deserialization code can build a WPASuite incrementally.
146 static WPASuite makeWPASuite() { return WPASuite(); }
147
148#define FIELD(CLASS, FIELD_NAME) \
149 static const auto &get##FIELD_NAME(const CLASS &X) { return X.FIELD_NAME; } \
150 static auto &get##FIELD_NAME(CLASS &X) { return X.FIELD_NAME; }
151#include "clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def"
152
153 /// Per-format plugin registry for analysis result (de)serializers.
154 ///
155 /// Each concrete format (e.g. JSONFormat) instantiates this template once
156 /// via a public \c using alias. Analysis authors register support with:
157 ///
158 /// \code
159 /// static MyFormat::AnalysisResultRegistry::Add<MyAnalysisResult>
160 /// Reg(serializeFn, deserializeFn);
161 /// \endcode
162 ///
163 /// The serializer receives a \c const reference to \c MyAnalysisResult
164 /// directly and the \c Add wrapper handles the downcast from \c
165 /// AnalysisResult internally via virtual dispatch.
166 ///
167 /// \tparam FormatT Phantom type is needed to disambiguate \c llvm::Registry
168 /// instantiations. \c llvm::Registry is keyed on the \c Entry type,
169 /// so two formats sharing the same serializer/deserializer signatures
170 /// would collide on the same registry without this parameter.
171 template <class FormatT, class SerializerFn, class DeserializerFn>
173
174 template <class FormatT, class SerRet, class... SerArgs, class DesRet,
175 class... DesArgs>
177 FormatT, llvm::function_ref<SerRet(const AnalysisResult &, SerArgs...)>,
178 llvm::function_ref<DesRet(DesArgs...)>> {
179
180 using DeserializerFn = DesRet (*)(DesArgs...);
181
182 public:
183 /// Abstract base type stored in \c llvm::Registry<Codec>.
184 /// Subclasses override \c serialize() and \c deserialize() to
185 /// dispatch to the plugin's concrete functions.
186 ///
187 /// There is one \c Codec type (and one \c llvm::Registry<Codec>) per
188 /// format. All analysis-specific concrete subclasses for a given format
189 /// register into that single registry. The \c FormatT phantom type
190 /// parameter on the enclosing class ensures that different formats
191 /// produce distinct \c Codec types and thus separate registries.
192 struct Codec {
193 virtual ~Codec() = default;
194 virtual SerRet serialize(const AnalysisResult &, SerArgs...) const = 0;
195 virtual DesRet deserialize(DesArgs...) const = 0;
196 };
197
198 template <class AnalysisResultT> struct Add {
199 using TypedSerializerFn = SerRet (*)(const AnalysisResultT &, SerArgs...);
200
202 static inline DeserializerFn SavedDeserialize;
203
204 /// Takes the plugin's typed serializer and the deserializer, and
205 /// inserts them into \c llvm::Registry<Codec>.
206 Add(TypedSerializerFn TypedSerialize, DeserializerFn Deserialize) {
207 /// Per-\c AnalysisResultT guard: each template instantiation gets
208 /// its own \c static \c bool, so double-registration of the same
209 /// analysis is caught even across translation units.
210 static bool Registered = false;
211 if (Registered) {
212 ErrorBuilder::fatal("support is already registered for analysis: {0}",
213 AnalysisResultT::analysisName());
214 }
215 Registered = true;
216
217 /// The plugin's serializer and deserializer are captured in
218 /// static inline members of the Add template so that the
219 /// \c ConcreteCodec default constructor (required by \c llvm::Registry)
220 /// can read them. They use raw function pointers to prevent dangling
221 /// references to temporary stack variables during registration.
222 ///
223 /// Once read by the constructor, they are stored as instance members
224 /// of \c ConcreteCodec rather than directly executed from the \c static
225 /// \c inline class members. This prevents symbol visibility issues
226 /// across shared library boundaries on Linux (where \c dlopen with \c
227 /// RTLD_LOCAL can give the host and plugin separate copies of \c static
228 /// \c inline members).
229 SavedSerialize = TypedSerialize;
230 SavedDeserialize = Deserialize;
231
232 /// Concrete subclass of \c Codec for \c AnalysisResultT.
233 /// The \c serialize() override performs the downcast from
234 /// \c AnalysisResult to \c AnalysisResultT.
235 struct ConcreteCodec final : Codec {
236 TypedSerializerFn SerFn;
237 DeserializerFn DesFn;
238
239 ConcreteCodec() : SerFn(SavedSerialize), DesFn(SavedDeserialize) {}
240
241 SerRet serialize(const AnalysisResult &Base,
242 SerArgs... args) const override {
243 return SerFn(static_cast<const AnalysisResultT &>(Base), args...);
244 }
245
246 DesRet deserialize(DesArgs... args) const override {
247 return DesFn(args...);
248 }
249 };
250
251 /// \c llvm::Registry stores the name as a \c StringRef, so the
252 /// underlying string must be kept alive with a static declaration.
253 static std::string NameStr =
254 AnalysisResultT::analysisName().str().str();
255
256 /// This performs the actual registration. It appends a factory for \c
257 /// ConcreteCodec to the global \c llvm::Registry<Codec>. \c static
258 /// ensures the `Registry::Add` object lives for the entire program,
259 /// keeping its codec and node alive in the registry's linked list.
260 [[maybe_unused]] static
261 typename llvm::Registry<Codec>::template Add<ConcreteCodec>
262 RegisterUsingCtorSideEffect(NameStr, "");
263 }
264 };
265
266 /// Looks up the codec for \p Name by walking the registry list.
269 for (const auto &E : llvm::Registry<Codec>::entries()) {
270 if (E.getName() == Name.str()) {
271 return E.instantiate();
272 }
273 }
274 return ErrorBuilder::create(std::errc::invalid_argument,
275 "no support registered for analysis: {0}",
276 Name)
277 .build();
278 }
279 };
280};
281
282template <class SerializerFn, class DeserializerFn> struct FormatInfoEntry {
287 virtual ~FormatInfoEntry() = default;
288
290 SerializerFn Serialize;
291 DeserializerFn Deserialize;
292};
293
294} // namespace clang::ssaf
295
296#endif // LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_SERIALIZATION_SERIALIZATIONFORMAT_H
static json::Object serialize(const EntitySummary &Summary, JSONFormat::EntityIdToJSONFn ToJSON)
static Expected< std::unique_ptr< EntitySummary > > deserialize(const json::Object &Obj, EntityIdTable &IdTable, JSONFormat::EntityIdFromJSONFn FromJSON)
Uniquely identifies a whole-program analysis and the AnalysisResult it produces.
llvm::StringRef str() const
Explicit conversion to the underlying string representation.
Base class for whole-program analysis results.
Lightweight opaque handle representing an entity in an EntityIdTable.
Definition EntityId.h:31
static ErrorBuilder create(std::error_code EC, const char *Fmt, Args &&...ArgVals)
Create an ErrorBuilder with an error code and formatted message.
static void fatal(const char *Fmt, Args &&...ArgVals)
Report a fatal error with formatted message and terminate execution.
llvm::Error build() const
Build and return the final error.
Represents a link unit summary in its serialized encoding.
Represents a link unit (LU) summary containing merged entity summaries.
Definition LUSummary.h:34
Represents a multi-architecture shared library.
Represents a multi-architecture static library.
static llvm::Expected< std::unique_ptr< Codec > > instantiate(const AnalysisName &Name)
Looks up the codec for Name by walking the registry list.
Per-format plugin registry for analysis result (de)serializers.
Abstract base class for serialization formats.
virtual llvm::Error writeMultiArchStaticLibrary(const MultiArchStaticLibrary &M, llvm::StringRef Path)=0
virtual llvm::Expected< StaticLibrary > readStaticLibrary(llvm::StringRef Path)=0
virtual llvm::Error writeLUSummary(const LUSummary &Summary, llvm::StringRef Path)=0
virtual llvm::Expected< Artifact > readArtifact(llvm::StringRef Path)=0
Generic read entry point.
virtual llvm::Error writeStaticLibrary(const StaticLibrary &S, llvm::StringRef Path)=0
virtual llvm::Error writeArtifact(const Artifact &A, llvm::StringRef Path)=0
Generic write entry point.
virtual llvm::Expected< ArtifactEncoding > readArtifactEncoding(llvm::StringRef Path)=0
Encoding-flavored counterpart of readArtifact.
virtual llvm::Expected< LUSummary > readLUSummary(llvm::StringRef Path)=0
virtual llvm::Expected< WPASuite > readWPASuite(llvm::StringRef Path)=0
static EntityId makeEntityId(const size_t Index)
virtual llvm::Error writeMultiArchSharedLibrary(const MultiArchSharedLibrary &M, llvm::StringRef Path)=0
virtual llvm::Expected< LUSummaryEncoding > readLUSummaryEncoding(llvm::StringRef Path)=0
virtual llvm::Error writeWPASuite(const WPASuite &Suite, llvm::StringRef Path)=0
virtual llvm::Expected< MultiArchSharedLibrary > readMultiArchSharedLibrary(llvm::StringRef Path)=0
virtual llvm::Error writeTUSummary(const TUSummary &Summary, llvm::StringRef Path)=0
virtual void forEachRegisteredAnalysis(llvm::function_ref< void(llvm::StringRef Name, llvm::StringRef Desc)> Callback) const =0
Invokes Callback once for each analysis that has registered serialization support for this format.
virtual llvm::Error writeArtifactEncoding(const ArtifactEncoding &E, llvm::StringRef Path)=0
Encoding-flavored counterpart of writeArtifact.
virtual ~SerializationFormat()=default
virtual llvm::Expected< TUSummaryEncoding > readTUSummaryEncoding(llvm::StringRef Path)=0
virtual llvm::Error writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding, llvm::StringRef Path)=0
virtual llvm::Expected< MultiArchStaticLibrary > readMultiArchStaticLibrary(llvm::StringRef Path)=0
virtual llvm::Expected< TUSummary > readTUSummary(llvm::StringRef Path)=0
virtual llvm::Error writeTUSummaryEncoding(const TUSummaryEncoding &SummaryEncoding, llvm::StringRef Path)=0
static WPASuite makeWPASuite()
Constructs an empty WPASuite.
Represents a static library of translation unit summary encodings.
Uniquely identifies an analysis summary.
Definition SummaryName.h:22
Represents a translation unit summary in its serialized encoding.
Data extracted for a given translation unit and for a given set of analyses.
Definition TUSummary.h:25
Bundles the EntityIdTable (moved from the LUSummary) and the analysis results produced by one Analysi...
Definition WPASuite.h:37
std::variant< TUSummaryEncoding, LUSummaryEncoding, StaticLibrary, MultiArchStaticLibrary, MultiArchSharedLibrary > ArtifactEncoding
Lazily-deserialized counterpart of Artifact: the same on-disk artifacts but with their per-entity sum...
std::variant< TUSummary, LUSummary, WPASuite > Artifact
Sum type returned by SerializationFormat::readArtifact, used when the caller does not know up-front w...
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
FormatInfoEntry(SummaryName ForSummary, SerializerFn Serialize, DeserializerFn Deserialize)
virtual ~FormatInfoEntry()=default
Add(TypedSerializerFn TypedSerialize, DeserializerFn Deserialize)
Takes the plugin's typed serializer and the deserializer, and inserts them into llvm::Registry<Codec>...