mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00
Appended fields
This commit is contained in:
parent
52544e6782
commit
1d2811f50d
22 changed files with 596 additions and 52 deletions
|
@ -149,6 +149,19 @@ namespace System
|
|||
public static void ExcludeThreadId(int thereadId) {}
|
||||
#endif
|
||||
|
||||
static void MarkAppendedObject(Object obj)
|
||||
{
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
ClassVData* maskedVData = (ClassVData*)(void*)(obj.[Friend]mClassVData & ~(int)0xFF);
|
||||
if (maskedVData == null)
|
||||
return;
|
||||
#else
|
||||
if (obj.mClassVData == null)
|
||||
return;
|
||||
#endif
|
||||
obj.[Friend]GCMarkMembers();
|
||||
}
|
||||
|
||||
static void MarkDerefedObject(Object* obj)
|
||||
{
|
||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||
|
|
|
@ -89,6 +89,8 @@ namespace System
|
|||
[CallingConvention(.Cdecl), NoReturn]
|
||||
public static extern void ThrowIndexOutOfRange(int stackOffset = 0);
|
||||
[CallingConvention(.Cdecl), NoReturn]
|
||||
public static extern void ThrowObjectNotInitialized(int stackOffset = 0);
|
||||
[CallingConvention(.Cdecl), NoReturn]
|
||||
public static extern void FatalError(String error, int stackOffset = 0);
|
||||
[Intrinsic("memcpy")]
|
||||
public static extern void MemCpy(void* dest, void* src, int length, int32 align = 1, bool isVolatile = false);
|
||||
|
|
|
@ -8,7 +8,8 @@ namespace System.Reflection
|
|||
public enum Error
|
||||
{
|
||||
InvalidTargetType,
|
||||
InvalidValueType
|
||||
InvalidValueType,
|
||||
AppendedField
|
||||
}
|
||||
|
||||
TypeInstance mTypeInstance;
|
||||
|
@ -24,6 +25,7 @@ namespace System.Reflection
|
|||
public int32 MemberOffset => (int32)mFieldData.mData;
|
||||
public Type FieldType => Type.[Friend]GetType(mFieldData.mFieldTypeId);
|
||||
public bool IsConst => mFieldData.mFlags.HasFlag(.Const);
|
||||
public bool IsAppended => mFieldData.mFlags.HasFlag(.Appended);
|
||||
public bool IsEnumCase => mFieldData.mFlags.HasFlag(.EnumCase);
|
||||
public bool IsReadOnly => mFieldData.mFlags.HasFlag(.ReadOnly);
|
||||
public bool IsStatic => mFieldData.mFlags.HasFlag(.Static);
|
||||
|
@ -86,7 +88,12 @@ namespace System.Reflection
|
|||
if (valueType == fieldType)
|
||||
{
|
||||
if (valueType.IsObject)
|
||||
{
|
||||
if (mFieldData.mFlags.HasFlag(.Appended))
|
||||
return .Err(.AppendedField);
|
||||
|
||||
*((void**)dataAddr) = Internal.UnsafeCastToPtr(value);
|
||||
}
|
||||
else
|
||||
Internal.MemCpy(dataAddr, valueDataAddr, fieldType.[Friend]mSize);
|
||||
}
|
||||
|
@ -385,7 +392,10 @@ namespace System.Reflection
|
|||
if (typeCode == TypeCode.Object)
|
||||
{
|
||||
value.[Friend]mStructType = 0;
|
||||
value.[Friend]mData = *(int*)targetDataAddr;
|
||||
if (mFieldData.mFlags.HasFlag(.Appended))
|
||||
value.[Friend]mData = (int)targetDataAddr;
|
||||
else
|
||||
value.[Friend]mData = *(int*)targetDataAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1480,6 +1480,7 @@ namespace System.Reflection
|
|||
EnumDiscriminator = 0x0200,
|
||||
EnumCase = 0x0400,
|
||||
ReadOnly = 0x0800,
|
||||
Appended = 0x1000,
|
||||
}
|
||||
|
||||
public enum MethodFlags : uint16
|
||||
|
|
|
@ -86,6 +86,7 @@ namespace bf
|
|||
BFRT_EXPORT static void ObjectDynCheck(Object* object, int typeId, bool allowNull);
|
||||
BFRT_EXPORT static void ObjectDynCheckFailed(Object* object, int typeId);
|
||||
BFRT_EXPORT static void ThrowIndexOutOfRange(intptr stackOffset);
|
||||
BFRT_EXPORT static void ThrowObjectNotInitialized(intptr stackOffset);
|
||||
BFRT_EXPORT static void FatalError(String* error, intptr stackOffset = 0);
|
||||
BFRT_EXPORT static void MemCpy(void* dest, void* src, intptr length);
|
||||
BFRT_EXPORT static void MemMove(void* dest, void* src, intptr length);
|
||||
|
@ -423,6 +424,30 @@ void Internal::ThrowIndexOutOfRange(intptr stackOffset)
|
|||
Internal_FatalError("Index out of range");
|
||||
}
|
||||
|
||||
void Internal::ThrowObjectNotInitialized(intptr stackOffset)
|
||||
{
|
||||
if (gClientPipe != NULL)
|
||||
{
|
||||
if (gTestBreakOnFailure)
|
||||
{
|
||||
SETUP_ERROR("Object not initialized", (int)(2 + stackOffset));
|
||||
BF_DEBUG_BREAK();
|
||||
}
|
||||
|
||||
Beefy::String str = ":TestFail\tObject not initialized\n";
|
||||
TestString(str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((stackOffset != -1) && (::IsDebuggerPresent()))
|
||||
{
|
||||
SETUP_ERROR("Object not initialized", (int)(2 + stackOffset));
|
||||
BF_DEBUG_BREAK();
|
||||
}
|
||||
|
||||
Internal_FatalError("Object not initialized");
|
||||
}
|
||||
|
||||
void Internal::FatalError(bf::System::String* error, intptr stackOffset)
|
||||
{
|
||||
if (gClientPipe != NULL)
|
||||
|
|
|
@ -4942,6 +4942,10 @@ namespace IDE.ui
|
|||
menuItem.SetDisabled(!isPaused);
|
||||
menuItem.mOnMenuItemSelected.Add(new (evt) => IDEApp.sApp.ShowDisassemblyAtCursor());
|
||||
|
||||
menuItem = menu.AddItem("Set Next Statement");
|
||||
menuItem.SetDisabled(!isPaused);
|
||||
menuItem.mOnMenuItemSelected.Add(new (evt) => IDEApp.sApp.[Friend]SetNextStatement());
|
||||
|
||||
var stepIntoSpecificMenu = menu.AddItem("Step into Specific");
|
||||
stepIntoSpecificMenu.SetDisabled(!isPaused);
|
||||
stepIntoSpecificMenu.IsParent = true;
|
||||
|
|
|
@ -3169,7 +3169,7 @@ public:
|
|||
BfAstNode* mConstSpecifier; // Could be 'const' or 'using'
|
||||
BfTokenNode* mVolatileSpecifier;
|
||||
BfTokenNode* mNewSpecifier;
|
||||
BfTokenNode* mExternSpecifier;
|
||||
BfTokenNode* mExternSpecifier; // Could be 'extern' or 'append'
|
||||
BfTypeReference* mTypeRef;
|
||||
BfIdentifierNode* mNameNode;
|
||||
BfTokenNode* mEqualsNode;
|
||||
|
|
|
@ -1741,7 +1741,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress
|
|||
{
|
||||
const char* tokens [] =
|
||||
{
|
||||
"alignof", "as", "asm", "base", "break", "case", "catch", "checked", "continue", "const", "default", "defer",
|
||||
"alignof", "append", "as", "asm", "base", "break", "case", "catch", "checked", "continue", "const", "default", "defer",
|
||||
"delegate", "delete", "do", "else", "false", "finally",
|
||||
"fixed", "for", "function", "if", "implicit", "in", "internal", "is", "isconst", "new", "mixin", "null",
|
||||
"offsetof", "out", "params", "readonly", "ref", "rettype", "return",
|
||||
|
@ -1762,7 +1762,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress
|
|||
{
|
||||
const char* tokens[] =
|
||||
{
|
||||
"abstract", "base", "class", "const",
|
||||
"abstract", "append", "base", "class", "const",
|
||||
"delegate", "extern", "enum", "explicit", "extension", "function",
|
||||
"interface", "in", "implicit", "internal", "mixin", "namespace", "new",
|
||||
"operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "rettype", "return",
|
||||
|
|
|
@ -1184,7 +1184,8 @@ void BfDefBuilder::Visit(BfFieldDeclaration* fieldDeclaration)
|
|||
fieldDef->mProtection = BfProtection_Public;
|
||||
fieldDef->mIsReadOnly = fieldDeclaration->mReadOnlySpecifier != NULL;
|
||||
fieldDef->mIsInline = (fieldDeclaration->mReadOnlySpecifier != NULL) && (fieldDeclaration->mReadOnlySpecifier->GetToken() == BfToken_Inline);
|
||||
fieldDef->mIsExtern = (fieldDeclaration->mExternSpecifier != NULL);
|
||||
fieldDef->mIsExtern = (fieldDeclaration->mExternSpecifier != NULL) && (fieldDeclaration->mExternSpecifier->mToken == BfToken_Extern);
|
||||
fieldDef->mIsAppend = (fieldDeclaration->mExternSpecifier != NULL) && (fieldDeclaration->mExternSpecifier->mToken == BfToken_Append);
|
||||
auto constSpecifierToken = BfNodeDynCast<BfTokenNode>(fieldDeclaration->mConstSpecifier);
|
||||
fieldDef->mIsConst = ((constSpecifierToken != NULL) && (constSpecifierToken->mToken == BfToken_Const)) || (isEnumEntryDecl);
|
||||
if (auto usingSpecifier = BfNodeDynCast<BfUsingSpecifierNode>(fieldDeclaration->mConstSpecifier))
|
||||
|
@ -2197,6 +2198,11 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
|
|||
}
|
||||
if (field->GetFieldDeclaration()->mFieldDtor != NULL)
|
||||
needsStaticDtor = true;
|
||||
if (field->mIsAppend)
|
||||
{
|
||||
needsStaticInit = true;
|
||||
needsStaticDtor = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2222,6 +2228,11 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
|
|||
hasNonStaticField = true;
|
||||
if (field->GetInitializer() != NULL)
|
||||
needsDefaultCtor = true;
|
||||
if (field->mIsAppend)
|
||||
{
|
||||
needsDefaultCtor = true;
|
||||
needsDtor = true;
|
||||
}
|
||||
if (auto fieldDecl = field->GetFieldDeclaration())
|
||||
{
|
||||
if (fieldDecl->mFieldDtor != NULL)
|
||||
|
|
|
@ -5008,6 +5008,42 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe
|
|||
bool isStaticCtor = (mModule->mCurMethodInstance != NULL) &&
|
||||
(mModule->mCurMethodInstance->mMethodDef->IsCtorOrInit()) &&
|
||||
(mModule->mCurMethodInstance->mMethodDef->mIsStatic);
|
||||
|
||||
if ((mModule->mCompiler->mOptions.mRuntimeChecks) && (fieldInstance->IsAppendedObject()) && (!mModule->mBfIRBuilder->mIgnoreWrites) &&
|
||||
(!mModule->IsSkippingExtraResolveChecks()))
|
||||
{
|
||||
auto intType = mModule->GetPrimitiveType(BfTypeCode_IntPtr);
|
||||
auto intPtrType = mModule->CreatePointerType(intType);
|
||||
auto intPtrVal = mModule->mBfIRBuilder->CreateBitCast(retVal.mValue, mModule->mBfIRBuilder->MapType(intPtrType));
|
||||
auto intVal = mModule->mBfIRBuilder->CreateLoad(intPtrVal);
|
||||
|
||||
auto oobBlock = mModule->mBfIRBuilder->CreateBlock("oob", true);
|
||||
auto contBlock = mModule->mBfIRBuilder->CreateBlock("cont", true);
|
||||
|
||||
auto cmpRes = mModule->mBfIRBuilder->CreateCmpEQ(intVal, mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0));
|
||||
mModule->mBfIRBuilder->CreateCondBr(cmpRes, oobBlock, contBlock);
|
||||
|
||||
mModule->mBfIRBuilder->SetInsertPoint(oobBlock);
|
||||
auto internalType = mModule->ResolveTypeDef(mModule->mCompiler->mInternalTypeDef);
|
||||
auto oobFunc = mModule->GetMethodByName(internalType->ToTypeInstance(), "ThrowObjectNotInitialized");
|
||||
if (oobFunc.mFunc)
|
||||
{
|
||||
if (mModule->mIsComptimeModule)
|
||||
mModule->mCompiler->mCeMachine->QueueMethod(oobFunc.mMethodInstance, oobFunc.mFunc);
|
||||
|
||||
SizedArray<BfIRValue, 1> args;
|
||||
args.push_back(mModule->GetConstValue(0));
|
||||
mModule->mBfIRBuilder->CreateCall(oobFunc.mFunc, args);
|
||||
mModule->mBfIRBuilder->CreateUnreachable();
|
||||
}
|
||||
else
|
||||
{
|
||||
mModule->Fail("System.Internal class must contain method 'ThrowObjectNotInitialized'", fieldDef->GetRefNode());
|
||||
}
|
||||
|
||||
mModule->mBfIRBuilder->SetInsertPoint(contBlock);
|
||||
}
|
||||
|
||||
if ((fieldDef->mIsReadOnly) && (!isStaticCtor))
|
||||
{
|
||||
if (retVal.IsAddr())
|
||||
|
@ -5135,8 +5171,16 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe
|
|||
if ((targetValue.IsAddr()) && (!typeInstance->IsValueType()))
|
||||
targetValue = mModule->LoadValue(targetValue);
|
||||
|
||||
retVal = BfTypedValue(mModule->mBfIRBuilder->CreateInBoundsGEP(targetValue.mValue, 0, fieldInstance->mDataIdx/*, fieldDef->mName*/),
|
||||
resolvedFieldType, target.IsReadOnly() ? BfTypedValueKind_ReadOnlyAddr : BfTypedValueKind_Addr);
|
||||
if (fieldInstance->IsAppendedObject())
|
||||
{
|
||||
auto elemPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(targetValue.mValue, 0, fieldInstance->mDataIdx);
|
||||
retVal = BfTypedValue(mModule->mBfIRBuilder->CreateBitCast(elemPtr, mModule->mBfIRBuilder->MapType(resolvedFieldType)), resolvedFieldType);
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = BfTypedValue(mModule->mBfIRBuilder->CreateInBoundsGEP(targetValue.mValue, 0, fieldInstance->mDataIdx/*, fieldDef->mName*/),
|
||||
resolvedFieldType, target.IsReadOnly() ? BfTypedValueKind_ReadOnlyAddr : BfTypedValueKind_Addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!retVal.IsSplat())
|
||||
|
@ -9649,15 +9693,24 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
|
||||
if (resolvedTypeInstance != NULL)
|
||||
{
|
||||
if ((!resolvedTypeInstance->IsStruct()) && (!resolvedTypeInstance->IsTypedPrimitive()))
|
||||
if ((mBfEvalExprFlags & BfEvalExprFlags_AppendFieldInitializer) == 0)
|
||||
{
|
||||
if (mModule->PreFail())
|
||||
mModule->Fail("Objects must be allocated through 'new' or 'scope'", targetSrc);
|
||||
return BfTypedValue();
|
||||
if ((!resolvedTypeInstance->IsStruct()) && (!resolvedTypeInstance->IsTypedPrimitive()))
|
||||
{
|
||||
if (mModule->PreFail())
|
||||
mModule->Fail("Objects must be allocated through 'new' or 'scope'", targetSrc);
|
||||
return BfTypedValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (auto identifier = BfNodeDynCastExact<BfIdentifierNode>(targetSrc))
|
||||
mModule->SetElementType(identifier, resolvedTypeInstance->IsEnum() ? BfSourceElementType_Type : BfSourceElementType_Struct);
|
||||
{
|
||||
auto elementType = resolvedTypeInstance->IsEnum() ? BfSourceElementType_Type : BfSourceElementType_Struct;
|
||||
if (resolvedTypeInstance->IsObject())
|
||||
elementType = BfSourceElementType_RefType;
|
||||
mModule->SetElementType(identifier, elementType);
|
||||
}
|
||||
|
||||
if (mModule->mCompiler->mResolvePassData != NULL)
|
||||
{
|
||||
if (!BfNodeIsA<BfMemberReferenceExpression>(targetSrc))
|
||||
|
@ -9688,7 +9741,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
mResultLocalVar = NULL;
|
||||
mResultFieldInstance = NULL;
|
||||
mResultLocalVarRefNode = NULL;
|
||||
auto result = MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, false);
|
||||
auto result = MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, resolvedTypeInstance->IsObject());
|
||||
if ((result) && (!result.mType->IsVoid()))
|
||||
return result;
|
||||
mModule->ValidateAllocation(resolvedTypeInstance, targetSrc);
|
||||
|
@ -17599,7 +17652,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
|
|||
{
|
||||
// Allow
|
||||
}
|
||||
else
|
||||
else if ((mBfEvalExprFlags & BfEvalExprFlags_AppendFieldInitializer) == 0)
|
||||
{
|
||||
gaveUnqualifiedDotError = true;
|
||||
if (mModule->PreFail())
|
||||
|
@ -21419,11 +21472,6 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
|
|||
auto oobFunc = mModule->GetMethodByName(internalType->ToTypeInstance(), "ThrowIndexOutOfRange");
|
||||
if (oobFunc.mFunc)
|
||||
{
|
||||
/*if (!mModule->mCompiler->mIsResolveOnly)
|
||||
{
|
||||
OutputDebugStrF("-OOB %d %d\n", oobFunc.mFunc.mId, oobFunc.mFunc.mFlags);
|
||||
}*/
|
||||
|
||||
if (mModule->mIsComptimeModule)
|
||||
mModule->mCompiler->mCeMachine->QueueMethod(oobFunc.mMethodInstance, oobFunc.mFunc);
|
||||
|
||||
|
@ -21431,13 +21479,13 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
|
|||
args.push_back(mModule->GetConstValue(0));
|
||||
mModule->mBfIRBuilder->CreateCall(oobFunc.mFunc, args);
|
||||
mModule->mBfIRBuilder->CreateUnreachable();
|
||||
|
||||
mModule->mBfIRBuilder->SetInsertPoint(contBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
mModule->Fail("System.Internal class must contain method 'ThrowIndexOutOfRange'");
|
||||
}
|
||||
|
||||
mModule->mBfIRBuilder->SetInsertPoint(contBlock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3203,6 +3203,9 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type)
|
|||
PopulateType(resolvedFieldType, BfIRPopulateType_Eventually_Full);
|
||||
resolvedFieldDIType = DbgGetType(resolvedFieldType);
|
||||
|
||||
if (fieldInstance->IsAppendedObject())
|
||||
resolvedFieldDIType = DbgGetTypeInst(resolvedFieldType->ToTypeInstance());
|
||||
|
||||
if ((fieldDef == NULL) && (typeInstance->IsPayloadEnum()))
|
||||
{
|
||||
orderedFields.push_back(fieldInstance);
|
||||
|
@ -3409,7 +3412,7 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type)
|
|||
if (fieldDef->mHasMultiDefs)
|
||||
fieldName += "$" + fieldDef->mDeclaringType->mProject->mName;
|
||||
auto memberType = DbgCreateMemberType(diForwardDecl, fieldName, fileDIScope, lineNum,
|
||||
resolvedFieldType->mSize * 8, resolvedFieldType->mAlign * 8, fieldInstance->mDataOffset * 8,
|
||||
fieldInstance->mDataSize * 8, resolvedFieldType->mAlign * 8, fieldInstance->mDataOffset * 8,
|
||||
flags, resolvedFieldDIType);
|
||||
diFieldTypes.push_back(memberType);
|
||||
}
|
||||
|
@ -3712,6 +3715,9 @@ void BfIRBuilder::CreateTypeDefinition_Data(BfModule* populateModule, BfTypeInst
|
|||
if ((fieldDef != NULL) && (resolvedFieldType->IsStruct()))
|
||||
PopulateType(resolvedFieldType, BfIRPopulateType_Eventually_Full);
|
||||
|
||||
if (fieldInstance->IsAppendedObject())
|
||||
PopulateType(resolvedFieldType, BfIRPopulateType_Eventually_Full);
|
||||
|
||||
if ((fieldDef == NULL) && (typeInstance->IsPayloadEnum()))
|
||||
{
|
||||
orderedFields.push_back(fieldInstance);
|
||||
|
@ -3761,10 +3767,27 @@ void BfIRBuilder::CreateTypeDefinition_Data(BfModule* populateModule, BfTypeInst
|
|||
if (fieldInstance == NULL)
|
||||
continue;
|
||||
|
||||
auto fieldDef = fieldInstance->GetFieldDef();
|
||||
|
||||
auto resolvedFieldType = fieldInstance->GetResolvedType();
|
||||
|
||||
BfIRType resolvedFieldIRType = MapType(resolvedFieldType);
|
||||
|
||||
if (fieldInstance->IsAppendedObject())
|
||||
{
|
||||
auto fieldTypeInst = fieldInstance->mResolvedType->ToTypeInstance();
|
||||
|
||||
if (fieldInstance->mDataSize != fieldTypeInst->mInstSize)
|
||||
{
|
||||
SizedArray<BfIRType, 2> types;
|
||||
types.push_back(MapTypeInst(fieldTypeInst));
|
||||
types.push_back(GetSizedArrayType(GetPrimitiveType(BfTypeCode_Int8), fieldInstance->mDataSize - fieldTypeInst->mInstSize));
|
||||
resolvedFieldIRType = CreateStructType(types);
|
||||
}
|
||||
else
|
||||
resolvedFieldIRType = MapTypeInst(fieldTypeInst);
|
||||
}
|
||||
|
||||
if (fieldInstance->mDataOffset > dataPos)
|
||||
{
|
||||
int fillSize = fieldInstance->mDataOffset - dataPos;
|
||||
|
|
|
@ -4048,8 +4048,18 @@ void BfModule::CreateStaticField(BfFieldInstance* fieldInstance, bool isThreadLo
|
|||
BfMangler::Mangle(staticVarName, mCompiler->GetMangleKind(), fieldInstance);
|
||||
if ((!fieldType->IsValuelessType()) && (!staticVarName.StartsWith("#")))
|
||||
{
|
||||
BfIRType irType;
|
||||
|
||||
if (fieldInstance->IsAppendedObject())
|
||||
{
|
||||
irType = mBfIRBuilder->MapTypeInst(fieldType->ToTypeInstance(), BfIRPopulateType_Eventually_Full);
|
||||
initValue = mBfIRBuilder->CreateConstAggZero(irType);
|
||||
}
|
||||
else
|
||||
irType = mBfIRBuilder->MapType(fieldType, BfIRPopulateType_Eventually_Full);
|
||||
|
||||
BfIRValue globalVar = mBfIRBuilder->CreateGlobalVariable(
|
||||
mBfIRBuilder->MapType(fieldType, BfIRPopulateType_Eventually_Full),
|
||||
irType,
|
||||
false,
|
||||
BfIRLinkageType_External,
|
||||
initValue,
|
||||
|
@ -4551,6 +4561,83 @@ BfTypedValue BfModule::GetFieldInitializerValue(BfFieldInstance* fieldInstance,
|
|||
return result;
|
||||
}
|
||||
|
||||
void BfModule::AppendedObjectInit(BfFieldInstance* fieldInst)
|
||||
{
|
||||
BfExprEvaluator exprEvaluator(this);
|
||||
|
||||
bool failed = false;
|
||||
|
||||
auto fieldDef = fieldInst->GetFieldDef();
|
||||
auto initializer = fieldDef->GetInitializer();
|
||||
|
||||
BfResolvedArgs resolvedArgs;
|
||||
if (auto invocationExpr = BfNodeDynCast<BfInvocationExpression>(initializer))
|
||||
{
|
||||
bool isDot = false;
|
||||
|
||||
if (auto memberRefExpr = BfNodeDynCast<BfMemberReferenceExpression>(invocationExpr->mTarget))
|
||||
isDot = (memberRefExpr->mTarget == NULL) && (memberRefExpr->mMemberName == NULL);
|
||||
|
||||
if (!isDot)
|
||||
{
|
||||
auto resolvedType = ResolveTypeRef(invocationExpr->mTarget, {});
|
||||
if ((resolvedType == NULL) || (resolvedType != fieldInst->mResolvedType))
|
||||
failed = true;
|
||||
}
|
||||
|
||||
SetAndRestoreValue<BfType*> prevExpectingType(exprEvaluator.mExpectingType, fieldInst->mResolvedType);
|
||||
|
||||
resolvedArgs.Init(invocationExpr->mOpenParen, &invocationExpr->mArguments, &invocationExpr->mCommas, invocationExpr->mCloseParen);
|
||||
exprEvaluator.ResolveArgValues(resolvedArgs, BfResolveArgsFlag_DeferParamEval);
|
||||
}
|
||||
else if (initializer != NULL)
|
||||
{
|
||||
GetFieldInitializerValue(fieldInst);
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (failed)
|
||||
Fail("Append fields can only be initialized with a call to their constructor", initializer);
|
||||
|
||||
auto intType = GetPrimitiveType(BfTypeCode_IntPtr);
|
||||
auto int8Type = mBfIRBuilder->GetPrimitiveType(BfTypeCode_Int8);
|
||||
auto ptrType = mBfIRBuilder->GetPointerTo(int8Type);
|
||||
auto ptrPtrType = mBfIRBuilder->GetPointerTo(ptrType);
|
||||
|
||||
|
||||
BfIRValue fieldAddr;
|
||||
if (fieldDef->mIsStatic)
|
||||
{
|
||||
fieldAddr = ReferenceStaticField(fieldInst).mValue;
|
||||
}
|
||||
else
|
||||
fieldAddr = mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[0]->mValue, 0, fieldInst->mDataIdx);
|
||||
auto thisValue = BfTypedValue(mBfIRBuilder->CreateBitCast(fieldAddr, mBfIRBuilder->MapType(fieldInst->mResolvedType)), fieldInst->mResolvedType);
|
||||
|
||||
auto indexVal = BfTypedValue(CreateAlloca(intType), CreateRefType(intType));
|
||||
auto intThisVal = mBfIRBuilder->CreatePtrToInt(thisValue.mValue, (intType->mSize == 4) ? BfTypeCode_Int32 : BfTypeCode_Int64);
|
||||
mBfIRBuilder->CreateStore(intThisVal, indexVal.mValue);
|
||||
|
||||
auto ctorResult = exprEvaluator.MatchConstructor(fieldDef->GetNameNode(), NULL, thisValue, fieldInst->mResolvedType->ToTypeInstance(), resolvedArgs, false, true, &indexVal);
|
||||
|
||||
auto vObjectAddr = mBfIRBuilder->CreateInBoundsGEP(thisValue.mValue, 0, 0);
|
||||
|
||||
auto vDataRef = CreateClassVDataGlobal(fieldInst->mResolvedType->ToTypeInstance());
|
||||
|
||||
auto destAddr = mBfIRBuilder->CreateBitCast(vObjectAddr, ptrPtrType);
|
||||
auto srcVal = mBfIRBuilder->CreateBitCast(vDataRef, ptrType);
|
||||
mBfIRBuilder->CreateStore(srcVal, destAddr);
|
||||
|
||||
if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsComptimeModule))
|
||||
{
|
||||
auto int8Type = mBfIRBuilder->GetPrimitiveType(BfTypeCode_Int8);
|
||||
auto ptrType = mBfIRBuilder->GetPointerTo(int8Type);
|
||||
|
||||
auto thisFlagsPtr = mBfIRBuilder->CreateBitCast(thisValue.mValue, ptrType);
|
||||
mBfIRBuilder->CreateStore(GetConstValue8(BfObjectFlag_AppendAlloc), thisFlagsPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void BfModule::CheckInterfaceMethod(BfMethodInstance* methodInstance)
|
||||
{
|
||||
|
||||
|
@ -5571,6 +5658,8 @@ BfIRValue BfModule::CreateFieldData(BfFieldInstance* fieldInstance, int customAt
|
|||
fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_EnumCase);
|
||||
if (fieldDef->mIsReadOnly)
|
||||
fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_ReadOnly);
|
||||
if (fieldInstance->IsAppendedObject())
|
||||
fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_Appended);
|
||||
|
||||
BfIRValue constValue;
|
||||
BfIRValue constValue2;
|
||||
|
@ -5608,8 +5697,13 @@ BfIRValue BfModule::CreateFieldData(BfFieldInstance* fieldInstance, int customAt
|
|||
}
|
||||
}
|
||||
|
||||
if ((refVal.IsAddr()) && (!isComptimeArg))
|
||||
constValue = mBfIRBuilder->CreatePtrToInt(refVal.mValue, BfTypeCode_IntPtr);
|
||||
if (!isComptimeArg)
|
||||
{
|
||||
if (refVal.IsAddr())
|
||||
constValue = mBfIRBuilder->CreatePtrToInt(refVal.mValue, BfTypeCode_IntPtr);
|
||||
else if (fieldInstance->IsAppendedObject())
|
||||
constValue = mBfIRBuilder->CreatePtrToInt(refVal.mValue, BfTypeCode_IntPtr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!constValue)
|
||||
|
@ -11240,7 +11334,7 @@ StringT<128> BfModule::MethodToString(BfMethodInstance* methodInst, BfMethodName
|
|||
for (int paramIdx = 0; paramIdx < (int)methodInst->GetParamCount(); paramIdx++)
|
||||
{
|
||||
int paramKind = methodInst->GetParamKind(paramIdx);
|
||||
if (paramKind == BfParamKind_ImplicitCapture)
|
||||
if ((paramKind == BfParamKind_ImplicitCapture) || (paramKind == BfParamKind_AppendIdx))
|
||||
continue;
|
||||
|
||||
if (dispParamIdx > 0)
|
||||
|
@ -14799,6 +14893,9 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
|
|||
{
|
||||
BfIRType irType = mBfIRBuilder->MapType(typeType);
|
||||
|
||||
if (fieldInstance->IsAppendedObject())
|
||||
irType = mBfIRBuilder->MapTypeInst(typeType->ToTypeInstance());
|
||||
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mBfIRBuilder->mIgnoreWrites || staticVarName.StartsWith('#'));
|
||||
|
||||
globalValue = mBfIRBuilder->CreateGlobalVariable(
|
||||
|
@ -14822,7 +14919,7 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
|
|||
|
||||
if (fieldDef->mIsVolatile)
|
||||
return BfTypedValue(globalValue, type, BfTypedValueKind_VolatileAddr);
|
||||
return BfTypedValue(globalValue, type, !fieldDef->mIsConst);
|
||||
return BfTypedValue(globalValue, type, !fieldDef->mIsConst && !fieldInstance->IsAppendedObject());
|
||||
}
|
||||
|
||||
BfFieldInstance* BfModule::GetFieldInstance(BfTypeInstance* typeInst, int fieldIdx, const char* fieldName)
|
||||
|
@ -16381,13 +16478,13 @@ void BfModule::CalcAppendAlign(BfMethodInstance* methodInst)
|
|||
methodInst->mAppendAllocAlign = 1;
|
||||
}
|
||||
|
||||
BfTypedValue BfModule::TryConstCalcAppend(BfMethodInstance* methodInst, SizedArrayImpl<BfIRValue>& args)
|
||||
BfTypedValue BfModule::TryConstCalcAppend(BfMethodInstance* methodInst, SizedArrayImpl<BfIRValue>& args, bool force)
|
||||
{
|
||||
BP_ZONE("BfModule::TryConstCalcAppend");
|
||||
|
||||
BF_ASSERT(methodInst->mMethodDef->mMethodType == BfMethodType_CtorCalcAppend);
|
||||
|
||||
if ((mCompiler->mIsResolveOnly) && (!mIsComptimeModule))
|
||||
if ((mCompiler->mIsResolveOnly) && (!mIsComptimeModule) && (!force))
|
||||
return BfTypedValue();
|
||||
|
||||
// We want to regenerate all ctor calls when the method internals change
|
||||
|
@ -16476,6 +16573,7 @@ BfTypedValue BfModule::TryConstCalcAppend(BfMethodInstance* methodInst, SizedArr
|
|||
BfConstResolveState constResolveState;
|
||||
constResolveState.mMethodInstance = methodInst;
|
||||
constResolveState.mPrevConstResolveState = mCurMethodState->mConstResolveState;
|
||||
constResolveState.mInCalcAppend = true;
|
||||
|
||||
SetAndRestoreValue<bool> ignoreWrites(mBfIRBuilder->mIgnoreWrites, true);
|
||||
BfMethodState methodState;
|
||||
|
@ -16630,7 +16728,7 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly)
|
|||
BF_ASSERT(bindResult.mIRArgs[0].IsFake());
|
||||
bindResult.mIRArgs.RemoveAt(0);
|
||||
auto calcAppendMethodModule = GetMethodInstanceAtIdx(bindResult.mMethodInstance->GetOwner(), bindResult.mMethodInstance->mMethodDef->mIdx + 1, BF_METHODNAME_CALCAPPEND);
|
||||
BfTypedValue appendSizeTypedValue = TryConstCalcAppend(calcAppendMethodModule.mMethodInstance, bindResult.mIRArgs);
|
||||
BfTypedValue appendSizeTypedValue = TryConstCalcAppend(calcAppendMethodModule.mMethodInstance, bindResult.mIRArgs, true);
|
||||
BF_ASSERT(calcAppendMethodModule.mMethodInstance->mAppendAllocAlign >= 0);
|
||||
mCurMethodInstance->mAppendAllocAlign = BF_MAX((int)mCurMethodInstance->mAppendAllocAlign, calcAppendMethodModule.mMethodInstance->mAppendAllocAlign);
|
||||
BF_ASSERT(calcAppendMethodModule.mMethodInstance->mEndingAppendAllocAlign > -1);
|
||||
|
@ -16757,7 +16855,10 @@ void BfModule::CreateStaticCtor()
|
|||
{
|
||||
continue;
|
||||
}
|
||||
GetFieldInitializerValue(fieldInst, NULL, NULL, NULL, true);
|
||||
if (fieldInst->IsAppendedObject())
|
||||
AppendedObjectInit(fieldInst);
|
||||
else
|
||||
GetFieldInitializerValue(fieldInst, NULL, NULL, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16789,7 +16890,12 @@ void BfModule::CreateStaticCtor()
|
|||
{
|
||||
wantType = ResolveTypeRef(fieldDef->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowInferredSizedArray);
|
||||
}
|
||||
CreateValueFromExpression(fieldDef->GetInitializer(), wantType, BfEvalExprFlags_FieldInitializer);
|
||||
|
||||
BfEvalExprFlags exprFlags = BfEvalExprFlags_FieldInitializer;
|
||||
if (fieldDef->mIsAppend)
|
||||
exprFlags = (BfEvalExprFlags)(exprFlags | BfEvalExprFlags_AppendFieldInitializer);
|
||||
|
||||
CreateValueFromExpression(fieldDef->GetInitializer(), wantType, exprFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16876,6 +16982,66 @@ void BfModule::EmitDtorBody()
|
|||
if (fieldDef != NULL)
|
||||
fieldDecl = fieldDef->GetFieldDeclaration();
|
||||
|
||||
if ((fieldDef != NULL) && (fieldDef->mIsStatic == methodDef->mIsStatic) && (fieldInst->IsAppendedObject()))
|
||||
{
|
||||
auto refNode = fieldDef->GetRefNode();
|
||||
UpdateSrcPos(refNode);
|
||||
|
||||
auto objectType = mContext->mBfObjectType;
|
||||
BfTypeInstance* checkTypeInst = mCurTypeInstance->ToTypeInstance();
|
||||
|
||||
BfTypedValue val;
|
||||
if (fieldDef->mIsStatic)
|
||||
val = ReferenceStaticField(fieldInst);
|
||||
else
|
||||
{
|
||||
auto fieldAddr = mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[0]->mValue, 0, fieldInst->mDataIdx);
|
||||
val = BfTypedValue(mBfIRBuilder->CreateBitCast(fieldAddr, mBfIRBuilder->MapType(fieldInst->mResolvedType)), fieldInst->mResolvedType);
|
||||
}
|
||||
|
||||
bool allowPrivate = checkTypeInst == mCurTypeInstance;
|
||||
bool allowProtected = allowPrivate || TypeIsSubTypeOf(mCurTypeInstance, checkTypeInst);
|
||||
while (checkTypeInst != NULL)
|
||||
{
|
||||
auto dtorMethodDef = checkTypeInst->mTypeDef->GetMethodByName("~this");
|
||||
if (dtorMethodDef)
|
||||
{
|
||||
if (!CheckProtection(dtorMethodDef->mProtection, checkTypeInst->mTypeDef, allowProtected, allowPrivate))
|
||||
{
|
||||
auto error = Fail(StrFormat("'%s.~this()' is inaccessible due to its protection level", TypeToString(checkTypeInst).c_str()), refNode); // CS0122
|
||||
}
|
||||
}
|
||||
checkTypeInst = checkTypeInst->mBaseType;
|
||||
allowPrivate = false;
|
||||
}
|
||||
|
||||
// call dtor
|
||||
BfExprEvaluator expressionEvaluator(this);
|
||||
PopulateType(val.mType);
|
||||
PopulateType(objectType, BfPopulateType_DataAndMethods);
|
||||
|
||||
if (objectType->mVirtualMethodTable.size() == 0)
|
||||
{
|
||||
if (!mCompiler->IsAutocomplete())
|
||||
AssertErrorState();
|
||||
}
|
||||
else if (!IsSkippingExtraResolveChecks())
|
||||
{
|
||||
BfMethodInstance* methodInstance = objectType->mVirtualMethodTable[mCompiler->GetVTableMethodOffset() + 0].mImplementingMethod;
|
||||
BF_ASSERT(methodInstance->mMethodDef->mName == "~this");
|
||||
SizedArray<BfIRValue, 4> llvmArgs;
|
||||
llvmArgs.push_back(mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(objectType)));
|
||||
expressionEvaluator.CreateCall(refNode, methodInstance, mBfIRBuilder->GetFakeVal(), false, llvmArgs);
|
||||
}
|
||||
|
||||
if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsComptimeModule))
|
||||
{
|
||||
auto int8PtrType = CreatePointerType(GetPrimitiveType(BfTypeCode_Int8));
|
||||
auto int8PtrVal = mBfIRBuilder->CreateBitCast(val.mValue, mBfIRBuilder->MapType(int8PtrType));
|
||||
mBfIRBuilder->CreateStore(GetConstValue8(BfObjectFlag_Deleted), int8PtrVal);
|
||||
}
|
||||
}
|
||||
|
||||
if ((fieldDef != NULL) && (fieldDef->mIsStatic == methodDef->mIsStatic) && (fieldDecl != NULL) && (fieldDecl->mFieldDtor != NULL))
|
||||
{
|
||||
if (fieldDef->mDeclaringType != mCurMethodInstance->mMethodDef->mDeclaringType)
|
||||
|
@ -17730,6 +17896,13 @@ void BfModule::EmitCtorBody(bool& skipBody)
|
|||
continue;
|
||||
auto initializer = fieldDef->GetInitializer();
|
||||
|
||||
if (fieldInst->IsAppendedObject())
|
||||
{
|
||||
UpdateSrcPos(fieldDef->GetNameNode());
|
||||
AppendedObjectInit(fieldInst);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (initializer == NULL)
|
||||
{
|
||||
continue;
|
||||
|
@ -17819,7 +17992,12 @@ void BfModule::EmitCtorBody(bool& skipBody)
|
|||
if ((wantType != NULL) &&
|
||||
((wantType->IsVar()) || (wantType->IsLet()) || (wantType->IsRef())))
|
||||
wantType = NULL;
|
||||
CreateValueFromExpression(initializer, wantType, BfEvalExprFlags_FieldInitializer);
|
||||
|
||||
BfEvalExprFlags exprFlags = BfEvalExprFlags_FieldInitializer;
|
||||
if (fieldDef->mIsAppend)
|
||||
exprFlags = (BfEvalExprFlags)(exprFlags | BfEvalExprFlags_AppendFieldInitializer);
|
||||
|
||||
CreateValueFromExpression(initializer, wantType, exprFlags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18375,6 +18553,21 @@ void BfModule::EmitIteratorBlock(bool& skipBody)
|
|||
return;
|
||||
}
|
||||
|
||||
void BfModule::EmitGCMarkAppended(BfTypedValue markVal)
|
||||
{
|
||||
auto gcType = ResolveTypeDef(mCompiler->mGCTypeDef, BfPopulateType_DataAndMethods);
|
||||
if (gcType == NULL)
|
||||
return;
|
||||
BfModuleMethodInstance markFromGCThreadMethodInstance = GetMethodByName(gcType->ToTypeInstance(), "MarkAppendedObject", 1);
|
||||
if (!markFromGCThreadMethodInstance)
|
||||
return;
|
||||
|
||||
SizedArray<BfIRValue, 1> args;
|
||||
args.push_back(mBfIRBuilder->CreateBitCast(markVal.mValue, mBfIRBuilder->MapType(mContext->mBfObjectType)));
|
||||
BfExprEvaluator exprEvaluator(this);
|
||||
exprEvaluator.CreateCall(NULL, markFromGCThreadMethodInstance.mMethodInstance, markFromGCThreadMethodInstance.mFunc, false, args);
|
||||
}
|
||||
|
||||
void BfModule::EmitGCMarkValue(BfTypedValue markVal, BfModuleMethodInstance markFromGCThreadMethodInstance)
|
||||
{
|
||||
auto fieldType = markVal.mType;
|
||||
|
@ -19048,7 +19241,7 @@ void BfModule::ProcessMethod_ProcessDeferredLocals(int startIdx)
|
|||
}
|
||||
}
|
||||
|
||||
void BfModule::EmitGCMarkValue(BfTypedValue& thisValue, BfType* checkType, int memberDepth, int curOffset, HashSet<int>& objectOffsets, BfModuleMethodInstance markFromGCThreadMethodInstance)
|
||||
void BfModule::EmitGCMarkValue(BfTypedValue& thisValue, BfType* checkType, int memberDepth, int curOffset, HashSet<int>& objectOffsets, BfModuleMethodInstance markFromGCThreadMethodInstance, bool isAppendObject)
|
||||
{
|
||||
if (checkType->IsComposite())
|
||||
PopulateType(checkType, BfPopulateType_Data);
|
||||
|
@ -19184,7 +19377,10 @@ void BfModule::EmitGCMarkValue(BfTypedValue& thisValue, BfType* checkType, int m
|
|||
markValue = BfTypedValue(mBfIRBuilder->CreateBitCast(offsetValue, mBfIRBuilder->MapType(memberPtrType)), memberType, true);
|
||||
}
|
||||
|
||||
EmitGCMarkValue(markValue, markFromGCThreadMethodInstance);
|
||||
if (isAppendObject)
|
||||
EmitGCMarkAppended(markValue);
|
||||
else
|
||||
EmitGCMarkValue(markValue, markFromGCThreadMethodInstance);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -19219,7 +19415,8 @@ void BfModule::EmitGCMarkValue(BfTypedValue& thisValue, BfType* checkType, int m
|
|||
if ((fieldDef->mDeclaringType->mTypeDeclaration != methodDef->mDeclaringType->mTypeDeclaration))
|
||||
continue;
|
||||
}
|
||||
EmitGCMarkValue(thisValue, fieldInst.mResolvedType, memberDepth + 1, curOffset + fieldInst.mDataOffset, objectOffsets, markFromGCThreadMethodInstance);
|
||||
|
||||
EmitGCMarkValue(thisValue, fieldInst.mResolvedType, memberDepth + 1, curOffset + fieldInst.mDataOffset, objectOffsets, markFromGCThreadMethodInstance, fieldInst.IsAppendedObject());
|
||||
}
|
||||
|
||||
if ((typeInstance->mBaseType != NULL) && (typeInstance->mBaseType != mContext->mBfObjectType))
|
||||
|
@ -19373,11 +19570,25 @@ void BfModule::EmitGCMarkMembers()
|
|||
}
|
||||
else if (!fieldDef->mIsStatic)
|
||||
{
|
||||
markVal = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(thisValue.mValue, 0, fieldInst.mDataIdx/*, fieldDef->mName*/), fieldInst.mResolvedType, true);
|
||||
if (fieldInst.IsAppendedObject())
|
||||
{
|
||||
auto fieldAddr = mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[0]->mValue, 0, fieldInst.mDataIdx);
|
||||
auto val = mBfIRBuilder->CreateBitCast(fieldAddr, mBfIRBuilder->MapType(mContext->mBfObjectType));
|
||||
markVal = BfTypedValue(mBfIRBuilder->CreateBitCast(fieldAddr, mBfIRBuilder->MapType(fieldInst.mResolvedType)), fieldInst.mResolvedType);
|
||||
}
|
||||
else
|
||||
{
|
||||
markVal = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(thisValue.mValue, 0, fieldInst.mDataIdx/*, fieldDef->mName*/), fieldInst.mResolvedType, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (markVal)
|
||||
EmitGCMarkValue(markVal, markFromGCThreadMethodInstance);
|
||||
{
|
||||
if (fieldInst.IsAppendedObject())
|
||||
EmitGCMarkAppended(markVal);
|
||||
else
|
||||
EmitGCMarkValue(markVal, markFromGCThreadMethodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20881,15 +21092,47 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup,
|
|||
}
|
||||
}
|
||||
}
|
||||
auto int8PtrType = CreatePointerType(GetPrimitiveType(BfTypeCode_Int8));
|
||||
|
||||
int curSize = mCurTypeInstance->mInstSize;
|
||||
if (curSize > prevSize)
|
||||
{
|
||||
auto int8PtrType = CreatePointerType(GetPrimitiveType(BfTypeCode_Int8));
|
||||
auto int8PtrVal = mBfIRBuilder->CreateBitCast(thisVal.mValue, mBfIRBuilder->MapType(int8PtrType));
|
||||
int8PtrVal = mBfIRBuilder->CreateInBoundsGEP(int8PtrVal, GetConstValue(prevSize));
|
||||
mBfIRBuilder->CreateMemSet(int8PtrVal, GetConstValue8(0), GetConstValue(curSize - prevSize), GetConstValue(mCurTypeInstance->mInstAlign));
|
||||
}
|
||||
|
||||
if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsComptimeModule))
|
||||
{
|
||||
auto useThis = mCurMethodState->mLocals[0]->mValue;
|
||||
auto useThisType = mCurTypeInstance;
|
||||
|
||||
auto checkTypeInst = mCurTypeInstance;
|
||||
while (checkTypeInst != NULL)
|
||||
{
|
||||
for (auto& fieldInstance : checkTypeInst->mFieldInstances)
|
||||
{
|
||||
auto fieldDef = fieldInstance.GetFieldDef();
|
||||
if ((fieldDef == NULL) || (fieldDef->mIsStatic))
|
||||
continue;
|
||||
if (fieldInstance.IsAppendedObject())
|
||||
{
|
||||
if (checkTypeInst != useThisType)
|
||||
{
|
||||
useThis = mBfIRBuilder->CreateBitCast(useThis, mBfIRBuilder->MapType(checkTypeInst));
|
||||
useThisType = checkTypeInst;
|
||||
}
|
||||
|
||||
BfIRValue fieldAddr = mBfIRBuilder->CreateInBoundsGEP(useThis, 0, fieldInstance.mDataIdx);
|
||||
auto int8PtrVal = mBfIRBuilder->CreateBitCast(fieldAddr, mBfIRBuilder->MapType(int8PtrType));
|
||||
mBfIRBuilder->CreateStore(GetConstValue8(BfObjectFlag_Deleted), int8PtrVal);
|
||||
}
|
||||
}
|
||||
|
||||
checkTypeInst = checkTypeInst->mBaseType;
|
||||
}
|
||||
}
|
||||
|
||||
skipUpdateSrcPos = true;
|
||||
}
|
||||
else if (((methodDef->mMethodType == BfMethodType_Ctor) || (methodDef->mMethodType == BfMethodType_CtorNoBody)) && (!hasExternSpecifier))
|
||||
|
|
|
@ -88,6 +88,7 @@ enum BfEvalExprFlags
|
|||
BfEvalExprFlags_FromConversionOp_Explicit = 0x10000000,
|
||||
BfEvalExprFlags_AllowGenericConstValue = 0x20000000,
|
||||
BfEvalExprFlags_IsExpressionBody = 0x40000000,
|
||||
BfEvalExprFlags_AppendFieldInitializer = 0x80000000,
|
||||
|
||||
BfEvalExprFlags_InheritFlags = BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_Comptime | BfEvalExprFlags_DeclType
|
||||
};
|
||||
|
@ -919,11 +920,13 @@ class BfConstResolveState
|
|||
public:
|
||||
BfMethodInstance* mMethodInstance;
|
||||
BfConstResolveState* mPrevConstResolveState;
|
||||
bool mInCalcAppend;
|
||||
|
||||
BfConstResolveState()
|
||||
{
|
||||
mMethodInstance = NULL;
|
||||
mPrevConstResolveState = NULL;
|
||||
mInCalcAppend = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1840,6 +1843,7 @@ public:
|
|||
void CreateStaticField(BfFieldInstance* fieldInstance, bool isThreadLocal = false);
|
||||
void ResolveConstField(BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfFieldDef* field, bool forceResolve = false);
|
||||
BfTypedValue GetFieldInitializerValue(BfFieldInstance* fieldInstance, BfExpression* initializer = NULL, BfFieldDef* fieldDef = NULL, BfType* fieldType = NULL, bool doStore = false);
|
||||
void AppendedObjectInit(BfFieldInstance* fieldInstance);
|
||||
void MarkFieldInitialized(BfFieldInstance* fieldInstance);
|
||||
bool IsThreadLocal(BfFieldInstance* fieldInstance);
|
||||
BfType* ResolveVarFieldType(BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfFieldDef* field);
|
||||
|
@ -1967,7 +1971,7 @@ public:
|
|||
void AddMethodToWorkList(BfMethodInstance* methodInstance);
|
||||
bool IsInterestedInMethod(BfTypeInstance* typeInstance, BfMethodDef* methodDef);
|
||||
void CalcAppendAlign(BfMethodInstance* methodInst);
|
||||
BfTypedValue TryConstCalcAppend(BfMethodInstance* methodInst, SizedArrayImpl<BfIRValue>& args);
|
||||
BfTypedValue TryConstCalcAppend(BfMethodInstance* methodInst, SizedArrayImpl<BfIRValue>& args, bool force = false);
|
||||
BfTypedValue CallBaseCtorCalc(bool constOnly);
|
||||
void EmitCtorCalcAppend();
|
||||
void CreateStaticCtor();
|
||||
|
@ -1980,7 +1984,8 @@ public:
|
|||
void EmitDtorBody();
|
||||
void EmitEnumToStringBody();
|
||||
void EmitTupleToStringBody();
|
||||
void EmitGCMarkValue(BfTypedValue& thisValue, BfType* checkType, int memberDepth, int curOffset, HashSet<int>& objectOffsets, BfModuleMethodInstance markFromGCThreadMethodInstance);
|
||||
void EmitGCMarkAppended(BfTypedValue markVal);
|
||||
void EmitGCMarkValue(BfTypedValue& thisValue, BfType* checkType, int memberDepth, int curOffset, HashSet<int>& objectOffsets, BfModuleMethodInstance markFromGCThreadMethodInstance, bool isAppendObject = false);
|
||||
void EmitGCMarkValue(BfTypedValue markVal, BfModuleMethodInstance markFromGCThreadMethodInstance);
|
||||
void EmitGCMarkMembers();
|
||||
void EmitGCFindTLSMembers();
|
||||
|
|
|
@ -820,6 +820,9 @@ void BfModule::InitType(BfType* resolvedTypeRef, BfPopulateType populateType)
|
|||
void BfModule::AddFieldDependency(BfTypeInstance* typeInstance, BfFieldInstance* fieldInstance, BfType* fieldType)
|
||||
{
|
||||
auto depFlag = fieldType->IsValueType() ? BfDependencyMap::DependencyFlag_ValueTypeMemberData : BfDependencyMap::DependencyFlag_PtrMemberData;
|
||||
if (fieldInstance->IsAppendedObject())
|
||||
depFlag = BfDependencyMap::DependencyFlag_ValueTypeMemberData;
|
||||
|
||||
AddDependency(fieldType, typeInstance, depFlag);
|
||||
|
||||
if ((fieldType->IsStruct()) && (fieldType->IsGenericTypeInstance()))
|
||||
|
@ -4565,6 +4568,12 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
|
||||
auto initializer = field->GetInitializer();
|
||||
|
||||
if ((field->mIsAppend) && (!resolvedTypeRef->IsObject()))
|
||||
Fail("Appended objects can only be declared in class types", field->GetFieldDeclaration()->mExternSpecifier, true);
|
||||
|
||||
if ((field->mIsAppend) && (isUnion))
|
||||
Fail("Appended objects cannot be declared in unions", field->GetFieldDeclaration()->mExternSpecifier, true);
|
||||
|
||||
if (field->IsEnumCaseEntry())
|
||||
{
|
||||
if (typeInstance->IsEnum())
|
||||
|
@ -5109,6 +5118,83 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
|
||||
int dataSize = resolvedFieldType->mSize;
|
||||
int alignSize = resolvedFieldType->mAlign;
|
||||
|
||||
if (fieldInstance->IsAppendedObject())
|
||||
{
|
||||
SetAndRestoreValue<BfFieldDef*> prevTypeRef(mContext->mCurTypeState->mCurFieldDef, fieldDef);
|
||||
SetAndRestoreValue<BfTypeState::ResolveKind> prevResolveKind(mContext->mCurTypeState->mResolveKind, BfTypeState::ResolveKind_FieldType);
|
||||
|
||||
auto fieldTypeInst = resolvedFieldType->ToTypeInstance();
|
||||
dataSize = fieldTypeInst->mInstSize;
|
||||
alignSize = fieldTypeInst->mInstAlign;
|
||||
|
||||
if ((typeInstance != NULL) && (fieldTypeInst->mTypeDef->mIsAbstract))
|
||||
{
|
||||
Fail("Cannot create an instance of an abstract class", nameRefNode);
|
||||
}
|
||||
|
||||
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true);
|
||||
BfMethodState methodState;
|
||||
SetAndRestoreValue<BfMethodState*> prevMethodState(mCurMethodState, &methodState);
|
||||
methodState.mTempKind = BfMethodState::TempKind_NonStatic;
|
||||
|
||||
BfTypedValue appendIndexValue;
|
||||
BfExprEvaluator exprEvaluator(this);
|
||||
|
||||
BfResolvedArgs resolvedArgs;
|
||||
|
||||
auto fieldDecl = fieldDef->GetFieldDeclaration();
|
||||
if (auto invocationExpr = BfNodeDynCast<BfInvocationExpression>(fieldDecl->mInitializer))
|
||||
{
|
||||
resolvedArgs.Init(invocationExpr->mOpenParen, &invocationExpr->mArguments, &invocationExpr->mCommas, invocationExpr->mCloseParen);
|
||||
exprEvaluator.ResolveArgValues(resolvedArgs, BfResolveArgsFlag_DeferParamEval);
|
||||
}
|
||||
|
||||
BfFunctionBindResult bindResult;
|
||||
bindResult.mSkipThis = true;
|
||||
bindResult.mWantsArgs = true;
|
||||
SetAndRestoreValue<BfFunctionBindResult*> prevBindResult(exprEvaluator.mFunctionBindResult, &bindResult);
|
||||
|
||||
BfTypedValue emptyThis(mBfIRBuilder->GetFakeVal(), resolvedTypeRef, resolvedTypeRef->IsStruct());
|
||||
|
||||
exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_Comptime;
|
||||
auto ctorResult = exprEvaluator.MatchConstructor(nameRefNode, NULL, emptyThis, fieldTypeInst, resolvedArgs, false, true);
|
||||
|
||||
if ((bindResult.mMethodInstance != NULL) && (bindResult.mMethodInstance->mMethodDef->mHasAppend))
|
||||
{
|
||||
auto calcAppendMethodModule = GetMethodInstanceAtIdx(bindResult.mMethodInstance->GetOwner(), bindResult.mMethodInstance->mMethodDef->mIdx + 1, BF_METHODNAME_CALCAPPEND);
|
||||
|
||||
SizedArray<BfIRValue, 2> irArgs;
|
||||
if (bindResult.mIRArgs.size() > 1)
|
||||
irArgs.Insert(0, &bindResult.mIRArgs[1], bindResult.mIRArgs.size() - 1);
|
||||
BfTypedValue appendSizeTypedValue = TryConstCalcAppend(calcAppendMethodModule.mMethodInstance, irArgs, true);
|
||||
if (appendSizeTypedValue)
|
||||
{
|
||||
int appendAlign = calcAppendMethodModule.mMethodInstance->mAppendAllocAlign;
|
||||
dataSize = BF_ALIGN(dataSize, appendAlign);
|
||||
alignSize = BF_MAX(alignSize, appendAlign);
|
||||
|
||||
auto constant = mBfIRBuilder->GetConstant(appendSizeTypedValue.mValue);
|
||||
if (constant != NULL)
|
||||
{
|
||||
dataSize += constant->mInt32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Fail(StrFormat("Append constructor '%s' does not result in a constant size", MethodToString(bindResult.mMethodInstance).c_str()), nameRefNode);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (fieldDef->mIsAppend)
|
||||
{
|
||||
if (typeInstance->IsObject())
|
||||
Fail("Append fields can only be declared in classes", nameRefNode, true);
|
||||
else if ((!resolvedFieldType->IsObject()) && (!resolvedFieldType->IsGenericParam()))
|
||||
Fail("Append fields must be classes", nameRefNode, true);
|
||||
}
|
||||
|
||||
fieldInstance->mDataSize = dataSize;
|
||||
if (!isUnion)
|
||||
{
|
||||
|
@ -5244,7 +5330,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
alignBuckets[alignBits].RemoveAt(0);
|
||||
dataFieldVec.push_back(fieldInst);
|
||||
curSize = BF_ALIGN(curSize, fieldInst->GetAlign(packing));
|
||||
curSize += fieldInst->mResolvedType->mSize;
|
||||
curSize += fieldInst->mDataSize;
|
||||
foundEntry = true;
|
||||
|
||||
if (!isHighestBucket)
|
||||
|
@ -5265,7 +5351,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
alignBuckets[alignBits].RemoveAt(0);
|
||||
dataFieldVec.push_back(fieldInst);
|
||||
curSize = BF_ALIGN(curSize, fieldInst->GetAlign(packing));
|
||||
curSize += fieldInst->mResolvedType->mSize;
|
||||
curSize += fieldInst->mDataSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -5281,9 +5367,12 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
|||
auto resolvedFieldType = fieldInstance->GetResolvedType();
|
||||
|
||||
BF_ASSERT(resolvedFieldType->mSize >= 0);
|
||||
int dataSize = resolvedFieldType->mSize;
|
||||
|
||||
if (fieldInstance->mDataSize == 0)
|
||||
fieldInstance->mDataSize = resolvedFieldType->mSize;
|
||||
|
||||
int dataSize = fieldInstance->mDataSize;
|
||||
int alignSize = fieldInstance->GetAlign(packing);
|
||||
fieldInstance->mDataSize = dataSize;
|
||||
|
||||
int nextDataPos = dataPos;
|
||||
nextDataPos = (dataPos + (alignSize - 1)) & ~(alignSize - 1);
|
||||
|
|
|
@ -6319,6 +6319,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, bool declStarted, i
|
|||
case BfToken_Override:
|
||||
case BfToken_Abstract:
|
||||
case BfToken_Concrete:
|
||||
case BfToken_Append:
|
||||
case BfToken_Extern:
|
||||
case BfToken_New:
|
||||
case BfToken_Implicit:
|
||||
|
@ -6575,6 +6576,30 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, bool declStarted, i
|
|||
|
||||
if (token == BfToken_Extern)
|
||||
{
|
||||
if ((fieldDecl->mExternSpecifier != NULL) && (fieldDecl->mExternSpecifier->mToken == BfToken_Append))
|
||||
{
|
||||
Fail("Extern cannot be used with 'append' specified", tokenNode);
|
||||
}
|
||||
else if (fieldDecl->mExternSpecifier != NULL)
|
||||
{
|
||||
Fail("Extern already specified", tokenNode);
|
||||
}
|
||||
|
||||
MEMBER_SET(fieldDecl, mExternSpecifier, tokenNode);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (token == BfToken_Append)
|
||||
{
|
||||
if ((fieldDecl->mExternSpecifier != NULL) && (fieldDecl->mExternSpecifier->mToken == BfToken_Extern))
|
||||
{
|
||||
Fail("Append cannot be used with 'extern' specified", tokenNode);
|
||||
}
|
||||
else if (fieldDecl->mExternSpecifier != NULL)
|
||||
{
|
||||
Fail("Append already specified", tokenNode);
|
||||
}
|
||||
|
||||
MEMBER_SET(fieldDecl, mExternSpecifier, tokenNode);
|
||||
handled = true;
|
||||
}
|
||||
|
|
|
@ -498,6 +498,8 @@ void BfFieldInstance::GetDataRange(int& dataIdx, int& dataCount)
|
|||
int BfFieldInstance::GetAlign(int packing)
|
||||
{
|
||||
int align = mResolvedType->mAlign;
|
||||
if (IsAppendedObject())
|
||||
align = mResolvedType->ToTypeInstance()->mInstAlign;
|
||||
if (packing > 0)
|
||||
align = BF_MIN(align, packing);
|
||||
if (mCustomAttributes != NULL)
|
||||
|
@ -528,6 +530,12 @@ int BfFieldInstance::GetAlign(int packing)
|
|||
return align;
|
||||
}
|
||||
|
||||
bool BfFieldInstance::IsAppendedObject()
|
||||
{
|
||||
auto fieldDef = GetFieldDef();
|
||||
return (fieldDef != NULL) && (fieldDef->mIsAppend) && (mResolvedType->IsObject()) && (mOwner->IsObject());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int64 BfDeferredMethodCallData::GenerateMethodId(BfModule* module, int64 methodId)
|
||||
|
|
|
@ -1469,6 +1469,7 @@ public:
|
|||
void SetResolvedType(BfType* type);
|
||||
void GetDataRange(int& dataIdx, int& dataCount);
|
||||
int GetAlign(int packing);
|
||||
bool IsAppendedObject();
|
||||
};
|
||||
|
||||
enum BfMethodRefKind
|
||||
|
|
|
@ -1929,6 +1929,13 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD
|
|||
BfLocalVariable* localVar = AddLocalVariableDef(localDef, true, false, BfIRValue(), initType);
|
||||
if (wantsStore)
|
||||
mBfIRBuilder->CreateAlignedStore(initValue.mValue, localVar->mAddr, localVar->mResolvedType->mAlign);
|
||||
|
||||
if ((mCurMethodState->mConstResolveState != NULL) && (mCurMethodState->mConstResolveState->mInCalcAppend))
|
||||
{
|
||||
if (localDef->mValue.IsConst())
|
||||
localDef->mConstValue = localDef->mValue;
|
||||
}
|
||||
|
||||
return localVar;
|
||||
}
|
||||
|
||||
|
|
|
@ -610,6 +610,7 @@ public:
|
|||
bool mIsInline;
|
||||
bool mIsVolatile;
|
||||
bool mIsExtern;
|
||||
bool mIsAppend;
|
||||
bool mIsProperty;
|
||||
BfAstNode* mFieldDeclaration;
|
||||
// It may seem that fields and properties don't need a 'mNextWithSameName', but with extensions it's possible
|
||||
|
@ -625,6 +626,7 @@ public:
|
|||
mUsingProtection = BfProtection_Hidden;
|
||||
mIsInline = false;
|
||||
mIsExtern = false;
|
||||
mIsAppend = false;
|
||||
mIsVolatile = false;
|
||||
mIsProperty = false;
|
||||
mFieldDeclaration = NULL;
|
||||
|
@ -1680,7 +1682,8 @@ enum BfFieldFlags
|
|||
BfFieldFlags_EnumPayload = 0x100,
|
||||
BfFieldFlags_EnumDiscriminator = 0x200,
|
||||
BfFieldFlags_EnumCase = 0x400,
|
||||
BfFieldFlags_ReadOnly = 0x800
|
||||
BfFieldFlags_ReadOnly = 0x800,
|
||||
BfFieldFlags_Appended = 0x1000
|
||||
};
|
||||
|
||||
enum BfReflectKind
|
||||
|
|
|
@ -5667,6 +5667,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
|
|||
Fail(_GetCurFrame(), "Array out of bounds");
|
||||
return false;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_OOB)
|
||||
{
|
||||
Fail(_GetCurFrame(), "Object not initialized");
|
||||
return false;
|
||||
}
|
||||
else if (checkFunction->mFunctionKind == CeFunctionKind_Malloc)
|
||||
{
|
||||
int64 size;
|
||||
|
@ -9340,6 +9345,8 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction)
|
|||
{
|
||||
if (methodDef->mName == "ThrowIndexOutOfRange")
|
||||
ceFunction->mFunctionKind = CeFunctionKind_OOB;
|
||||
else if (methodDef->mName == "ThrowObjectNotInitialized")
|
||||
ceFunction->mFunctionKind = CeFunctionKind_ObjectNotInitialized;
|
||||
else if (methodDef->mName == "FatalError")
|
||||
ceFunction->mFunctionKind = CeFunctionKind_FatalError;
|
||||
else if (methodDef->mName == "Dbg_RawAlloc")
|
||||
|
|
|
@ -422,6 +422,7 @@ enum CeFunctionKind
|
|||
CeFunctionKind_Normal,
|
||||
CeFunctionKind_Extern,
|
||||
CeFunctionKind_OOB,
|
||||
CeFunctionKind_ObjectNotInitialized,
|
||||
CeFunctionKind_Malloc,
|
||||
CeFunctionKind_Free,
|
||||
CeFunctionKind_DynCheckFailed,
|
||||
|
|
|
@ -76,6 +76,13 @@ namespace Tests
|
|||
}
|
||||
}
|
||||
|
||||
class ClassF
|
||||
{
|
||||
public int mA = 123;
|
||||
public append String mB = .(mA);
|
||||
public int mC = 234;
|
||||
}
|
||||
|
||||
static void CheckData(Object obj, int lastAllocSize, uint8[] data)
|
||||
{
|
||||
int objSize = typeof(Object).InstanceSize;
|
||||
|
@ -110,6 +117,17 @@ namespace Tests
|
|||
0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10
|
||||
));
|
||||
delete:trackedAlloc ce;
|
||||
|
||||
int sizeDiff = Math.Abs(typeof(ClassF).InstanceSize - (1024 + sizeof(int)*5));
|
||||
Test.Assert(sizeDiff < 32);
|
||||
|
||||
ClassF cf = scope .();
|
||||
cf.mB.Append("Abc");
|
||||
Test.Assert(cf.mA == 123);
|
||||
Test.Assert(cf.mB == "Abc");
|
||||
Test.Assert(cf.mB.AllocSize == 1024);
|
||||
Test.Assert(cf.mC == 234);
|
||||
cf.mB.Append('!', 2048);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue