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