35 void printIDImpl(raw_ostream &OS,
const CASID &ID)
const final;
37 StringRef getHashSchemaIdentifier()
const final {
return SchemaName; }
39 static Expected<std::shared_ptr<PluginCASContext>>
40 create(StringRef PluginPath, StringRef OnDiskPath,
41 ArrayRef<std::pair<std::string, std::string>> PluginArgs);
43 ~PluginCASContext() { Functions.cas_dispose(c_cas); }
45 llcas_functions_t Functions{};
47 std::string SchemaName;
49 static Error errorAndDispose(
char *c_err,
const llcas_functions_t &Funcs) {
55 Error errorAndDispose(
char *c_err)
const {
56 return errorAndDispose(c_err, Functions);
63 ArrayRef<uint8_t> Hash =
ID.getHash();
64 char *c_printed_id =
nullptr;
65 char *c_err =
nullptr;
66 if (Functions.
digest_print(c_cas, llcas_digest_t{Hash.data(), Hash.size()},
67 &c_printed_id, &c_err))
74static Expected<llcas_functions_t> loadPluginFunctions(StringRef PluginPath) {
81 SmallString<256> PathBuf = PluginPath;
83 sys::DynamicLibrary
Lib =
88 llcas_functions_t Functions{};
90#define CASPLUGINAPI_FUNCTION(name, required) \
91 if (!(Functions.name = (decltype(llcas_functions_t::name)) \
92 Lib.getAddressOfSymbol("llcas_" #name))) { \
94 return reportError("failed symbol 'llcas_" #name "' lookup"); \
96#include "PluginAPI_functions.def"
97#undef CASPLUGINAPI_FUNCTION
104static Expected<llcas_cas_options_t>
106 ArrayRef<std::pair<std::string, std::string>> PluginArgs) {
111 Functions.cas_options_set_ondisk_path(c_opts, OnDiskPathBuf.
c_str());
112 for (
const auto &Pair : PluginArgs) {
113 char *c_err =
nullptr;
114 if (Functions.cas_options_set_option(c_opts, Pair.first.c_str(),
115 Pair.second.c_str(), &c_err)) {
116 Functions.cas_options_dispose(c_opts);
117 return PluginCASContext::errorAndDispose(c_err, Functions);
123Expected<std::shared_ptr<PluginCASContext>> PluginCASContext::create(
124 StringRef PluginPath, StringRef OnDiskPath,
125 ArrayRef<std::pair<std::string, std::string>> PluginArgs) {
126 llcas_functions_t Functions{};
127 if (
Error E = loadPluginFunctions(PluginPath).moveInto(Functions))
136 char *c_err =
nullptr;
139 return errorAndDispose(c_err, Functions);
142 std::string SchemaName = c_schema;
145 auto Ctx = std::make_shared<PluginCASContext>();
146 Ctx->Functions = Functions;
148 Ctx->SchemaName = std::move(SchemaName);
158class PluginObjectStore :
public ObjectStore {
160 Expected<CASID> parseID(StringRef ID)
final;
162 ArrayRef<char>
Data)
final;
163 Expected<ObjectRef> storeFromFile(StringRef Path)
final;
164 Error exportDataToFile(ObjectHandle Node, StringRef Path)
const final;
165 CASID getID(ObjectRef
Ref)
const final;
166 std::optional<ObjectRef> getReference(
const CASID &ID)
const final;
167 Expected<bool> isMaterialized(ObjectRef
Ref)
const final;
168 Expected<std::optional<ObjectHandle>> loadIfExists(ObjectRef
Ref)
final;
170 Error forEachRef(ObjectHandle Node,
171 function_ref<
Error(ObjectRef)> Callback)
const final;
172 ObjectRef readRef(ObjectHandle Node,
size_t I)
const final;
173 size_t getNumRefs(ObjectHandle Node)
const final;
174 ArrayRef<char> getData(ObjectHandle Node,
175 bool RequiresNullTerminator =
false)
const final;
176 std::unique_ptr<MemoryBuffer>
177 getStandaloneMemoryBufferImpl(ObjectHandle Node, StringRef Name,
178 bool RequiresNullTerminator) final;
187 Expected<std::optional<uint64_t>> getStorageSize()
const final;
188 Error pruneStorageData() final;
190 PluginObjectStore(std::shared_ptr<PluginCASContext>);
193 ObjectRef makeRef(
uint64_t InternalRef)
const {
194 return makeObjectRef(InternalRef);
197 std::shared_ptr<PluginCASContext> Ctx;
202Expected<CASID> PluginObjectStore::parseID(StringRef ID) {
204 SmallString<148> IDBuf(ID);
207 auto parseDigest = [&]() -> Expected<unsigned> {
208 char *c_err =
nullptr;
209 unsigned NumBytes = Ctx->Functions.digest_parse(
210 Ctx->c_cas, IDBuf.c_str(), BytesBuf.data(), BytesBuf.size(), &c_err);
212 return Ctx->errorAndDispose(c_err);
216 Expected<unsigned> NumBytes = parseDigest();
220 if (*NumBytes > BytesBuf.size()) {
221 BytesBuf.resize(*NumBytes);
222 NumBytes = parseDigest();
225 assert(*NumBytes == BytesBuf.size());
227 BytesBuf.truncate(*NumBytes);
234 ArrayRef<char>
Data) {
237 for (ObjectRef
Ref : Refs) {
238 c_ids.
push_back(llcas_objectid_t{
Ref.getInternalRef(*
this)});
241 llcas_objectid_t c_stored_id;
242 char *c_err =
nullptr;
243 if (Ctx->Functions.cas_store_object(
244 Ctx->c_cas, llcas_data_t{Data.data(), Data.size()}, c_ids.
data(),
245 c_ids.
size(), &c_stored_id, &c_err))
246 return Ctx->errorAndDispose(c_err);
248 return makeObjectRef(c_stored_id.
opaque);
251Expected<ObjectRef> PluginObjectStore::storeFromFile(StringRef Path) {
252 if (!Ctx->Functions.cas_store_from_filepath)
255 llcas_objectid_t c_stored_id;
256 char *c_err =
nullptr;
257 std::string PathStr =
Path.str();
258 if (Ctx->Functions.cas_store_from_filepath(Ctx->c_cas, PathStr.c_str(),
259 &c_stored_id, &c_err))
260 return Ctx->errorAndDispose(c_err);
262 return makeObjectRef(c_stored_id.
opaque);
265Error PluginObjectStore::exportDataToFile(ObjectHandle Node,
266 StringRef Path)
const {
267 if (!Ctx->Functions.loaded_object_export_data_to_filepath)
270 char *c_err =
nullptr;
271 std::string PathStr =
Path.str();
272 if (Ctx->Functions.loaded_object_export_data_to_filepath(
273 Ctx->c_cas, llcas_loaded_object_t{Node.getInternalRef(*this)},
274 PathStr.c_str(), &c_err))
275 return Ctx->errorAndDispose(c_err);
284CASID PluginObjectStore::getID(ObjectRef
Ref)
const {
285 llcas_objectid_t c_id{
Ref.getInternalRef(*
this)};
286 llcas_digest_t c_digest =
287 Ctx->Functions.objectid_get_digest(Ctx->c_cas, c_id);
291std::optional<ObjectRef>
292PluginObjectStore::getReference(
const CASID &ID)
const {
293 ArrayRef<uint8_t> Hash =
ID.getHash();
294 llcas_objectid_t c_id;
295 char *c_err =
nullptr;
296 if (Ctx->Functions.cas_get_objectid(
297 Ctx->c_cas, llcas_digest_t{Hash.data(), Hash.size()}, &c_id, &c_err))
300 return makeObjectRef(c_id.
opaque);
303Expected<bool> PluginObjectStore::isMaterialized(ObjectRef
Ref)
const {
304 llcas_objectid_t c_id{
Ref.getInternalRef(*
this)};
305 char *c_err =
nullptr;
307 Ctx->c_cas, c_id,
false, &c_err);
314 return Ctx->errorAndDispose(c_err);
319Expected<std::optional<ObjectHandle>>
320PluginObjectStore::loadIfExists(ObjectRef
Ref) {
321 llcas_objectid_t c_id{
Ref.getInternalRef(*
this)};
322 llcas_loaded_object_t c_obj;
323 char *c_err =
nullptr;
325 Ctx->Functions.cas_load_object(Ctx->c_cas, c_id, &c_obj, &c_err);
328 return makeObjectHandle(c_obj.
opaque);
332 return Ctx->errorAndDispose(c_err);
339class ObjectRefsWrapper {
341 ObjectRefsWrapper(
const ObjectHandle &Node,
const PluginObjectStore &
Store)
343 llcas_loaded_object_t c_obj{
Node.getInternalRef(
Store)};
347 size_t size()
const {
351 ObjectRef operator[](
size_t I)
const {
352 llcas_objectid_t c_id =
358 const PluginObjectStore &
Store;
359 PluginCASContext &Ctx;
360 llcas_object_refs_t c_refs;
366Error PluginObjectStore::forEachRef(
367 ObjectHandle Node, function_ref<
Error(ObjectRef)> Callback)
const {
368 ObjectRefsWrapper Refs(Node, *
this);
369 for (
unsigned I = 0,
E = Refs.size();
I !=
E; ++
I) {
376ObjectRef PluginObjectStore::readRef(ObjectHandle Node,
size_t I)
const {
377 ObjectRefsWrapper Refs(Node, *
this);
381size_t PluginObjectStore::getNumRefs(ObjectHandle Node)
const {
382 ObjectRefsWrapper Refs(Node, *
this);
388uint64_t PluginObjectStore::getDataSize(ObjectHandle Node)
const {
389 ArrayRef<char>
Data = getData(Node);
393ArrayRef<char> PluginObjectStore::getData(ObjectHandle Node,
394 bool RequiresNullTerminator)
const {
397 llcas_data_t c_data = Ctx->Functions.loaded_object_get_data(
398 Ctx->c_cas, llcas_loaded_object_t{Node.getInternalRef(*this)});
406class PluginStandaloneMemoryBuffer final :
public MemoryBuffer {
408 using DisposeFn = void (*)(llcas_data_t);
410 PluginStandaloneMemoryBuffer(llcas_data_t
Data, StringRef Name,
413 const char *
Start =
static_cast<const char *
>(
Data.data);
414 init(Start, Start +
Data.size,
true);
417 ~PluginStandaloneMemoryBuffer()
override { Dispose(
Data); }
419 StringRef getBufferIdentifier()
const final {
return Name; }
421 BufferKind getBufferKind()
const final {
return MemoryBuffer_Malloc; }
430std::unique_ptr<MemoryBuffer> PluginObjectStore::getStandaloneMemoryBufferImpl(
431 ObjectHandle Node, StringRef Name,
bool RequiresNullTerminator) {
434 if (!Ctx->Functions.loaded_object_get_standalone_data ||
435 !Ctx->Functions.standalone_data_dispose)
437 RequiresNullTerminator);
439 llcas_data_t c_data = Ctx->Functions.loaded_object_get_standalone_data(
440 Ctx->c_cas, llcas_loaded_object_t{Node.getInternalRef(*this)});
443 RequiresNullTerminator);
445 return std::make_unique<PluginStandaloneMemoryBuffer>(
446 c_data, Name, Ctx->Functions.standalone_data_dispose);
449Error PluginObjectStore::setSizeLimit(std::optional<uint64_t>
SizeLimit) {
450 if (Ctx->Functions.cas_set_ondisk_size_limit) {
451 char *c_err =
nullptr;
452 if (Ctx->Functions.cas_set_ondisk_size_limit(Ctx->c_cas,
454 return Ctx->errorAndDispose(c_err);
459Expected<std::optional<uint64_t>> PluginObjectStore::getStorageSize()
const {
460 if (!Ctx->Functions.cas_get_ondisk_size)
462 char *c_err =
nullptr;
463 int64_t ret = Ctx->Functions.cas_get_ondisk_size(Ctx->c_cas, &c_err);
468 return Ctx->errorAndDispose(c_err);
474Error PluginObjectStore::pruneStorageData() {
475 if (Ctx->Functions.cas_prune_ondisk_data) {
476 char *c_err =
nullptr;
477 if (Ctx->Functions.cas_prune_ondisk_data(Ctx->c_cas, &c_err))
478 return Ctx->errorAndDispose(c_err);
483Error PluginObjectStore::validate(
bool CheckHash)
const {
484 if (Ctx->Functions.cas_validate) {
485 char *c_err =
nullptr;
486 if (Ctx->Functions.cas_validate(Ctx->c_cas, CheckHash, &c_err))
487 return Ctx->errorAndDispose(c_err);
493PluginObjectStore::PluginObjectStore(std::shared_ptr<PluginCASContext> CASCtx)
494 : ObjectStore(*CASCtx), Ctx(std::
move(CASCtx)) {}
504 Expected<std::optional<CASID>> getImpl(ArrayRef<uint8_t> ResolvedKey,
505 bool CanBeDistributed)
const final;
507 Error putImpl(ArrayRef<uint8_t> ResolvedKey,
const CASID &Result,
508 bool CanBeDistributed)
final;
510 PluginActionCache(std::shared_ptr<PluginCASContext>);
515 std::shared_ptr<PluginCASContext> Ctx;
520Expected<std::optional<CASID>>
521PluginActionCache::getImpl(
ArrayRef<uint8_t> ResolvedKey,
522 bool CanBeDistributed)
const {
523 llcas_objectid_t c_value;
524 char *c_err =
nullptr;
526 Ctx->c_cas, llcas_digest_t{ResolvedKey.data(), ResolvedKey.size()},
527 &c_value, CanBeDistributed, &c_err);
530 llcas_digest_t c_digest =
531 Ctx->Functions.objectid_get_digest(Ctx->c_cas, c_value);
537 return Ctx->errorAndDispose(c_err);
542Error PluginActionCache::putImpl(ArrayRef<uint8_t> ResolvedKey,
543 const CASID &Result,
bool CanBeDistributed) {
544 ArrayRef<uint8_t> Hash =
Result.getHash();
545 llcas_objectid_t c_value;
546 char *c_err =
nullptr;
547 if (Ctx->Functions.cas_get_objectid(Ctx->c_cas,
548 llcas_digest_t{Hash.data(), Hash.size()},
550 return Ctx->errorAndDispose(c_err);
552 if (Ctx->Functions.actioncache_put_for_digest(
553 Ctx->c_cas, llcas_digest_t{ResolvedKey.data(), ResolvedKey.size()},
554 c_value, CanBeDistributed, &c_err))
555 return Ctx->errorAndDispose(c_err);
560PluginActionCache::PluginActionCache(std::shared_ptr<PluginCASContext> CASCtx)
561 : ActionCache(*CASCtx), Ctx(std::
move(CASCtx)) {}
563Error PluginActionCache::validate()
const {
564 if (Ctx->Functions.actioncache_validate) {
565 char *c_err =
nullptr;
566 if (Ctx->Functions.actioncache_validate(Ctx->c_cas, &c_err))
567 return Ctx->errorAndDispose(c_err);
577Expected<std::pair<std::shared_ptr<ObjectStore>, std::shared_ptr<ActionCache>>>
580 ArrayRef<std::pair<std::string, std::string>> PluginArgs) {
581 std::shared_ptr<PluginCASContext> Ctx;
582 if (
Error E = PluginCASContext::create(PluginPath, OnDiskPath, PluginArgs)
585 auto CAS = std::make_shared<PluginObjectStore>(Ctx);
586 auto AC = std::make_shared<PluginActionCache>(std::move(Ctx));
587 return std::make_pair(std::move(CAS), std::move(AC));
595 ArrayRef<std::pair<std::string, std::string>> PluginArgs,
600 if (
Error E = loadPluginFunctions(PluginPath).moveInto(Functions))
607 scope_exit DisposeOptions([&]() { Functions.cas_options_dispose(c_opts); });
609 char *c_err =
nullptr;
611 if (
Error E = Fn(Functions, c_opts, &c_err).moveInto(Result))
621 return PluginCASContext::errorAndDispose(c_err, Functions);
627 OS <<
"unknown validation result " <<
static_cast<int>(Result) <<
" from '"
628 << PluginPath <<
"'";
631 Functions.string_dispose(c_err);
638 ArrayRef<std::pair<std::string, std::string>> PluginArgs,
bool CheckHash,
639 bool ForceValidation) {
641 PluginPath, OnDiskPath, PluginArgs,
644 if (!Functions.cas_validate_if_needed)
646 "plugin cas doesn't support validate-if-needed");
647 return Functions.cas_validate_if_needed(c_opts, CheckHash,
648 ForceValidation, c_err);
654 ArrayRef<std::pair<std::string, std::string>> PluginArgs) {
656 PluginPath, OnDiskPath, PluginArgs,
659 if (!Functions.cas_recover_ondisk_data)
661 return Functions.cas_recover_ondisk_data(c_opts, c_err);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declaration of the ActionCache class, which is the base class for ActionCache ...
static Error reportError(StringRef Message)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static cl::opt< unsigned > SizeLimit("eif-limit", cl::init(6), cl::Hidden, cl::desc("Size limit in Hexagon early if-conversion"))
This file contains the declaration of the ObjectStore class.
Defines llcas_functions_t, the table of function pointers that is populated by looking up the llcas_*...
struct llcas_cas_options_s * llcas_cas_options_t
#define LLCAS_VERSION_MAJOR
struct llcas_cas_s * llcas_cas_t
#define LLCAS_VERSION_MINOR
llcas_validation_result_t
Return values for llcas_cas_validate_if_needed and llcas_cas_recover_ondisk_data.
@ LLCAS_VALIDATION_RESULT_SKIPPED
Validation or recovery was skipped, as it was not needed.
@ LLCAS_VALIDATION_RESULT_ERROR
An error occurred.
@ LLCAS_VALIDATION_RESULT_RECOVERED
The data was invalid, but was recovered.
@ LLCAS_VALIDATION_RESULT_VALID
The data is valid.
llcas_lookup_result_t
Return values for a load operation.
@ LLCAS_LOOKUP_RESULT_NOTFOUND
The object was not found.
@ LLCAS_LOOKUP_RESULT_SUCCESS
The object was found.
@ LLCAS_LOOKUP_RESULT_ERROR
An error occurred.
static Expected< ValidationResult > callPluginValidationFunction(StringRef PluginPath, StringRef OnDiskPath, ArrayRef< std::pair< std::string, std::string > > PluginArgs, function_ref< Expected< llcas_validation_result_t >(const llcas_functions_t &, llcas_cas_options_t, char **)> Fn)
Loads the plugin and calls Fn with a llcas_cas_options_t for OnDiskPath and PluginArgs,...
static Expected< llcas_cas_options_t > createPluginOptions(const llcas_functions_t &Functions, StringRef OnDiskPath, ArrayRef< std::pair< std::string, std::string > > PluginArgs)
Creates a llcas_cas_options_t for OnDiskPath and PluginArgs.
This file defines the scope_exit class, which executes user-defined cleanup logic at scope exit.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void reserve(size_type N)
void push_back(const T &Elt)
pointer data()
Return a pointer to the vector's buffer, even if empty().
Represent a constant reference to a string, i.e.
A cache from a key (that describes an action) to the result of performing that action.
Context for CAS identifiers.
Unique identifier for a CAS object.
static CASID create(const CASContext *Context, StringRef Hash)
Create CASID from CASContext and raw hash bytes.
virtual std::unique_ptr< MemoryBuffer > getStandaloneMemoryBufferImpl(ObjectHandle Node, StringRef Name, bool RequiresNullTerminator)
Customization point for getStandaloneMemoryBuffer().
virtual Error exportDataToFile(ObjectHandle Node, StringRef Path) const
Exports the data of an object to a file path.
virtual Expected< ObjectRef > storeFromFile(StringRef Path)
Stores the data of a file into ObjectStore.
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
static LLVM_ABI DynamicLibrary getPermanentLibrary(const char *filename, std::string *errMsg=nullptr)
This function permanently loads the dynamic library at the given path using the library load operatio...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void validate(const Triple &TT, const FeatureBitset &FeatureBits)
@ Valid
The data is already valid.
@ Recovered
The data was invalid, but was recovered.
@ Skipped
Validation or recovery was skipped, as it was not needed.
LLVM_ABI Expected< ValidationResult > validatePluginCASDatabasesIfNeeded(StringRef PluginPath, StringRef OnDiskPath, ArrayRef< std::pair< std::string, std::string > > PluginArgs, bool CheckHash, bool ForceValidation)
Validate the on-disk data of a plugin-backed CAS in-process if needed, by calling the plugin's llcas_...
LLVM_ABI Expected< std::pair< std::shared_ptr< ObjectStore >, std::shared_ptr< ActionCache > > > createPluginCASDatabases(StringRef PluginPath, StringRef OnDiskPath, ArrayRef< std::pair< std::string, std::string > > PluginArgs)
Create ObjectStore and ActionCache instances backed by a plugin that implements the C API in "llvm-c/...
LLVM_ABI Expected< ValidationResult > recoverPluginCASDatabases(StringRef PluginPath, StringRef OnDiskPath, ArrayRef< std::pair< std::string, std::string > > PluginArgs)
Recover the on-disk data of a plugin-backed CAS after a failed validatePluginCASDatabasesIfNeeded,...
initializer< Ty > init(const Ty &Val)
uint64_t getDataSize(const FuncRecordTy *Record)
Return the coverage map data size for the function.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
NodeAddr< NodeBase * > Node
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
scope_exit(Callable) -> scope_exit< Callable >
@ Store
The extracted value is stored (ExtractElement only).
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Ref
The access may reference the value stored in memory.
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
StringRef toStringRef(bool B)
Construct a string ref from a boolean.
See documentation in "llvm-c/CAS/PluginAPI_functions.h" for how these functions are used.
void(* string_dispose)(char *)
size_t(* object_refs_get_count)(llcas_cas_t, llcas_object_refs_t)
bool(* digest_print)(llcas_cas_t, llcas_digest_t, char **printed_id, char **error)
llcas_object_refs_t(* loaded_object_get_refs)(llcas_cas_t, llcas_loaded_object_t)
llcas_cas_t(* cas_create)(llcas_cas_options_t, char **error)
char *(* cas_get_hash_schema_name)(llcas_cas_t)
void(* cas_options_dispose)(llcas_cas_options_t)
llcas_objectid_t(* object_refs_get_id)(llcas_cas_t, llcas_object_refs_t, size_t index)