1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-09 20:12:21 +02:00

Improved boxed value support in attribute data

This commit is contained in:
Brian Fiete 2023-10-10 10:36:04 -07:00
parent 2dcc9552e2
commit a34e5a737d
10 changed files with 222 additions and 9 deletions

View file

@ -1,8 +1,13 @@
using System.Collections;
using System.Threading;
namespace System.Reflection
{
class AttributeInfo
{
static Monitor sBoxedMonitor = new .() ~ delete _;
static Dictionary<void*, Object> sBoxedValues = new .() ~ DeleteDictionaryAndValues!(_);
static mixin Decode<T2>(void* data)
{
*((*(T2**)&data)++)
@ -99,7 +104,23 @@ namespace System.Reflection
case (TypeCode)typeof(TypeCode).MaxValue + 9: //BfConstType_TypeOf
let argTypeId = Decode!<int32>(data);
args[argIdx] = Type.[Friend]GetType((.)argTypeId);
case (TypeCode)255:
case (TypeCode)typeof(TypeCode).MaxValue + 18: // BfConstType_Box
let boxedTypeId = Decode!<int32>(data);
var boxedType = Type.[Friend]GetType_(boxedTypeId);
int dataSize = boxedType.InstanceSize - boxedType.[Friend]mMemberDataOffset;
using (sBoxedMonitor.Enter())
{
if (sBoxedValues.TryAdd(data, var keyPtr, var valuePtr))
{
Object boxedValue = boxedType.CreateObject().Value;
void* boxedDataPtr = (uint8*)Internal.UnsafeCastToPtr(boxedValue) + boxedType.[Friend]mMemberDataOffset;
Internal.MemCpy(boxedDataPtr, data, dataSize);
*valuePtr = boxedValue;
}
args[argIdx] = *valuePtr;
}
data = (uint8*)data + dataSize;
case (TypeCode)255: // String
let stringId = Decode!<int32>(data);
String str = String.[Friend]sIdStringLiterals[stringId];
args[argIdx] = str;
@ -195,6 +216,22 @@ namespace System.Reflection
case (TypeCode)typeof(TypeCode).MaxValue + 9: //BfConstType_TypeOf
let argTypeId = AttributeInfo.Decode!<int32>(mData);
args[argIdx] = Variant.Create(Type.[Friend]GetType((.)argTypeId));
case (TypeCode)typeof(TypeCode).MaxValue + 18: // BfConstType_Box
let boxedTypeId = AttributeInfo.Decode!<int32>(mData);
var boxedType = Type.[Friend]GetType_(boxedTypeId);
int dataSize = boxedType.InstanceSize - boxedType.[Friend]mMemberDataOffset;
using (sBoxedMonitor.Enter())
{
if (sBoxedValues.TryAdd(mData, var keyPtr, var valuePtr))
{
Object boxedValue = boxedType.CreateObject().Value;
void* boxedDataPtr = (uint8*)Internal.UnsafeCastToPtr(boxedValue) + boxedType.[Friend]mMemberDataOffset;
Internal.MemCpy(boxedDataPtr, mData, dataSize);
*valuePtr = boxedValue;
}
args[argIdx] = Variant.Create(*valuePtr);
}
mData = (uint8*)mData + dataSize;
case (TypeCode)255:
let stringId = AttributeInfo.Decode!<int32>(mData);
String str = String.[Friend]sIdStringLiterals[stringId];

View file

@ -312,7 +312,7 @@ namespace System.Reflection
mixin AddArg(int argIdx, var arg, void* argPtr, Type paramType, bool splat)
{
var argType = arg.VariantType;
var argType = arg.RawVariantType;
void* dataPtr = arg.DataPtr;
bool isPtrToPtr = false;
bool isValid = true;

View file

@ -1003,7 +1003,7 @@ namespace System.Reflection
public override bool IsSubtypeOf(Type checkBaseType)
{
TypeInstance curType = this;
if (curType.IsBoxed)
if ((curType.IsBoxed) && (checkBaseType.IsValueType))
{
curType = curType.UnderlyingType as TypeInstance;
if (curType == null)

View file

@ -71,6 +71,22 @@ namespace System
}
}
public Type RawVariantType
{
get
{
if (mStructType == 2)
{
return (Type)Internal.UnsafeCastToObject((void*)mData);
}
if (mStructType <= 1)
{
return Internal.UnsafeCastToObject((void*)mData).[Friend]RawGetType();
}
return (Type)Internal.UnsafeCastToObject((void*)(mStructType & ~3));
}
}
public bool HasValue
{
get

View file

@ -167,7 +167,7 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
}
else
{
mResult = mModule->Cast(expr, mResult, wantType, (BfCastFlags)(BfCastFlags_NoConversionOperator | (explicitCast ? BfCastFlags_Explicit : BfCastFlags_None)));
mResult = mModule->Cast(expr, mResult, wantType, (BfCastFlags)(BfCastFlags_WantsConst | BfCastFlags_NoConversionOperator | (explicitCast ? BfCastFlags_Explicit : BfCastFlags_None)));
}
}
@ -393,7 +393,7 @@ bool BfConstResolver::PrepareMethodArguments(BfAstNode* targetSrc, BfMethodMatch
if (argExpr != NULL)
{
argValue = mModule->Cast(argExpr, argValue, wantType);
argValue = mModule->Cast(argExpr, argValue, wantType, (BfCastFlags)(BfCastFlags_WantsConst | BfCastFlags_NoConversionOperator));
if (!argValue)
return false;
}

View file

@ -963,7 +963,17 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
ptrToInt->mToType = fromPtrToInt->mToType;
copiedConst = (BfConstant*)ptrToInt;
}
else if (fromConst->mConstType == BfConstType_Box)
{
auto fromBox = (BfConstantBox*)fromConst;
auto fromTarget = fromHolder->GetConstantById(fromBox->mTarget);
auto copiedTarget = CreateConst(fromTarget, fromHolder);
auto box = mTempAlloc.Alloc<BfConstantBox>();
box->mConstType = BfConstType_Box;
box->mTarget = copiedTarget.mId;
box->mToType = fromBox->mToType;
copiedConst = (BfConstant*)box;
}
else
{
BF_FATAL("not handled");

View file

@ -5729,6 +5729,49 @@ void BfModule::EncodeAttributeData(BfTypeInstance* typeInstance, BfType* argType
for (int i = 0; i < argType->mSize; i++)
data.Add(0);
}
else if (constant->mConstType == BfConstType_Box)
{
auto box = (BfConstantBox*)constant;
PUSH_INT32(box->mToType.mId);
BfType* resultType = NULL;
if (box->mToType.mKind == BfIRTypeData::TypeKind_TypeId)
resultType = mContext->FindTypeById(box->mToType.mId);
if ((resultType != NULL) && (resultType->IsBoxed()))
{
auto boxedType = (BfBoxedType*)resultType;
int dataOffset = 0;
if (!boxedType->mFieldInstances.IsEmpty())
dataOffset = BF_MAX(boxedType->mFieldInstances.back().mDataOffset, 0);
int dataSize = boxedType->mInstSize - dataOffset;
for (int i = 0; i < dataSize; i++)
data.Add(0);
typeInstance->mConstHolder->WriteConstant(BfIRValue(BfIRValueFlags_Const, box->mTarget), &data[data.mSize - dataSize], boxedType->GetUnderlyingType());
return;
}
//int dataOffset =
//mBfIRBuilder->WriteConstant()
// BfType* resultType = NULL;
// if (box->mToType.mKind == BfIRTypeData::TypeKind_TypeId)
// resultType = mContext->FindTypeById(box->mToType.mId);
//
// if ((resultType != NULL) && (resultType->IsBoxed()))
// {
// auto boxedType = (BfBoxedType*)resultType;
// EncodeAttributeData(typeInstance, boxedType->GetUnderlyingType(), BfIRValue(BfIRValueFlags_Const, box->mTarget), data, usedStringIdMap);
// return;
// }
Fail(StrFormat("Unhandled constant box in '%s'", TypeToString(typeInstance).c_str()));
}
// else if (constant->mConstType == BfConstType_Agg)
// {
@ -5995,6 +6038,8 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
{
BF_ASSERT((type->mDefineState >= BfTypeDefineState_DefinedAndMethodsSlotted) || mIsComptimeModule);
typeCode = typeInstance->mTypeDef->mTypeCode;
if (typeInstance->IsBoxed())
typeCode = BfTypeCode_Object;
}
else if (type->IsPrimitiveType())
{
@ -11639,7 +11684,7 @@ void BfModule::CurrentAddToConstHolder(BfIRValue& irVal)
{
auto bitcast = (BfConstantBitCast*)constant;
BfIRValue newVal;
if (bitcast->mTarget)
if (constant->mConstType == BfConstType_BitCast)
{
newVal = BfIRValue(BfIRValueFlags_Const, bitcast->mTarget);
CurrentAddToConstHolder(newVal);
@ -11782,12 +11827,13 @@ BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* con
{
if (!allowUnactualized)
{
if ((wantType->IsInstanceOf(mCompiler->mStringTypeDef)) ||
if ((wantType == NULL) ||
(wantType->IsInstanceOf(mCompiler->mStringTypeDef)) ||
((wantType->IsPointer()) && (wantType->GetUnderlyingType() == GetPrimitiveType(BfTypeCode_Char8))))
{
const StringImpl& str = mContext->mStringObjectIdMap[constant->mInt32].mString;
BfIRValue stringObjConst = GetStringObjectValue(str, false, true);
if (wantType->IsPointer())
if ((wantType != NULL) && (wantType->IsPointer()))
return GetStringCharPtr(stringObjConst, true);
return stringObjConst;
}

View file

@ -4817,6 +4817,47 @@ BfIRValue CeContext::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType
return module->CreateTypeDataRef(module->mContext->mTypes[typeId]);
}
if (typeInst == module->mContext->mBfObjectType)
{
// Allow boxing
CE_CREATECONST_CHECKPTR(instData, ceModule->mSystem->mPtrSize);
addr_ce typeId = *(int*)(instData);
BfType* type = GetBfType(typeId);
if (type->IsInstanceOf(mCeMachine->mCompiler->mStringTypeDef))
{
return CreateConstant(module, ptr, type, outType);
}
else if (type->IsBoxed())
{
auto underlyingType = type->GetUnderlyingType();
module->PopulateType(type);
auto boxedType = (BfBoxedType*)type;
int dataOffset = boxedType->mFieldInstances.back().mDataOffset;
auto origValue = CreateConstant(module, ptr + dataOffset, underlyingType, outType);
if (origValue)
{
if (outType != NULL)
*outType = typeInst;
return irBuilder->CreateConstBox(origValue, irBuilder->MapType(boxedType));
}
}
// else if (type->IsValueType())
// {
// auto origValue = CreateConstant(module, ptr, type, outType);
// if (origValue)
// {
// auto boxedType = module->CreateBoxedType(type);
// irBuilder->PopulateType(boxedType);
// return irBuilder->CreateConstBox(origValue, irBuilder->MapType(boxedType));
// }
// }
}
if (typeInst->IsObjectOrInterface())
{
Fail(StrFormat("Reference type '%s' return value not allowed", module->TypeToString(typeInst).c_str()));

View file

@ -1,3 +1,5 @@
#pragma warning disable 168
using System;
namespace Tests

View file

@ -213,6 +213,43 @@ namespace Tests
}
}
[AttributeUsage(.Field, .ReflectAttribute)]
struct OptionAttribute : Attribute, IOnFieldInit
{
public Object mDefaultValue;
public String mShortName;
public String mLongName;
public this(Object defaultValue, String shortName, String longName)
{
mDefaultValue = defaultValue;
mShortName = shortName;
mLongName = longName;
}
public void OnFieldInit(FieldInfo fieldInfo, Self* prev)
{
if (mDefaultValue != null)
{
Type defaultType = mDefaultValue.GetType();
if (defaultType.IsBoxed)
defaultType = defaultType.UnderlyingType;
if ((defaultType == fieldInfo.FieldType) || (defaultType.UnderlyingType == fieldInfo.FieldType))
return;
Runtime.FatalError(scope $"Default value type mismatch. Expected {fieldInfo.FieldType.GetFullName(.. scope .())} but got {defaultType.GetFullName(.. scope .())}");
}
}
}
class ClassF
{
[Option("123", "Short", "Long")]
String mStr;
[Option((int32)123, "Short", "Long")]
int32 mInt;
}
[Test]
static void TestTypes()
{
@ -372,6 +409,30 @@ namespace Tests
methodIdx++;
}
for (var fieldInfo in typeof(ClassF).GetFields())
{
int idx = @fieldInfo.Index;
var oa = fieldInfo.GetCustomAttribute<OptionAttribute>().Value;
void TestOA()
{
switch (idx)
{
case 0:
Test.Assert(oa.mDefaultValue == "123");
case 1:
Test.Assert(oa.mDefaultValue == (int32)123);
}
}
TestOA();
for (var option in fieldInfo.GetCustomAttributes())
{
oa = option.Get<OptionAttribute>();
TestOA();
}
}
}
[Test]