diff options
Diffstat (limited to 'source/slang/slang-serialize.cpp')
| -rw-r--r-- | source/slang/slang-serialize.cpp | 1178 |
1 files changed, 0 insertions, 1178 deletions
diff --git a/source/slang/slang-serialize.cpp b/source/slang/slang-serialize.cpp index 2a1a92302..a1c555a9b 100644 --- a/source/slang/slang-serialize.cpp +++ b/source/slang/slang-serialize.cpp @@ -8,1182 +8,4 @@ namespace Slang { -const SerialClass* SerialClasses::add(const SerialClass* cls) -{ - List<const SerialClass*>& classes = m_classesByTypeKind[Index(cls->typeKind)]; - - if (cls->subType >= classes.getCount()) - { - classes.setCount(cls->subType + 1); - } - else - { - if (classes[cls->subType]) - { - SLANG_ASSERT(!"Type is already set"); - return nullptr; - } - } - - SerialClass* copy = _createSerialClass(cls); - classes[cls->subType] = copy; - - return copy; -} - -const SerialClass* SerialClasses::add( - SerialTypeKind kind, - SerialSubType subType, - const SerialField* fields, - Index fieldsCount, - const SerialClass* superCls) -{ - SerialClass cls; - cls.typeKind = kind; - cls.subType = subType; - - cls.fields = fields; - cls.fieldsCount = fieldsCount; - - // If the superCls is set it must be owned - SLANG_ASSERT(superCls == nullptr || isOwned(superCls)); - - cls.super = superCls; - - // Set to invalid values for now - cls.alignment = 0; - cls.size = 0; - cls.flags = 0; - - return add(&cls); -} - -const SerialClass* SerialClasses::addUnserialized(SerialTypeKind kind, SerialSubType subType) -{ - List<const SerialClass*>& classes = m_classesByTypeKind[Index(kind)]; - - if (subType >= classes.getCount()) - { - classes.setCount(subType + 1); - } - else - { - if (classes[subType]) - { - SLANG_ASSERT(!"Type is already set"); - return nullptr; - } - } - - SerialClass* dst = m_arena.allocate<SerialClass>(); - - dst->typeKind = kind; - dst->subType = subType; - - dst->size = 0; - dst->alignment = 0; - - dst->fields = nullptr; - dst->fieldsCount = 0; - dst->flags = SerialClassFlag::DontSerialize; - dst->super = nullptr; - - classes[subType] = dst; - return dst; -} - -bool SerialClasses::isOwned(const SerialClass* cls) const -{ - const List<const SerialClass*>& classes = m_classesByTypeKind[Index(cls->typeKind)]; - return cls->subType < classes.getCount() && classes[cls->subType] == cls; -} - -SerialClass* SerialClasses::_createSerialClass(const SerialClass* cls) -{ - uint32_t maxAlignment = 1; - uint32_t offset = 0; - - if (cls->super) - { - SLANG_ASSERT(isOwned(cls->super)); - - maxAlignment = cls->super->alignment; - offset = cls->super->size; - } - - // Can't be 0 - SLANG_ASSERT(maxAlignment != 0); - // Must be a power of 2 - SLANG_ASSERT((maxAlignment & (maxAlignment - 1)) == 0); - - // Check it is correctly aligned - SLANG_ASSERT((offset & (maxAlignment - 1)) == 0); - - SerialField* dstFields = m_arena.allocateArray<SerialField>(cls->fieldsCount); - - // Okay, go through fields setting their offset - const SerialField* srcFields = cls->fields; - for (Index j = 0; j < cls->fieldsCount; j++) - { - const SerialField& srcField = srcFields[j]; - SerialField& dstField = dstFields[j]; - - // Copy the field - dstField = srcField; - - uint32_t alignment = srcField.type->serialAlignment; - // Make sure the offset is aligned for the field requirement - offset = (offset + alignment - 1) & ~(alignment - 1); - - // Save the field offset - dstField.serialOffset = uint32_t(offset); - - // Move past the field - offset += uint32_t(srcField.type->serialSizeInBytes); - - // Calc the maximum alignment - maxAlignment = (alignment > maxAlignment) ? alignment : maxAlignment; - } - - // Align with maximum alignment - offset = (offset + maxAlignment - 1) & ~(maxAlignment - 1); - - SerialClass* dst = m_arena.allocate<SerialClass>(); - *dst = *cls; - - dst->alignment = uint8_t(maxAlignment); - dst->size = uint32_t(offset); - - dst->fields = dstFields; - - return dst; -} - -bool SerialClasses::isOk() const -{ - StringSlicePool pool(StringSlicePool::Style::Default); - - for (const auto& classes : m_classesByTypeKind) - { - for (const SerialClass* cls : classes) - { - // It is possible potentially to have gaps - if (cls == nullptr) - { - continue; - } - - if (cls->super && cls->super->typeKind != cls->typeKind) - { - // If has a super type, must be the same typeKind - return false; - } - - // Make sure the fields are uniquely named - - pool.clear(); - - { - const SerialClass* curCls = cls; - - do - { - for (Index i = 0; i < curCls->fieldsCount; ++i) - { - const SerialField& field = curCls->fields[i]; - - StringSlicePool::Handle handle; - if (pool.findOrAdd(UnownedStringSlice(field.name), handle)) - { - return false; - } - } - - // Add the fields of the parent - curCls = curCls->super; - } while (curCls); - } - } - } - - return true; -} - - -SerialClasses::SerialClasses() - : m_arena(2097152) -{ -} - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SerialWriter !!!!!!!!!!!!!!!!!!!!!!!!!!!! - -SerialWriter::SerialWriter(SerialClasses* classes, SerialFilter* filter, Flags flags) - : m_arena(2097152), m_classes(classes), m_filter(filter), m_flags(flags) -{ - // 0 is always the null pointer - m_entries.add(nullptr); - m_ptrMap.add(nullptr, 0); -} - -struct SkipFunctionBodyRAII -{ - FunctionDeclBase* funcDecl = nullptr; - Stmt* oldBody = nullptr; - SkipFunctionBodyRAII(SerialWriter::Flags flags, const SerialClass* serialCls, const void* ptr) - { - if ((flags & SerialWriter::Flag::SkipFunctionBody) == 0) - return; - - if (serialCls->typeKind != SerialTypeKind::NodeBase) - return; - auto cls = serialCls; - while (cls) - { - auto astNodeType = (ASTNodeType)cls->subType; - if (astNodeType == ASTNodeType::FunctionDeclBase) - { - funcDecl = (FunctionDeclBase*)ptr; - break; - } - cls = cls->super; - } - if (funcDecl) - { - oldBody = funcDecl->body; - // We always need to include body of unsafeForceInlineEarly functions - // since they will need to be available at IR lowering time of the - // user module for pre-linking inling. - if (!isUnsafeForceInlineFunc(funcDecl)) - { - funcDecl->body = nullptr; - } - } - } - ~SkipFunctionBodyRAII() - { - if (funcDecl) - { - funcDecl->body = oldBody; - } - } -}; - -SerialIndex SerialWriter::writeObject(const SerialClass* serialCls, const void* ptr) -{ - if (serialCls->flags & SerialClassFlag::DontSerialize) - { - return SerialIndex(0); - } - - if (serialCls->typeKind == SerialTypeKind::NodeBase && - ReflectClassInfo::isSubClassOf(serialCls->subType, Val::kReflectClassInfo)) - { - return writeValObject((Val*)ptr); - } - - // If we are skipping function bodies, set the body field to nullptr, and - // restore it after serialization. - SkipFunctionBodyRAII clearFunctionBodyRAII(m_flags, serialCls, ptr); - - // This pointer cannot be in the map - SLANG_ASSERT(m_ptrMap.tryGetValue(ptr) == nullptr); - - typedef SerialInfo::ObjectEntry ObjectEntry; - - ObjectEntry* nodeEntry = (ObjectEntry*)m_arena.allocateAligned( - sizeof(ObjectEntry) + serialCls->size, - SerialInfo::MAX_ALIGNMENT); - - nodeEntry->typeKind = serialCls->typeKind; - nodeEntry->subType = serialCls->subType; - nodeEntry->_pad0 = 0; - - nodeEntry->info = SerialInfo::makeEntryInfo(serialCls->alignment); - - // We add before adding fields, so if the fields point to this, the entry will be set - auto index = _add(ptr, nodeEntry); - - // Point to start of payload - uint8_t* serialPayload = (uint8_t*)(nodeEntry + 1); - - if (m_flags & Flag::ZeroInitialize) - { - ::memset(serialPayload, 0, serialCls->size); - } - - while (serialCls) - { - for (Index i = 0; i < serialCls->fieldsCount; ++i) - { - auto field = serialCls->fields[i]; - - // Work out the offsets - auto srcField = ((const uint8_t*)ptr) + field.nativeOffset; - auto dstField = serialPayload + field.serialOffset; - - field.type->toSerialFunc(this, srcField, dstField); - } - - // Get the super class - serialCls = serialCls->super; - } - - return index; -} - -SerialIndex SerialWriter::writeObject(const NodeBase* node) -{ - const SerialClass* serialClass = - m_classes->getSerialClass(SerialTypeKind::NodeBase, SerialSubType(node->astNodeType)); - return writeObject(serialClass, (const void*)node); -} - -SerialIndex SerialWriter::writeValObject(const Val* node) -{ - typedef SerialInfo::ValEntry ValEntry; - - size_t size = node->getOperandCount() * sizeof(SerialInfo::SerialValOperand); - ValEntry* nodeEntry = - (ValEntry*)m_arena.allocateAligned(sizeof(ValEntry) + size, SerialInfo::MAX_ALIGNMENT); - - nodeEntry->typeKind = SerialTypeKind::NodeBase; - nodeEntry->subType = (SerialSubType)node->astNodeType; - nodeEntry->operandCount = (uint32_t)node->getOperandCount(); - nodeEntry->info = SerialInfo::makeEntryInfo(SerialInfo::MAX_ALIGNMENT); - - // We add before adding fields, so if the fields point to this, the entry will be set - auto index = _add(node, nodeEntry); - - ShortList<SerialIndex, 4> serializedOperands; - - for (Index i = 0; i < node->getOperandCount(); i++) - { - auto operand = node->m_operands[i]; - switch (operand.kind) - { - case ValNodeOperandKind::ConstantValue: - serializedOperands.add((SerialIndex)0); - break; - case ValNodeOperandKind::ValNode: - case ValNodeOperandKind::ASTNode: - serializedOperands.add(addPointer(operand.values.nodeOperand)); - break; - } - } - - SLANG_ASSERT(serializedOperands.getCount() == node->getOperandCount()); - - auto serialOperands = (SerialInfo::SerialValOperand*)(nodeEntry + 1); - for (Index i = 0; i < node->getOperandCount(); i++) - { - auto serialOperand = serialOperands + i; - auto operand = node->m_operands[i]; - serialOperand->type = (int)operand.kind; - switch (operand.kind) - { - case ValNodeOperandKind::ConstantValue: - serialOperand->payload = operand.values.intOperand; - break; - case ValNodeOperandKind::ValNode: - serialOperand->payload = (uint64_t)serializedOperands[i]; - break; - case ValNodeOperandKind::ASTNode: - serialOperand->payload = (uint64_t)serializedOperands[i]; - break; - } - } - return index; -} - -SerialIndex SerialWriter::writeObject(const RefObject* obj) -{ - const SerialRefObject* serialObj = as<const SerialRefObject>(obj); - if (!serialObj) - { - SLANG_ASSERT(!"Unhandled type"); - return SerialIndex(0); - } - - const ReflectClassInfo* classInfo = serialObj->getClassInfo(); - SLANG_ASSERT(classInfo); - - const SerialClass* serialClass = - m_classes->getSerialClass(SerialTypeKind::RefObject, SerialSubType(classInfo->m_classId)); - return writeObject(serialClass, (const void*)obj); -} - -void SerialWriter::setPointerIndex(const NodeBase* ptr, SerialIndex index) -{ - m_ptrMap.add(ptr, Index(index)); -} - -void SerialWriter::setPointerIndex(const RefObject* ptr, SerialIndex index) -{ - m_ptrMap.add(ptr, Index(index)); -} - -SerialIndex SerialWriter::addPointer(const NodeBase* node) -{ - // Null is always 0 - if (node == nullptr) - { - return SerialIndex(0); - } - // Look up in the map - Index* indexPtr = m_ptrMap.tryGetValue(node); - if (indexPtr) - { - return SerialIndex(*indexPtr); - } - - if (m_filter) - { - return m_filter->writePointer(this, node); - } - else - { - return writeObject(node); - } -} - -SerialIndex SerialWriter::addPointer(const RefObject* obj) -{ - // Null is always 0 - if (obj == nullptr) - { - return SerialIndex(0); - } - // Look up in the map - Index* indexPtr = m_ptrMap.tryGetValue(obj); - if (indexPtr) - { - return SerialIndex(*indexPtr); - } - - // TODO(JS): - // Arguably the lookup for these types should be done the same way as arbitrary RefObject types - // and have a enum for them, such we can use a switch instead of all this casting - - if (auto stringRep = dynamicCast<StringRepresentation>(obj)) - { - SerialIndex index = addString(StringRepresentation::asSlice(stringRep)); - m_ptrMap.add(obj, Index(index)); - return index; - } - else if (auto name = dynamicCast<const Name>(obj)) - { - return addName(name); - } - - if (m_filter) - { - return m_filter->writePointer(this, obj); - } - else - { - return writeObject(obj); - } -} - -SerialIndex SerialWriter::_addStringSlice( - SerialTypeKind typeKind, - SliceMap& sliceMap, - const UnownedStringSlice& slice) -{ - typedef ByteEncodeUtil Util; - typedef SerialInfo::StringEntry StringEntry; - - if (slice.getLength() == 0) - { - return SerialIndex(0); - } - - Index* indexPtr = sliceMap.tryGetValue(slice); - if (indexPtr) - { - return SerialIndex(*indexPtr); - } - - // Okay we need to add the string - - uint8_t encodeBuf[Util::kMaxLiteEncodeUInt32]; - const int encodeCount = Util::encodeLiteUInt32(uint32_t(slice.getLength()), encodeBuf); - - StringEntry* entry = (StringEntry*)m_arena.allocateUnaligned( - SLANG_OFFSET_OF(StringEntry, sizeAndChars) + encodeCount + slice.getLength()); - entry->info = SerialInfo::EntryInfo::Alignment1; - entry->typeKind = typeKind; - - uint8_t* dst = (uint8_t*)(entry->sizeAndChars); - for (int i = 0; i < encodeCount; ++i) - { - dst[i] = encodeBuf[i]; - } - - memcpy(dst + encodeCount, slice.begin(), slice.getLength()); - - // Make a key that will stay in scope -> it's actually just stored in the arena. - // NOTE! without terminating 0 - UnownedStringSlice keySlice(((const char*)dst) + encodeCount, slice.getLength()); - - Index newIndex = m_entries.getCount(); - sliceMap.add(keySlice, newIndex); - - m_entries.add(entry); - return SerialIndex(newIndex); -} - -SerialIndex SerialWriter::addString(const String& in) -{ - return addPointer(in.getStringRepresentation()); -} - -SerialIndex SerialWriter::addName(const Name* name) -{ - if (name == nullptr) - { - return SerialIndex(0); - } - - // Look it up - Index* indexPtr = m_ptrMap.tryGetValue(name); - if (indexPtr) - { - return SerialIndex(*indexPtr); - } - - SerialIndex index = addString(name->text); - m_ptrMap.add(name, Index(index)); - return index; -} - -SerialIndex SerialWriter::addSerialArray( - size_t elementSize, - size_t alignment, - const void* elements, - Index elementCount) -{ - typedef SerialInfo::ArrayEntry Entry; - - if (elementCount == 0) - { - return SerialIndex(0); - } - - SLANG_ASSERT(alignment >= 1 && alignment <= SerialInfo::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, alignment); - - entry->typeKind = SerialTypeKind::Array; - entry->info = SerialInfo::makeEntryInfo(int(alignment)); - entry->elementSize = uint16_t(elementSize); - entry->elementCount = uint32_t(elementCount); - - memcpy(entry + 1, elements, payloadSize); - - m_entries.add(entry); - return SerialIndex(m_entries.getCount() - 1); -} - -static const uint8_t s_fixBuffer[SerialInfo::MAX_ALIGNMENT]{ - 0, -}; - -SlangResult SerialWriter::write(Stream* stream) -{ - const Int entriesCount = m_entries.getCount(); - - // Add a sentinal so we don't need special handling for - SerialInfo::Entry sentinal; - sentinal.typeKind = SerialTypeKind::String; - sentinal.info = SerialInfo::EntryInfo::Alignment1; - - m_entries.add(&sentinal); - m_entries.removeLast(); - - SerialInfo::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; - - { - size_t offset = 0; - - SerialInfo::Entry* entry = entries[1]; - // We start on 1, because 0 is nullptr and not used for anything - for (Index i = 1; i < entriesCount; ++i) - { - SerialInfo::Entry* next = entries[i + 1]; - - // Before writing we need to store the next alignment - - const size_t nextAlignment = SerialInfo::getAlignment(next->info); - const size_t alignment = SerialInfo::getAlignment(entry->info); - SLANG_UNUSED(alignment); - - entry->info = SerialInfo::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 < SerialInfo::MAX_ALIGNMENT); - - SLANG_RETURN_ON_FAIL(stream->write(entry, entrySize)); - // If we needed to fix so that subsequent alignment is right, write out extra bytes here - if (alignmentFixSize) - { - SLANG_RETURN_ON_FAIL(stream->write(s_fixBuffer, alignmentFixSize)); - } - - // Onto next - offset = nextOffset; - entry = next; - } - } - - return SLANG_OK; -} - -SlangResult SerialWriter::writeIntoContainer(FourCC fourCc, RiffContainer* container) -{ - typedef RiffContainer::Chunk Chunk; - typedef RiffContainer::ScopeChunk ScopeChunk; - - { - ScopeChunk scopeData(container, Chunk::Kind::Data, fourCc); - - { - // Sentinel so we don't need special handling for end of list - SerialInfo::Entry sentinal; - sentinal.typeKind = SerialTypeKind::String; - sentinal.info = SerialInfo::EntryInfo::Alignment1; - - size_t offset = 0; - const Int entriesCount = m_entries.getCount(); - - { - m_entries.add(&sentinal); - m_entries.removeLast(); - // 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. - m_entries.getBuffer()[entriesCount] = &sentinal; - } - - SerialInfo::Entry* const* entries = m_entries.getBuffer(); - - SerialInfo::Entry* entry = entries[1]; - // We start on 1, because 0 is nullptr and not used for anything - for (Index i = 1; i < entriesCount; ++i) - { - SerialInfo::Entry* next = entries[i + 1]; - - // Before writing we need to store the next alignment - - const size_t nextAlignment = SerialInfo::getAlignment(next->info); - const size_t alignment = SerialInfo::getAlignment(entry->info); - SLANG_UNUSED(alignment); - - entry->info = SerialInfo::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 < SerialInfo::MAX_ALIGNMENT); - - container->write(entry, entrySize); - if (alignmentFixSize) - { - container->write(s_fixBuffer, alignmentFixSize); - } - - // Onto next - offset = nextOffset; - entry = next; - } - } - } - - return SLANG_OK; -} - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SerialInfo::Entry !!!!!!!!!!!!!!!!!!!!!!!! - -size_t SerialInfo::Entry::calcSize(SerialClasses* serialClasses) const -{ - switch (typeKind) - { - case SerialTypeKind::ImportSymbol: - case SerialTypeKind::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 SerialTypeKind::Array: - { - auto entry = static_cast<const ArrayEntry*>(this); - return sizeof(ArrayEntry) + entry->elementSize * entry->elementCount; - } - case SerialTypeKind::RefObject: - case SerialTypeKind::NodeBase: - { - auto entry = static_cast<const ObjectEntry*>(this); - - auto serialClass = serialClasses->getSerialClass(typeKind, entry->subType); - - if (ReflectClassInfo::isSubClassOf(entry->subType, Val::kReflectClassInfo)) - return sizeof(ValEntry) + - static_cast<const ValEntry*>(this)->operandCount * sizeof(SerialValOperand); - - // Align by the alignment of the entry - size_t alignment = getAlignment(entry->info); - size_t size = sizeof(ObjectEntry) + serialClass->size; - - size = size + (alignment - 1) & ~(alignment - 1); - return size; - } - - default: - break; - } - - SLANG_ASSERT(!"Unknown type"); - return 0; -} - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SerialReader !!!!!!!!!!!!!!!!!!!!!!!!!!!! - -SerialReader::~SerialReader() -{ - for (const RefObject* obj : m_scope) - { - const_cast<RefObject*>(obj)->releaseReference(); - } -} - -const void* SerialReader::getArray(SerialIndex index, Index& outCount) -{ - if (index == SerialIndex(0)) - { - outCount = 0; - return nullptr; - } - - SLANG_ASSERT(SerialIndexRaw(index) < SerialIndexRaw(m_entries.getCount())); - const Entry* entry = m_entries[Index(index)]; - - switch (entry->typeKind) - { - case SerialTypeKind::Array: - { - auto arrayEntry = static_cast<const SerialInfo::ArrayEntry*>(entry); - outCount = Index(arrayEntry->elementCount); - return (arrayEntry + 1); - } - default: - break; - } - - SLANG_ASSERT(!"Not an array"); - outCount = 0; - return nullptr; -} - -SerialPointer SerialReader::getPointer(SerialIndex index) -{ - if (index == SerialIndex(0)) - { - return SerialPointer(); - } - - SLANG_ASSERT(SerialIndexRaw(index) < SerialIndexRaw(m_entries.getCount())); - const Entry* entry = m_entries[Index(index)]; - - const SerialPointer& ptr = m_objects[Index(index)]; - - switch (entry->typeKind) - { - case SerialTypeKind::String: - { - // Hmm. Tricky -> we don't know if will be cast as Name or String. Lets assume string. - String string = getString(index); - return SerialPointer(string.getStringRepresentation()); - } - case SerialTypeKind::ImportSymbol: - { - if (ptr.m_kind == SerialTypeKind::Unknown) - { - // TODO(JS): - // Could have an error here, because import symbol was not set - // For now just return nullptr - return SerialPointer(); - } - break; - } - default: - break; - } - - return ptr; -} - -SerialPointer SerialReader::getValPointer(SerialIndex index) -{ - if (index == SerialIndex(0)) - { - return SerialPointer(); - } - - SLANG_ASSERT(SerialIndexRaw(index) < SerialIndexRaw(m_entries.getCount())); - - SerialPointer& ptr = m_objects[Index(index)]; - - if (ptr.m_ptr) - return ptr; - - const SerialInfo::ValEntry* entry = (SerialInfo::ValEntry*)m_entries[Index(index)]; - ValNodeDesc desc; - desc.type = (ASTNodeType)entry->subType; - auto readPtr = (SerialInfo::SerialValOperand*)(entry + 1); - for (uint32_t i = 0; i < entry->operandCount; i++) - { - auto serialOperand = readPtr[i]; - ValNodeOperand operand; - operand.kind = (ValNodeOperandKind)(serialOperand.type); - switch (operand.kind) - { - case ValNodeOperandKind::ConstantValue: - operand.values.intOperand = serialOperand.payload; - break; - case ValNodeOperandKind::ASTNode: - operand.values.nodeOperand = - (NodeBase*)getPointer((SerialIndex)serialOperand.payload).m_ptr; - break; - case ValNodeOperandKind::ValNode: - operand.values.nodeOperand = - (Val*)getValPointer((SerialIndex)serialOperand.payload).m_ptr; - break; - } - desc.operands.add(operand); - } - desc.init(); - ptr.m_kind = SerialTypeKind::NodeBase; - ptr.m_ptr = this->m_objectFactory->getOrCreateVal(_Move(desc)); - return ptr; -} - -String SerialReader::getString(SerialIndex index) -{ - if (index == SerialIndex(0)) - { - return String(); - } - - SLANG_ASSERT(SerialIndexRaw(index) < SerialIndexRaw(m_entries.getCount())); - const Entry* entry = m_entries[Index(index)]; - - // It has to be a string type - if (entry->typeKind != SerialTypeKind::String) - { - SLANG_ASSERT(!"Not a string"); - return String(); - } - - RefObject* obj = m_objects[Index(index)].dynamicCast<RefObject>(); - - 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); - - StringRepresentation* stringRep = nullptr; - - const Index length = slice.getLength(); - if (length) - { - stringRep = StringRepresentation::createWithCapacityAndLength(length, length); - memcpy(stringRep->getData(), slice.begin(), length * sizeof(char)); - addScope(stringRep); - } - - m_objects[Index(index)] = stringRep; - return String(stringRep); -} - -Name* SerialReader::getName(SerialIndex index) -{ - if (index == SerialIndex(0)) - { - return nullptr; - } - - SLANG_ASSERT(SerialIndexRaw(index) < SerialIndexRaw(m_entries.getCount())); - const Entry* entry = m_entries[Index(index)]; - - // It has to be a string type - if (entry->typeKind != SerialTypeKind::String) - { - SLANG_ASSERT(!"Not a string"); - return nullptr; - } - - RefObject* obj = m_objects[Index(index)].dynamicCast<RefObject>(); - - 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 SerialReader::getStringSlice(SerialIndex index) -{ - SLANG_ASSERT(SerialIndexRaw(index) < SerialIndexRaw(m_entries.getCount())); - const Entry* entry = m_entries[Index(index)]; - - // It has to be a string type - if (entry->typeKind == SerialTypeKind::String || - entry->typeKind == SerialTypeKind::ImportSymbol) - { - auto stringEntry = static_cast<const SerialInfo::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); - } - - // Can't be accessed as a slice - SLANG_ASSERT(!"Not accessible as a slice"); - return UnownedStringSlice(); -} - -/* static */ SlangResult SerialReader::loadEntries( - const uint8_t* data, - size_t dataCount, - SerialClasses* serialClasses, - List<const 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) & (SerialInfo::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(serialClasses); - cur += entrySize; - - // Need to get the next alignment - const size_t nextAlignment = SerialInfo::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 SerialReader::constructObjects(NamePool* namePool) -{ - 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->typeKind) - { - case SerialTypeKind::ImportSymbol: - { - // We don't construct any object for an imported symbol. - // It will be the responsibility of external code to interpet the symbols and *set* - // the appopriate objects prior to a call to `deserializeObjects` - break; - } - case SerialTypeKind::String: - { - // Don't need to construct an object. This is probably a StringRepresentation, or a - // Name Will evaluate lazily. - break; - } - case SerialTypeKind::RefObject: - case SerialTypeKind::NodeBase: - { - auto objectEntry = static_cast<const SerialInfo::ObjectEntry*>(entry); - - // Don't create object for Vals. - if (objectEntry->typeKind == SerialTypeKind::NodeBase && - ReflectClassInfo::isSubClassOf(objectEntry->subType, Val::kReflectClassInfo)) - break; - - void* obj = m_objectFactory->create(objectEntry->typeKind, objectEntry->subType); - if (!obj) - { - return SLANG_FAIL; - } - m_objects[i].set(entry->typeKind, obj); - break; - } - case SerialTypeKind::Array: - { - // Don't need to construct an object, as will be accessed and interpreted by the - // object that holds it - break; - } - } - } - - return SLANG_OK; -} - -SlangResult SerialReader::deserializeObjects() -{ - // Deserialize - for (Index i = 1; i < m_entries.getCount(); ++i) - { - const Entry* entry = m_entries[i]; - // First see if there is anything to construct - SerialPointer& dstPtr = m_objects[i]; - if (!dstPtr) - { - continue; - } - switch (entry->typeKind) - { - case SerialTypeKind::NodeBase: - case SerialTypeKind::RefObject: - { - auto objectEntry = static_cast<const SerialInfo::ObjectEntry*>(entry); - auto serialClass = - m_classes->getSerialClass(objectEntry->typeKind, objectEntry->subType); - if (!serialClass) - { - return SLANG_FAIL; - } - if (ReflectClassInfo::isSubClassOf(objectEntry->subType, Val::kReflectClassInfo)) - continue; - - const uint8_t* src = (const uint8_t*)(objectEntry + 1); - uint8_t* dst = (uint8_t*)dstPtr.m_ptr; - - // 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); - } - - // Get the super class - serialClass = serialClass->super; - } - - break; - } - default: - break; - } - } - - return SLANG_OK; -} - - -SlangResult SerialReader::load(const uint8_t* data, size_t dataCount, NamePool* namePool) -{ - // Load and place entries into entries table - SLANG_RETURN_ON_FAIL(loadEntries(data, dataCount)); - // Construct all of the objects - SLANG_RETURN_ON_FAIL(constructObjects(namePool)); - SLANG_RETURN_ON_FAIL(deserializeObjects()); - return SLANG_OK; -} - } // namespace Slang |
