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) {}
|
public static void ExcludeThreadId(int thereadId) {}
|
||||||
#endif
|
#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)
|
static void MarkDerefedObject(Object* obj)
|
||||||
{
|
{
|
||||||
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
||||||
|
|
|
@ -89,6 +89,8 @@ namespace System
|
||||||
[CallingConvention(.Cdecl), NoReturn]
|
[CallingConvention(.Cdecl), NoReturn]
|
||||||
public static extern void ThrowIndexOutOfRange(int stackOffset = 0);
|
public static extern void ThrowIndexOutOfRange(int stackOffset = 0);
|
||||||
[CallingConvention(.Cdecl), NoReturn]
|
[CallingConvention(.Cdecl), NoReturn]
|
||||||
|
public static extern void ThrowObjectNotInitialized(int stackOffset = 0);
|
||||||
|
[CallingConvention(.Cdecl), NoReturn]
|
||||||
public static extern void FatalError(String error, int stackOffset = 0);
|
public static extern void FatalError(String error, int stackOffset = 0);
|
||||||
[Intrinsic("memcpy")]
|
[Intrinsic("memcpy")]
|
||||||
public static extern void MemCpy(void* dest, void* src, int length, int32 align = 1, bool isVolatile = false);
|
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
|
public enum Error
|
||||||
{
|
{
|
||||||
InvalidTargetType,
|
InvalidTargetType,
|
||||||
InvalidValueType
|
InvalidValueType,
|
||||||
|
AppendedField
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeInstance mTypeInstance;
|
TypeInstance mTypeInstance;
|
||||||
|
@ -24,6 +25,7 @@ namespace System.Reflection
|
||||||
public int32 MemberOffset => (int32)mFieldData.mData;
|
public int32 MemberOffset => (int32)mFieldData.mData;
|
||||||
public Type FieldType => Type.[Friend]GetType(mFieldData.mFieldTypeId);
|
public Type FieldType => Type.[Friend]GetType(mFieldData.mFieldTypeId);
|
||||||
public bool IsConst => mFieldData.mFlags.HasFlag(.Const);
|
public bool IsConst => mFieldData.mFlags.HasFlag(.Const);
|
||||||
|
public bool IsAppended => mFieldData.mFlags.HasFlag(.Appended);
|
||||||
public bool IsEnumCase => mFieldData.mFlags.HasFlag(.EnumCase);
|
public bool IsEnumCase => mFieldData.mFlags.HasFlag(.EnumCase);
|
||||||
public bool IsReadOnly => mFieldData.mFlags.HasFlag(.ReadOnly);
|
public bool IsReadOnly => mFieldData.mFlags.HasFlag(.ReadOnly);
|
||||||
public bool IsStatic => mFieldData.mFlags.HasFlag(.Static);
|
public bool IsStatic => mFieldData.mFlags.HasFlag(.Static);
|
||||||
|
@ -86,7 +88,12 @@ namespace System.Reflection
|
||||||
if (valueType == fieldType)
|
if (valueType == fieldType)
|
||||||
{
|
{
|
||||||
if (valueType.IsObject)
|
if (valueType.IsObject)
|
||||||
|
{
|
||||||
|
if (mFieldData.mFlags.HasFlag(.Appended))
|
||||||
|
return .Err(.AppendedField);
|
||||||
|
|
||||||
*((void**)dataAddr) = Internal.UnsafeCastToPtr(value);
|
*((void**)dataAddr) = Internal.UnsafeCastToPtr(value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Internal.MemCpy(dataAddr, valueDataAddr, fieldType.[Friend]mSize);
|
Internal.MemCpy(dataAddr, valueDataAddr, fieldType.[Friend]mSize);
|
||||||
}
|
}
|
||||||
|
@ -385,7 +392,10 @@ namespace System.Reflection
|
||||||
if (typeCode == TypeCode.Object)
|
if (typeCode == TypeCode.Object)
|
||||||
{
|
{
|
||||||
value.[Friend]mStructType = 0;
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1480,6 +1480,7 @@ namespace System.Reflection
|
||||||
EnumDiscriminator = 0x0200,
|
EnumDiscriminator = 0x0200,
|
||||||
EnumCase = 0x0400,
|
EnumCase = 0x0400,
|
||||||
ReadOnly = 0x0800,
|
ReadOnly = 0x0800,
|
||||||
|
Appended = 0x1000,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum MethodFlags : uint16
|
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 ObjectDynCheck(Object* object, int typeId, bool allowNull);
|
||||||
BFRT_EXPORT static void ObjectDynCheckFailed(Object* object, int typeId);
|
BFRT_EXPORT static void ObjectDynCheckFailed(Object* object, int typeId);
|
||||||
BFRT_EXPORT static void ThrowIndexOutOfRange(intptr stackOffset);
|
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 FatalError(String* error, intptr stackOffset = 0);
|
||||||
BFRT_EXPORT static void MemCpy(void* dest, void* src, intptr length);
|
BFRT_EXPORT static void MemCpy(void* dest, void* src, intptr length);
|
||||||
BFRT_EXPORT static void MemMove(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");
|
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)
|
void Internal::FatalError(bf::System::String* error, intptr stackOffset)
|
||||||
{
|
{
|
||||||
if (gClientPipe != NULL)
|
if (gClientPipe != NULL)
|
||||||
|
|
|
@ -4942,6 +4942,10 @@ namespace IDE.ui
|
||||||
menuItem.SetDisabled(!isPaused);
|
menuItem.SetDisabled(!isPaused);
|
||||||
menuItem.mOnMenuItemSelected.Add(new (evt) => IDEApp.sApp.ShowDisassemblyAtCursor());
|
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");
|
var stepIntoSpecificMenu = menu.AddItem("Step into Specific");
|
||||||
stepIntoSpecificMenu.SetDisabled(!isPaused);
|
stepIntoSpecificMenu.SetDisabled(!isPaused);
|
||||||
stepIntoSpecificMenu.IsParent = true;
|
stepIntoSpecificMenu.IsParent = true;
|
||||||
|
|
|
@ -3169,7 +3169,7 @@ public:
|
||||||
BfAstNode* mConstSpecifier; // Could be 'const' or 'using'
|
BfAstNode* mConstSpecifier; // Could be 'const' or 'using'
|
||||||
BfTokenNode* mVolatileSpecifier;
|
BfTokenNode* mVolatileSpecifier;
|
||||||
BfTokenNode* mNewSpecifier;
|
BfTokenNode* mNewSpecifier;
|
||||||
BfTokenNode* mExternSpecifier;
|
BfTokenNode* mExternSpecifier; // Could be 'extern' or 'append'
|
||||||
BfTypeReference* mTypeRef;
|
BfTypeReference* mTypeRef;
|
||||||
BfIdentifierNode* mNameNode;
|
BfIdentifierNode* mNameNode;
|
||||||
BfTokenNode* mEqualsNode;
|
BfTokenNode* mEqualsNode;
|
||||||
|
|
|
@ -1741,7 +1741,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress
|
||||||
{
|
{
|
||||||
const char* tokens [] =
|
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",
|
"delegate", "delete", "do", "else", "false", "finally",
|
||||||
"fixed", "for", "function", "if", "implicit", "in", "internal", "is", "isconst", "new", "mixin", "null",
|
"fixed", "for", "function", "if", "implicit", "in", "internal", "is", "isconst", "new", "mixin", "null",
|
||||||
"offsetof", "out", "params", "readonly", "ref", "rettype", "return",
|
"offsetof", "out", "params", "readonly", "ref", "rettype", "return",
|
||||||
|
@ -1762,7 +1762,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress
|
||||||
{
|
{
|
||||||
const char* tokens[] =
|
const char* tokens[] =
|
||||||
{
|
{
|
||||||
"abstract", "base", "class", "const",
|
"abstract", "append", "base", "class", "const",
|
||||||
"delegate", "extern", "enum", "explicit", "extension", "function",
|
"delegate", "extern", "enum", "explicit", "extension", "function",
|
||||||
"interface", "in", "implicit", "internal", "mixin", "namespace", "new",
|
"interface", "in", "implicit", "internal", "mixin", "namespace", "new",
|
||||||
"operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "rettype", "return",
|
"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->mProtection = BfProtection_Public;
|
||||||
fieldDef->mIsReadOnly = fieldDeclaration->mReadOnlySpecifier != NULL;
|
fieldDef->mIsReadOnly = fieldDeclaration->mReadOnlySpecifier != NULL;
|
||||||
fieldDef->mIsInline = (fieldDeclaration->mReadOnlySpecifier != NULL) && (fieldDeclaration->mReadOnlySpecifier->GetToken() == BfToken_Inline);
|
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);
|
auto constSpecifierToken = BfNodeDynCast<BfTokenNode>(fieldDeclaration->mConstSpecifier);
|
||||||
fieldDef->mIsConst = ((constSpecifierToken != NULL) && (constSpecifierToken->mToken == BfToken_Const)) || (isEnumEntryDecl);
|
fieldDef->mIsConst = ((constSpecifierToken != NULL) && (constSpecifierToken->mToken == BfToken_Const)) || (isEnumEntryDecl);
|
||||||
if (auto usingSpecifier = BfNodeDynCast<BfUsingSpecifierNode>(fieldDeclaration->mConstSpecifier))
|
if (auto usingSpecifier = BfNodeDynCast<BfUsingSpecifierNode>(fieldDeclaration->mConstSpecifier))
|
||||||
|
@ -2197,6 +2198,11 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
|
||||||
}
|
}
|
||||||
if (field->GetFieldDeclaration()->mFieldDtor != NULL)
|
if (field->GetFieldDeclaration()->mFieldDtor != NULL)
|
||||||
needsStaticDtor = true;
|
needsStaticDtor = true;
|
||||||
|
if (field->mIsAppend)
|
||||||
|
{
|
||||||
|
needsStaticInit = true;
|
||||||
|
needsStaticDtor = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2222,6 +2228,11 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
|
||||||
hasNonStaticField = true;
|
hasNonStaticField = true;
|
||||||
if (field->GetInitializer() != NULL)
|
if (field->GetInitializer() != NULL)
|
||||||
needsDefaultCtor = true;
|
needsDefaultCtor = true;
|
||||||
|
if (field->mIsAppend)
|
||||||
|
{
|
||||||
|
needsDefaultCtor = true;
|
||||||
|
needsDtor = true;
|
||||||
|
}
|
||||||
if (auto fieldDecl = field->GetFieldDeclaration())
|
if (auto fieldDecl = field->GetFieldDeclaration())
|
||||||
{
|
{
|
||||||
if (fieldDecl->mFieldDtor != NULL)
|
if (fieldDecl->mFieldDtor != NULL)
|
||||||
|
|
|
@ -5008,6 +5008,42 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe
|
||||||
bool isStaticCtor = (mModule->mCurMethodInstance != NULL) &&
|
bool isStaticCtor = (mModule->mCurMethodInstance != NULL) &&
|
||||||
(mModule->mCurMethodInstance->mMethodDef->IsCtorOrInit()) &&
|
(mModule->mCurMethodInstance->mMethodDef->IsCtorOrInit()) &&
|
||||||
(mModule->mCurMethodInstance->mMethodDef->mIsStatic);
|
(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 ((fieldDef->mIsReadOnly) && (!isStaticCtor))
|
||||||
{
|
{
|
||||||
if (retVal.IsAddr())
|
if (retVal.IsAddr())
|
||||||
|
@ -5135,8 +5171,16 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe
|
||||||
if ((targetValue.IsAddr()) && (!typeInstance->IsValueType()))
|
if ((targetValue.IsAddr()) && (!typeInstance->IsValueType()))
|
||||||
targetValue = mModule->LoadValue(targetValue);
|
targetValue = mModule->LoadValue(targetValue);
|
||||||
|
|
||||||
retVal = BfTypedValue(mModule->mBfIRBuilder->CreateInBoundsGEP(targetValue.mValue, 0, fieldInstance->mDataIdx/*, fieldDef->mName*/),
|
if (fieldInstance->IsAppendedObject())
|
||||||
resolvedFieldType, target.IsReadOnly() ? BfTypedValueKind_ReadOnlyAddr : BfTypedValueKind_Addr);
|
{
|
||||||
|
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())
|
if (!retVal.IsSplat())
|
||||||
|
@ -9649,15 +9693,24 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
|
|
||||||
if (resolvedTypeInstance != NULL)
|
if (resolvedTypeInstance != NULL)
|
||||||
{
|
{
|
||||||
if ((!resolvedTypeInstance->IsStruct()) && (!resolvedTypeInstance->IsTypedPrimitive()))
|
if ((mBfEvalExprFlags & BfEvalExprFlags_AppendFieldInitializer) == 0)
|
||||||
{
|
{
|
||||||
if (mModule->PreFail())
|
if ((!resolvedTypeInstance->IsStruct()) && (!resolvedTypeInstance->IsTypedPrimitive()))
|
||||||
mModule->Fail("Objects must be allocated through 'new' or 'scope'", targetSrc);
|
{
|
||||||
return BfTypedValue();
|
if (mModule->PreFail())
|
||||||
|
mModule->Fail("Objects must be allocated through 'new' or 'scope'", targetSrc);
|
||||||
|
return BfTypedValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto identifier = BfNodeDynCastExact<BfIdentifierNode>(targetSrc))
|
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 (mModule->mCompiler->mResolvePassData != NULL)
|
||||||
{
|
{
|
||||||
if (!BfNodeIsA<BfMemberReferenceExpression>(targetSrc))
|
if (!BfNodeIsA<BfMemberReferenceExpression>(targetSrc))
|
||||||
|
@ -9688,7 +9741,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
mResultLocalVar = NULL;
|
mResultLocalVar = NULL;
|
||||||
mResultFieldInstance = NULL;
|
mResultFieldInstance = NULL;
|
||||||
mResultLocalVarRefNode = 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()))
|
if ((result) && (!result.mType->IsVoid()))
|
||||||
return result;
|
return result;
|
||||||
mModule->ValidateAllocation(resolvedTypeInstance, targetSrc);
|
mModule->ValidateAllocation(resolvedTypeInstance, targetSrc);
|
||||||
|
@ -17564,7 +17617,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
|
||||||
else
|
else
|
||||||
mResult = BfTypedValue(mModule->CreateAlloca(expectingType), expectingType, BfTypedValueKind_TempAddr);
|
mResult = BfTypedValue(mModule->CreateAlloca(expectingType), expectingType, BfTypedValueKind_TempAddr);
|
||||||
|
|
||||||
auto ctorResult = MatchConstructor(target, methodBoundExpr, mResult, expectingType->ToTypeInstance(), argValues, false, false);
|
auto ctorResult = MatchConstructor(target, methodBoundExpr, mResult, expectingType->ToTypeInstance(), argValues, false, false);
|
||||||
if ((ctorResult) && (!ctorResult.mType->IsVoid()))
|
if ((ctorResult) && (!ctorResult.mType->IsVoid()))
|
||||||
mResult = ctorResult;
|
mResult = ctorResult;
|
||||||
mModule->ValidateAllocation(expectingType, invocationExpr->mTarget);
|
mModule->ValidateAllocation(expectingType, invocationExpr->mTarget);
|
||||||
|
@ -17599,7 +17652,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
|
||||||
{
|
{
|
||||||
// Allow
|
// Allow
|
||||||
}
|
}
|
||||||
else
|
else if ((mBfEvalExprFlags & BfEvalExprFlags_AppendFieldInitializer) == 0)
|
||||||
{
|
{
|
||||||
gaveUnqualifiedDotError = true;
|
gaveUnqualifiedDotError = true;
|
||||||
if (mModule->PreFail())
|
if (mModule->PreFail())
|
||||||
|
@ -21419,25 +21472,20 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
|
||||||
auto oobFunc = mModule->GetMethodByName(internalType->ToTypeInstance(), "ThrowIndexOutOfRange");
|
auto oobFunc = mModule->GetMethodByName(internalType->ToTypeInstance(), "ThrowIndexOutOfRange");
|
||||||
if (oobFunc.mFunc)
|
if (oobFunc.mFunc)
|
||||||
{
|
{
|
||||||
/*if (!mModule->mCompiler->mIsResolveOnly)
|
|
||||||
{
|
|
||||||
OutputDebugStrF("-OOB %d %d\n", oobFunc.mFunc.mId, oobFunc.mFunc.mFlags);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (mModule->mIsComptimeModule)
|
if (mModule->mIsComptimeModule)
|
||||||
mModule->mCompiler->mCeMachine->QueueMethod(oobFunc.mMethodInstance, oobFunc.mFunc);
|
mModule->mCompiler->mCeMachine->QueueMethod(oobFunc.mMethodInstance, oobFunc.mFunc);
|
||||||
|
|
||||||
SizedArray<BfIRValue, 1> args;
|
SizedArray<BfIRValue, 1> args;
|
||||||
args.push_back(mModule->GetConstValue(0));
|
args.push_back(mModule->GetConstValue(0));
|
||||||
mModule->mBfIRBuilder->CreateCall(oobFunc.mFunc, args);
|
mModule->mBfIRBuilder->CreateCall(oobFunc.mFunc, args);
|
||||||
mModule->mBfIRBuilder->CreateUnreachable();
|
mModule->mBfIRBuilder->CreateUnreachable();
|
||||||
|
|
||||||
mModule->mBfIRBuilder->SetInsertPoint(contBlock);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mModule->Fail("System.Internal class must contain method 'ThrowIndexOutOfRange'");
|
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);
|
PopulateType(resolvedFieldType, BfIRPopulateType_Eventually_Full);
|
||||||
resolvedFieldDIType = DbgGetType(resolvedFieldType);
|
resolvedFieldDIType = DbgGetType(resolvedFieldType);
|
||||||
|
|
||||||
|
if (fieldInstance->IsAppendedObject())
|
||||||
|
resolvedFieldDIType = DbgGetTypeInst(resolvedFieldType->ToTypeInstance());
|
||||||
|
|
||||||
if ((fieldDef == NULL) && (typeInstance->IsPayloadEnum()))
|
if ((fieldDef == NULL) && (typeInstance->IsPayloadEnum()))
|
||||||
{
|
{
|
||||||
orderedFields.push_back(fieldInstance);
|
orderedFields.push_back(fieldInstance);
|
||||||
|
@ -3409,7 +3412,7 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type)
|
||||||
if (fieldDef->mHasMultiDefs)
|
if (fieldDef->mHasMultiDefs)
|
||||||
fieldName += "$" + fieldDef->mDeclaringType->mProject->mName;
|
fieldName += "$" + fieldDef->mDeclaringType->mProject->mName;
|
||||||
auto memberType = DbgCreateMemberType(diForwardDecl, fieldName, fileDIScope, lineNum,
|
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);
|
flags, resolvedFieldDIType);
|
||||||
diFieldTypes.push_back(memberType);
|
diFieldTypes.push_back(memberType);
|
||||||
}
|
}
|
||||||
|
@ -3712,6 +3715,9 @@ void BfIRBuilder::CreateTypeDefinition_Data(BfModule* populateModule, BfTypeInst
|
||||||
if ((fieldDef != NULL) && (resolvedFieldType->IsStruct()))
|
if ((fieldDef != NULL) && (resolvedFieldType->IsStruct()))
|
||||||
PopulateType(resolvedFieldType, BfIRPopulateType_Eventually_Full);
|
PopulateType(resolvedFieldType, BfIRPopulateType_Eventually_Full);
|
||||||
|
|
||||||
|
if (fieldInstance->IsAppendedObject())
|
||||||
|
PopulateType(resolvedFieldType, BfIRPopulateType_Eventually_Full);
|
||||||
|
|
||||||
if ((fieldDef == NULL) && (typeInstance->IsPayloadEnum()))
|
if ((fieldDef == NULL) && (typeInstance->IsPayloadEnum()))
|
||||||
{
|
{
|
||||||
orderedFields.push_back(fieldInstance);
|
orderedFields.push_back(fieldInstance);
|
||||||
|
@ -3761,10 +3767,27 @@ void BfIRBuilder::CreateTypeDefinition_Data(BfModule* populateModule, BfTypeInst
|
||||||
if (fieldInstance == NULL)
|
if (fieldInstance == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
auto fieldDef = fieldInstance->GetFieldDef();
|
||||||
|
|
||||||
auto resolvedFieldType = fieldInstance->GetResolvedType();
|
auto resolvedFieldType = fieldInstance->GetResolvedType();
|
||||||
|
|
||||||
BfIRType resolvedFieldIRType = MapType(resolvedFieldType);
|
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)
|
if (fieldInstance->mDataOffset > dataPos)
|
||||||
{
|
{
|
||||||
int fillSize = 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);
|
BfMangler::Mangle(staticVarName, mCompiler->GetMangleKind(), fieldInstance);
|
||||||
if ((!fieldType->IsValuelessType()) && (!staticVarName.StartsWith("#")))
|
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(
|
BfIRValue globalVar = mBfIRBuilder->CreateGlobalVariable(
|
||||||
mBfIRBuilder->MapType(fieldType, BfIRPopulateType_Eventually_Full),
|
irType,
|
||||||
false,
|
false,
|
||||||
BfIRLinkageType_External,
|
BfIRLinkageType_External,
|
||||||
initValue,
|
initValue,
|
||||||
|
@ -4551,6 +4561,83 @@ BfTypedValue BfModule::GetFieldInitializerValue(BfFieldInstance* fieldInstance,
|
||||||
return result;
|
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)
|
void BfModule::CheckInterfaceMethod(BfMethodInstance* methodInstance)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -5570,7 +5657,9 @@ BfIRValue BfModule::CreateFieldData(BfFieldInstance* fieldInstance, int customAt
|
||||||
if (fieldDef->IsEnumCaseEntry())
|
if (fieldDef->IsEnumCaseEntry())
|
||||||
fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_EnumCase);
|
fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_EnumCase);
|
||||||
if (fieldDef->mIsReadOnly)
|
if (fieldDef->mIsReadOnly)
|
||||||
fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_ReadOnly);
|
fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_ReadOnly);
|
||||||
|
if (fieldInstance->IsAppendedObject())
|
||||||
|
fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_Appended);
|
||||||
|
|
||||||
BfIRValue constValue;
|
BfIRValue constValue;
|
||||||
BfIRValue constValue2;
|
BfIRValue constValue2;
|
||||||
|
@ -5608,8 +5697,13 @@ BfIRValue BfModule::CreateFieldData(BfFieldInstance* fieldInstance, int customAt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((refVal.IsAddr()) && (!isComptimeArg))
|
if (!isComptimeArg)
|
||||||
constValue = mBfIRBuilder->CreatePtrToInt(refVal.mValue, BfTypeCode_IntPtr);
|
{
|
||||||
|
if (refVal.IsAddr())
|
||||||
|
constValue = mBfIRBuilder->CreatePtrToInt(refVal.mValue, BfTypeCode_IntPtr);
|
||||||
|
else if (fieldInstance->IsAppendedObject())
|
||||||
|
constValue = mBfIRBuilder->CreatePtrToInt(refVal.mValue, BfTypeCode_IntPtr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!constValue)
|
if (!constValue)
|
||||||
|
@ -11240,7 +11334,7 @@ StringT<128> BfModule::MethodToString(BfMethodInstance* methodInst, BfMethodName
|
||||||
for (int paramIdx = 0; paramIdx < (int)methodInst->GetParamCount(); paramIdx++)
|
for (int paramIdx = 0; paramIdx < (int)methodInst->GetParamCount(); paramIdx++)
|
||||||
{
|
{
|
||||||
int paramKind = methodInst->GetParamKind(paramIdx);
|
int paramKind = methodInst->GetParamKind(paramIdx);
|
||||||
if (paramKind == BfParamKind_ImplicitCapture)
|
if ((paramKind == BfParamKind_ImplicitCapture) || (paramKind == BfParamKind_AppendIdx))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (dispParamIdx > 0)
|
if (dispParamIdx > 0)
|
||||||
|
@ -14799,6 +14893,9 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
|
||||||
{
|
{
|
||||||
BfIRType irType = mBfIRBuilder->MapType(typeType);
|
BfIRType irType = mBfIRBuilder->MapType(typeType);
|
||||||
|
|
||||||
|
if (fieldInstance->IsAppendedObject())
|
||||||
|
irType = mBfIRBuilder->MapTypeInst(typeType->ToTypeInstance());
|
||||||
|
|
||||||
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mBfIRBuilder->mIgnoreWrites || staticVarName.StartsWith('#'));
|
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mBfIRBuilder->mIgnoreWrites || staticVarName.StartsWith('#'));
|
||||||
|
|
||||||
globalValue = mBfIRBuilder->CreateGlobalVariable(
|
globalValue = mBfIRBuilder->CreateGlobalVariable(
|
||||||
|
@ -14822,7 +14919,7 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
|
||||||
|
|
||||||
if (fieldDef->mIsVolatile)
|
if (fieldDef->mIsVolatile)
|
||||||
return BfTypedValue(globalValue, type, BfTypedValueKind_VolatileAddr);
|
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)
|
BfFieldInstance* BfModule::GetFieldInstance(BfTypeInstance* typeInst, int fieldIdx, const char* fieldName)
|
||||||
|
@ -16381,13 +16478,13 @@ void BfModule::CalcAppendAlign(BfMethodInstance* methodInst)
|
||||||
methodInst->mAppendAllocAlign = 1;
|
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");
|
BP_ZONE("BfModule::TryConstCalcAppend");
|
||||||
|
|
||||||
BF_ASSERT(methodInst->mMethodDef->mMethodType == BfMethodType_CtorCalcAppend);
|
BF_ASSERT(methodInst->mMethodDef->mMethodType == BfMethodType_CtorCalcAppend);
|
||||||
|
|
||||||
if ((mCompiler->mIsResolveOnly) && (!mIsComptimeModule))
|
if ((mCompiler->mIsResolveOnly) && (!mIsComptimeModule) && (!force))
|
||||||
return BfTypedValue();
|
return BfTypedValue();
|
||||||
|
|
||||||
// We want to regenerate all ctor calls when the method internals change
|
// We want to regenerate all ctor calls when the method internals change
|
||||||
|
@ -16476,6 +16573,7 @@ BfTypedValue BfModule::TryConstCalcAppend(BfMethodInstance* methodInst, SizedArr
|
||||||
BfConstResolveState constResolveState;
|
BfConstResolveState constResolveState;
|
||||||
constResolveState.mMethodInstance = methodInst;
|
constResolveState.mMethodInstance = methodInst;
|
||||||
constResolveState.mPrevConstResolveState = mCurMethodState->mConstResolveState;
|
constResolveState.mPrevConstResolveState = mCurMethodState->mConstResolveState;
|
||||||
|
constResolveState.mInCalcAppend = true;
|
||||||
|
|
||||||
SetAndRestoreValue<bool> ignoreWrites(mBfIRBuilder->mIgnoreWrites, true);
|
SetAndRestoreValue<bool> ignoreWrites(mBfIRBuilder->mIgnoreWrites, true);
|
||||||
BfMethodState methodState;
|
BfMethodState methodState;
|
||||||
|
@ -16630,7 +16728,7 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly)
|
||||||
BF_ASSERT(bindResult.mIRArgs[0].IsFake());
|
BF_ASSERT(bindResult.mIRArgs[0].IsFake());
|
||||||
bindResult.mIRArgs.RemoveAt(0);
|
bindResult.mIRArgs.RemoveAt(0);
|
||||||
auto calcAppendMethodModule = GetMethodInstanceAtIdx(bindResult.mMethodInstance->GetOwner(), bindResult.mMethodInstance->mMethodDef->mIdx + 1, BF_METHODNAME_CALCAPPEND);
|
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);
|
BF_ASSERT(calcAppendMethodModule.mMethodInstance->mAppendAllocAlign >= 0);
|
||||||
mCurMethodInstance->mAppendAllocAlign = BF_MAX((int)mCurMethodInstance->mAppendAllocAlign, calcAppendMethodModule.mMethodInstance->mAppendAllocAlign);
|
mCurMethodInstance->mAppendAllocAlign = BF_MAX((int)mCurMethodInstance->mAppendAllocAlign, calcAppendMethodModule.mMethodInstance->mAppendAllocAlign);
|
||||||
BF_ASSERT(calcAppendMethodModule.mMethodInstance->mEndingAppendAllocAlign > -1);
|
BF_ASSERT(calcAppendMethodModule.mMethodInstance->mEndingAppendAllocAlign > -1);
|
||||||
|
@ -16757,7 +16855,10 @@ void BfModule::CreateStaticCtor()
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
GetFieldInitializerValue(fieldInst, NULL, NULL, NULL, true);
|
if (fieldInst->IsAppendedObject())
|
||||||
|
AppendedObjectInit(fieldInst);
|
||||||
|
else
|
||||||
|
GetFieldInitializerValue(fieldInst, NULL, NULL, NULL, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16788,8 +16889,13 @@ void BfModule::CreateStaticCtor()
|
||||||
if ((!BfNodeIsA<BfVarTypeReference>(fieldDef->mTypeRef)) && (!BfNodeIsA<BfLetTypeReference>(fieldDef->mTypeRef)))
|
if ((!BfNodeIsA<BfVarTypeReference>(fieldDef->mTypeRef)) && (!BfNodeIsA<BfLetTypeReference>(fieldDef->mTypeRef)))
|
||||||
{
|
{
|
||||||
wantType = ResolveTypeRef(fieldDef->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowInferredSizedArray);
|
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)
|
if (fieldDef != NULL)
|
||||||
fieldDecl = fieldDef->GetFieldDeclaration();
|
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 != NULL) && (fieldDef->mIsStatic == methodDef->mIsStatic) && (fieldDecl != NULL) && (fieldDecl->mFieldDtor != NULL))
|
||||||
{
|
{
|
||||||
if (fieldDef->mDeclaringType != mCurMethodInstance->mMethodDef->mDeclaringType)
|
if (fieldDef->mDeclaringType != mCurMethodInstance->mMethodDef->mDeclaringType)
|
||||||
|
@ -17730,6 +17896,13 @@ void BfModule::EmitCtorBody(bool& skipBody)
|
||||||
continue;
|
continue;
|
||||||
auto initializer = fieldDef->GetInitializer();
|
auto initializer = fieldDef->GetInitializer();
|
||||||
|
|
||||||
|
if (fieldInst->IsAppendedObject())
|
||||||
|
{
|
||||||
|
UpdateSrcPos(fieldDef->GetNameNode());
|
||||||
|
AppendedObjectInit(fieldInst);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (initializer == NULL)
|
if (initializer == NULL)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -17819,7 +17992,12 @@ void BfModule::EmitCtorBody(bool& skipBody)
|
||||||
if ((wantType != NULL) &&
|
if ((wantType != NULL) &&
|
||||||
((wantType->IsVar()) || (wantType->IsLet()) || (wantType->IsRef())))
|
((wantType->IsVar()) || (wantType->IsLet()) || (wantType->IsRef())))
|
||||||
wantType = NULL;
|
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;
|
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)
|
void BfModule::EmitGCMarkValue(BfTypedValue markVal, BfModuleMethodInstance markFromGCThreadMethodInstance)
|
||||||
{
|
{
|
||||||
auto fieldType = markVal.mType;
|
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())
|
if (checkType->IsComposite())
|
||||||
PopulateType(checkType, BfPopulateType_Data);
|
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);
|
markValue = BfTypedValue(mBfIRBuilder->CreateBitCast(offsetValue, mBfIRBuilder->MapType(memberPtrType)), memberType, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitGCMarkValue(markValue, markFromGCThreadMethodInstance);
|
if (isAppendObject)
|
||||||
|
EmitGCMarkAppended(markValue);
|
||||||
|
else
|
||||||
|
EmitGCMarkValue(markValue, markFromGCThreadMethodInstance);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19219,7 +19415,8 @@ void BfModule::EmitGCMarkValue(BfTypedValue& thisValue, BfType* checkType, int m
|
||||||
if ((fieldDef->mDeclaringType->mTypeDeclaration != methodDef->mDeclaringType->mTypeDeclaration))
|
if ((fieldDef->mDeclaringType->mTypeDeclaration != methodDef->mDeclaringType->mTypeDeclaration))
|
||||||
continue;
|
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))
|
if ((typeInstance->mBaseType != NULL) && (typeInstance->mBaseType != mContext->mBfObjectType))
|
||||||
|
@ -19373,11 +19570,25 @@ void BfModule::EmitGCMarkMembers()
|
||||||
}
|
}
|
||||||
else if (!fieldDef->mIsStatic)
|
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)
|
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;
|
int curSize = mCurTypeInstance->mInstSize;
|
||||||
if (curSize > prevSize)
|
if (curSize > prevSize)
|
||||||
{
|
{
|
||||||
auto int8PtrType = CreatePointerType(GetPrimitiveType(BfTypeCode_Int8));
|
|
||||||
auto int8PtrVal = mBfIRBuilder->CreateBitCast(thisVal.mValue, mBfIRBuilder->MapType(int8PtrType));
|
auto int8PtrVal = mBfIRBuilder->CreateBitCast(thisVal.mValue, mBfIRBuilder->MapType(int8PtrType));
|
||||||
int8PtrVal = mBfIRBuilder->CreateInBoundsGEP(int8PtrVal, GetConstValue(prevSize));
|
int8PtrVal = mBfIRBuilder->CreateInBoundsGEP(int8PtrVal, GetConstValue(prevSize));
|
||||||
mBfIRBuilder->CreateMemSet(int8PtrVal, GetConstValue8(0), GetConstValue(curSize - prevSize), GetConstValue(mCurTypeInstance->mInstAlign));
|
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;
|
skipUpdateSrcPos = true;
|
||||||
}
|
}
|
||||||
else if (((methodDef->mMethodType == BfMethodType_Ctor) || (methodDef->mMethodType == BfMethodType_CtorNoBody)) && (!hasExternSpecifier))
|
else if (((methodDef->mMethodType == BfMethodType_Ctor) || (methodDef->mMethodType == BfMethodType_CtorNoBody)) && (!hasExternSpecifier))
|
||||||
|
|
|
@ -88,6 +88,7 @@ enum BfEvalExprFlags
|
||||||
BfEvalExprFlags_FromConversionOp_Explicit = 0x10000000,
|
BfEvalExprFlags_FromConversionOp_Explicit = 0x10000000,
|
||||||
BfEvalExprFlags_AllowGenericConstValue = 0x20000000,
|
BfEvalExprFlags_AllowGenericConstValue = 0x20000000,
|
||||||
BfEvalExprFlags_IsExpressionBody = 0x40000000,
|
BfEvalExprFlags_IsExpressionBody = 0x40000000,
|
||||||
|
BfEvalExprFlags_AppendFieldInitializer = 0x80000000,
|
||||||
|
|
||||||
BfEvalExprFlags_InheritFlags = BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_Comptime | BfEvalExprFlags_DeclType
|
BfEvalExprFlags_InheritFlags = BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_Comptime | BfEvalExprFlags_DeclType
|
||||||
};
|
};
|
||||||
|
@ -919,11 +920,13 @@ class BfConstResolveState
|
||||||
public:
|
public:
|
||||||
BfMethodInstance* mMethodInstance;
|
BfMethodInstance* mMethodInstance;
|
||||||
BfConstResolveState* mPrevConstResolveState;
|
BfConstResolveState* mPrevConstResolveState;
|
||||||
|
bool mInCalcAppend;
|
||||||
|
|
||||||
BfConstResolveState()
|
BfConstResolveState()
|
||||||
{
|
{
|
||||||
mMethodInstance = NULL;
|
mMethodInstance = NULL;
|
||||||
mPrevConstResolveState = NULL;
|
mPrevConstResolveState = NULL;
|
||||||
|
mInCalcAppend = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1840,6 +1843,7 @@ public:
|
||||||
void CreateStaticField(BfFieldInstance* fieldInstance, bool isThreadLocal = false);
|
void CreateStaticField(BfFieldInstance* fieldInstance, bool isThreadLocal = false);
|
||||||
void ResolveConstField(BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfFieldDef* field, bool forceResolve = 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);
|
BfTypedValue GetFieldInitializerValue(BfFieldInstance* fieldInstance, BfExpression* initializer = NULL, BfFieldDef* fieldDef = NULL, BfType* fieldType = NULL, bool doStore = false);
|
||||||
|
void AppendedObjectInit(BfFieldInstance* fieldInstance);
|
||||||
void MarkFieldInitialized(BfFieldInstance* fieldInstance);
|
void MarkFieldInitialized(BfFieldInstance* fieldInstance);
|
||||||
bool IsThreadLocal(BfFieldInstance* fieldInstance);
|
bool IsThreadLocal(BfFieldInstance* fieldInstance);
|
||||||
BfType* ResolveVarFieldType(BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfFieldDef* field);
|
BfType* ResolveVarFieldType(BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfFieldDef* field);
|
||||||
|
@ -1967,7 +1971,7 @@ public:
|
||||||
void AddMethodToWorkList(BfMethodInstance* methodInstance);
|
void AddMethodToWorkList(BfMethodInstance* methodInstance);
|
||||||
bool IsInterestedInMethod(BfTypeInstance* typeInstance, BfMethodDef* methodDef);
|
bool IsInterestedInMethod(BfTypeInstance* typeInstance, BfMethodDef* methodDef);
|
||||||
void CalcAppendAlign(BfMethodInstance* methodInst);
|
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);
|
BfTypedValue CallBaseCtorCalc(bool constOnly);
|
||||||
void EmitCtorCalcAppend();
|
void EmitCtorCalcAppend();
|
||||||
void CreateStaticCtor();
|
void CreateStaticCtor();
|
||||||
|
@ -1980,7 +1984,8 @@ public:
|
||||||
void EmitDtorBody();
|
void EmitDtorBody();
|
||||||
void EmitEnumToStringBody();
|
void EmitEnumToStringBody();
|
||||||
void EmitTupleToStringBody();
|
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 EmitGCMarkValue(BfTypedValue markVal, BfModuleMethodInstance markFromGCThreadMethodInstance);
|
||||||
void EmitGCMarkMembers();
|
void EmitGCMarkMembers();
|
||||||
void EmitGCFindTLSMembers();
|
void EmitGCFindTLSMembers();
|
||||||
|
|
|
@ -820,6 +820,9 @@ void BfModule::InitType(BfType* resolvedTypeRef, BfPopulateType populateType)
|
||||||
void BfModule::AddFieldDependency(BfTypeInstance* typeInstance, BfFieldInstance* fieldInstance, BfType* fieldType)
|
void BfModule::AddFieldDependency(BfTypeInstance* typeInstance, BfFieldInstance* fieldInstance, BfType* fieldType)
|
||||||
{
|
{
|
||||||
auto depFlag = fieldType->IsValueType() ? BfDependencyMap::DependencyFlag_ValueTypeMemberData : BfDependencyMap::DependencyFlag_PtrMemberData;
|
auto depFlag = fieldType->IsValueType() ? BfDependencyMap::DependencyFlag_ValueTypeMemberData : BfDependencyMap::DependencyFlag_PtrMemberData;
|
||||||
|
if (fieldInstance->IsAppendedObject())
|
||||||
|
depFlag = BfDependencyMap::DependencyFlag_ValueTypeMemberData;
|
||||||
|
|
||||||
AddDependency(fieldType, typeInstance, depFlag);
|
AddDependency(fieldType, typeInstance, depFlag);
|
||||||
|
|
||||||
if ((fieldType->IsStruct()) && (fieldType->IsGenericTypeInstance()))
|
if ((fieldType->IsStruct()) && (fieldType->IsGenericTypeInstance()))
|
||||||
|
@ -4565,6 +4568,12 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
||||||
|
|
||||||
auto initializer = field->GetInitializer();
|
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 (field->IsEnumCaseEntry())
|
||||||
{
|
{
|
||||||
if (typeInstance->IsEnum())
|
if (typeInstance->IsEnum())
|
||||||
|
@ -5109,6 +5118,83 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
||||||
|
|
||||||
int dataSize = resolvedFieldType->mSize;
|
int dataSize = resolvedFieldType->mSize;
|
||||||
int alignSize = resolvedFieldType->mAlign;
|
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;
|
fieldInstance->mDataSize = dataSize;
|
||||||
if (!isUnion)
|
if (!isUnion)
|
||||||
{
|
{
|
||||||
|
@ -5244,7 +5330,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
||||||
alignBuckets[alignBits].RemoveAt(0);
|
alignBuckets[alignBits].RemoveAt(0);
|
||||||
dataFieldVec.push_back(fieldInst);
|
dataFieldVec.push_back(fieldInst);
|
||||||
curSize = BF_ALIGN(curSize, fieldInst->GetAlign(packing));
|
curSize = BF_ALIGN(curSize, fieldInst->GetAlign(packing));
|
||||||
curSize += fieldInst->mResolvedType->mSize;
|
curSize += fieldInst->mDataSize;
|
||||||
foundEntry = true;
|
foundEntry = true;
|
||||||
|
|
||||||
if (!isHighestBucket)
|
if (!isHighestBucket)
|
||||||
|
@ -5265,7 +5351,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
||||||
alignBuckets[alignBits].RemoveAt(0);
|
alignBuckets[alignBits].RemoveAt(0);
|
||||||
dataFieldVec.push_back(fieldInst);
|
dataFieldVec.push_back(fieldInst);
|
||||||
curSize = BF_ALIGN(curSize, fieldInst->GetAlign(packing));
|
curSize = BF_ALIGN(curSize, fieldInst->GetAlign(packing));
|
||||||
curSize += fieldInst->mResolvedType->mSize;
|
curSize += fieldInst->mDataSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5281,9 +5367,12 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
|
||||||
auto resolvedFieldType = fieldInstance->GetResolvedType();
|
auto resolvedFieldType = fieldInstance->GetResolvedType();
|
||||||
|
|
||||||
BF_ASSERT(resolvedFieldType->mSize >= 0);
|
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);
|
int alignSize = fieldInstance->GetAlign(packing);
|
||||||
fieldInstance->mDataSize = dataSize;
|
|
||||||
|
|
||||||
int nextDataPos = dataPos;
|
int nextDataPos = dataPos;
|
||||||
nextDataPos = (dataPos + (alignSize - 1)) & ~(alignSize - 1);
|
nextDataPos = (dataPos + (alignSize - 1)) & ~(alignSize - 1);
|
||||||
|
|
|
@ -6319,6 +6319,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, bool declStarted, i
|
||||||
case BfToken_Override:
|
case BfToken_Override:
|
||||||
case BfToken_Abstract:
|
case BfToken_Abstract:
|
||||||
case BfToken_Concrete:
|
case BfToken_Concrete:
|
||||||
|
case BfToken_Append:
|
||||||
case BfToken_Extern:
|
case BfToken_Extern:
|
||||||
case BfToken_New:
|
case BfToken_New:
|
||||||
case BfToken_Implicit:
|
case BfToken_Implicit:
|
||||||
|
@ -6575,6 +6576,30 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, bool declStarted, i
|
||||||
|
|
||||||
if (token == BfToken_Extern)
|
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);
|
MEMBER_SET(fieldDecl, mExternSpecifier, tokenNode);
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -498,6 +498,8 @@ void BfFieldInstance::GetDataRange(int& dataIdx, int& dataCount)
|
||||||
int BfFieldInstance::GetAlign(int packing)
|
int BfFieldInstance::GetAlign(int packing)
|
||||||
{
|
{
|
||||||
int align = mResolvedType->mAlign;
|
int align = mResolvedType->mAlign;
|
||||||
|
if (IsAppendedObject())
|
||||||
|
align = mResolvedType->ToTypeInstance()->mInstAlign;
|
||||||
if (packing > 0)
|
if (packing > 0)
|
||||||
align = BF_MIN(align, packing);
|
align = BF_MIN(align, packing);
|
||||||
if (mCustomAttributes != NULL)
|
if (mCustomAttributes != NULL)
|
||||||
|
@ -528,6 +530,12 @@ int BfFieldInstance::GetAlign(int packing)
|
||||||
return align;
|
return align;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BfFieldInstance::IsAppendedObject()
|
||||||
|
{
|
||||||
|
auto fieldDef = GetFieldDef();
|
||||||
|
return (fieldDef != NULL) && (fieldDef->mIsAppend) && (mResolvedType->IsObject()) && (mOwner->IsObject());
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int64 BfDeferredMethodCallData::GenerateMethodId(BfModule* module, int64 methodId)
|
int64 BfDeferredMethodCallData::GenerateMethodId(BfModule* module, int64 methodId)
|
||||||
|
|
|
@ -1469,6 +1469,7 @@ public:
|
||||||
void SetResolvedType(BfType* type);
|
void SetResolvedType(BfType* type);
|
||||||
void GetDataRange(int& dataIdx, int& dataCount);
|
void GetDataRange(int& dataIdx, int& dataCount);
|
||||||
int GetAlign(int packing);
|
int GetAlign(int packing);
|
||||||
|
bool IsAppendedObject();
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BfMethodRefKind
|
enum BfMethodRefKind
|
||||||
|
|
|
@ -1929,6 +1929,13 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD
|
||||||
BfLocalVariable* localVar = AddLocalVariableDef(localDef, true, false, BfIRValue(), initType);
|
BfLocalVariable* localVar = AddLocalVariableDef(localDef, true, false, BfIRValue(), initType);
|
||||||
if (wantsStore)
|
if (wantsStore)
|
||||||
mBfIRBuilder->CreateAlignedStore(initValue.mValue, localVar->mAddr, localVar->mResolvedType->mAlign);
|
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;
|
return localVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -610,6 +610,7 @@ public:
|
||||||
bool mIsInline;
|
bool mIsInline;
|
||||||
bool mIsVolatile;
|
bool mIsVolatile;
|
||||||
bool mIsExtern;
|
bool mIsExtern;
|
||||||
|
bool mIsAppend;
|
||||||
bool mIsProperty;
|
bool mIsProperty;
|
||||||
BfAstNode* mFieldDeclaration;
|
BfAstNode* mFieldDeclaration;
|
||||||
// It may seem that fields and properties don't need a 'mNextWithSameName', but with extensions it's possible
|
// 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;
|
mUsingProtection = BfProtection_Hidden;
|
||||||
mIsInline = false;
|
mIsInline = false;
|
||||||
mIsExtern = false;
|
mIsExtern = false;
|
||||||
|
mIsAppend = false;
|
||||||
mIsVolatile = false;
|
mIsVolatile = false;
|
||||||
mIsProperty = false;
|
mIsProperty = false;
|
||||||
mFieldDeclaration = NULL;
|
mFieldDeclaration = NULL;
|
||||||
|
@ -1680,7 +1682,8 @@ enum BfFieldFlags
|
||||||
BfFieldFlags_EnumPayload = 0x100,
|
BfFieldFlags_EnumPayload = 0x100,
|
||||||
BfFieldFlags_EnumDiscriminator = 0x200,
|
BfFieldFlags_EnumDiscriminator = 0x200,
|
||||||
BfFieldFlags_EnumCase = 0x400,
|
BfFieldFlags_EnumCase = 0x400,
|
||||||
BfFieldFlags_ReadOnly = 0x800
|
BfFieldFlags_ReadOnly = 0x800,
|
||||||
|
BfFieldFlags_Appended = 0x1000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BfReflectKind
|
enum BfReflectKind
|
||||||
|
|
|
@ -5667,6 +5667,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
|
||||||
Fail(_GetCurFrame(), "Array out of bounds");
|
Fail(_GetCurFrame(), "Array out of bounds");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else if (checkFunction->mFunctionKind == CeFunctionKind_OOB)
|
||||||
|
{
|
||||||
|
Fail(_GetCurFrame(), "Object not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
else if (checkFunction->mFunctionKind == CeFunctionKind_Malloc)
|
else if (checkFunction->mFunctionKind == CeFunctionKind_Malloc)
|
||||||
{
|
{
|
||||||
int64 size;
|
int64 size;
|
||||||
|
@ -9340,6 +9345,8 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction)
|
||||||
{
|
{
|
||||||
if (methodDef->mName == "ThrowIndexOutOfRange")
|
if (methodDef->mName == "ThrowIndexOutOfRange")
|
||||||
ceFunction->mFunctionKind = CeFunctionKind_OOB;
|
ceFunction->mFunctionKind = CeFunctionKind_OOB;
|
||||||
|
else if (methodDef->mName == "ThrowObjectNotInitialized")
|
||||||
|
ceFunction->mFunctionKind = CeFunctionKind_ObjectNotInitialized;
|
||||||
else if (methodDef->mName == "FatalError")
|
else if (methodDef->mName == "FatalError")
|
||||||
ceFunction->mFunctionKind = CeFunctionKind_FatalError;
|
ceFunction->mFunctionKind = CeFunctionKind_FatalError;
|
||||||
else if (methodDef->mName == "Dbg_RawAlloc")
|
else if (methodDef->mName == "Dbg_RawAlloc")
|
||||||
|
|
|
@ -422,6 +422,7 @@ enum CeFunctionKind
|
||||||
CeFunctionKind_Normal,
|
CeFunctionKind_Normal,
|
||||||
CeFunctionKind_Extern,
|
CeFunctionKind_Extern,
|
||||||
CeFunctionKind_OOB,
|
CeFunctionKind_OOB,
|
||||||
|
CeFunctionKind_ObjectNotInitialized,
|
||||||
CeFunctionKind_Malloc,
|
CeFunctionKind_Malloc,
|
||||||
CeFunctionKind_Free,
|
CeFunctionKind_Free,
|
||||||
CeFunctionKind_DynCheckFailed,
|
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)
|
static void CheckData(Object obj, int lastAllocSize, uint8[] data)
|
||||||
{
|
{
|
||||||
int objSize = typeof(Object).InstanceSize;
|
int objSize = typeof(Object).InstanceSize;
|
||||||
|
@ -110,6 +117,17 @@ namespace Tests
|
||||||
0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10
|
0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10
|
||||||
));
|
));
|
||||||
delete:trackedAlloc ce;
|
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