summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/slang-ast-builder.cpp14
-rw-r--r--source/slang/slang-ast-builder.h2
-rw-r--r--source/slang/slang-ast-reflect.cpp2
-rw-r--r--source/slang/slang-ast-serialize.cpp511
-rw-r--r--source/slang/slang-ast-serialize.h140
-rw-r--r--source/slang/slang-ast-support-types.h2
-rw-r--r--source/slang/slang.cpp14
7 files changed, 631 insertions, 54 deletions
diff --git a/source/slang/slang-ast-builder.cpp b/source/slang/slang-ast-builder.cpp
index 3ff6130bd..ec4fd20f1 100644
--- a/source/slang/slang-ast-builder.cpp
+++ b/source/slang/slang-ast-builder.cpp
@@ -167,6 +167,20 @@ ASTBuilder::~ASTBuilder()
}
}
+NodeBase* ASTBuilder::createByNodeType(ASTNodeType nodeType)
+{
+ const ReflectClassInfo* info = ReflectClassInfo::getInfo(nodeType);
+
+ auto createFunc = info->m_createFunc;
+ SLANG_ASSERT(createFunc);
+ if (!createFunc)
+ {
+ return nullptr;
+ }
+
+ return (NodeBase*)createFunc(this);
+}
+
PtrType* ASTBuilder::getPtrType(Type* valueType)
{
return dynamicCast<PtrType>(getPtrType(valueType, "PtrType"));
diff --git a/source/slang/slang-ast-builder.h b/source/slang/slang-ast-builder.h
index 5bf7441f4..2cc03054b 100644
--- a/source/slang/slang-ast-builder.h
+++ b/source/slang/slang-ast-builder.h
@@ -103,6 +103,8 @@ public:
template<typename T, typename P0, typename P1>
T* create(const P0& p0, const P1& p1) { return _initAndAdd(new (m_arena.allocate(sizeof(T))) T(p0, p1));}
+ NodeBase* createByNodeType(ASTNodeType nodeType);
+
/// Get the built in types
SLANG_FORCE_INLINE Type* getBoolType() { return m_sharedASTBuilder->m_builtinTypes[Index(BaseType::Bool)]; }
SLANG_FORCE_INLINE Type* getHalfType() { return m_sharedASTBuilder->m_builtinTypes[Index(BaseType::Half)]; }
diff --git a/source/slang/slang-ast-reflect.cpp b/source/slang/slang-ast-reflect.cpp
index 7d4fd0c1a..7ed5057b9 100644
--- a/source/slang/slang-ast-reflect.cpp
+++ b/source/slang/slang-ast-reflect.cpp
@@ -72,7 +72,7 @@ struct ASTConstructAccess
#define SLANG_GET_DESTROY_FUNC_NONE(NAME) &ASTConstructAccess::Impl<NAME>::destroy
#define SLANG_REFLECT_CLASS_INFO(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \
- /* static */const ReflectClassInfo NAME::kReflectClassInfo = { uint32_t(ASTNodeType::NAME), uint32_t(ASTNodeType::LAST), SLANG_GET_SUPER_##TYPE(SUPER), #NAME, SLANG_GET_CREATE_FUNC_##MARKER(NAME), SLANG_GET_DESTROY_FUNC_##MARKER(NAME) };
+ /* static */const ReflectClassInfo NAME::kReflectClassInfo = { uint32_t(ASTNodeType::NAME), uint32_t(ASTNodeType::LAST), SLANG_GET_SUPER_##TYPE(SUPER), #NAME, SLANG_GET_CREATE_FUNC_##MARKER(NAME), SLANG_GET_DESTROY_FUNC_##MARKER(NAME), uint32_t(sizeof(NAME)), uint8_t(SLANG_ALIGN_OF(NAME)) };
SLANG_ALL_ASTNode_NodeBase(SLANG_REFLECT_CLASS_INFO, _)
diff --git a/source/slang/slang-ast-serialize.cpp b/source/slang/slang-ast-serialize.cpp
index 411e7a7ad..f8364e777 100644
--- a/source/slang/slang-ast-serialize.cpp
+++ b/source/slang/slang-ast-serialize.cpp
@@ -387,8 +387,8 @@ struct ASTSerialTypeInfo<SyntaxClass<T>>
static void toNative(ASTSerialReader* reader, const void* serial, void* native)
{
SLANG_UNUSED(reader);
- auto& src = *(const SerialType*)native;
- auto& dst = *(NativeType*)serial;
+ auto& src = *(const SerialType*)serial;
+ auto& dst = *(NativeType*)native;
dst.classInfo = ReflectClassInfo::getInfo(ASTNodeType(src));
}
};
@@ -428,17 +428,17 @@ struct ASTSerialTypeInfo<QualType>
};
enum { SerialAlignment = SLANG_ALIGN_OF(ASTSerialIndex) };
- static void toSerial(ASTSerialWriter* writer, const void* inNative, void* outSerial)
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
{
- auto dst = (SerialType*)outSerial;
- auto src = (const NativeType*)inNative;
+ auto dst = (SerialType*)serial;
+ auto src = (const NativeType*)native;
dst->isLeftValue = src->isLeftValue ? 1 : 0;
dst->type = writer->addPointer(src->type);
}
- static void toNative(ASTSerialReader* reader, const void* inSerial, void* outNative)
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
{
- auto src = (const SerialType*)inSerial;
- auto dst = (NativeType*)outNative;
+ auto src = (const SerialType*)serial;
+ auto dst = (NativeType*)native;
dst->type = reader->getPointer(src->type).dynamicCast<Type>();
dst->isLeftValue = src->isLeftValue != 0;
}
@@ -968,33 +968,33 @@ ASTSerialClasses::ASTSerialClasses():
}
// Okay, go through fields setting their offset
- ASTSerialField* field = serialClass.fields;
+ ASTSerialField* fields = serialClass.fields;
for (Index j = 0; j < serialClass.fieldsCount; j++)
{
- size_t alignment = field->type->serialAlignment;
+ ASTSerialField& field = fields[j];
+
+ size_t alignment = field.type->serialAlignment;
// Make sure the offset is aligned for the field requirement
offset = (offset + alignment - 1) & ~(alignment - 1);
// Save the field offset
- field->serialOffset = uint32_t(offset);
+ field.serialOffset = uint32_t(offset);
// Move past the field
- offset += field->type->serialSizeInBytes;
+ offset += field.type->serialSizeInBytes;
// Calc the maximum alignment
maxAlignment = (alignment > maxAlignment) ? alignment : maxAlignment;
}
// Align with maximum alignment
- offset += (offset + maxAlignment - 1) & ~(maxAlignment - 1);
+ offset = (offset + maxAlignment - 1) & ~(maxAlignment - 1);
serialClass.alignment = uint8_t(maxAlignment);
serialClass.size = uint32_t(offset);
}
}
-
-
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTSerialWriter !!!!!!!!!!!!!!!!!!!!!!!!!!!!
ASTSerialWriter::ASTSerialWriter(ASTSerialClasses* classes) :
@@ -1024,11 +1024,11 @@ ASTSerialIndex ASTSerialWriter::addPointer(const NodeBase* node)
typedef ASTSerialInfo::NodeEntry NodeEntry;
- NodeEntry* nodeEntry = (NodeEntry*)m_arena.allocateAligned(sizeof(NodeEntry) + serialClass->size, 8);
+ NodeEntry* nodeEntry = (NodeEntry*)m_arena.allocateAligned(sizeof(NodeEntry) + serialClass->size, ASTSerialInfo::MAX_ALIGNMENT);
nodeEntry->type = ASTSerialInfo::Type::Node;
nodeEntry->astNodeType = uint16_t(node->astNodeType);
- nodeEntry->nextAlignment = 0;
+ nodeEntry->info = ASTSerialInfo::makeEntryInfo(serialClass->alignment);
auto index = _add(node, nodeEntry);
@@ -1080,15 +1080,19 @@ ASTSerialIndex ASTSerialWriter::addPointer(const RefObject* obj)
typedef ASTSerialTypeInfo<LookupResultItem::Breadcrumb> TypeInfo;
typedef ASTSerialInfo::RefObjectEntry RefObjectEntry;
- RefObjectEntry* refEntry = (RefObjectEntry*)m_arena.allocateAligned(sizeof(RefObjectEntry) + sizeof(TypeInfo::SerialType), 8);
+ size_t alignment = TypeInfo::SerialAlignment;
+ alignment = (alignment < SLANG_ALIGN_OF(ASTSerialInfo::RefObjectEntry)) ? SLANG_ALIGN_OF(ASTSerialInfo::RefObjectEntry) : alignment;
- refEntry->type = ASTSerialInfo::Type::RefObject;
- refEntry->subType = RefObjectEntry::SubType::Breadcrumb;
+ RefObjectEntry* entry = (RefObjectEntry*)m_arena.allocateAligned(sizeof(RefObjectEntry) + sizeof(TypeInfo::SerialType), alignment);
- auto index = _add(breadcrumb, refEntry);
+ entry->type = ASTSerialInfo::Type::RefObject;
+ entry->info = ASTSerialInfo::makeEntryInfo(int(alignment));
+ entry->subType = RefObjectEntry::SubType::Breadcrumb;
+
+ auto index = _add(breadcrumb, entry);
// Do any conversion
- TypeInfo::toSerial(this, breadcrumb, refEntry + 1);
+ TypeInfo::toSerial(this, breadcrumb, entry + 1);
return index;
}
else if (auto name = dynamicCast<const Name>(obj))
@@ -1133,11 +1137,11 @@ ASTSerialIndex ASTSerialWriter::addString(const UnownedStringSlice& slice)
uint8_t encodeBuf[Util::kMaxLiteEncodeUInt32];
const int encodeCount = Util::encodeLiteUInt32(uint32_t(slice.getLength()), encodeBuf);
- StringEntry* entry = (StringEntry*)m_arena.allocateUnaligned(sizeof(StringEntry) + encodeCount + slice.getLength());
- entry->nextAlignment = 0;
+ StringEntry* entry = (StringEntry*)m_arena.allocateUnaligned(SLANG_OFFSET_OF(StringEntry, sizeAndChars) + encodeCount + slice.getLength());
+ entry->info = ASTSerialInfo::EntryInfo::Alignment1;
entry->type = ASTSerialInfo::Type::String;
- uint8_t* dst = (uint8_t*)(entry + 1);
+ uint8_t* dst = (uint8_t*)(entry->sizeAndChars);
for (int i = 0; i < encodeCount; ++i)
{
dst[i] = encodeBuf[i];
@@ -1180,7 +1184,7 @@ ASTSerialSourceLoc ASTSerialWriter::addSourceLoc(SourceLoc sourceLoc)
return 0;
}
-ASTSerialIndex ASTSerialWriter::_addArray(size_t elementSize, const void* elements, Index elementCount)
+ASTSerialIndex ASTSerialWriter::_addArray(size_t elementSize, size_t alignment, const void* elements, Index elementCount)
{
typedef ASTSerialInfo::ArrayEntry Entry;
@@ -1189,39 +1193,261 @@ ASTSerialIndex ASTSerialWriter::_addArray(size_t elementSize, const void* elemen
return ASTSerialIndex(0);
}
+ SLANG_ASSERT(alignment >= 1 && alignment <= ASTSerialInfo::MAX_ALIGNMENT);
+
+ // We must at a minimum have the alignment for the array prefix info
+ alignment = (alignment < SLANG_ALIGN_OF(Entry)) ? SLANG_ALIGN_OF(Entry) : alignment;
+
size_t payloadSize = elementCount * elementSize;
- Entry* entry = (Entry*)m_arena.allocateAligned(sizeof(Entry) + payloadSize, 8);
+ Entry* entry = (Entry*)m_arena.allocateAligned(sizeof(Entry) + payloadSize, alignment);
entry->type = ASTSerialInfo::Type::Array;
- entry->nextAlignment = 0;
+ entry->info = ASTSerialInfo::makeEntryInfo(int(alignment));
entry->elementSize = uint16_t(elementSize);
entry->elementCount = uint32_t(elementCount);
memcpy(entry + 1, elements, payloadSize);
m_entries.add(entry);
- ASTSerialIndex index = ASTSerialIndex(m_entries.getCount() - 1);
+ return ASTSerialIndex(m_entries.getCount() - 1);
+}
- // We don't add to a pointer map, because arrays are not shared
+SlangResult ASTSerialWriter::write(Stream* stream)
+{
+ const Int entriesCount = m_entries.getCount();
- // Do the conversion
+ // Add a sentinal so we don't need special handling for
+ ASTSerialInfo::Entry sentinal;
+ sentinal.type = ASTSerialInfo::Type::String;
+ sentinal.info = ASTSerialInfo::EntryInfo::Alignment1;
- return index;
+ m_entries.add(&sentinal);
+ m_entries.removeLast();
+
+ ASTSerialInfo::Entry** entries = m_entries.getBuffer();
+ // Note strictly required in our impl of List. But by writing this and
+ // knowing that removeLast cannot release memory, means the sentinal must be at the last position.
+ entries[entriesCount] = &sentinal;
+
+
+ static const uint8_t fixBuffer[ASTSerialInfo::MAX_ALIGNMENT] { 0, };
+
+ {
+ size_t offset = 0;
+
+ ASTSerialInfo::Entry* entry = entries[1];
+ // We start on 1, because 0 is nullptr and not used for anything
+ for (Index i = 1; i < entriesCount; ++i)
+ {
+ ASTSerialInfo::Entry* next = entries[i + 1];
+ // Before writing we need to store the next alignment
+
+ const size_t nextAlignment = ASTSerialInfo::getAlignment(next->info);
+ const size_t alignment = ASTSerialInfo::getAlignment(entry->info);
+
+ entry->info = ASTSerialInfo::combineWithNext(entry->info, next->info);
+
+ // Check we are aligned correctly
+ SLANG_ASSERT((offset & (alignment - 1)) == 0);
+
+ // When we write, we need to make sure it take into account the next alignment
+ const size_t entrySize = entry->calcSize(m_classes);
+
+ // Work out the fix for next alignment
+ size_t nextOffset = offset + entrySize;
+ nextOffset = (nextOffset + nextAlignment - 1) & ~(nextAlignment - 1);
+
+ size_t alignmentFixSize = nextOffset - (offset + entrySize);
+
+ // The fix must be less than max alignment. We require it to be less because we aligned each Entry to
+ // MAX_ALIGNMENT, and so < MAX_ALIGNMENT is the most extra bytes we can write
+ SLANG_ASSERT( alignmentFixSize < ASTSerialInfo::MAX_ALIGNMENT);
+
+ try
+ {
+ stream->write(entry, entrySize);
+ // If we needed to fix so that subsequent alignment is right, write out extra bytes here
+ if (alignmentFixSize)
+ {
+ stream->write(fixBuffer, alignmentFixSize);
+ }
+ }
+ catch (const IOException&)
+ {
+ return SLANG_FAIL;
+ }
+
+ // Onto next
+ offset = nextOffset;
+ entry = next;
+ }
+ }
+
+ return SLANG_OK;
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTSerialInfo::Entry !!!!!!!!!!!!!!!!!!!!!!!!
+
+size_t ASTSerialInfo::Entry::calcSize(ASTSerialClasses* serialClasses) const
+{
+ switch (type)
+ {
+ case Type::String:
+ {
+ auto entry = static_cast<const StringEntry*>(this);
+ const uint8_t* cur = (const uint8_t*)entry->sizeAndChars;
+ uint32_t charsSize;
+ int sizeSize = ByteEncodeUtil::decodeLiteUInt32(cur, &charsSize);
+ return SLANG_OFFSET_OF(StringEntry, sizeAndChars) + sizeSize + charsSize;
+ }
+ case Type::Node:
+ {
+ auto entry = static_cast<const NodeEntry*>(this);
+ auto serialClass = serialClasses->getSerialClass(ASTNodeType(entry->astNodeType));
+
+ // Align by the alignment of the entry
+ size_t alignment = getAlignment(entry->info);
+ size_t size = sizeof(NodeEntry) + serialClass->size;
+
+ size = size + (alignment - 1) & ~(alignment - 1);
+ return size;
+ }
+ case Type::RefObject:
+ {
+ auto entry = static_cast<const RefObjectEntry*>(this);
+
+ size_t payloadSize;
+ switch (entry->subType)
+ {
+ case RefObjectEntry::SubType::Breadcrumb:
+ {
+ payloadSize = sizeof(ASTSerialTypeInfo<LookupResultItem::Breadcrumb>::SerialType);
+ break;
+ }
+ default:
+ {
+ SLANG_ASSERT(!"Unknown type");
+ return 0;
+ }
+ }
+
+ return sizeof(RefObjectEntry) + payloadSize;
+ }
+ case Type::Array:
+ {
+ auto entry = static_cast<const ArrayEntry*>(this);
+ return sizeof(ArrayEntry) + entry->elementSize * entry->elementCount;
+ }
+ default: break;
+ }
+
+ SLANG_ASSERT(!"Unknown type");
+ return 0;
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTSerialReader !!!!!!!!!!!!!!!!!!!!!!!!!!!!
+const void* ASTSerialReader::getArray(ASTSerialIndex index, Index& outCount)
+{
+ if (index == ASTSerialIndex(0))
+ {
+ outCount = 0;
+ return nullptr;
+ }
+
+ SLANG_ASSERT(ASTSerialIndexRaw(index) < ASTSerialIndexRaw(m_entries.getCount()));
+ const Entry* entry = m_entries[Index(index)];
+
+ switch (entry->type)
+ {
+ case Type::Array:
+ {
+ auto arrayEntry = static_cast<const ASTSerialInfo::ArrayEntry*>(entry);
+ outCount = Index(arrayEntry->elementCount);
+ return (arrayEntry + 1);
+ }
+ default: break;
+ }
+
+ SLANG_ASSERT(!"Not an array");
+ outCount = 0;
+ return nullptr;
+}
+
ASTSerialPointer ASTSerialReader::getPointer(ASTSerialIndex index)
{
- SLANG_UNUSED(index);
+ if (index == ASTSerialIndex(0))
+ {
+ return ASTSerialPointer();
+ }
+
+ SLANG_ASSERT(ASTSerialIndexRaw(index) < ASTSerialIndexRaw(m_entries.getCount()));
+ const Entry* entry = m_entries[Index(index)];
+
+ switch (entry->type)
+ {
+ case Type::String:
+ {
+ // Hmm. Tricky -> we don't know if will be cast as Name or String. Lets assume string.
+ String string = getString(index);
+ return ASTSerialPointer(string.getStringRepresentation());
+ }
+ case Type::Node:
+ {
+ return ASTSerialPointer((NodeBase*)m_objects[Index(index)]);
+ }
+ case Type::RefObject:
+ {
+ return ASTSerialPointer((RefObject*)m_objects[Index(index)]);
+ }
+ default: break;
+ }
+
+ SLANG_ASSERT(!"Cannot access as a pointer");
return ASTSerialPointer();
}
String ASTSerialReader::getString(ASTSerialIndex index)
{
- SLANG_UNUSED(index);
- return String();
+ if (index == ASTSerialIndex(0))
+ {
+ return String();
+ }
+
+ SLANG_ASSERT(ASTSerialIndexRaw(index) < ASTSerialIndexRaw(m_entries.getCount()));
+ const Entry* entry = m_entries[Index(index)];
+
+ // It has to be a string type
+ if (entry->type != Type::String)
+ {
+ SLANG_ASSERT(!"Not a string");
+ return String();
+ }
+
+ RefObject* obj = (RefObject*)m_objects[Index(index)];
+
+ if (obj)
+ {
+ StringRepresentation* stringRep = dynamicCast<StringRepresentation>(obj);
+ if (stringRep)
+ {
+ return String(stringRep);
+ }
+ // Must be a name then
+ Name* name = dynamicCast<Name>(obj);
+ SLANG_ASSERT(name);
+ return name->text;
+ }
+
+ // Okay we need to construct as a string
+ UnownedStringSlice slice = getStringSlice(index);
+ String string(slice);
+ StringRepresentation* stringRep = string.getStringRepresentation();
+
+ m_scope.add(stringRep);
+ m_objects[Index(index)] = stringRep;
+ return string;
}
Name* ASTSerialReader::getName(ASTSerialIndex index)
@@ -1230,13 +1456,66 @@ Name* ASTSerialReader::getName(ASTSerialIndex index)
{
return nullptr;
}
- return nullptr;
+
+ SLANG_ASSERT(ASTSerialIndexRaw(index) < ASTSerialIndexRaw(m_entries.getCount()));
+ const Entry* entry = m_entries[Index(index)];
+
+ // It has to be a string type
+ if (entry->type != Type::String)
+ {
+ SLANG_ASSERT(!"Not a string");
+ return nullptr;
+ }
+
+ RefObject* obj = (RefObject*)m_objects[Index(index)];
+
+ if (obj)
+ {
+ Name* name = dynamicCast<Name>(obj);
+ if (name)
+ {
+ return name;
+ }
+ // Can only be a string then
+ StringRepresentation* stringRep = dynamicCast<StringRepresentation>(obj);
+ SLANG_ASSERT(stringRep);
+
+ // I don't need to scope, as scoped in NamePool
+ name = m_namePool->getName(String(stringRep));
+
+ // Store as name, as can always access the inner string if needed
+ m_objects[Index(index)] = name;
+ return name;
+ }
+
+ UnownedStringSlice slice = getStringSlice(index);
+ String string(slice);
+ Name* name = m_namePool->getName(string);
+ // Don't need to add to scope, because scoped on the pool
+ m_objects[Index(index)] = name;
+ return name;
}
UnownedStringSlice ASTSerialReader::getStringSlice(ASTSerialIndex index)
{
- SLANG_UNUSED(index);
- return UnownedStringSlice();
+ SLANG_ASSERT(ASTSerialIndexRaw(index) < ASTSerialIndexRaw(m_entries.getCount()));
+ const Entry* entry = m_entries[Index(index)];
+
+ // It has to be a string type
+ if (entry->type != Type::String)
+ {
+ SLANG_ASSERT(!"Not a string");
+ return UnownedStringSlice();
+ }
+
+ auto stringEntry = static_cast<const ASTSerialInfo::StringEntry*>(entry);
+
+ const uint8_t* src = (const uint8_t*)stringEntry->sizeAndChars;
+
+ // Decode the string
+ uint32_t size;
+ int sizeSize = ByteEncodeUtil::decodeLiteUInt32(src, &size);
+ return UnownedStringSlice((const char*)src + sizeSize, size);
}
SourceLoc ASTSerialReader::getSourceLoc(ASTSerialSourceLoc loc)
@@ -1245,6 +1524,162 @@ SourceLoc ASTSerialReader::getSourceLoc(ASTSerialSourceLoc loc)
return SourceLoc();
}
+SlangResult ASTSerialReader::loadEntries(const uint8_t* data, size_t dataCount, List<const ASTSerialInfo::Entry*>& outEntries)
+{
+ // Check the input data is at least aligned to the max alignment (otherwise everything cannot be aligned correctly)
+ SLANG_ASSERT((size_t(data) & (ASTSerialInfo::MAX_ALIGNMENT - 1)) == 0);
+
+ outEntries.setCount(1);
+ outEntries[0] = nullptr;
+
+ const uint8_t*const end = data + dataCount;
+
+ const uint8_t* cur = data;
+ while (cur < end)
+ {
+ const Entry* entry = (const Entry*)cur;
+ outEntries.add(entry);
+
+ const size_t entrySize = entry->calcSize(m_classes);
+ cur += entrySize;
+
+ // Need to get the next alignment
+ const size_t nextAlignment = ASTSerialInfo::getNextAlignment(entry->info);
+
+ // Need to fix cur with the alignment
+ cur = (const uint8_t*)((size_t(cur) + nextAlignment - 1) & ~(nextAlignment - 1));
+ }
+
+ return SLANG_OK;
+}
+
+SlangResult ASTSerialReader::load(const uint8_t* data, size_t dataCount, ASTBuilder* builder, NamePool* namePool)
+{
+ SLANG_RETURN_ON_FAIL(loadEntries(data, dataCount, m_entries));
+
+ m_namePool = namePool;
+
+ m_objects.clearAndDeallocate();
+ m_objects.setCount(m_entries.getCount());
+ memset(m_objects.getBuffer(), 0, m_objects.getCount() * sizeof(void*));
+
+ // Go through entries, constructing objects.
+ for (Index i = 1; i < m_entries.getCount(); ++i)
+ {
+ const Entry* entry = m_entries[i];
+
+ switch (entry->type)
+ {
+ case Type::String:
+ {
+ // Don't need to construct an object. This is probably a StringRepresentation, or a Name
+ // Will evaluate lazily.
+ break;
+ }
+ case Type::Node:
+ {
+ auto nodeEntry = static_cast<const ASTSerialInfo::NodeEntry*>(entry);
+ m_objects[i] = builder->createByNodeType(ASTNodeType(nodeEntry->astNodeType));
+ break;
+ }
+ case Type::RefObject:
+ {
+ auto objEntry = static_cast<const ASTSerialInfo::RefObjectEntry*>(entry);
+ switch (objEntry->subType)
+ {
+ case ASTSerialInfo::RefObjectEntry::SubType::Breadcrumb:
+ {
+ typedef LookupResultItem::Breadcrumb Breadcrumb;
+
+ auto breadcrumb = new LookupResultItem::Breadcrumb(Breadcrumb::Kind::Member, DeclRef<Decl>(), nullptr);
+ m_scope.add(breadcrumb);
+ m_objects[i] = breadcrumb;
+ break;
+ }
+ default:
+ {
+ SLANG_ASSERT(!"Unknown type");
+ return SLANG_FAIL;
+ }
+ }
+ break;
+ }
+ case Type::Array:
+ {
+ // Don't need to construct an object, as will be accessed an interpreted by the object that holds it
+ break;
+ }
+ }
+ }
+
+ // Deserialize
+ for (Index i = 1; i < m_entries.getCount(); ++i)
+ {
+ const Entry* entry = m_entries[i];
+ void* native = m_objects[i];
+ if (!native)
+ {
+ continue;
+ }
+ switch (entry->type)
+ {
+ case Type::Node:
+ {
+ auto nodeEntry = static_cast<const ASTSerialInfo::NodeEntry*>(entry);
+ auto serialClass = m_classes->getSerialClass(ASTNodeType(nodeEntry->astNodeType));
+
+ const uint8_t* src = (const uint8_t*)(nodeEntry + 1);
+ uint8_t* dst = (uint8_t*)m_objects[i];
+
+ // It must be constructed
+ SLANG_ASSERT(dst);
+
+ while (serialClass)
+ {
+ for (Index j = 0; j < serialClass->fieldsCount; ++j)
+ {
+ auto field = serialClass->fields[j];
+ auto fieldType = field.type;
+ fieldType->toNativeFunc(this, src + field.serialOffset, dst + field.nativeOffset);
+ }
+
+ auto cls = ReflectClassInfo::getInfo(serialClass->type);
+ auto superCls = cls->m_superClass;
+
+ // Get the super class
+ serialClass = superCls ? m_classes->getSerialClass(ASTNodeType(superCls->m_classId)) : nullptr;
+ }
+
+ break;
+ }
+ case Type::RefObject:
+ {
+ auto objEntry = static_cast<const ASTSerialInfo::RefObjectEntry*>(entry);
+ switch (objEntry->subType)
+ {
+ case ASTSerialInfo::RefObjectEntry::SubType::Breadcrumb:
+ {
+ typedef LookupResultItem::Breadcrumb Breadcrumb;
+ auto serialType = ASTSerialGetType<Breadcrumb>::getType();
+ serialType->toNativeFunc(this, (entry + 1), m_objects[i]);
+ break;
+ }
+ default:
+ {
+ SLANG_ASSERT(!"Unknown type");
+ return SLANG_FAIL;
+ }
+ }
+ break;
+ }
+ default: break;
+ }
+ }
+
+ return SLANG_OK;
+}
+
+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTSerializeUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!
/* static */SlangResult ASTSerializeUtil::selfTest()
diff --git a/source/slang/slang-ast-serialize.h b/source/slang/slang-ast-serialize.h
index a20da2e37..453102835 100644
--- a/source/slang/slang-ast-serialize.h
+++ b/source/slang/slang-ast-serialize.h
@@ -7,15 +7,58 @@
#include "slang-ast-support-types.h"
#include "slang-ast-all.h"
+#include "../core/slang-byte-encode-util.h"
+
+#include "../core/slang-stream.h"
+
namespace Slang
{
+class ASTSerialClasses;
+
// Type used to implement mechanisms to convert to and from serial types.
template <typename T>
struct ASTSerialTypeInfo;
struct ASTSerialInfo
{
+ enum
+ {
+ // Data held in serialized format, the maximally allowed alignment
+ MAX_ALIGNMENT = 8,
+ };
+
+ // We only allow up to MAX_ALIGNMENT bytes of alignment. We store alignments as shifts, so 2 bits needed for 1 - 8
+ enum class EntryInfo : uint8_t
+ {
+ Alignment1 = 0,
+ };
+
+ static EntryInfo makeEntryInfo(int alignment, int nextAlignment)
+ {
+ // Make sure they are power of 2
+ SLANG_ASSERT((alignment & (alignment - 1)) == 0);
+ SLANG_ASSERT((nextAlignment & (nextAlignment - 1)) == 0);
+
+ const int alignmentShift = ByteEncodeUtil::calcMsb8(alignment);
+ const int nextAlignmentShift = ByteEncodeUtil::calcMsb8(nextAlignment);
+ return EntryInfo((nextAlignmentShift << 2) | alignmentShift);
+ }
+ static EntryInfo makeEntryInfo(int alignment)
+ {
+ // Make sure they are power of 2
+ SLANG_ASSERT((alignment & (alignment - 1)) == 0);
+ return EntryInfo(ByteEncodeUtil::calcMsb8(alignment));
+ }
+ /// Apply with the next alignment
+ static EntryInfo combineWithNext(EntryInfo cur, EntryInfo next)
+ {
+ return EntryInfo((int(cur) & ~0xc0) | ((int(next) & 3) << 2));
+ }
+
+ static int getAlignment(EntryInfo info) { return 1 << (int(info) & 3); }
+ static int getNextAlignment(EntryInfo info) { return 1 << ((int(info) >> 2) & 3); }
+
enum class Type : uint8_t
{
String, ///< String
@@ -24,20 +67,30 @@ struct ASTSerialInfo
Array, ///< Array
};
+
+ /* Alignment is a little tricky. We have a 'Entry' header before the payload. The payload alignment may change.
+ If we only align on the Entry header, then it's size *must* be some modulo of the maximum alignment allowed.
+
+ We could hold Entry separate from payload. We could make the header not require the alignment of the payload - but then
+ we'd need payload alignment separate from entry alignment.
+ */
struct Entry
{
Type type;
- uint8_t nextAlignment; ///< Alignment of next entry
+ EntryInfo info;
+
+ size_t calcSize(ASTSerialClasses* serialClasses) const;
};
struct StringEntry : Entry
{
+ char sizeAndChars[1];
};
struct NodeEntry : Entry
{
uint16_t astNodeType;
- uint32_t _pad0;
+ uint32_t _pad0; ///< Necessary, because a node *can* have MAX_ALIGNEMENT
};
struct RefObjectEntry : Entry
@@ -47,7 +100,8 @@ struct ASTSerialInfo
Breadcrumb,
};
SubType subType;
- uint32_t _pad0;
+ uint8_t _pad0;
+ uint32_t _pad1; ///< Necessary because RefObjectEntry *can* have MAX_ALIGNEMENT
};
struct ArrayEntry : Entry
@@ -57,7 +111,8 @@ struct ASTSerialInfo
};
};
-enum class ASTSerialIndex : uint32_t;
+typedef uint32_t ASTSerialIndexRaw;
+enum class ASTSerialIndex : ASTSerialIndexRaw;
typedef uint32_t ASTSerialSourceLoc;
/* A type to convert pointers into types such that they can be passed around to readers/writers without
@@ -112,23 +167,78 @@ class ASTSerialReader : public RefObject
{
public:
- ASTSerialPointer getPointer(ASTSerialIndex index);
+ typedef ASTSerialInfo::Entry Entry;
+ typedef ASTSerialInfo::Type Type;
+
template <typename T>
- void getArray(ASTSerialIndex index, List<T>& outArray);
+ void getArray(ASTSerialIndex index, List<T>& out);
+
+ const void* getArray(ASTSerialIndex index, Index& outCount);
+
+ ASTSerialPointer getPointer(ASTSerialIndex index);
String getString(ASTSerialIndex index);
Name* getName(ASTSerialIndex index);
UnownedStringSlice getStringSlice(ASTSerialIndex index);
SourceLoc getSourceLoc(ASTSerialSourceLoc loc);
+
+
+ /// Load the entries table (without deserializing anything)
+ /// NOTE! data must stay ins scope for outEntries to be valid
+ SlangResult loadEntries(const uint8_t* data, size_t dataCount, List<const ASTSerialInfo::Entry*>& outEntries);
+
+ /// NOTE! data must stay ins scope when reading takes place
+ SlangResult load(const uint8_t* data, size_t dataCount, ASTBuilder* builder, NamePool* namePool);
+
+ ASTSerialReader(ASTSerialClasses* classes):
+ m_classes(classes)
+ {
+ }
+
+protected:
+ List<const Entry*> m_entries; ///< The entries
+ List<void*> m_objects; ///< The constructed objects
+
+ List<RefPtr<RefObject>> m_scope; ///< Objects to keep in scope during construction
+
+ NamePool* m_namePool;
+
+ ASTSerialClasses* m_classes; ///< Used to deserialize
};
// ---------------------------------------------------------------------------
template <typename T>
-void ASTSerialReader::getArray(ASTSerialIndex index, List<T>& outArray)
+void ASTSerialReader::getArray(ASTSerialIndex index, List<T>& out)
{
- SLANG_UNUSED(index);
- outArray.clear();
+ typedef ASTSerialTypeInfo<T> ElementTypeInfo;
+ typedef typename ElementTypeInfo::SerialType ElementSerialType;
+
+ Index count;
+ auto serialElements = (const ElementSerialType*)getArray(index, count);
+
+ if (count == 0)
+ {
+ out.clear();
+ return;
+ }
+
+ if (std::is_same<T, ElementSerialType>::value)
+ {
+ // If they are the same we can just write out
+ out.clear();
+ out.insertRange(0, (const T*)serialElements, count);
+ }
+ else
+ {
+ // Else we need to convert
+ out.setCount(count);
+ for (Index i = 0; i < count; ++i)
+ {
+ ElementTypeInfo::toNative(this, (const void*)&serialElements[i], (void*)&out[i]);
+ }
+ }
}
+
class ASTSerialClasses;
/* This is a class used tby toSerial implementations to turn native type into the serial type */
@@ -146,11 +256,17 @@ public:
ASTSerialIndex addName(const Name* name);
ASTSerialSourceLoc addSourceLoc(SourceLoc sourceLoc);
+ /// Get the entries table holding how each index maps to an entry
+ const List<ASTSerialInfo::Entry*>& getEntries() const { return m_entries; }
+
+ /// Write to a stream
+ SlangResult write(Stream* stream);
+
ASTSerialWriter(ASTSerialClasses* classes);
protected:
- ASTSerialIndex _addArray(size_t elementSize, const void* elements, Index elementCount);
+ ASTSerialIndex _addArray(size_t elementSize, size_t alignment, const void* elements, Index elementCount);
ASTSerialIndex _add(const void* nativePtr, ASTSerialInfo::Entry* entry)
{
@@ -182,7 +298,7 @@ ASTSerialIndex ASTSerialWriter::addArray(const T* in, Index count)
if (std::is_same<T, ElementSerialType>::value)
{
// If they are the same we can just write out
- return _addArray(sizeof(T), in, count);
+ return _addArray(sizeof(T), SLANG_ALIGN_OF(ElementSerialType), in, count);
}
else
{
@@ -194,7 +310,7 @@ ASTSerialIndex ASTSerialWriter::addArray(const T* in, Index count)
{
ElementTypeInfo::toSerial(this, &in[i], &work[i]);
}
- return _addArray(sizeof(ElementSerialType), in, count);
+ return _addArray(sizeof(ElementSerialType), SLANG_ALIGN_OF(ElementSerialType), work.getBuffer(), count);
}
}
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index 6fe8781c5..6ab9167f2 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -499,6 +499,8 @@ namespace Slang
const char* m_name; ///< Textual class name, for debugging
CreateFunc m_createFunc; ///< Callback to use when creating instances (using an ASTBuilder for backing memory)
DestructorFunc m_destructorFunc; ///< The destructor for this type. Being just destructor, does not free backing memory for type.
+ uint32_t m_sizeInBytes; ///< Total size of the type
+ uint8_t m_alignment; ///< The required alignment of the type
struct Infos
{
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 7c535d64b..6d4a27733 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -1080,10 +1080,18 @@ void FrontEndCompileRequest::parseTranslationUnit(
// Test serialization
{
RefPtr<ASTSerialClasses> classes = new ASTSerialClasses;
- ASTSerialWriter writer(classes);
- // Lets serialize it all
- writer.addPointer(translationUnit->getModuleDecl());
+ OwnedMemoryStream stream(FileAccess::ReadWrite);
+
+ {
+ ASTSerialWriter writer(classes);
+
+ // Lets serialize it all
+ writer.addPointer(translationUnit->getModuleDecl());
+ // Let's stick it all in a stream
+ writer.write(&stream);
+ }
+
}
#endif