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:
parent
2dcc9552e2
commit
a34e5a737d
10 changed files with 222 additions and 9 deletions
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable 168
|
||||
|
||||
using System;
|
||||
|
||||
namespace Tests
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue