diff options
| -rw-r--r-- | source/core/slang-shared-library.cpp | 58 | ||||
| -rw-r--r-- | source/core/slang-shared-library.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-api.cpp | 72 |
3 files changed, 136 insertions, 1 deletions
diff --git a/source/core/slang-shared-library.cpp b/source/core/slang-shared-library.cpp index 746e14e4c..8d362fd89 100644 --- a/source/core/slang-shared-library.cpp +++ b/source/core/slang-shared-library.cpp @@ -5,6 +5,18 @@ #include "slang-io.h" #include "slang-string-util.h" +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#elif defined(__linux__) +#include <dlfcn.h> +#endif +#include <sys/stat.h> +#include <sys/types.h> +#ifndef WIN32 +# include <unistd.h> +#endif + namespace Slang { @@ -87,4 +99,50 @@ void* DefaultSharedLibrary::findSymbolAddressByName(char const* name) return SharedLibrary::findSymbolAddressByName(m_sharedLibraryHandle, name); } + +String SharedLibraryUtils::getSharedLibraryFileName(void* symbolInLib) +{ +#if defined(_WIN32) + HMODULE moduleHandle; + GetModuleHandleExA( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCSTR)symbolInLib, + &moduleHandle); + const int maxLength = 1024; + wchar_t filenameBuffer[maxLength]; + auto length = GetModuleFileNameW(moduleHandle, filenameBuffer, maxLength); + if (length == maxLength) + { + // Insufficient buffer, return empty. + return String(); + } + return String::fromWString(filenameBuffer); + +#elif defined(__linux__) + Dl_info dllInfo; + if (!dladdr(symbolInLib, &dllInfo)) + { + return String(); + } + return dllInfo.dli_fname; + +#else + return String(); +#endif +} + +uint64_t SharedLibraryUtils::getSharedLibraryTimestamp(void* symbolInLib) +{ + auto fileName = getSharedLibraryFileName(symbolInLib); + if (fileName.getLength() == 0) + return 0; + struct stat result; + if (stat(fileName.getBuffer(), &result) == 0) + { + auto mod_time = result.st_mtime; + return (uint64_t)mod_time; + } + return 0; +} + } diff --git a/source/core/slang-shared-library.h b/source/core/slang-shared-library.h index c29f16289..c33f1f41b 100644 --- a/source/core/slang-shared-library.h +++ b/source/core/slang-shared-library.h @@ -94,6 +94,13 @@ protected: String m_path; }; +class SharedLibraryUtils +{ +public: + static String getSharedLibraryFileName(void* symbolInLib); + static uint64_t getSharedLibraryTimestamp(void* symbolInLib); +}; + } #endif // SLANG_SHARED_LIBRARY_H_INCLUDED diff --git a/source/slang/slang-api.cpp b/source/slang/slang-api.cpp index 56dc44c04..251a3980b 100644 --- a/source/slang/slang-api.cpp +++ b/source/slang/slang-api.cpp @@ -4,6 +4,8 @@ #include "slang-repro.h" +#include "../core/slang-shared-library.h" + // implementation of C interface SLANG_API SlangSession* spCreateSession(const char*) @@ -17,6 +19,65 @@ SLANG_API SlangSession* spCreateSession(const char*) return globalSession.detach(); } +// Attempt to load a previously compiled stdlib from the same file system location as the slang dll. +// Returns SLANG_OK when the cache is sucessfully loaded. +// Also returns the filename to the stdlib cache and the timestamp of current slang dll. +SlangResult tryLoadStdLibFromCache( + slang::IGlobalSession* globalSession, + Slang::String& outCachePath, + uint64_t& outTimestamp) +{ + auto fileName = + Slang::SharedLibraryUtils::getSharedLibraryFileName((void*)slang_createGlobalSession); + uint64_t currentLibTimestamp = + Slang::SharedLibraryUtils::getSharedLibraryTimestamp((void*)slang_createGlobalSession); + auto dirName = Slang::Path::getParentDirectory(fileName); + auto cacheFileName = Slang::Path::combine(dirName, "slang-stdlib.bin"); + outTimestamp = currentLibTimestamp; + outCachePath = cacheFileName; + if (currentLibTimestamp == 0) + { + return SLANG_FAIL; + } + Slang::ScopedAllocation cacheData; + SLANG_RETURN_ON_FAIL(Slang::File::readAllBytes(cacheFileName, cacheData)); + + // The first 8 bytes stores the timestamp of the slang dll that created this stdlib cache. + if (cacheData.getSizeInBytes() < sizeof(uint64_t)) + return SLANG_FAIL; + auto cacheTimestamp = *(uint64_t*)(cacheData.getData()); + if (cacheTimestamp != currentLibTimestamp) + return SLANG_FAIL; + SLANG_RETURN_ON_FAIL(globalSession->loadStdLib( + (uint8_t*)cacheData.getData() + sizeof(uint64_t), + cacheData.getSizeInBytes() - sizeof(uint64_t))); + return SLANG_OK; +} + +SlangResult trySaveStdLibToCache( + slang::IGlobalSession* globalSession, + const Slang::String& cacheFilename, + uint64_t dllTimestamp) +{ + if (dllTimestamp != 0 && cacheFilename.getLength() != 0) + { + Slang::ComPtr<ISlangBlob> stdLibBlobPtr; + SLANG_RETURN_ON_FAIL( + globalSession->saveStdLib(SLANG_ARCHIVE_TYPE_RIFF_LZ4, stdLibBlobPtr.writeRef())); + try + { + Slang::FileStream fileStream(cacheFilename, Slang::FileMode::Create); + fileStream.write(&dllTimestamp, sizeof(dllTimestamp)); + fileStream.write(stdLibBlobPtr->getBufferPointer(), stdLibBlobPtr->getBufferSize()); + return SLANG_OK; + } + catch (...) + { + } + } + return SLANG_FAIL; +} + SLANG_API SlangResult slang_createGlobalSession( SlangInt apiVersion, slang::IGlobalSession** outGlobalSession) @@ -32,7 +93,16 @@ SLANG_API SlangResult slang_createGlobalSession( } else { - SLANG_RETURN_ON_FAIL(globalSession->compileStdLib()); + Slang::String cacheFilename; + uint64_t dllTimestamp = 0; + if (tryLoadStdLibFromCache(globalSession, cacheFilename, dllTimestamp) != SLANG_OK) + { + // Compile std lib from embeded source. + SLANG_RETURN_ON_FAIL(globalSession->compileStdLib()); + + // Store the compiled stdlib to cache file. + trySaveStdLibToCache(globalSession, cacheFilename, dllTimestamp); + } } *outGlobalSession = globalSession.detach(); |
