1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 04:22:20 +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.Collections;
using System.Threading;
namespace System.Reflection namespace System.Reflection
{ {
class AttributeInfo class AttributeInfo
{ {
static Monitor sBoxedMonitor = new .() ~ delete _;
static Dictionary<void*, Object> sBoxedValues = new .() ~ DeleteDictionaryAndValues!(_);
static mixin Decode<T2>(void* data) static mixin Decode<T2>(void* data)
{ {
*((*(T2**)&data)++) *((*(T2**)&data)++)
@ -99,7 +104,23 @@ namespace System.Reflection
case (TypeCode)typeof(TypeCode).MaxValue + 9: //BfConstType_TypeOf case (TypeCode)typeof(TypeCode).MaxValue + 9: //BfConstType_TypeOf
let argTypeId = Decode!<int32>(data); let argTypeId = Decode!<int32>(data);
args[argIdx] = Type.[Friend]GetType((.)argTypeId); 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); let stringId = Decode!<int32>(data);
String str = String.[Friend]sIdStringLiterals[stringId]; String str = String.[Friend]sIdStringLiterals[stringId];
args[argIdx] = str; args[argIdx] = str;
@ -195,6 +216,22 @@ namespace System.Reflection
case (TypeCode)typeof(TypeCode).MaxValue + 9: //BfConstType_TypeOf case (TypeCode)typeof(TypeCode).MaxValue + 9: //BfConstType_TypeOf
let argTypeId = AttributeInfo.Decode!<int32>(mData); let argTypeId = AttributeInfo.Decode!<int32>(mData);
args[argIdx] = Variant.Create(Type.[Friend]GetType((.)argTypeId)); 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: case (TypeCode)255:
let stringId = AttributeInfo.Decode!<int32>(mData); let stringId = AttributeInfo.Decode!<int32>(mData);
String str = String.[Friend]sIdStringLiterals[stringId]; 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) mixin AddArg(int argIdx, var arg, void* argPtr, Type paramType, bool splat)
{ {
var argType = arg.VariantType; var argType = arg.RawVariantType;
void* dataPtr = arg.DataPtr; void* dataPtr = arg.DataPtr;
bool isPtrToPtr = false; bool isPtrToPtr = false;
bool isValid = true; bool isValid = true;

View file

@ -1003,7 +1003,7 @@ namespace System.Reflection
public override bool IsSubtypeOf(Type checkBaseType) public override bool IsSubtypeOf(Type checkBaseType)
{ {
TypeInstance curType = this; TypeInstance curType = this;
if (curType.IsBoxed) if ((curType.IsBoxed) && (checkBaseType.IsValueType))
{ {
curType = curType.UnderlyingType as TypeInstance; curType = curType.UnderlyingType as TypeInstance;
if (curType == null) 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 public bool HasValue
{ {
get get

View file

@ -167,7 +167,7 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
} }
else 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) if (argExpr != NULL)
{ {
argValue = mModule->Cast(argExpr, argValue, wantType); argValue = mModule->Cast(argExpr, argValue, wantType, (BfCastFlags)(BfCastFlags_WantsConst | BfCastFlags_NoConversionOperator));
if (!argValue) if (!argValue)
return false; return false;
} }

View file

@ -963,7 +963,17 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
ptrToInt->mToType = fromPtrToInt->mToType; ptrToInt->mToType = fromPtrToInt->mToType;
copiedConst = (BfConstant*)ptrToInt; 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 else
{ {
BF_FATAL("not handled"); 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++) for (int i = 0; i < argType->mSize; i++)
data.Add(0); 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) // 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); BF_ASSERT((type->mDefineState >= BfTypeDefineState_DefinedAndMethodsSlotted) || mIsComptimeModule);
typeCode = typeInstance->mTypeDef->mTypeCode; typeCode = typeInstance->mTypeDef->mTypeCode;
if (typeInstance->IsBoxed())
typeCode = BfTypeCode_Object;
} }
else if (type->IsPrimitiveType()) else if (type->IsPrimitiveType())
{ {
@ -11639,7 +11684,7 @@ void BfModule::CurrentAddToConstHolder(BfIRValue& irVal)
{ {
auto bitcast = (BfConstantBitCast*)constant; auto bitcast = (BfConstantBitCast*)constant;
BfIRValue newVal; BfIRValue newVal;
if (bitcast->mTarget) if (constant->mConstType == BfConstType_BitCast)
{ {
newVal = BfIRValue(BfIRValueFlags_Const, bitcast->mTarget); newVal = BfIRValue(BfIRValueFlags_Const, bitcast->mTarget);
CurrentAddToConstHolder(newVal); CurrentAddToConstHolder(newVal);
@ -11782,12 +11827,13 @@ BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* con
{ {
if (!allowUnactualized) if (!allowUnactualized)
{ {
if ((wantType->IsInstanceOf(mCompiler->mStringTypeDef)) || if ((wantType == NULL) ||
(wantType->IsInstanceOf(mCompiler->mStringTypeDef)) ||
((wantType->IsPointer()) && (wantType->GetUnderlyingType() == GetPrimitiveType(BfTypeCode_Char8)))) ((wantType->IsPointer()) && (wantType->GetUnderlyingType() == GetPrimitiveType(BfTypeCode_Char8))))
{ {
const StringImpl& str = mContext->mStringObjectIdMap[constant->mInt32].mString; const StringImpl& str = mContext->mStringObjectIdMap[constant->mInt32].mString;
BfIRValue stringObjConst = GetStringObjectValue(str, false, true); BfIRValue stringObjConst = GetStringObjectValue(str, false, true);
if (wantType->IsPointer()) if ((wantType != NULL) && (wantType->IsPointer()))
return GetStringCharPtr(stringObjConst, true); return GetStringCharPtr(stringObjConst, true);
return stringObjConst; return stringObjConst;
} }

View file

@ -4817,6 +4817,47 @@ BfIRValue CeContext::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType
return module->CreateTypeDataRef(module->mContext->mTypes[typeId]); 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()) if (typeInst->IsObjectOrInterface())
{ {
Fail(StrFormat("Reference type '%s' return value not allowed", module->TypeToString(typeInst).c_str())); 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; using System;
namespace Tests 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] [Test]
static void TestTypes() static void TestTypes()
{ {
@ -372,6 +409,30 @@ namespace Tests
methodIdx++; 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] [Test]