summaryrefslogtreecommitdiffstats
path: root/source/compiler-core/slang-artifact-handler-impl.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2022-08-16 03:39:41 -0400
committerGitHub <noreply@github.com>2022-08-16 00:39:41 -0700
commitac71724c03392b429e44641a3641b2bcf7cc55fc (patch)
tree8f7ffa61329dd24bc9be551e293840b6b94aab36 /source/compiler-core/slang-artifact-handler-impl.cpp
parent786f48d32340c36a06865a333ff9066033b5b2bc (diff)
Remove CompileResult to use IArtifact (#2357)
* #include an absolute path didn't work - because paths were taken to always be relative. * WIP with hierarchical enums. * Some small fixes and improvements around artifact desc related types. * Improvements around hierarchical enum. * Fixes to get Artifact types refactor to be able to execute tests. * Attempt to better categorize PTX. * Work around for potentially unused function warning. * Typo fix. * Simplify Artifact header. * Small improvements around Artifact kind/payload/style. * Added IDestroyable/ICastable * Add IArtifactList. * First impl of IArtifactUtil. * Use the ICastable interface for IArtifactRepresentation. * Added IArtifactRepresentation & IArtifactAssociated. * Add SLANG_OVERRIDE to avoid gcc/clang warning. * Fix calling convention issue on win32. * Fix missing SLANG_OVERRIDE. * First attempt at file abstraction around Artifact. * Added creation of lock file. * Move functionality for determining file paths to the IArtifactUtil. Add casting to ICastable. * Added some casting/finding mechanisms. * Simplify IArtifact interface, and use Items for file reps. * Fix problem with libraries on DXIL. * Split out ArtifactRepresentation. * Move ArtifactDesc functionality to ArtifactDescUtil. ArtifactInfoUtil becomes ArtifactDescUtil. * Split implementations from the interfaces for Artifact. * Use TypeTextUtil for target name outputting. * Add artifact impls. * Add ICastableList * Added UnknownCastableAdapter * Make ISlangSharedLibrary derive from ICastable, and remain backwards compatible with slang-llvm. * Refactor Representation on Artifact. * Make our ISlangBlobs also derive from ICastable. Make ISlangBlob atomic ref counted. * Split out CastableList and related types, and placed in core. * Small fixes around IArtifact. Improve IArtifact docs. First impl of getChildren for IArtifact. * Documentation improvements for Artifact related types. * Fix typo. * Special case adding a ICastableList to a LazyCastableList. * Small simplification of LazyCastableList, by adding State member. * Removed the ILockFile interface because IFileArtifactRepresentation can be used. * Implement DiagnosticsArtifactRepresentation. * Added PostEmitMetadataArtifactRepresentation * Add searching by predicate. Added handling of accessing Artifact as ISharedLibrary * Fix typo. * Add find to IArtifacgtList. Fix some missing SLANG_NO_THROW. * Small improvements around ArtifactDesc types. * Another small change around ArtifactKind. * Some more shuffling of ArtifactDesc. * Make IArtifact castable Remove IArtifactList Made IArtifactContainer derive from IArtifact Made ModuleLibrary atomic ref counted/given IModuleLibrary interface. * Must call _requireChildren before any children access. * Fix missing SLANG_MCALL on castAs. * Fix missing SLANG_OVERRIDE. * Added IArtifactHandler * Use ICastable for basis of scope/lookup. * WIP first attempt to remove CompileResult. * Fix support for for downstream compiler shared library adapter. * Fix issues found when replacing CompileResult. * Fix typo. * Fix getting items form 'significant' member of an Artifact. * Split out ArtifactUtil & ArtifactHandler. * Work around for problem on Visual studio. * Improve searching. * Add missing files.
Diffstat (limited to 'source/compiler-core/slang-artifact-handler-impl.cpp')
-rw-r--r--source/compiler-core/slang-artifact-handler-impl.cpp380
1 files changed, 380 insertions, 0 deletions
diff --git a/source/compiler-core/slang-artifact-handler-impl.cpp b/source/compiler-core/slang-artifact-handler-impl.cpp
new file mode 100644
index 000000000..c93a4907b
--- /dev/null
+++ b/source/compiler-core/slang-artifact-handler-impl.cpp
@@ -0,0 +1,380 @@
+// slang-artifact-handler-impl.cpp
+#include "slang-artifact-handler-impl.h"
+
+#include "slang-artifact-impl.h"
+#include "slang-artifact-representation-impl.h"
+
+#include "slang-artifact-desc-util.h"
+
+#include "slang-artifact-helper.h"
+
+#include "../core/slang-castable-list-impl.h"
+
+#include "../core/slang-file-system.h"
+#include "../core/slang-io.h"
+#include "../core/slang-shared-library.h"
+
+// For workaround for DownstreamResult
+#include "slang-downstream-compiler.h"
+
+namespace Slang {
+
+// A temporary class that adapts `ISlangSharedLibrary_Dep1` to ISlangSharedLibrary
+
+class SharedLibraryDep1Adapter : public ComBaseObject, public ISlangSharedLibrary
+{
+public:
+ SLANG_COM_BASE_IUNKNOWN_ALL
+
+ // ICastable
+ virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE;
+
+ // ISlangSharedLibrary
+ virtual SLANG_NO_THROW void* SLANG_MCALL findSymbolAddressByName(char const* name) SLANG_OVERRIDE { return m_contained->findSymbolAddressByName(name); }
+
+ SharedLibraryDep1Adapter(ISlangSharedLibrary_Dep1* dep1) :
+ m_contained(dep1)
+ {
+ }
+
+protected:
+ void* getInterface(const Guid& guid)
+ {
+ if (guid == ISlangUnknown::getTypeGuid() ||
+ guid == ICastable::getTypeGuid() ||
+ guid == ISlangSharedLibrary::getTypeGuid())
+ {
+ return static_cast<ISlangSharedLibrary*>(this);
+ }
+ return nullptr;
+ }
+ void* getObject(const Guid& guid)
+ {
+ SLANG_UNUSED(guid);
+ return nullptr;
+ }
+
+ ComPtr<ISlangSharedLibrary_Dep1> m_contained;
+};
+
+void* SharedLibraryDep1Adapter::castAs(const SlangUUID& guid)
+{
+ if (auto intf = getInterface(guid))
+ {
+ return intf;
+ }
+ return getObject(guid);
+}
+
+/* Hack to take into account downstream compilers shared library interface might need an adapter */
+static SlangResult _getDownstreamSharedLibrary(DownstreamCompileResult* downstreamResult, ComPtr<ISlangSharedLibrary>& outSharedLibrary)
+{
+ ComPtr<ISlangSharedLibrary> lib;
+ SLANG_RETURN_ON_FAIL(downstreamResult->getHostCallableSharedLibrary(lib));
+
+ if (SLANG_SUCCEEDED(lib->queryInterface(ISlangSharedLibrary::getTypeGuid(), (void**)outSharedLibrary.writeRef())))
+ {
+ return SLANG_OK;
+ }
+
+ ComPtr<ISlangSharedLibrary_Dep1> libDep1;
+ if (SLANG_SUCCEEDED(lib->queryInterface(ISlangSharedLibrary_Dep1::getTypeGuid(), (void**)libDep1.writeRef())))
+ {
+ // Okay, we need to adapt for now
+ outSharedLibrary = new SharedLibraryDep1Adapter(libDep1);
+ return SLANG_OK;
+ }
+ return SLANG_E_NOT_FOUND;
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! DefaultArtifactHandler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+/* static */DefaultArtifactHandler DefaultArtifactHandler::g_singleton;
+
+SlangResult DefaultArtifactHandler::queryInterface(SlangUUID const& uuid, void** outObject)
+{
+ if (auto ptr = getInterface(uuid))
+ {
+ addRef();
+ *outObject = static_cast<IArtifactHandler*>(this);
+ return SLANG_OK;
+ }
+ return SLANG_E_NO_INTERFACE;
+}
+
+void* DefaultArtifactHandler::castAs(const Guid& guid)
+{
+ if (auto ptr = getInterface(guid))
+ {
+ return ptr;
+ }
+ return getObject(guid);
+}
+
+void* DefaultArtifactHandler::getInterface(const Guid& uuid)
+{
+ if (uuid == ISlangUnknown::getTypeGuid() ||
+ uuid == ICastable::getTypeGuid() ||
+ uuid == IArtifactHandler::getTypeGuid())
+ {
+ return static_cast<IArtifactHandler*>(this);
+ }
+
+ return nullptr;
+}
+
+void* DefaultArtifactHandler::getObject(const Guid& uuid)
+{
+ SLANG_UNUSED(uuid);
+ return nullptr;
+}
+
+SlangResult DefaultArtifactHandler::_addRepresentation(IArtifact* artifact, ArtifactKeep keep, ISlangUnknown* rep, ICastable** outCastable)
+{
+ SLANG_ASSERT(rep);
+
+ // See if it implements ICastable
+ {
+ ComPtr<ICastable> castable;
+ if (SLANG_SUCCEEDED(rep->queryInterface(ICastable::getTypeGuid(), (void**)castable.writeRef())) && castable)
+ {
+ return _addRepresentation(artifact, keep, castable, outCastable);
+ }
+ }
+
+ // We have to wrap
+ ComPtr<IUnknownCastableAdapter> adapter(new UnknownCastableAdapter(rep));
+ return _addRepresentation(artifact, keep, adapter, outCastable);
+}
+
+SlangResult DefaultArtifactHandler::_addRepresentation(IArtifact* artifact, ArtifactKeep keep, ICastable* castable, ICastable** outCastable)
+{
+ SLANG_ASSERT(castable);
+
+ if (canKeep(keep))
+ {
+ artifact->addRepresentation(castable);
+ }
+
+ castable->addRef();
+ *outCastable = castable;
+ return SLANG_OK;
+}
+
+SlangResult DefaultArtifactHandler::expandChildren(IArtifactContainer* container)
+{
+ SlangResult res = container->getExpandChildrenResult();
+ if (res != SLANG_E_UNINITIALIZED)
+ {
+ // It's already expanded
+ return res;
+ }
+
+ // For the generic container type, we just expand as empty
+ const auto desc = container->getDesc();
+ if (desc.kind == ArtifactKind::Container)
+ {
+ container->setChildren(nullptr, 0);
+ return SLANG_OK;
+ }
+ // TODO(JS):
+ // Proper implementation should (for example) be able to expand a Zip file etc.
+ return SLANG_E_NOT_IMPLEMENTED;
+}
+
+
+
+SlangResult DefaultArtifactHandler::getOrCreateRepresentation(IArtifact* artifact, const Guid& guid, ArtifactKeep keep, ICastable** outCastable)
+{
+ // See if we already have a rep of this type
+ {
+ for (ICastable* rep : artifact->getRepresentations())
+ {
+ if (rep->castAs(guid))
+ {
+ rep->addRef();
+ *outCastable = rep;
+ return SLANG_OK;
+ }
+ }
+ }
+
+ // TODO(JS): Temporary whilst DownstreamCompileResult is
+ // Special handling for DownstreamCompileResult
+ if (auto downstreamResult = findRepresentation<DownstreamCompileResult>(artifact))
+ {
+ if (guid == ISlangBlob::getTypeGuid())
+ {
+ ComPtr<ISlangBlob> blob;
+ SLANG_RETURN_ON_FAIL(downstreamResult->getBinary(blob));
+ return _addRepresentation(artifact, keep, blob, outCastable);
+ }
+ else if (guid == ISlangSharedLibrary::getTypeGuid())
+ {
+ ComPtr<ISlangSharedLibrary> lib;
+ SLANG_RETURN_ON_FAIL(_getDownstreamSharedLibrary(downstreamResult, lib));
+ return _addRepresentation(artifact, keep, lib, outCastable);
+ }
+ }
+
+ // Normal construction
+ if (guid == ISlangBlob::getTypeGuid())
+ {
+ ComPtr<ISlangBlob> blob;
+ SLANG_RETURN_ON_FAIL(_loadBlob(artifact, keep, blob.writeRef()));
+ return _addRepresentation(artifact, keep, blob, outCastable);
+ }
+ else if (guid == ISlangSharedLibrary::getTypeGuid())
+ {
+ ComPtr<ISlangSharedLibrary> sharedLib;
+ SLANG_RETURN_ON_FAIL(_loadSharedLibrary(artifact, keep, sharedLib.writeRef()));
+ return _addRepresentation(artifact, keep, sharedLib, outCastable);
+ }
+
+ return SLANG_E_NOT_AVAILABLE;
+}
+
+static bool _isFileSystemFile(ICastable* castable, void* data)
+{
+ if (auto fileRep = as<IFileArtifactRepresentation>(castable))
+ {
+ ISlangMutableFileSystem* fileSystem = (ISlangMutableFileSystem*)data;
+ if (fileRep->getFileSystem() == fileSystem)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+SlangResult DefaultArtifactHandler::getOrCreateFileRepresentation(IArtifact* artifact, ArtifactKeep keep, ISlangMutableFileSystem* fileSystem, IFileArtifactRepresentation** outFileRep)
+{
+ // See if we already have it
+ if (auto fileRep = as<IFileArtifactRepresentation>(artifact->findRepresentationWithPredicate(&_isFileSystemFile, fileSystem)))
+ {
+ fileRep->addRef();
+ *outFileRep = fileRep;
+ return SLANG_OK;
+ }
+
+ auto helper = DefaultArtifactHelper::getSingleton();
+
+ // If we are going to access as a file we need to be able to write it, and to do that we need a blob
+ ComPtr<ISlangBlob> blob;
+ SLANG_RETURN_ON_FAIL(artifact->loadBlob(getIntermediateKeep(keep), blob.writeRef()));
+
+ // Okay we need to store as a temporary. Get a lock file.
+ ComPtr<IFileArtifactRepresentation> lockFile;
+ SLANG_RETURN_ON_FAIL(helper->createLockFile(artifact->getName(), fileSystem, lockFile.writeRef()));
+
+ // Now we need the appropriate name for this item
+ ComPtr<ISlangBlob> pathBlob;
+ SLANG_RETURN_ON_FAIL(helper->calcArtifactPath(artifact->getDesc(), lockFile->getPath(), pathBlob.writeRef()));
+
+ const auto path = StringUtil::getString(pathBlob);
+
+ // Write the contents
+ SLANG_RETURN_ON_FAIL(File::writeAllBytes(path, blob->getBufferPointer(), blob->getBufferSize()));
+
+ ComPtr<IFileArtifactRepresentation> fileRep;
+
+ // TODO(JS): This path comparison is perhaps not perfect, in that it assumes the path is not changed
+ // in any way. For example an impl of calcArtifactPath that changed slashes or used a canonical path
+ // might mean the lock file and the rep have the same path.
+ // As it stands calcArtifactPath impl doesn't do that, but that is perhaps somewhatfragile
+
+ // If the paths are identical, we can just use the lock file for the rep
+ if (UnownedStringSlice(lockFile->getPath()) == path.getUnownedSlice())
+ {
+ fileRep.swap(lockFile);
+ }
+ else
+ {
+ // Create a new rep that references the lock file
+ fileRep = new FileArtifactRepresentation(IFileArtifactRepresentation::Kind::Owned, path, lockFile, lockFile->getFileSystem());
+ }
+
+ // Create the rep
+ if (canKeep(keep))
+ {
+ artifact->addRepresentation(fileRep);
+ }
+
+ // Return the file
+ *outFileRep = fileRep.detach();
+ return SLANG_OK;
+}
+
+SlangResult DefaultArtifactHandler::_loadSharedLibrary(IArtifact* artifact, ArtifactKeep keep, ISlangSharedLibrary** outSharedLibrary)
+{
+ // If it is 'shared library' for a CPU like thing, we can try and load it
+ const auto desc = artifact->getDesc();
+ if ((isDerivedFrom(desc.kind, ArtifactKind::HostCallable) ||
+ isDerivedFrom(desc.kind, ArtifactKind::SharedLibrary)) &&
+ isDerivedFrom(desc.payload, ArtifactPayload::CPULike))
+ {
+ // Get as a file represenation on the OS file system
+ ComPtr<IFileArtifactRepresentation> fileRep;
+ SLANG_RETURN_ON_FAIL(artifact->requireFile(ArtifactKeep::No, nullptr, fileRep.writeRef()));
+
+ // We requested on the OS file system, just check that's what we got...
+ SLANG_ASSERT(fileRep->getFileSystem() == nullptr);
+
+ // Try loading the shared library
+ SharedLibrary::Handle handle;
+ if (SLANG_FAILED(SharedLibrary::loadWithPlatformPath(fileRep->getPath(), handle)))
+ {
+ return SLANG_FAIL;
+ }
+
+ // The ScopeSharedLibrary will keep the fileRep in scope as long as is needed
+ auto sharedLibrary = new ScopeSharedLibrary(handle, fileRep);
+
+ if (canKeep(keep))
+ {
+ // We want to keep the fileRep, as that is necessary for the sharedLibrary to even work
+ artifact->addRepresentation(fileRep);
+ // Keep the shared library
+ artifact->addRepresentation(sharedLibrary);
+ }
+
+ // Output
+ sharedLibrary->addRef();
+ *outSharedLibrary = sharedLibrary;
+
+ return SLANG_OK;
+ }
+
+ return SLANG_FAIL;
+}
+
+SlangResult DefaultArtifactHandler::_loadBlob(IArtifact* artifact, ArtifactKeep keep, ISlangBlob** outBlob)
+{
+ SLANG_UNUSED(keep);
+
+ ComPtr<ISlangBlob> blob;
+
+ // Look for a representation that we can serialize into a blob
+ for (auto rep : artifact->getRepresentations())
+ {
+ if (auto artifactRep = as<IArtifactRepresentation>(rep))
+ {
+ SlangResult res = artifactRep->writeToBlob(blob.writeRef());
+ if (SLANG_SUCCEEDED(res) && blob)
+ {
+ break;
+ }
+ }
+ }
+
+ // Wasn't able to construct
+ if (!blob)
+ {
+ return SLANG_E_NOT_FOUND;
+ }
+
+ *outBlob = blob.detach();
+ return SLANG_OK;
+}
+
+} // namespace Slang