aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/BPF/BTFDebug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/BPF/BTFDebug.cpp')
-rw-r--r--lib/Target/BPF/BTFDebug.cpp281
1 files changed, 83 insertions, 198 deletions
diff --git a/lib/Target/BPF/BTFDebug.cpp b/lib/Target/BPF/BTFDebug.cpp
index fa35c6619e21..db551e739bd7 100644
--- a/lib/Target/BPF/BTFDebug.cpp
+++ b/lib/Target/BPF/BTFDebug.cpp
@@ -184,9 +184,7 @@ void BTFTypeEnum::emitType(MCStreamer &OS) {
}
}
-BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t ElemSize,
- uint32_t NumElems)
- : ElemSize(ElemSize) {
+BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems) {
Kind = BTF::BTF_KIND_ARRAY;
BTFType.NameOff = 0;
BTFType.Info = Kind << 24;
@@ -216,12 +214,6 @@ void BTFTypeArray::emitType(MCStreamer &OS) {
OS.EmitIntValue(ArrayInfo.Nelems, 4);
}
-void BTFTypeArray::getLocInfo(uint32_t Loc, uint32_t &LocOffset,
- uint32_t &ElementTypeId) {
- ElementTypeId = ArrayInfo.ElemType;
- LocOffset = Loc * ElemSize;
-}
-
/// Represent either a struct or a union.
BTFTypeStruct::BTFTypeStruct(const DICompositeType *STy, bool IsStruct,
bool HasBitField, uint32_t Vlen)
@@ -251,7 +243,8 @@ void BTFTypeStruct::completeType(BTFDebug &BDebug) {
} else {
BTFMember.Offset = DDTy->getOffsetInBits();
}
- BTFMember.Type = BDebug.getTypeId(DDTy->getBaseType());
+ const auto *BaseTy = DDTy->getBaseType();
+ BTFMember.Type = BDebug.getTypeId(BaseTy);
Members.push_back(BTFMember);
}
}
@@ -268,15 +261,6 @@ void BTFTypeStruct::emitType(MCStreamer &OS) {
std::string BTFTypeStruct::getName() { return STy->getName(); }
-void BTFTypeStruct::getMemberInfo(uint32_t Loc, uint32_t &MemberOffset,
- uint32_t &MemberType) {
- MemberType = Members[Loc].Type;
- MemberOffset =
- HasBitField ? Members[Loc].Offset & 0xffffff : Members[Loc].Offset;
-}
-
-uint32_t BTFTypeStruct::getStructSize() { return STy->getSizeInBits() >> 3; }
-
/// The Func kind represents both subprogram and pointee of function
/// pointers. If the FuncName is empty, it represents a pointee of function
/// pointer. Otherwise, it represents a subprogram. The func arg names
@@ -428,7 +412,7 @@ void BTFDebug::visitBasicType(const DIBasicType *BTy, uint32_t &TypeId) {
// Create a BTF type instance for this DIBasicType and put it into
// DIToIdMap for cross-type reference check.
- auto TypeEntry = llvm::make_unique<BTFTypeInt>(
+ auto TypeEntry = std::make_unique<BTFTypeInt>(
Encoding, BTy->getSizeInBits(), BTy->getOffsetInBits(), BTy->getName());
TypeId = addType(std::move(TypeEntry), BTy);
}
@@ -447,7 +431,7 @@ void BTFDebug::visitSubroutineType(
// a function pointer has an empty name. The subprogram type will
// not be added to DIToIdMap as it should not be referenced by
// any other types.
- auto TypeEntry = llvm::make_unique<BTFTypeFuncProto>(STy, VLen, FuncArgNames);
+ auto TypeEntry = std::make_unique<BTFTypeFuncProto>(STy, VLen, FuncArgNames);
if (ForSubprog)
TypeId = addType(std::move(TypeEntry)); // For subprogram
else
@@ -478,7 +462,7 @@ void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
}
auto TypeEntry =
- llvm::make_unique<BTFTypeStruct>(CTy, IsStruct, HasBitField, VLen);
+ std::make_unique<BTFTypeStruct>(CTy, IsStruct, HasBitField, VLen);
StructTypes.push_back(TypeEntry.get());
TypeId = addType(std::move(TypeEntry), CTy);
@@ -489,35 +473,29 @@ void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct,
void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
// Visit array element type.
- uint32_t ElemTypeId, ElemSize;
+ uint32_t ElemTypeId;
const DIType *ElemType = CTy->getBaseType();
visitTypeEntry(ElemType, ElemTypeId, false, false);
- ElemSize = ElemType->getSizeInBits() >> 3;
- if (!CTy->getSizeInBits()) {
- auto TypeEntry = llvm::make_unique<BTFTypeArray>(ElemTypeId, 0, 0);
- ArrayTypes.push_back(TypeEntry.get());
- ElemTypeId = addType(std::move(TypeEntry), CTy);
- } else {
- // Visit array dimensions.
- DINodeArray Elements = CTy->getElements();
- for (int I = Elements.size() - 1; I >= 0; --I) {
- if (auto *Element = dyn_cast_or_null<DINode>(Elements[I]))
- if (Element->getTag() == dwarf::DW_TAG_subrange_type) {
- const DISubrange *SR = cast<DISubrange>(Element);
- auto *CI = SR->getCount().dyn_cast<ConstantInt *>();
- int64_t Count = CI->getSExtValue();
-
- auto TypeEntry =
- llvm::make_unique<BTFTypeArray>(ElemTypeId, ElemSize, Count);
- ArrayTypes.push_back(TypeEntry.get());
- if (I == 0)
- ElemTypeId = addType(std::move(TypeEntry), CTy);
- else
- ElemTypeId = addType(std::move(TypeEntry));
- ElemSize = ElemSize * Count;
- }
- }
+ // Visit array dimensions.
+ DINodeArray Elements = CTy->getElements();
+ for (int I = Elements.size() - 1; I >= 0; --I) {
+ if (auto *Element = dyn_cast_or_null<DINode>(Elements[I]))
+ if (Element->getTag() == dwarf::DW_TAG_subrange_type) {
+ const DISubrange *SR = cast<DISubrange>(Element);
+ auto *CI = SR->getCount().dyn_cast<ConstantInt *>();
+ int64_t Count = CI->getSExtValue();
+
+ // For struct s { int b; char c[]; }, the c[] will be represented
+ // as an array with Count = -1.
+ auto TypeEntry =
+ std::make_unique<BTFTypeArray>(ElemTypeId,
+ Count >= 0 ? Count : 0);
+ if (I == 0)
+ ElemTypeId = addType(std::move(TypeEntry), CTy);
+ else
+ ElemTypeId = addType(std::move(TypeEntry));
+ }
}
// The array TypeId is the type id of the outermost dimension.
@@ -526,7 +504,7 @@ void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) {
// The IR does not have a type for array index while BTF wants one.
// So create an array index type if there is none.
if (!ArrayIndexTypeId) {
- auto TypeEntry = llvm::make_unique<BTFTypeInt>(dwarf::DW_ATE_unsigned, 32,
+ auto TypeEntry = std::make_unique<BTFTypeInt>(dwarf::DW_ATE_unsigned, 32,
0, "__ARRAY_SIZE_TYPE__");
ArrayIndexTypeId = addType(std::move(TypeEntry));
}
@@ -538,7 +516,7 @@ void BTFDebug::visitEnumType(const DICompositeType *CTy, uint32_t &TypeId) {
if (VLen > BTF::MAX_VLEN)
return;
- auto TypeEntry = llvm::make_unique<BTFTypeEnum>(CTy, VLen);
+ auto TypeEntry = std::make_unique<BTFTypeEnum>(CTy, VLen);
TypeId = addType(std::move(TypeEntry), CTy);
// No need to visit base type as BTF does not encode it.
}
@@ -546,7 +524,7 @@ void BTFDebug::visitEnumType(const DICompositeType *CTy, uint32_t &TypeId) {
/// Handle structure/union forward declarations.
void BTFDebug::visitFwdDeclType(const DICompositeType *CTy, bool IsUnion,
uint32_t &TypeId) {
- auto TypeEntry = llvm::make_unique<BTFTypeFwd>(CTy->getName(), IsUnion);
+ auto TypeEntry = std::make_unique<BTFTypeFwd>(CTy->getName(), IsUnion);
TypeId = addType(std::move(TypeEntry), CTy);
}
@@ -588,7 +566,7 @@ void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId,
/// Find a candidate, generate a fixup. Later on the struct/union
/// pointee type will be replaced with either a real type or
/// a forward declaration.
- auto TypeEntry = llvm::make_unique<BTFTypeDerived>(DTy, Tag, true);
+ auto TypeEntry = std::make_unique<BTFTypeDerived>(DTy, Tag, true);
auto &Fixup = FixupDerivedTypes[CTy->getName()];
Fixup.first = CTag == dwarf::DW_TAG_union_type;
Fixup.second.push_back(TypeEntry.get());
@@ -602,7 +580,7 @@ void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId,
if (Tag == dwarf::DW_TAG_pointer_type || Tag == dwarf::DW_TAG_typedef ||
Tag == dwarf::DW_TAG_const_type || Tag == dwarf::DW_TAG_volatile_type ||
Tag == dwarf::DW_TAG_restrict_type) {
- auto TypeEntry = llvm::make_unique<BTFTypeDerived>(DTy, Tag, false);
+ auto TypeEntry = std::make_unique<BTFTypeDerived>(DTy, Tag, false);
TypeId = addType(std::move(TypeEntry), DTy);
} else if (Tag != dwarf::DW_TAG_member) {
return;
@@ -669,7 +647,7 @@ void BTFDebug::visitMapDefType(const DIType *Ty, uint32_t &TypeId) {
}
auto TypeEntry =
- llvm::make_unique<BTFTypeStruct>(CTy, true, HasBitField, Elements.size());
+ std::make_unique<BTFTypeStruct>(CTy, true, HasBitField, Elements.size());
StructTypes.push_back(TypeEntry.get());
TypeId = addType(std::move(TypeEntry), CTy);
@@ -774,9 +752,10 @@ void BTFDebug::emitBTFSection() {
}
void BTFDebug::emitBTFExtSection() {
- // Do not emit section if empty FuncInfoTable and LineInfoTable.
+ // Do not emit section if empty FuncInfoTable and LineInfoTable
+ // and FieldRelocTable.
if (!FuncInfoTable.size() && !LineInfoTable.size() &&
- !OffsetRelocTable.size() && !ExternRelocTable.size())
+ !FieldRelocTable.size())
return;
MCContext &Ctx = OS.getContext();
@@ -788,8 +767,8 @@ void BTFDebug::emitBTFExtSection() {
// Account for FuncInfo/LineInfo record size as well.
uint32_t FuncLen = 4, LineLen = 4;
- // Do not account for optional OffsetReloc/ExternReloc.
- uint32_t OffsetRelocLen = 0, ExternRelocLen = 0;
+ // Do not account for optional FieldReloc.
+ uint32_t FieldRelocLen = 0;
for (const auto &FuncSec : FuncInfoTable) {
FuncLen += BTF::SecFuncInfoSize;
FuncLen += FuncSec.second.size() * BTF::BPFFuncInfoSize;
@@ -798,28 +777,20 @@ void BTFDebug::emitBTFExtSection() {
LineLen += BTF::SecLineInfoSize;
LineLen += LineSec.second.size() * BTF::BPFLineInfoSize;
}
- for (const auto &OffsetRelocSec : OffsetRelocTable) {
- OffsetRelocLen += BTF::SecOffsetRelocSize;
- OffsetRelocLen += OffsetRelocSec.second.size() * BTF::BPFOffsetRelocSize;
- }
- for (const auto &ExternRelocSec : ExternRelocTable) {
- ExternRelocLen += BTF::SecExternRelocSize;
- ExternRelocLen += ExternRelocSec.second.size() * BTF::BPFExternRelocSize;
+ for (const auto &FieldRelocSec : FieldRelocTable) {
+ FieldRelocLen += BTF::SecFieldRelocSize;
+ FieldRelocLen += FieldRelocSec.second.size() * BTF::BPFFieldRelocSize;
}
- if (OffsetRelocLen)
- OffsetRelocLen += 4;
- if (ExternRelocLen)
- ExternRelocLen += 4;
+ if (FieldRelocLen)
+ FieldRelocLen += 4;
OS.EmitIntValue(0, 4);
OS.EmitIntValue(FuncLen, 4);
OS.EmitIntValue(FuncLen, 4);
OS.EmitIntValue(LineLen, 4);
OS.EmitIntValue(FuncLen + LineLen, 4);
- OS.EmitIntValue(OffsetRelocLen, 4);
- OS.EmitIntValue(FuncLen + LineLen + OffsetRelocLen, 4);
- OS.EmitIntValue(ExternRelocLen, 4);
+ OS.EmitIntValue(FieldRelocLen, 4);
// Emit func_info table.
OS.AddComment("FuncInfo");
@@ -853,35 +824,20 @@ void BTFDebug::emitBTFExtSection() {
}
}
- // Emit offset reloc table.
- if (OffsetRelocLen) {
- OS.AddComment("OffsetReloc");
- OS.EmitIntValue(BTF::BPFOffsetRelocSize, 4);
- for (const auto &OffsetRelocSec : OffsetRelocTable) {
- OS.AddComment("Offset reloc section string offset=" +
- std::to_string(OffsetRelocSec.first));
- OS.EmitIntValue(OffsetRelocSec.first, 4);
- OS.EmitIntValue(OffsetRelocSec.second.size(), 4);
- for (const auto &OffsetRelocInfo : OffsetRelocSec.second) {
- Asm->EmitLabelReference(OffsetRelocInfo.Label, 4);
- OS.EmitIntValue(OffsetRelocInfo.TypeID, 4);
- OS.EmitIntValue(OffsetRelocInfo.OffsetNameOff, 4);
- }
- }
- }
-
- // Emit extern reloc table.
- if (ExternRelocLen) {
- OS.AddComment("ExternReloc");
- OS.EmitIntValue(BTF::BPFExternRelocSize, 4);
- for (const auto &ExternRelocSec : ExternRelocTable) {
- OS.AddComment("Extern reloc section string offset=" +
- std::to_string(ExternRelocSec.first));
- OS.EmitIntValue(ExternRelocSec.first, 4);
- OS.EmitIntValue(ExternRelocSec.second.size(), 4);
- for (const auto &ExternRelocInfo : ExternRelocSec.second) {
- Asm->EmitLabelReference(ExternRelocInfo.Label, 4);
- OS.EmitIntValue(ExternRelocInfo.ExternNameOff, 4);
+ // Emit field reloc table.
+ if (FieldRelocLen) {
+ OS.AddComment("FieldReloc");
+ OS.EmitIntValue(BTF::BPFFieldRelocSize, 4);
+ for (const auto &FieldRelocSec : FieldRelocTable) {
+ OS.AddComment("Field reloc section string offset=" +
+ std::to_string(FieldRelocSec.first));
+ OS.EmitIntValue(FieldRelocSec.first, 4);
+ OS.EmitIntValue(FieldRelocSec.second.size(), 4);
+ for (const auto &FieldRelocInfo : FieldRelocSec.second) {
+ Asm->EmitLabelReference(FieldRelocInfo.Label, 4);
+ OS.EmitIntValue(FieldRelocInfo.TypeID, 4);
+ OS.EmitIntValue(FieldRelocInfo.OffsetNameOff, 4);
+ OS.EmitIntValue(FieldRelocInfo.RelocKind, 4);
}
}
}
@@ -942,7 +898,7 @@ void BTFDebug::beginFunctionImpl(const MachineFunction *MF) {
// Construct subprogram func type
auto FuncTypeEntry =
- llvm::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId);
+ std::make_unique<BTFTypeFunc>(SP->getName(), ProtoTypeId);
uint32_t FuncTypeId = addType(std::move(FuncTypeEntry));
for (const auto &TypeEntry : TypeEntries)
@@ -980,71 +936,27 @@ unsigned BTFDebug::populateStructType(const DIType *Ty) {
return Id;
}
-// Find struct/array debuginfo types given a type id.
-void BTFDebug::setTypeFromId(uint32_t TypeId, BTFTypeStruct **PrevStructType,
- BTFTypeArray **PrevArrayType) {
- for (const auto &StructType : StructTypes) {
- if (StructType->getId() == TypeId) {
- *PrevStructType = StructType;
- return;
- }
- }
- for (const auto &ArrayType : ArrayTypes) {
- if (ArrayType->getId() == TypeId) {
- *PrevArrayType = ArrayType;
- return;
- }
- }
-}
-
-/// Generate a struct member offset relocation.
-void BTFDebug::generateOffsetReloc(const MachineInstr *MI,
+/// Generate a struct member field relocation.
+void BTFDebug::generateFieldReloc(const MachineInstr *MI,
const MCSymbol *ORSym, DIType *RootTy,
StringRef AccessPattern) {
- BTFTypeStruct *PrevStructType = nullptr;
- BTFTypeArray *PrevArrayType = nullptr;
unsigned RootId = populateStructType(RootTy);
- setTypeFromId(RootId, &PrevStructType, &PrevArrayType);
- unsigned RootTySize = PrevStructType->getStructSize();
-
- BTFOffsetReloc OffsetReloc;
- OffsetReloc.Label = ORSym;
- OffsetReloc.OffsetNameOff = addString(AccessPattern.drop_back());
- OffsetReloc.TypeID = RootId;
-
- uint32_t Start = 0, End = 0, Offset = 0;
- bool FirstAccess = true;
- for (auto C : AccessPattern) {
- if (C != ':') {
- End++;
- } else {
- std::string SubStr = AccessPattern.substr(Start, End - Start);
- int Loc = std::stoi(SubStr);
-
- if (FirstAccess) {
- Offset = Loc * RootTySize;
- FirstAccess = false;
- } else if (PrevStructType) {
- uint32_t MemberOffset, MemberTypeId;
- PrevStructType->getMemberInfo(Loc, MemberOffset, MemberTypeId);
-
- Offset += MemberOffset >> 3;
- PrevStructType = nullptr;
- setTypeFromId(MemberTypeId, &PrevStructType, &PrevArrayType);
- } else if (PrevArrayType) {
- uint32_t LocOffset, ElementTypeId;
- PrevArrayType->getLocInfo(Loc, LocOffset, ElementTypeId);
-
- Offset += LocOffset;
- PrevArrayType = nullptr;
- setTypeFromId(ElementTypeId, &PrevStructType, &PrevArrayType);
- }
- Start = End + 1;
- End = Start;
- }
- }
- AccessOffsets[RootTy->getName().str() + ":" + AccessPattern.str()] = Offset;
- OffsetRelocTable[SecNameOff].push_back(OffsetReloc);
+ size_t FirstDollar = AccessPattern.find_first_of('$');
+ size_t FirstColon = AccessPattern.find_first_of(':');
+ size_t SecondColon = AccessPattern.find_first_of(':', FirstColon + 1);
+ StringRef IndexPattern = AccessPattern.substr(FirstDollar + 1);
+ StringRef RelocKindStr = AccessPattern.substr(FirstColon + 1,
+ SecondColon - FirstColon);
+ StringRef PatchImmStr = AccessPattern.substr(SecondColon + 1,
+ FirstDollar - SecondColon);
+
+ BTFFieldReloc FieldReloc;
+ FieldReloc.Label = ORSym;
+ FieldReloc.OffsetNameOff = addString(IndexPattern);
+ FieldReloc.TypeID = RootId;
+ FieldReloc.RelocKind = std::stoull(RelocKindStr);
+ PatchImms[AccessPattern.str()] = std::stoul(PatchImmStr);
+ FieldRelocTable[SecNameOff].push_back(FieldReloc);
}
void BTFDebug::processLDimm64(const MachineInstr *MI) {
@@ -1052,7 +964,7 @@ void BTFDebug::processLDimm64(const MachineInstr *MI) {
// will generate an .BTF.ext record.
//
// If the insn is "r2 = LD_imm64 @__BTF_...",
- // add this insn into the .BTF.ext OffsetReloc subsection.
+ // add this insn into the .BTF.ext FieldReloc subsection.
// Relocation looks like:
// . SecName:
// . InstOffset
@@ -1083,16 +995,7 @@ void BTFDebug::processLDimm64(const MachineInstr *MI) {
MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index);
DIType *Ty = dyn_cast<DIType>(MDN);
- generateOffsetReloc(MI, ORSym, Ty, GVar->getName());
- } else if (GVar && !GVar->hasInitializer() && GVar->hasExternalLinkage() &&
- GVar->getSection() == BPFCoreSharedInfo::PatchableExtSecName) {
- MCSymbol *ORSym = OS.getContext().createTempSymbol();
- OS.EmitLabel(ORSym);
-
- BTFExternReloc ExternReloc;
- ExternReloc.Label = ORSym;
- ExternReloc.ExternNameOff = addString(GVar->getName());
- ExternRelocTable[SecNameOff].push_back(ExternReloc);
+ generateFieldReloc(MI, ORSym, Ty, GVar->getName());
}
}
}
@@ -1200,12 +1103,12 @@ void BTFDebug::processGlobals(bool ProcessingMapDef) {
? BTF::VAR_GLOBAL_ALLOCATED
: BTF::VAR_STATIC;
auto VarEntry =
- llvm::make_unique<BTFKindVar>(Global.getName(), GVTypeId, GVarInfo);
+ std::make_unique<BTFKindVar>(Global.getName(), GVTypeId, GVarInfo);
uint32_t VarId = addType(std::move(VarEntry));
// Find or create a DataSec
if (DataSecEntries.find(SecName) == DataSecEntries.end()) {
- DataSecEntries[SecName] = llvm::make_unique<BTFKindDataSec>(Asm, SecName);
+ DataSecEntries[SecName] = std::make_unique<BTFKindDataSec>(Asm, SecName);
}
// Calculate symbol size
@@ -1224,30 +1127,12 @@ bool BTFDebug::InstLower(const MachineInstr *MI, MCInst &OutMI) {
const GlobalValue *GVal = MO.getGlobal();
auto *GVar = dyn_cast<GlobalVariable>(GVal);
if (GVar && GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) {
- MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index);
- DIType *Ty = dyn_cast<DIType>(MDN);
- std::string TypeName = Ty->getName();
- int64_t Imm = AccessOffsets[TypeName + ":" + GVar->getName().str()];
-
- // Emit "mov ri, <imm>" for abstract member accesses.
+ // Emit "mov ri, <imm>" for patched immediate.
+ uint32_t Imm = PatchImms[GVar->getName().str()];
OutMI.setOpcode(BPF::MOV_ri);
OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
OutMI.addOperand(MCOperand::createImm(Imm));
return true;
- } else if (GVar && !GVar->hasInitializer() &&
- GVar->hasExternalLinkage() &&
- GVar->getSection() == BPFCoreSharedInfo::PatchableExtSecName) {
- const IntegerType *IntTy = dyn_cast<IntegerType>(GVar->getValueType());
- assert(IntTy);
- // For patchable externals, emit "LD_imm64, ri, 0" if the external
- // variable is 64bit width, emit "mov ri, 0" otherwise.
- if (IntTy->getBitWidth() == 64)
- OutMI.setOpcode(BPF::LD_imm64);
- else
- OutMI.setOpcode(BPF::MOV_ri);
- OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
- OutMI.addOperand(MCOperand::createImm(0));
- return true;
}
}
}
@@ -1281,7 +1166,7 @@ void BTFDebug::endModule() {
}
if (StructTypeId == 0) {
- auto FwdTypeEntry = llvm::make_unique<BTFTypeFwd>(TypeName, IsUnion);
+ auto FwdTypeEntry = std::make_unique<BTFTypeFwd>(TypeName, IsUnion);
StructTypeId = addType(std::move(FwdTypeEntry));
}