diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/core/core.vcxproj | 2 | ||||
| -rw-r--r-- | source/core/core.vcxproj.filters | 6 | ||||
| -rw-r--r-- | source/core/slang-object-scope-manager.cpp | 23 | ||||
| -rw-r--r-- | source/core/slang-object-scope-manager.h | 67 | ||||
| -rw-r--r-- | source/core/slang-string-slice-pool.cpp | 50 | ||||
| -rw-r--r-- | source/core/slang-string-slice-pool.h | 17 | ||||
| -rw-r--r-- | source/slang/ir-insts.h | 4 | ||||
| -rw-r--r-- | source/slang/ir-serialize.cpp | 440 | ||||
| -rw-r--r-- | source/slang/ir-serialize.h | 140 | ||||
| -rw-r--r-- | source/slang/ir.h | 27 |
10 files changed, 508 insertions, 268 deletions
diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj index 2d0c67342..f3e89b518 100644 --- a/source/core/core.vcxproj +++ b/source/core/core.vcxproj @@ -188,6 +188,7 @@ <ClInclude Include="slang-io.h" /> <ClInclude Include="slang-math.h" /> <ClInclude Include="slang-memory-arena.h" /> + <ClInclude Include="slang-object-scope-manager.h" /> <ClInclude Include="slang-random-generator.h" /> <ClInclude Include="slang-string-slice-pool.h" /> <ClInclude Include="slang-string-util.h" /> @@ -204,6 +205,7 @@ <ClCompile Include="slang-free-list.cpp" /> <ClCompile Include="slang-io.cpp" /> <ClCompile Include="slang-memory-arena.cpp" /> + <ClCompile Include="slang-object-scope-manager.cpp" /> <ClCompile Include="slang-random-generator.cpp" /> <ClCompile Include="slang-string-slice-pool.cpp" /> <ClCompile Include="slang-string-util.cpp" /> diff --git a/source/core/core.vcxproj.filters b/source/core/core.vcxproj.filters index 1548217b4..5031e67e7 100644 --- a/source/core/core.vcxproj.filters +++ b/source/core/core.vcxproj.filters @@ -63,6 +63,9 @@ <ClInclude Include="slang-memory-arena.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-object-scope-manager.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-random-generator.h"> <Filter>Header Files</Filter> </ClInclude> @@ -107,6 +110,9 @@ <ClCompile Include="slang-memory-arena.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="slang-object-scope-manager.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="slang-random-generator.cpp"> <Filter>Source Files</Filter> </ClCompile> diff --git a/source/core/slang-object-scope-manager.cpp b/source/core/slang-object-scope-manager.cpp new file mode 100644 index 000000000..313bd4cd5 --- /dev/null +++ b/source/core/slang-object-scope-manager.cpp @@ -0,0 +1,23 @@ +#include "slang-object-scope-manager.h" + +namespace Slang { + +void ObjectScopeManager::_releaseAll() +{ + RefObject*const* objs = m_objs.begin(); + const int numObjs = int(m_objs.Count()); + for (int i = 0; i < numObjs; ++i) + { + objs[i]->decreaseReference(); + } +} + +void ObjectScopeManager::clear() +{ + _releaseAll(); + // Free the memory as well as resizing + m_objs = List<RefObject*>(); +} + +} // namespace Slang + diff --git a/source/core/slang-object-scope-manager.h b/source/core/slang-object-scope-manager.h new file mode 100644 index 000000000..14008a490 --- /dev/null +++ b/source/core/slang-object-scope-manager.h @@ -0,0 +1,67 @@ +#ifndef SLANG_OBJECT_SCOPE_MANAGER_H +#define SLANG_OBJECT_SCOPE_MANAGER_H + +#include "smart-pointer.h" +#include "list.h" + +namespace Slang { + +/** Keep objects added in scope. + +This is currently about the most simple implementation possible. Objects are added to a list +which members are released when ObjectScopeManager loses scope, or clear is called. + +The same object can be added multiple times. This implementation will just add the same object +multiple times. A more complex implementation might notice that the object is already in scope +and not add a reference. + +Another potential improvement would be to hold the pointers in a MemoryArena. Doing so would remove +the requirement of a List of contiguous memory. + +In implementations that can hold multiple references to the same thing, we may want to add some +garbage collection to remove repeat references. +*/ +struct ObjectScopeManager +{ +public: + + /// Add an object which will be kept in scope until manager is destroyed + SLANG_INLINE RefObject* add(RefObject* obj); + /// Add an object, where it may be nullptr. If it null its a no-op + SLANG_INLINE RefObject* addMaybeNull(RefObject* obj); + + /// Clear the contents + void clear(); + + /// Dtor + ~ObjectScopeManager() { _releaseAll(); } + +protected: + void _releaseAll(); + + List<RefObject*> m_objs; +}; + +// --------------------------------------------------------------------------- +RefObject* ObjectScopeManager::addMaybeNull(RefObject* obj) +{ + if (obj) + { + obj->addReference(); + m_objs.Add(obj); + } + return obj; +} + +// --------------------------------------------------------------------------- +RefObject* ObjectScopeManager::add(RefObject* obj) +{ + SLANG_ASSERT(obj); + obj->addReference(); + m_objs.Add(obj); + return obj; +} + +} // namespace Slang + +#endif // SLANG_OBJECT_SCOPE_MANAGER_H
\ No newline at end of file diff --git a/source/core/slang-string-slice-pool.cpp b/source/core/slang-string-slice-pool.cpp index 88963d68f..797da5a0f 100644 --- a/source/core/slang-string-slice-pool.cpp +++ b/source/core/slang-string-slice-pool.cpp @@ -2,6 +2,12 @@ namespace Slang { +/* static */ const StringSlicePool::Handle StringSlicePool::kNullHandle; +/* static */ const StringSlicePool::Handle StringSlicePool::kEmptyHandle; + +/* static */const int StringSlicePool::kNumDefaultHandles; + + StringSlicePool::StringSlicePool() : m_arena(1024) { @@ -10,18 +16,23 @@ StringSlicePool::StringSlicePool() : void StringSlicePool::clear() { - m_slices.SetSize(1); - m_slices[0] = UnownedStringSlice::fromLiteral(""); + m_slices.SetSize(2); + + m_slices[0] = UnownedStringSlice((const char*)nullptr, (const char*)nullptr); + m_slices[1] = UnownedStringSlice::fromLiteral(""); + + // Add the empty entry + m_map.Add(m_slices[1], kEmptyHandle); m_map.Clear(); } StringSlicePool::Handle StringSlicePool::add(const Slice& slice) { - const int* indexPtr = m_map.TryGetValue(slice); - if (indexPtr) + const Handle* handlePtr = m_map.TryGetValue(slice); + if (handlePtr) { - return Handle(*indexPtr); + return *handlePtr; } // Create a scoped copy @@ -30,14 +41,37 @@ StringSlicePool::Handle StringSlicePool::add(const Slice& slice) const int index = int(m_slices.Count()); m_slices.Add(scopePath); - m_map.Add(scopePath, index); + m_map.Add(scopePath, Handle(index)); return Handle(index); } +StringSlicePool::Handle StringSlicePool::add(StringRepresentation* stringRep) +{ + if (stringRep == nullptr) + { + return kNullHandle; + } + return add(StringRepresentation::asSlice(stringRep)); +} + + +StringSlicePool::Handle StringSlicePool::add(const char* chars) +{ + if (!chars) + { + return kNullHandle; + } + if (chars[0] == 0) + { + return kEmptyHandle; + } + return add(UnownedStringSlice(chars)); +} + int StringSlicePool::findIndex(const Slice& slice) const { - const int* index = m_map.TryGetValue(slice); - return index ? *index : -1; + const Handle* handlePtr = m_map.TryGetValue(slice); + return handlePtr ? int(*handlePtr) : -1; } } // namespace Slang diff --git a/source/core/slang-string-slice-pool.h b/source/core/slang-string-slice-pool.h index e6846b3dd..c9c8b8db9 100644 --- a/source/core/slang-string-slice-pool.h +++ b/source/core/slang-string-slice-pool.h @@ -12,10 +12,16 @@ namespace Slang { class StringSlicePool { public: + /// Handle of 0 is null. If accessed will be returned as the empty string enum class Handle : uint32_t; typedef UnownedStringSlice Slice; + static const Handle kNullHandle = Handle(0); + static const Handle kEmptyHandle = Handle(1); + + static const int kNumDefaultHandles = 2; + /// Returns the index of a slice, if contained, or -1 if not found int findIndex(const Slice& slice) const; @@ -23,6 +29,12 @@ public: bool has(const Slice& slice) { return findIndex(slice) >= 0; } /// Add a slice Handle add(const Slice& slice); + /// Add from a string + Handle add(const char* chars); + /// Add a StringRepresentation + Handle add(StringRepresentation* string); + /// Add a string + Handle add(const String& string) { return add(string.getUnownedSlice()); } /// Empty contents void clear(); @@ -33,6 +45,9 @@ public: /// Get all the slices const List<UnownedStringSlice>& getSlices() const { return m_slices; } + /// Get the number of slices + int getNumSlices() const { return int(m_slices.Count()); } + /// Convert a handle to and index. (A handle is just an index!) static int asIndex(Handle handle) { return int(handle); } @@ -41,7 +56,7 @@ public: protected: List<UnownedStringSlice> m_slices; - Dictionary<UnownedStringSlice, int> m_map; + Dictionary<UnownedStringSlice, Handle> m_map; MemoryArena m_arena; }; diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h index 8d1c4708a..05ccd76e7 100644 --- a/source/slang/ir-insts.h +++ b/source/slang/ir-insts.h @@ -873,13 +873,13 @@ struct IRBuilder template <typename T> T* addRefObjectToFree(T* ptr) { - getModule()->addRefObjectToFree(ptr); + getModule()->getObjectScopeManager()->addMaybeNull(ptr); return ptr; } StringRepresentation* addStringToFree(const String& string) { StringRepresentation* stringRep = string.getStringRepresentation(); - getModule()->addRefObjectToFree(stringRep); + getModule()->getObjectScopeManager()->addMaybeNull(stringRep); return stringRep; } diff --git a/source/slang/ir-serialize.cpp b/source/slang/ir-serialize.cpp index e204944a7..e2fd6d3f8 100644 --- a/source/slang/ir-serialize.cpp +++ b/source/slang/ir-serialize.cpp @@ -81,13 +81,183 @@ struct CharReader } // anonymous -static UnownedStringSlice asStringSlice(const PrefixString* prefixString) +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StringRepresentationCache !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +StringRepresentationCache::StringRepresentationCache(): + m_stringTable(nullptr), + m_namePool(nullptr), + m_scopeManager(nullptr) +{ +} + +void StringRepresentationCache::init(const List<char>* stringTable, NamePool* namePool, ObjectScopeManager* scopeManager) +{ + m_stringTable = stringTable; + m_namePool = namePool; + m_scopeManager = scopeManager; + + // Decode the table + m_entries.SetSize(StringSlicePool::kNumDefaultHandles); + SLANG_COMPILE_TIME_ASSERT(StringSlicePool::kNumDefaultHandles == 2); + + { + Entry& entry = m_entries[0]; + entry.m_numChars = 0; + entry.m_startIndex = 0; + entry.m_object = nullptr; + } + { + Entry& entry = m_entries[1]; + entry.m_numChars = 0; + entry.m_startIndex = 0; + entry.m_object = nullptr; + } + + { + const char* start = stringTable->begin(); + const char* cur = start; + const char* end = stringTable->end(); + + while (cur < end) + { + CharReader reader(cur); + const int len = GetUnicodePointFromUTF8(reader); + + Entry entry; + entry.m_startIndex = uint32_t(reader.m_pos - start); + entry.m_numChars = len; + entry.m_object = nullptr; + + m_entries.Add(entry); + + cur = reader.m_pos + len; + } + } + + m_entries.Compress(); +} + +Name* StringRepresentationCache::getName(Handle handle) +{ + if (handle == StringSlicePool::kNullHandle) + { + return nullptr; + } + + Entry& entry = m_entries[int(handle)]; + if (entry.m_object) + { + Name* name = dynamic_cast<Name*>(entry.m_object); + if (name) + { + return name; + } + StringRepresentation* stringRep = static_cast<StringRepresentation*>(entry.m_object); + // Promote it to a name + name = m_namePool->getName(String(stringRep)); + entry.m_object = name; + return name; + } + + Name* name = m_namePool->getName(String(getStringSlice(handle))); + entry.m_object = name; + return name; +} + +String StringRepresentationCache::getString(Handle handle) +{ + return String(getStringRepresentation(handle)); +} + +UnownedStringSlice StringRepresentationCache::getStringSlice(Handle handle) const +{ + const Entry& entry = m_entries[int(handle)]; + const char* start = m_stringTable->begin(); + + return UnownedStringSlice(start + entry.m_startIndex, int(entry.m_numChars)); +} + +StringRepresentation* StringRepresentationCache::getStringRepresentation(Handle handle) +{ + if (handle == StringSlicePool::kNullHandle || handle == StringSlicePool::kEmptyHandle) + { + return nullptr; + } + + Entry& entry = m_entries[int(handle)]; + if (entry.m_object) + { + Name* name = dynamic_cast<Name*>(entry.m_object); + if (name) + { + return name->text.getStringRepresentation(); + } + return static_cast<StringRepresentation*>(entry.m_object); + } + + const UnownedStringSlice slice = getStringSlice(handle); + const UInt size = slice.size(); + + StringRepresentation* stringRep = StringRepresentation::createWithCapacityAndLength(size, size); + memcpy(stringRep->getData(), slice.begin(), size); + entry.m_object = stringRep; + + // Keep the StringRepresentation in scope + m_scopeManager->add(stringRep); + + return stringRep; +} + +char* StringRepresentationCache::getCStr(Handle handle) +{ + // It turns out StringRepresentation is always 0 terminated, so can just use that + StringRepresentation* rep = getStringRepresentation(handle); + return rep->getData(); +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SerialStringTableUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +/* static */void SerialStringTableUtil::encodeStringTable(const StringSlicePool& pool, List<char>& stringTable) +{ + // Skip the default handles -> nothing is encoded via them + return encodeStringTable(pool.getSlices().begin() + StringSlicePool::kNumDefaultHandles, pool.getNumSlices() - StringSlicePool::kNumDefaultHandles, stringTable); +} + +/* static */void SerialStringTableUtil::encodeStringTable(const UnownedStringSlice* slices, size_t numSlices, List<char>& stringTable) +{ + stringTable.Clear(); + for (size_t i = 0; i < numSlices; ++i) + { + const UnownedStringSlice slice = slices[i]; + const int len = int(slice.size()); + + // We need to write into the the string array + char prefixBytes[6]; + const int numPrefixBytes = EncodeUnicodePointToUTF8(prefixBytes, len); + const int baseIndex = int(stringTable.Count()); + + stringTable.SetSize(baseIndex + numPrefixBytes + len); + + char* dst = stringTable.begin() + baseIndex; + + memcpy(dst, prefixBytes, numPrefixBytes); + memcpy(dst + numPrefixBytes, slice.begin(), len); + } +} + +/* static */void SerialStringTableUtil::decodeStringTable(const List<char>& stringTable, List<UnownedStringSlice>& slices) { - const char* prefix = (char*)prefixString; + const char* start = stringTable.begin(); + const char* cur = start; + const char* end = stringTable.end(); - CharReader reader(prefix); - const int len = GetUnicodePointFromUTF8(reader); - return UnownedStringSlice(reader.m_pos, len); + while (cur < end) + { + CharReader reader(cur); + const int len = GetUnicodePointFromUTF8(reader); + slices.Add(UnownedStringSlice(reader.m_pos, len)); + cur = reader.m_pos + len; + } } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IRSerialData !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -105,8 +275,15 @@ size_t IRSerialData::calcSizeInBytes() const _calcArraySize(m_childRuns) + _calcArraySize(m_decorationRuns) + _calcArraySize(m_externalOperands) + - _calcArraySize(m_rawSourceLocs) + - _calcArraySize(m_strings); + _calcArraySize(m_stringTable) + + /* Raw source locs */ + _calcArraySize(m_rawSourceLocs) + + /* Debug */ + _calcArraySize(m_debugSourceFiles) + + _calcArraySize(m_debugLineOffsets) + + _calcArraySize(m_debugViewEntries) + + _calcArraySize(m_debugLocRuns) + + _calcArraySize(m_debugStrings); } void IRSerialData::clear() @@ -120,9 +297,16 @@ void IRSerialData::clear() m_externalOperands.Clear(); m_rawSourceLocs.Clear(); - m_strings.SetSize(2); - m_strings[int(kNullStringIndex)] = 0; - m_strings[int(kEmptyStringIndex)] = 0; + // Debug data + m_debugSourceFiles.Clear(); + m_debugLineOffsets.Clear(); + m_debugViewEntries.Clear(); + m_debugLocRuns.Clear(); + m_debugStrings.Clear(); + + m_stringTable.SetSize(2); + m_stringTable[int(kNullStringIndex)] = 0; + m_stringTable[int(kEmptyStringIndex)] = 0; m_decorationBaseIndex = 0; } @@ -166,7 +350,7 @@ bool IRSerialData::operator==(const ThisType& rhs) const _isEqual(m_decorationRuns, rhs.m_decorationRuns) && _isEqual(m_externalOperands, rhs.m_externalOperands) && _isEqual(m_rawSourceLocs, rhs.m_rawSourceLocs) && - _isEqual(m_strings, rhs.m_strings)); + _isEqual(m_stringTable, rhs.m_stringTable)); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IRSerialWriter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -208,17 +392,28 @@ void IRSerialWriter::_addInstruction(IRInst* inst) } } -IRSerialData::StringIndex IRSerialWriter::getStringIndex(Name* name) -{ - return name ? getStringIndex(name->text.getStringRepresentation()) : Ser::kNullStringIndex; -} - -UnownedStringSlice IRSerialWriter::getStringSlice(Ser::StringIndex index) const +// Find a view index that matches the view by file (and perhaps other characteristics in the future) +int _findSourceViewIndex(const List<SourceView*>& viewsIn, SourceView* view) { - Ser::StringOffset offset = m_stringStarts[int(index)]; - return asStringSlice((const PrefixString*)(m_serialData->m_strings.begin() + int(offset))); + const int numViews = int(viewsIn.Count()); + SourceView*const* views = viewsIn.begin(); + + SourceFile* sourceFile = view->getSourceFile(); + + for (int i = 0; i < numViews; ++i) + { + SourceView* curView = views[i]; + // For now we just match on source file + if (curView->getSourceFile() == sourceFile) + { + // It's a hit + return i; + } + } + return -1; } + Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, OptionFlags options, IRSerialData* serialData) { typedef Ser::Inst::PayloadType PayloadType; @@ -229,23 +424,6 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt serialData->clear(); - // Set up the stringStarts - m_stringStarts.SetSize(2); - m_stringStarts[0] = Ser::StringOffset(0); // Null - m_stringStarts[1] = Ser::StringOffset(1); // Empty - SLANG_ASSERT(serialData->m_strings.Count() == 2); - - // We'll keep StringRepresentations in scope (and for simplicity keep in order of StringIndex) - m_scopeStrings.SetSize(2); - m_scopeStrings[0] = nullptr; - m_scopeStrings[1] = nullptr; - - m_stringMap.Clear(); - - // Add the empty string index. - // We can't add the null string index, because that doesn't have any meaning as an UnownedStringSlice - m_stringMap.Add(UnownedStringSlice(""), Ser::kEmptyStringIndex); - // We reserve 0 for null m_insts.Clear(); m_insts.Add(nullptr); @@ -556,6 +734,12 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt } } + // Convert strings into a string table + { + SerialStringTableUtil::encodeStringTable(m_stringSlicePool, serialData->m_stringTable); + } + + // If the option to use RawSourceLocations is enabled, serialize out as is if (options & OptionFlag::RawSourceLocation) { @@ -571,80 +755,11 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt dstLocs[i] = Ser::RawSourceLoc(srcInst->sourceLoc.getRaw()); } } - + m_serialData = nullptr; return SLANG_OK; } -IRSerialData::StringIndex IRSerialWriter::getStringIndex(StringRepresentation* rep) -{ - if (rep == nullptr) - { - return Ser::kNullStringIndex; - } - - const UnownedStringSlice slice(rep->getData(), rep->getLength()); - const int len = int(rep->getLength()); - - Ser::StringIndex index; - if (m_stringMap.TryGetValue(slice, index)) - { - return index; - } - - // We need to write into the the string array - char prefixBytes[6]; - const int numPrefixBytes = EncodeUnicodePointToUTF8(prefixBytes, len); - const int baseIndex = int(m_serialData->m_strings.Count()); - - m_serialData->m_strings.SetSize(baseIndex + numPrefixBytes + len); - - char* dst = m_serialData->m_strings.begin() + baseIndex; - - memcpy(dst, prefixBytes, numPrefixBytes); - memcpy(dst + numPrefixBytes, slice.begin(), len); - - // We need to add 1, because the 0 is used for null, which is not in the map - const Ser::StringIndex stringIndex = Ser::StringIndex(m_stringMap.Count() + 1); - - SLANG_ASSERT(stringIndex == Ser::StringIndex(m_scopeStrings.Count())); - // Make sure the rep stays in scope (because the UnownedStringSlice is pointing to it's contents) - m_scopeStrings.Add(rep); - - // Add the start offset - m_stringStarts.Add(Ser::StringOffset(baseIndex)); - m_stringMap.Add(slice, stringIndex); - - return stringIndex; -} - -IRSerialData::StringIndex IRSerialWriter::getStringIndex(const char* chars) -{ - if (!chars) - { - return Ser::kNullStringIndex; - } - if (chars[0] == 0) - { - return Ser::kEmptyStringIndex; - } - - // Get as a StringRepresentation - String string(chars); - return getStringIndex(string.getStringRepresentation()); -} - -IRSerialData::StringIndex IRSerialWriter::getStringIndex(const UnownedStringSlice& slice) -{ - const int len = int(slice.size()); - if (len <= 0) - { - return Ser::kEmptyStringIndex; - } - String string(slice); - return getStringIndex(string.getStringRepresentation()); -} - template <typename T> static size_t _calcChunkSize(IRSerialBinary::CompressionType compressionType, const List<T>& array) { @@ -966,7 +1081,7 @@ static size_t _calcInstChunkSize(IRSerialBinary::CompressionType compressionType _calcChunkSize(compressionType, data.m_childRuns) + _calcChunkSize(compressionType, data.m_decorationRuns) + _calcChunkSize(compressionType, data.m_externalOperands) + - _calcChunkSize(Bin::CompressionType::None, data.m_strings) + + _calcChunkSize(Bin::CompressionType::None, data.m_stringTable) + _calcChunkSize(Bin::CompressionType::None, data.m_rawSourceLocs); { @@ -990,7 +1105,7 @@ static size_t _calcInstChunkSize(IRSerialBinary::CompressionType compressionType SLANG_RETURN_ON_FAIL(_writeArrayChunk(compressionType, Bin::kChildRunFourCc, data.m_childRuns, stream)); SLANG_RETURN_ON_FAIL(_writeArrayChunk(compressionType, Bin::kDecoratorRunFourCc, data.m_decorationRuns, stream)); SLANG_RETURN_ON_FAIL(_writeArrayChunk(compressionType, Bin::kExternalOperandsFourCc, data.m_externalOperands, stream)); - SLANG_RETURN_ON_FAIL(_writeArrayChunk(Bin::CompressionType::None, Bin::kStringFourCc, data.m_strings, stream)); + SLANG_RETURN_ON_FAIL(_writeArrayChunk(Bin::CompressionType::None, Bin::kStringFourCc, data.m_stringTable, stream)); SLANG_RETURN_ON_FAIL(_writeArrayChunk(Bin::CompressionType::None, Bin::kUInt32SourceLocFourCc, data.m_rawSourceLocs, stream)); @@ -1345,7 +1460,7 @@ int64_t _calcChunkTotalSize(const IRSerialBinary::Chunk& chunk) } case Bin::kStringFourCc: { - SLANG_RETURN_ON_FAIL(_readArrayUncompressedChunk(slangHeader, chunk, stream, &bytesRead, dataOut->m_strings)); + SLANG_RETURN_ON_FAIL(_readArrayUncompressedChunk(slangHeader, chunk, stream, &bytesRead, dataOut->m_stringTable)); remainingBytes -= _calcChunkTotalSize(chunk); break; } @@ -1367,85 +1482,6 @@ int64_t _calcChunkTotalSize(const IRSerialBinary::Chunk& chunk) return SLANG_OK; } -Name* IRSerialReader::getName(Ser::StringIndex index) -{ - if (index == Ser::kNullStringIndex) - { - return nullptr; - } - - StringRepresentation* rep = getStringRepresentation(index); - String string(rep); - Session* session = m_module->getSession(); - - return session->getNameObj(string); -} - -String IRSerialReader::getString(Ser::StringIndex index) -{ - return String(getStringRepresentation(index)); -} - -UnownedStringSlice IRSerialReader::getStringSlice(Ser::StringOffset offset) -{ - return asStringSlice((PrefixString*)(m_serialData->m_strings.begin() + int(offset))); -} - -StringRepresentation* IRSerialReader::getStringRepresentation(Ser::StringIndex index) -{ - if (index == Ser::kNullStringIndex) - { - return nullptr; - } - - StringRepresentation* rep = m_stringRepresentationCache[int(index)]; - if (rep) - { - return rep; - } - - const UnownedStringSlice slice = getStringSlice(index); - String string(slice); - - StringRepresentation* stringRep = string.getStringRepresentation(); - m_module->addRefObjectToFree(stringRep); - - m_stringRepresentationCache[int(index)] = stringRep; - - return stringRep; -} - -char* IRSerialReader::getCStr(Ser::StringIndex index) -{ - // It turns out StringRepresentation is always 0 terminated, so can just use that - StringRepresentation* rep = getStringRepresentation(index); - return rep->getData(); -} - -void IRSerialReader::_calcStringStarts() -{ - m_stringStarts.Clear(); - - const char* start = m_serialData->m_strings.begin(); - const char* cur = start; - const char* end = m_serialData->m_strings.end(); - - while (cur < end) - { - m_stringStarts.Add(Ser::StringOffset(cur - start)); - - CharReader reader(cur); - const int len = GetUnicodePointFromUTF8(reader); - cur = reader.m_pos + len; - } - - m_stringRepresentationCache.Clear(); - // Resize cache - m_stringRepresentationCache.SetSize(m_stringStarts.Count()); - // Make sure all values are null initially - memset(m_stringRepresentationCache.begin(), 0, sizeof(StringRepresentation*) * m_stringStarts.Count()); -} - IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) { typedef Ser::Inst::PayloadType PayloadType; @@ -1478,29 +1514,29 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) { auto decor = createEmptyDecoration<IRTargetDecoration>(m_module); SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - decor->targetName = getStringRepresentation(srcInst.m_payload.m_stringIndices[0]); + decor->targetName = m_stringRepresentationCache.getStringRepresentation(StringHandle(srcInst.m_payload.m_stringIndices[0])); return decor; } case kIRDecorationOp_TargetIntrinsic: { auto decor = createEmptyDecoration<IRTargetIntrinsicDecoration>(m_module); SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_2); - decor->targetName = getStringRepresentation(srcInst.m_payload.m_stringIndices[0]); - decor->definition = getStringRepresentation(srcInst.m_payload.m_stringIndices[1]); + decor->targetName = m_stringRepresentationCache.getStringRepresentation(StringHandle(srcInst.m_payload.m_stringIndices[0])); + decor->definition = m_stringRepresentationCache.getStringRepresentation(StringHandle(srcInst.m_payload.m_stringIndices[1])); return decor; } case kIRDecorationOp_GLSLOuterArray: { auto decor = createEmptyDecoration<IRGLSLOuterArrayDecoration>(m_module); SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - decor->outerArrayName = getCStr(srcInst.m_payload.m_stringIndices[0]); + decor->outerArrayName = m_stringRepresentationCache.getCStr(StringHandle(srcInst.m_payload.m_stringIndices[0])); return decor; } case kIRDecorationOp_Semantic: { auto decor = createEmptyDecoration<IRSemanticDecoration>(m_module); SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - decor->semanticName = getName(srcInst.m_payload.m_stringIndices[0]); + decor->semanticName = m_stringRepresentationCache.getName(StringHandle(srcInst.m_payload.m_stringIndices[0])); return decor; } case kIRDecorationOp_InterpolationMode: @@ -1514,7 +1550,7 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) { auto decor = createEmptyDecoration<IRNameHintDecoration>(m_module); SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - decor->name = getName(srcInst.m_payload.m_stringIndices[0]); + decor->name = m_stringRepresentationCache.getName(StringHandle(srcInst.m_payload.m_stringIndices[0])); return decor; } case kIRDecorationOp_VulkanRayPayload: @@ -1533,7 +1569,7 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) { auto decor = createEmptyDecoration<IRRequireGLSLExtensionDecoration>(m_module); SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - decor->extensionName = getStringRepresentation(srcInst.m_payload.m_stringIndices[0]); + decor->extensionName = m_stringRepresentationCache.getStringRepresentation(StringHandle(srcInst.m_payload.m_stringIndices[0])); return decor; } case kIRDecorationOp_RequireGLSLVersion: @@ -1556,13 +1592,15 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) typedef Ser::Inst::PayloadType PayloadType; m_serialData = &data; - _calcStringStarts(); - + auto module = new IRModule(); moduleOut = module; m_module = module; module->session = session; + + // Set up the string rep cache + m_stringRepresentationCache.init(&data.m_stringTable, session->getNamePool(), module->getObjectScopeManager()); // Add all the instructions @@ -1613,7 +1651,7 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) insts[i] = globalValueInst; // Set the global value SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - globalValueInst->mangledName = getName(srcInst.m_payload.m_stringIndices[0]); + globalValueInst->mangledName = m_stringRepresentationCache.getName(StringHandle(srcInst.m_payload.m_stringIndices[0])); } else { @@ -1659,7 +1697,7 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) { SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - const UnownedStringSlice slice = getStringSlice(srcInst.m_payload.m_stringIndices[0]); + const UnownedStringSlice slice = m_stringRepresentationCache.getStringSlice(StringHandle(srcInst.m_payload.m_stringIndices[0])); const size_t sliceSize = slice.size(); const size_t instSize = prefixSize + SLANG_OFFSET_OF(IRConstant::StringValue, chars) + sliceSize; @@ -1813,6 +1851,8 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) // !!!!!!!!!!!!!!!!!!!!!!!!!!!! Free functions !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +#if 0 + Result serializeModule(IRModule* module, SourceManager* sourceManager, Stream* stream) { IRSerialWriter serializer; @@ -1837,4 +1877,6 @@ Result readModule(Session* session, Stream* stream, RefPtr<IRModule>& moduleOut) return reader.read(serialData, session, moduleOut); } +#endif + } // namespace Slang diff --git a/source/slang/ir-serialize.h b/source/slang/ir-serialize.h index 0146765a0..ec560233f 100644 --- a/source/slang/ir-serialize.h +++ b/source/slang/ir-serialize.h @@ -5,6 +5,8 @@ #include "../core/basic.h" #include "../core/stream.h" +#include "../core/slang-object-scope-manager.h" + #include "ir.h" // For TranslationUnitRequest @@ -12,6 +14,51 @@ namespace Slang { +class StringRepresentationCache +{ + public: + typedef StringSlicePool::Handle Handle; + + struct Entry + { + uint32_t m_startIndex; + uint32_t m_numChars; + RefObject* m_object; ///< Could be nullptr, Name, or StringRepresentation. + }; + + /// Get as a name + Name* getName(Handle handle); + /// Get as a string + String getString(Handle handle); + /// Get as string representation + StringRepresentation* getStringRepresentation(Handle handle); + /// Get as a string slice + UnownedStringSlice getStringSlice(Handle handle) const; + /// Get as a 0 terminated 'c style' string + char* getCStr(Handle handle); + + /// Initialize a cache to use a string table, namePool and scopeManager + void init(const List<char>* stringTable, NamePool* namePool, ObjectScopeManager* scopeManager); + + /// Ctor + StringRepresentationCache(); + + protected: + ObjectScopeManager* m_scopeManager; + NamePool* m_namePool; + const List<char>* m_stringTable; + List<Entry> m_entries; +}; + +struct SerialStringTableUtil +{ + /// Convert a pool into a string table + static void encodeStringTable(const StringSlicePool& pool, List<char>& stringTable); + static void encodeStringTable(const UnownedStringSlice* slices, size_t numSlices, List<char>& stringTable); + /// Converts a pool into a string table, appending the strings to the slices + static void decodeStringTable(const List<char>& stringTable, List<UnownedStringSlice>& slicesOut); +}; + // Pre-declare class Name; @@ -23,13 +70,13 @@ struct IRSerialData enum class StringIndex : uint32_t; enum class ArrayIndex : uint32_t; - enum class RawSourceLoc : SourceLoc::RawValue; ///< This is just to copy over source loc data (ie not strictly serialize) - enum class StringOffset : uint32_t; ///< Offset into the m_stringsBuffer + enum class RawSourceLoc : SourceLoc::RawValue; ///< This is just to copy over source loc data (ie not strictly serialize) + enum class StringOffset : uint32_t; ///< Offset into the m_stringsBuffer typedef uint32_t SizeType; - static const StringIndex kNullStringIndex = StringIndex(0); - static const StringIndex kEmptyStringIndex = StringIndex(1); + static const StringIndex kNullStringIndex = StringIndex(StringSlicePool::kNullHandle); + static const StringIndex kEmptyStringIndex = StringIndex(StringSlicePool::kEmptyHandle); /// A run of instructions struct InstRun @@ -125,6 +172,32 @@ struct IRSerialData Payload m_payload; }; + + struct DebugSourceFile + { + uint32_t m_startLoc; ///< Start of the location range + uint32_t m_endLoc; ///< The end of the location range + + uint32_t m_pathIndex; ///< Path associated + + uint32_t m_numLocRuns; ///< The number of location runs associated with this source file + uint32_t m_numLineOffsets; ///< The number of offsets associated with the file + uint32_t m_numDebugViewEntries; ///< The number of debug view entries + }; + + struct DebugViewEntry + { + uint32_t m_startLoc; ///< Where does this entry begin? + uint32_t m_pathIndex; ///< What is the presumed path for this entry. If 0 it means there is no path. + int32_t m_lineAdjust; ///< The line adjustment + }; + + struct DebugLocRun + { + uint32_t m_sourceLoc; ///< The location + uint32_t startInstIndex; ///< The start instruction index + uint32_t numInst; ///< The amount of instructions + }; /// Clear to initial state void clear(); @@ -150,10 +223,16 @@ struct IRSerialData List<InstIndex> m_externalOperands; ///< Holds external operands (for instructions with more than kNumOperands) - List<char> m_strings; ///< All strings. Indexed into by StringIndex + List<char> m_stringTable; ///< All strings. Indexed into by StringIndex List<RawSourceLoc> m_rawSourceLocs; ///< A source location per instruction (saved without modification from IRInst)s + List<DebugSourceFile> m_debugSourceFiles; ///< The files associated + List<uint32_t> m_debugLineOffsets; ///< All of the debug line offsets + List<uint32_t> m_debugViewEntries; ///< The debug view entries - that modify line meanings + List<DebugLocRun> m_debugLocRuns; ///< Maps source locations to instructions + List<char> m_debugStrings; ///< All of the debug strings + static const PayloadInfo s_payloadInfos[int(Inst::PayloadType::CountOf)]; int m_decorationBaseIndex; ///< All decorations insts are at indices >= to this value @@ -296,24 +375,26 @@ struct IRSerialWriter static Result writeStream(const IRSerialData& data, Bin::CompressionType compressionType, Stream* stream); - /// Get a slice from an index - UnownedStringSlice getStringSlice(Ser::StringIndex index) const; - + /// Get an instruction index from an instruction Ser::InstIndex getInstIndex(IRInst* inst) const { return inst ? Ser::InstIndex(m_instMap[inst]) : Ser::InstIndex(0); } - Ser::StringIndex getStringIndex(StringRepresentation* string); - Ser::StringIndex getStringIndex(const UnownedStringSlice& string); - Ser::StringIndex getStringIndex(Name* name); - Ser::StringIndex getStringIndex(const char* chars); - + /// Get a slice from an index + UnownedStringSlice getStringSlice(Ser::StringIndex index) const { return m_stringSlicePool.getSlice(StringSlicePool::Handle(index)); } + /// Get index from string representations + Ser::StringIndex getStringIndex(StringRepresentation* string) { return Ser::StringIndex(m_stringSlicePool.add(string)); } + Ser::StringIndex getStringIndex(const UnownedStringSlice& slice) { return Ser::StringIndex(m_stringSlicePool.add(slice)); } + Ser::StringIndex getStringIndex(Name* name) { return name ? getStringIndex(name->text) : Ser::kNullStringIndex; } + Ser::StringIndex getStringIndex(const char* chars) { return Ser::StringIndex(m_stringSlicePool.add(chars)); } + Ser::StringIndex getStringIndex(const String& string) { return Ser::StringIndex(m_stringSlicePool.add(string.getUnownedSlice())); } + IRSerialWriter() : m_serialData(nullptr) {} protected: void _addInstruction(IRInst* inst); - + List<IRInst*> m_insts; ///< Instructions in same order as stored in the List<IRDecoration*> m_decorations; ///< Holds all decorations in order of the instructions as found @@ -321,20 +402,16 @@ protected: Dictionary<IRInst*, Ser::InstIndex> m_instMap; ///< Map an instruction to an instruction index - List<Ser::StringOffset> m_stringStarts; ///< Offset for each string index into the m_strings + StringSlicePool m_stringSlicePool; + IRSerialData* m_serialData; ///< Where the data is stored - // TODO (JS): - // We could perhaps improve this, if we stored at string indices (when linearized) the StringRepresentation - // Doing so would mean if a String or Name was looked up we wouldn't have to re-allocate on the arena - Dictionary<UnownedStringSlice, Ser::StringIndex> m_stringMap; ///< String map - List<RefPtr<StringRepresentation> > m_scopeStrings; ///< - - IRSerialData* m_serialData; ///< Where the data is stored + StringSlicePool m_debugStringSlicePool; ///< Slices held just for debug usage }; struct IRSerialReader { typedef IRSerialData Ser; + typedef StringRepresentationCache::Handle StringHandle; /// Read a stream to fill in dataOut IRSerialData static Result readStream(Stream* stream, IRSerialData* dataOut); @@ -342,14 +419,9 @@ struct IRSerialReader /// Read a module from serial data Result read(const IRSerialData& data, Session* session, RefPtr<IRModule>& moduleOut); - Name* getName(Ser::StringIndex index); - String getString(Ser::StringIndex index); - StringRepresentation* getStringRepresentation(Ser::StringIndex index); - UnownedStringSlice getStringSlice(Ser::StringIndex index) { return getStringSlice(m_stringStarts[int(index)]); } - char* getCStr(Ser::StringIndex index); - - UnownedStringSlice getStringSlice(Ser::StringOffset offset); - + /// Get the representation cache + StringRepresentationCache& getStringRepresentationCache() { return m_stringRepresentationCache; } + IRSerialReader(): m_serialData(nullptr), m_module(nullptr) @@ -358,21 +430,15 @@ struct IRSerialReader protected: - void _calcStringStarts(); IRDecoration* _createDecoration(const Ser::Inst& srcIns); static Result _skip(const IRSerialBinary::Chunk& chunk, Stream* stream, int64_t* remainingBytesInOut); - List<Ser::StringOffset> m_stringStarts; - List<StringRepresentation*> m_stringRepresentationCache; + StringRepresentationCache m_stringRepresentationCache; const IRSerialData* m_serialData; IRModule* m_module; }; - -Result serializeModule(IRModule* module, SourceManager* sourceManager, Stream* stream); -Result readModule(Session* session, Stream* stream, RefPtr<IRModule>& moduleOut); - } // namespace Slang #endif diff --git a/source/slang/ir.h b/source/slang/ir.h index e54a32043..41c9ab6ab 100644 --- a/source/slang/ir.h +++ b/source/slang/ir.h @@ -12,6 +12,7 @@ #include "source-loc.h" #include "../core/slang-memory-arena.h" +#include "../core/slang-object-scope-manager.h" #include "type-system-shared.h" @@ -1073,32 +1074,15 @@ struct IRModule : RefObject IRInstListBase getGlobalInsts() const { return getModuleInst()->getChildren(); } - void addRefObjectToFree(RefObject* obj) - { - if (obj) - { - obj->addReference(); - m_refObjectsToFree.Add(obj); - } - } - + /// Get the object scope manager + SLANG_FORCE_INLINE ObjectScopeManager* getObjectScopeManager() { return &m_objectScopeManager; } + /// Ctor IRModule(): memoryArena(kMemoryArenaBlockSize) { } - ~IRModule() - { - // Release all ref objects - for (RefObject* ptr: m_refObjectsToFree) - { - ptr->releaseReference(); - } - // Clear any memory too - m_refObjectsToFree = List<RefObject*>(); - } - MemoryArena memoryArena; // The compilation session in use. @@ -1106,7 +1090,8 @@ struct IRModule : RefObject IRModuleInst* moduleInst; protected: - List<RefObject*> m_refObjectsToFree; + + ObjectScopeManager m_objectScopeManager; }; void printSlangIRAssembly(StringBuilder& builder, IRModule* module); |
