1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Comptime method reflection, method entry/exit emission

This commit is contained in:
Brian Fiete 2021-01-13 05:09:09 -08:00
parent bc8758bbac
commit 8f3060fd3c
18 changed files with 944 additions and 117 deletions

View file

@ -1,3 +1,4 @@
using System.Reflection;
namespace System
{
public struct Attribute
@ -542,6 +543,6 @@ namespace System
interface IComptimeMethodApply
{
void ApplyToMethod(Type type);
void ApplyToMethod(ComptimeMethodInfo methodInfo);
}
}

View file

@ -69,7 +69,10 @@ namespace System
static extern void* Comptime_MethodBuilder_EmitStr(void* native, StringView str);
static extern void* Comptime_CreateMethod(int32 typeId, StringView methodName, Type returnType, MethodFlags methodFlags);
static extern void Comptime_EmitDefinition(int32 typeId, StringView text);
static extern void Comptime_EmitTypeBody(int32 typeId, StringView text);
static extern void Comptime_EmitMethodEntry(int64 methodHandle, StringView text);
static extern void Comptime_EmitMethodExit(int64 methodHandle, StringView text);
static extern void Comptime_EmitMixin(StringView text);
[Comptime(OnlyFromComptime=true)]
public static MethodBuilder CreateMethod(Type owner, StringView methodName, Type returnType, MethodFlags methodFlags)
@ -80,9 +83,28 @@ namespace System
}
[Comptime(OnlyFromComptime=true)]
public static void EmitDefinition(Type owner, StringView text)
public static void EmitTypeBody(Type owner, StringView text)
{
Comptime_EmitDefinition((.)owner.TypeId, text);
Comptime_EmitTypeBody((.)owner.TypeId, text);
}
[Comptime(OnlyFromComptime=true)]
public static void EmitMethodEntry(ComptimeMethodInfo methodHandle, StringView text)
{
Comptime_EmitMethodEntry(methodHandle.mNativeMethodInstance, text);
}
[Comptime(OnlyFromComptime=true)]
public static void EmitMethodExit(ComptimeMethodInfo methodHandle, StringView text)
{
Comptime_EmitMethodExit(methodHandle.mNativeMethodInstance, text);
}
[Comptime]
public static void Mixin(StringView text)
{
if (Compiler.IsComptime)
Comptime_EmitMixin(text);
}
}
}

View file

@ -0,0 +1,153 @@
using System.Diagnostics;
using System.Collections;
namespace System.Reflection
{
struct ComptimeMethodInfo
{
[CRepr, Packed]
public struct Info
{
public int32 mReturnTypeId;
public int32 mParamCount;
public MethodFlags mMethodFlags;
}
[CRepr, Packed]
public struct ParamInfo
{
public int32 mParamTypeId;
public TypeInstance.ParamFlags mParamFlags;
public String mName;
}
public int64 mNativeMethodInstance;
public bool IsInitialized => true;
public StringView Name
{
get
{
if (Compiler.IsComptime)
Type.[Friend]Comptime_Method_GetName(mNativeMethodInstance);
return "";
}
}
public int ParamCount
{
get
{
if (Compiler.IsComptime)
return Type.[Friend]Comptime_Method_GetInfo(mNativeMethodInstance).mParamCount;
return 0;
}
}
public bool IsConstructor => Name == "__BfCtor" || Name == "__BfStaticCtor";
public bool IsDestructor => Name == "__BfStaticDtor" || Name == "__BfStaticDtor";
public Type ReturnType
{
get
{
if (Compiler.IsComptime)
Type.[Friend]GetType((.)Type.[Friend]Comptime_Method_GetInfo(mNativeMethodInstance).mReturnTypeId);
return null;
}
}
public this(int64 nativeMethodInstance)
{
mNativeMethodInstance = nativeMethodInstance;
}
public Type GetParamType(int paramIdx)
{
if (Compiler.IsComptime)
return Type.[Friend]GetType((.)Type.[Friend]Comptime_Method_GetParamInfo(mNativeMethodInstance, (.)paramIdx).mParamTypeId);
return null;
}
public StringView GetParamName(int paramIdx)
{
if (Compiler.IsComptime)
return Type.[Friend]Comptime_Method_GetParamInfo(mNativeMethodInstance, (.)paramIdx).mName;
return default;
}
public override void ToString(String strBuffer)
{
if (Compiler.IsComptime)
{
String str = Type.[Friend]Comptime_Method_ToString(mNativeMethodInstance);
strBuffer.Append(str);
}
}
public struct Enumerator : IEnumerator<ComptimeMethodInfo>
{
BindingFlags mBindingFlags;
TypeInstance mTypeInstance;
int32 mIdx;
int32 mCount;
public this(TypeInstance typeInst, BindingFlags bindingFlags)
{
//Debug.WriteLine($"this {typeInst}");
mTypeInstance = typeInst;
mBindingFlags = bindingFlags;
mIdx = -1;
if ((mTypeInstance == null) || (!Compiler.IsComptime))
mCount = 0;
else
mCount = Type.[Friend]Comptime_GetMethodCount((.)mTypeInstance.TypeId);
}
public void Reset() mut
{
mIdx = -1;
}
public void Dispose()
{
}
public bool MoveNext() mut
{
if (mTypeInstance == null)
return false;
for (;;)
{
mIdx++;
if (mIdx == mCount)
return false;
int64 nativeMethodHandle = Type.[Friend]Comptime_GetMethod((int32)mTypeInstance.TypeId, mIdx);
let info = Type.[Friend]Comptime_Method_GetInfo(nativeMethodHandle);
bool matches = (mBindingFlags.HasFlag(BindingFlags.Static) && (info.mMethodFlags.HasFlag(.Static)));
matches |= (mBindingFlags.HasFlag(BindingFlags.Instance) && (!info.mMethodFlags.HasFlag(.Static)));
if (matches)
break;
}
return true;
}
public ComptimeMethodInfo Current
{
get
{
int64 nativeMethodHandle = Type.[Friend]Comptime_GetMethod((int32)mTypeInstance.TypeId, mIdx);
return ComptimeMethodInfo(nativeMethodHandle);
}
}
public Result<ComptimeMethodInfo> GetNext() mut
{
if (!MoveNext())
return .Err;
return Current;
}
}
}
}

View file

@ -16,6 +16,12 @@ namespace System
return MethodInfo.Enumerator(null, bindingFlags);
}
[Comptime]
public virtual ComptimeMethodInfo.Enumerator GetMethods(BindingFlags bindingFlags = cDefaultLookup)
{
return ComptimeMethodInfo.Enumerator(null, bindingFlags);
}
public virtual Result<MethodInfo, MethodError> GetMethod(StringView methodName, BindingFlags bindingFlags = cDefaultLookup)
{
MethodInfo matched = default;
@ -40,6 +46,16 @@ namespace System
return .Err(.NoResults);
}
[Comptime]
public virtual Result<ComptimeMethodInfo, MethodError> GetMethod(int methodIdx)
{
int64 nativeMethod = Comptime_GetMethod((.)TypeId, (.)methodIdx);
if (nativeMethod == 0)
return .Err(.NoResults);
return ComptimeMethodInfo(nativeMethod);
}
public virtual Result<Object> CreateObject()
{
return .Err;
@ -66,6 +82,12 @@ namespace System.Reflection
return MethodInfo.Enumerator(this, bindingFlags);
}
[Comptime]
public override ComptimeMethodInfo.Enumerator GetMethods(BindingFlags bindingFlags = cDefaultLookup)
{
return ComptimeMethodInfo.Enumerator(this, bindingFlags);
}
public override Result<MethodInfo, MethodError> GetMethod(int methodIdx)
{
if ((methodIdx < 0) || (methodIdx >= mMethodDataCount))

View file

@ -475,6 +475,12 @@ namespace System
static extern Type Comptime_GetTypeByName(StringView name);
static extern Type Comptime_GetSpecializedType(Type unspecializedType, Span<Type> typeArgs);
static extern bool Comptime_Type_GetCustomAttribute(int32 typeId, int32 attributeId, void* dataPtr);
static extern int32 Comptime_GetMethodCount(int32 typeId);
static extern int64 Comptime_GetMethod(int32 typeId, int32 methodIdx);
static extern String Comptime_Method_ToString(int64 methodHandle);
static extern String Comptime_Method_GetName(int64 methodHandle);
static extern ComptimeMethodInfo.Info Comptime_Method_GetInfo(int64 methodHandle);
static extern ComptimeMethodInfo.ParamInfo Comptime_Method_GetParamInfo(int64 methodHandle, int32 paramIdx);
protected static Type GetType(TypeId typeId)
{

View file

@ -777,8 +777,11 @@ namespace IDE.ui
if (itr.GetNext() case .Ok(let fileName))
{
entry.mFile = new String(fileName);
entry.mLine = int.Parse(itr.GetNext()).Get();
entry.mColumn = int.Parse(itr.GetNext()).Get();
if (!entry.mFile.IsEmpty)
{
entry.mLine = int.Parse(itr.GetNext()).Get();
entry.mColumn = int.Parse(itr.GetNext()).Get();
}
}
}
}

View file

@ -1111,6 +1111,11 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType == activeDef, prevMethodDef->mDeclaringType == activeDef);
RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType->IsExtension(), prevMethodDef->mDeclaringType->IsExtension());
RETURN_BETTER_OR_WORSE(newMethodDef->mIsMutating, prevMethodDef->mIsMutating);
if (newMethodDef->mHasComptime != prevMethodDef->mHasComptime)
{
bool isComptime = (mModule->mIsComptimeModule) || ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0);
RETURN_BETTER_OR_WORSE(newMethodDef->mHasComptime == isComptime, prevMethodDef->mHasComptime == isComptime);
}
RETURN_RESULTS;
}
@ -5190,9 +5195,8 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
// We didn't properly resolve this so queue for a rebuild later
mModule->DeferRebuildType(mModule->mCurTypeInstance);
}
doConstReturn = true;
}
doConstReturn = true;
}
}
else if (mModule->mIsComptimeModule)

View file

@ -1989,6 +1989,12 @@ void BfIRBuilder::Write(const BfIRValue& irValue)
Write(MapType(typeofConst->mType, BfIRPopulateType_Identity));
}
break;
case (int)BfConstType_Undef:
{
auto undefConst = (BfConstantUndef*)constant;
Write(undefConst->mType);
}
break;
case (int)BfConstType_TypeOf_WithData:
{
auto typeofConst = (BfTypeOf_WithData_Const*)constant;

View file

@ -2798,6 +2798,14 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
if (mIsComptimeModule)
{
if ((mCompiler->mCEMachine->mCurContext != NULL) && (mCompiler->mCEMachine->mCurContext->mCurTargetSrc != NULL))
{
BfError* bfError = mCompiler->mPassInstance->Fail("Comptime method generation had errors", mCompiler->mCEMachine->mCurContext->mCurTargetSrc);
if (bfError != NULL)
mCompiler->mPassInstance->MoreInfo(error, refNode);
return bfError;
}
mHadBuildError = true;
return NULL;
}
@ -2925,6 +2933,14 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
if (!mHadBuildError)
mHadBuildError = true;
if ((mCurMethodState != NULL) && (mCurMethodState->mEmitRefNode != NULL))
{
BfError* bfError = mCompiler->mPassInstance->Fail("Emitted code had errors", mCurMethodState->mEmitRefNode);
if (bfError != NULL)
mCompiler->mPassInstance->MoreInfo(errorString, refNode);
return bfError;
}
// Check mixins
{
auto checkMethodInstance = mCurMethodState;
@ -2934,7 +2950,8 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
if (rootMixinState != NULL)
{
BfError* bfError = mCompiler->mPassInstance->Fail(StrFormat("Failed to inject mixin '%s'", MethodToString(rootMixinState->mMixinMethodInstance).c_str()), rootMixinState->mSource);
mCompiler->mPassInstance->MoreInfo(errorString, refNode);
if (bfError != NULL)
mCompiler->mPassInstance->MoreInfo(errorString, refNode);
auto mixinState = checkMethodInstance->mMixinState;
while ((mixinState != NULL) && (mixinState->mPrevMixinState != NULL))
@ -3043,6 +3060,14 @@ BfError* BfModule::Warn(int warningNum, const StringImpl& warning, BfAstNode* re
return NULL;
}
if ((mCurMethodState != NULL) && (mCurMethodState->mEmitRefNode != NULL))
{
BfError* bfError = mCompiler->mPassInstance->Warn(warningNum, "Emitted code had errors", mCurMethodState->mEmitRefNode);
if (bfError != NULL)
mCompiler->mPassInstance->MoreInfo(warning, refNode);
return bfError;
}
BfError* bfError;
if (refNode != NULL)
bfError = mCompiler->mPassInstance->WarnAt(warningNum, warning, refNode->GetSourceData(), refNode->GetSrcStart(), refNode->GetSrcLength());
@ -4973,6 +4998,8 @@ BfIRValue BfModule::CreateTypeDataRef(BfType* type)
return mBfIRBuilder->Comptime_GetReflectType(type->mTypeId, mBfIRBuilder->MapType(typeTypeInst));
}
PopulateType(type);
BfIRValue globalVariable;
BfIRValue* globalVariablePtr = NULL;
@ -4997,6 +5024,11 @@ BfIRValue BfModule::CreateTypeDataRef(BfType* type)
BfMangler::Mangle(typeDataName, mCompiler->GetMangleKind(), type, this);
}
if (typeDataName == "?sBfTypeData@Zoing@BeefTest@bf@@2HA")
{
NOP;
}
BfLogSysM("Creating TypeData %s\n", typeDataName.c_str());
globalVariable = mBfIRBuilder->CreateGlobalVariable(mBfIRBuilder->MapTypeInst(typeTypeInst, BfIRPopulateType_Full), true, BfIRLinkageType_External, BfIRValue(), typeDataName);
@ -5110,6 +5142,11 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
BfMangler::Mangle(typeDataName, mCompiler->GetMangleKind(), type, mContext->mScratchModule);
}
if (typeDataName == "?sBfTypeData@@bf@@2HA")
{
NOP;
}
int typeCode = BfTypeCode_None;
if (typeInstance != NULL)
@ -6401,6 +6438,8 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
auto methodDef = typeDef->mMethods[methodIdx];
if (methodDef->mIsNoReflect)
continue;
if (methodDef->mHasComptime)
continue;
auto defaultMethod = methodInstanceGroup->mDefault;
if (defaultMethod == NULL)
@ -6481,43 +6520,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
BfIRValue methodNameConst = GetStringObjectValue(methodDef->mName, true);
enum MethodFlags
{
MethodFlags_Protected = 3,
MethodFlags_Public = 6,
MethodFlags_Static = 0x10,
MethodFlags_Virtual = 0x40,
MethodFlags_StdCall = 0x1000,
MethodFlags_FastCall = 0x2000,
MethodFlags_ThisCall = 0x3000,
MethodFlags_Mutating = 0x4000,
MethodFlags_Constructor = 0x8000,
};
MethodFlags methodFlags = (MethodFlags)0;
if (methodDef->mProtection == BfProtection_Protected)
methodFlags = (MethodFlags)(methodFlags | MethodFlags_Protected);
if (methodDef->mProtection == BfProtection_Public)
methodFlags = (MethodFlags)(methodFlags | MethodFlags_Public);
if (methodDef->mIsStatic)
methodFlags = (MethodFlags)(methodFlags | MethodFlags_Static);
if ((methodDef->mIsVirtual) || (moduleMethodInstance.mMethodInstance->mVirtualTableIdx != -1))
methodFlags = (MethodFlags)(methodFlags | MethodFlags_Virtual);
if (methodDef->mCallingConvention == BfCallingConvention_Fastcall)
methodFlags = (MethodFlags)(methodFlags | MethodFlags_FastCall);
if (methodDef->mIsMutating)
methodFlags = (MethodFlags)(methodFlags | MethodFlags_Mutating);
if (methodDef->mMethodType == BfMethodType_Ctor)
methodFlags = (MethodFlags)(methodFlags | MethodFlags_Constructor);
auto callingConvention = GetIRCallingConvention(defaultMethod);
if (callingConvention == BfIRCallingConv_ThisCall)
methodFlags = (MethodFlags)(methodFlags | MethodFlags_ThisCall);
else if (callingConvention == BfIRCallingConv_StdCall)
methodFlags = (MethodFlags)(methodFlags | MethodFlags_StdCall);
else if (callingConvention == BfIRCallingConv_FastCall)
methodFlags = (MethodFlags)(methodFlags | MethodFlags_FastCall);
BfMethodFlags methodFlags = moduleMethodInstance.mMethodInstance->GetMethodFlags();
int customAttrIdx = _HandleCustomAttrs(methodCustomAttributes);
@ -9830,8 +9833,11 @@ BfMethodInstance* BfModule::GetUnspecializedMethodInstance(BfMethodInstance* met
return methodInstance;
if ((owner->IsDelegateFromTypeRef()) ||
(owner->IsFunctionFromTypeRef()) ||
(owner->IsTuple()))
{
return methodInstance;
}
auto genericType = (BfTypeInstance*)owner;
if ((genericType->IsUnspecializedType()) && (!genericType->IsUnspecializedTypeVariation()))
@ -10451,11 +10457,16 @@ StringT<128> BfModule::MethodToString(BfMethodInstance* methodInst, BfMethodName
return methodName;
}
void BfModule::pv(BfType* type)
void BfModule::pt(BfType* type)
{
OutputDebugStrF("%s\n", TypeToString(type).c_str());
}
void BfModule::pm(BfMethodInstance* type)
{
OutputDebugStrF("%s\n", MethodToString(type).c_str());
}
static void AddAttributeTargetName(BfAttributeTargets& flagsLeft, BfAttributeTargets checkFlag, String& str, String addString)
{
if ((flagsLeft & checkFlag) == 0)
@ -12080,6 +12091,8 @@ bool BfModule::CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstan
return false;
if (methodA->mMethodDef->mCheckedKind != methodB->mMethodDef->mCheckedKind)
return false;
if (methodA->mMethodDef->mHasComptime != methodB->mMethodDef->mHasComptime)
return false;
if ((methodA->mMethodDef->mMethodType == BfMethodType_Mixin) != (methodB->mMethodDef->mMethodType == BfMethodType_Mixin))
return false;
@ -14271,6 +14284,7 @@ void BfModule::EmitDeferredScopeCalls(bool useSrcPositions, BfScopeData* scopeDa
{
if (deferredCallEntry->mDeferredBlock != NULL)
{
SetAndRestoreValue<BfAstNode*> prevCustomAttribute(mCurMethodState->mEmitRefNode, deferredCallEntry->mEmitRefNode);
VisitEmbeddedStatement(deferredCallEntry->mDeferredBlock, NULL, BfEmbeddedStatementFlags_IsDeferredBlock);
}
deferredCallEntry = deferredCallEntry->mNext;
@ -19583,6 +19597,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
isExpressionBody = true;
}
DoCEEmit(methodInstance);
if (auto fieldDtorBody = BfNodeDynCast<BfFieldDtorDeclaration>(methodDef->mBody))
{
while (fieldDtorBody != NULL)
@ -19790,7 +19806,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
}
// Avoid linking any internal funcs that were just supposed to be comptime-accessible
if (((methodInstance->mComptimeFlags & BfComptimeFlag_OnlyFromComptime) != 0) && (!mIsComptimeModule))
if ((methodDef->mHasComptime) && (!mIsComptimeModule))
wantsRemoveBody = true;
if ((hasExternSpecifier) && (!skipBody))

View file

@ -273,6 +273,7 @@ public:
SizedArray<BfIRValue, 1> mScopeArgs;
Array<BfDeferredCapture> mCaptures;
BfBlock* mDeferredBlock;
BfAstNode* mEmitRefNode;
int64 mBlockId;
int mHandlerCount;
bool mBypassVirtual;
@ -292,6 +293,7 @@ public:
mNext = NULL;
mSrcNode = NULL;
mDeferredBlock = NULL;
mEmitRefNode = NULL;
mBlockId = -1;
mHandlerCount = 0;
mArgsNeedLoad = false;
@ -991,6 +993,7 @@ public:
BfScopeData* mCurScope;
BfScopeData* mTailScope; // Usually equals mCurScope
BfScopeData* mOverrideScope;
BfAstNode* mEmitRefNode;
TempKind mTempKind; // Used for var inference, etc
bool mInDeferredBlock;
bool mHadReturn;
@ -1024,6 +1027,7 @@ public:
mHeadScope.mIsScopeHead = true;
mCurScope = &mHeadScope;
mTailScope = &mHeadScope;
mEmitRefNode = NULL;
mOverrideScope = NULL;
mHadReturn = false;
mLeftBlockUncond = false;
@ -1370,6 +1374,12 @@ public:
#define BFMODULE_FATAL(module, msg) (module)->FatalError((msg), __FILE__, __LINE__)
struct BfCEParseContext
{
int mFailIdx;
int mWarnIdx;
};
class BfModule : public BfStructuralVisitor
{
public:
@ -1523,7 +1533,8 @@ public:
StringT<128> TypeToString(BfType* resolvedType, BfTypeNameFlags typeNameFlags, Array<String>* genericMethodParamNameOverrides = NULL);
void DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameFlags typeNameFlags = BfTypeNameFlags_None, Array<String>* genericMethodParamNameOverrides = NULL);
StringT<128> MethodToString(BfMethodInstance* methodInst, BfMethodNameFlags methodNameFlags = BfMethodNameFlag_ResolveGenericParamNames, BfTypeVector* typeGenericArgs = NULL, BfTypeVector* methodGenericArgs = NULL);
void pv(BfType* type);
void pt(BfType* type);
void pm(BfMethodInstance* type);
void CurrentAddToConstHolder(BfIRValue& irVal);
void ClearConstData();
BfTypedValue GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType);
@ -1562,7 +1573,7 @@ public:
void EmitDefaultReturn();
void EmitDeferredCall(BfModuleMethodInstance moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfDeferredBlockFlags flags = BfDeferredBlockFlag_None);
bool AddDeferredCallEntry(BfDeferredCallEntry* deferredCallEntry, BfScopeData* scope);
void AddDeferredBlock(BfBlock* block, BfScopeData* scope, Array<BfDeferredCapture>* captures = NULL);
BfDeferredCallEntry* AddDeferredBlock(BfBlock* block, BfScopeData* scope, Array<BfDeferredCapture>* captures = NULL);
BfDeferredCallEntry* AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfScopeData* scope, BfAstNode* srcNode = NULL, bool bypassVirtual = false, bool doNullCheck = false);
void EmitDeferredCall(BfDeferredCallEntry& deferredCallEntry, bool moveBlocks);
void EmitDeferredCallProcessor(SLIList<BfDeferredCallEntry*>& callEntries, BfIRValue callTail);
@ -1698,10 +1709,14 @@ public:
void SetTypeOptions(BfTypeInstance* typeInstance);
BfModuleOptions GetModuleOptions();
BfCheckedKind GetDefaultCheckedKind();
void FinishCEParseContext(BfAstNode* refNode, BfTypeInstance* typeInstance, BfCEParseContext* ceParseContext);
BfCEParseContext CEEmitParse(BfTypeInstance* typeInstance, BfTypeDef* activeTypeDef, const StringImpl& src);
void UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfTypeDef* activeTypeDef, const StringImpl& ctxString, BfAstNode* refNode);
void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCustomAttributes* customAttributes, HashSet<BfTypeInstance*> foundAttributes);
void CEMixin(BfAstNode* refNode, const StringImpl& src);
void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind);
void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers);
void DoCEEmit(BfMethodInstance* methodInstance);
void DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateType = BfPopulateType_Data);
static BfModule* GetModuleFor(BfType* type);
void DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance);

View file

@ -1933,24 +1933,11 @@ void BfModule::SetTypeOptions(BfTypeInstance* typeInstance)
typeInstance->mTypeOptionsIdx = GenerateTypeOptions(typeInstance->mCustomAttributes, typeInstance, true);
}
void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfTypeDef* activeTypeDef, const StringImpl& ctxString, BfAstNode* refNode)
BfCEParseContext BfModule::CEEmitParse(BfTypeInstance* typeInstance, BfTypeDef* activeTypeDef, const StringImpl& src)
{
if (ceEmitContext->mEmitData.IsEmpty())
return;
int prevFailIdx = mCompiler->mPassInstance->mFailedIdx;
int prevWarnIdx = mCompiler->mPassInstance->mWarnIdx;
String src;
if (activeTypeDef->mEmitParser != NULL)
src += "\n\n";
src += "// Code emission in ";
src += ctxString;
src += "\n\n";
src += ceEmitContext->mEmitData;
ceEmitContext->mEmitData.Clear();
BfCEParseContext ceParseContext;
ceParseContext.mFailIdx = mCompiler->mPassInstance->mFailedIdx;
ceParseContext.mWarnIdx = mCompiler->mPassInstance->mWarnIdx;
bool createdParser = false;
int startSrcIdx = 0;
@ -1989,6 +1976,46 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn
activeTypeDef->mEmitParser->Parse(mCompiler->mPassInstance);
activeTypeDef->mEmitParser->FinishSideNodes();
if (createdParser)
{
AutoCrit crit(mSystem->mDataLock);
mSystem->mParsers.Add(activeTypeDef->mEmitParser);
}
return ceParseContext;
}
void BfModule::FinishCEParseContext(BfAstNode* refNode, BfTypeInstance* typeInstance, BfCEParseContext* ceParseContext)
{
if ((ceParseContext->mFailIdx != mCompiler->mPassInstance->mFailedIdx) && (refNode != NULL))
Fail("Emitted code had errors", refNode);
else if ((ceParseContext->mWarnIdx != mCompiler->mPassInstance->mWarnIdx) && (refNode != NULL))
Warn(0, "Emitted code had warnings", refNode);
else if ((ceParseContext->mFailIdx != mCompiler->mPassInstance->mFailedIdx) ||
(ceParseContext->mWarnIdx != mCompiler->mPassInstance->mWarnIdx))
{
AddFailType(typeInstance);
}
}
void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfTypeDef* activeTypeDef, const StringImpl& ctxString, BfAstNode* refNode)
{
if (ceEmitContext->mEmitData.IsEmpty())
return;
String src;
if (activeTypeDef->mEmitParser != NULL)
src += "\n\n";
src += "// Code emission in ";
src += ctxString;
src += "\n\n";
src += ceEmitContext->mEmitData;
ceEmitContext->mEmitData.Clear();
BfCEParseContext ceParseContext = CEEmitParse(typeInstance, activeTypeDef, src);
auto typeDeclaration = activeTypeDef->mEmitParser->mAlloc->Alloc<BfTypeDeclaration>();
BfReducer bfReducer;
@ -2008,21 +2035,7 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn
defBuilder.DoVisitChild(typeDeclaration->mDefineNode);
defBuilder.FinishTypeDef(typeInstance->mTypeDef->mTypeCode == BfTypeCode_Enum);
if (createdParser)
{
AutoCrit crit(mSystem->mDataLock);
mSystem->mParsers.Add(activeTypeDef->mEmitParser);
}
if ((prevFailIdx != mCompiler->mPassInstance->mFailedIdx) && (refNode != NULL))
Fail("Emitted code had errors", refNode);
else if ((prevWarnIdx != mCompiler->mPassInstance->mWarnIdx) && (refNode != NULL))
Warn(0, "Emitted code had warnings", refNode);
else if ((prevFailIdx != mCompiler->mPassInstance->mFailedIdx) ||
(prevWarnIdx != mCompiler->mPassInstance->mWarnIdx))
{
AddFailType(typeInstance);
}
FinishCEParseContext(refNode, typeInstance, &ceParseContext);
}
void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet<BfTypeInstance*> foundAttributes)
@ -2066,7 +2079,12 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance*
auto result = ceContext->Call(customAttribute.mRef, this, methodInstance, args, CeEvalFlags_None, NULL);
if (!ceEmitContext->mEmitData.IsEmpty())
if (typeInstance->mDefineState != BfTypeDefineState_CETypeInit)
{
// We populated before we could finish
AssertErrorState();
}
else if (!ceEmitContext->mEmitData.IsEmpty())
{
String ctxStr = "comptime ApplyToType of ";
ctxStr += TypeToString(attrType);
@ -2082,6 +2100,76 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance*
}
}
void BfModule::CEMixin(BfAstNode* refNode, const StringImpl& code)
{
auto activeTypeDef = mCurMethodInstance->mMethodDef->mDeclaringType;
String src;
if (activeTypeDef->mEmitParser != NULL)
src += "\n\n";
src += "// Code emission in ";
src += MethodToString(mCurMethodInstance);
src += "\n";
src += code;
BfReducer bfReducer;
bfReducer.mSource = activeTypeDef->mEmitParser;
bfReducer.mPassInstance = mCompiler->mPassInstance;
bfReducer.mSystem = mSystem;
bfReducer.mCurTypeDecl = activeTypeDef->mTypeDeclaration;
bfReducer.mCurMethodDecl = BfNodeDynCast<BfMethodDeclaration>(mCurMethodInstance->mMethodDef->mMethodDeclaration);
SetAndRestoreValue<BfAstNode*> prevCustomAttribute(mCurMethodState->mEmitRefNode, refNode);
EmitEnsureInstructionAt();
bool wantsDIData = (mBfIRBuilder->DbgHasInfo()) && (mHasFullDebugInfo);
mBfIRBuilder->SaveDebugLocation();
BfCEParseContext ceParseContext = CEEmitParse(mCurTypeInstance, activeTypeDef, src);
bfReducer.mAlloc = activeTypeDef->mEmitParser->mAlloc;
bfReducer.HandleBlock(activeTypeDef->mEmitParser->mRootNode, false);
SetAndRestoreValue<BfIRMDNode> prevInlinedAt(mCurMethodState->mCurScope->mDIInlinedAt);
SetAndRestoreValue<BfIRMDNode> prevDIScope(mCurMethodState->mCurScope->mDIScope);
SetAndRestoreValue<BfIRMDNode> prevAltDIFile(mCurMethodState->mCurScope->mAltDIFile);
if (wantsDIData)
{
llvm::SmallVector<BfIRMDNode, 8> diParams;
diParams.push_back(mBfIRBuilder->DbgGetType(GetPrimitiveType(BfTypeCode_None)));
BfIRMDNode diFuncType = mBfIRBuilder->DbgCreateSubroutineType(diParams);
//int defLine = mModule->mCurFilePosition.mCurLine;
int flags = 0;
mCurMethodState->mCurScope->mDIInlinedAt = mBfIRBuilder->DbgGetCurrentLocation();
// We used to have the "def" line be the inlining position, but the linker we de-duplicate instances of these functions without regard to their unique line
// definitions, so we need to be consistent and use the actual line
UpdateSrcPos(activeTypeDef->mEmitParser->mRootNode, BfSrcPosFlag_NoSetDebugLoc);
int defLine = mCurFilePosition.mCurLine;
auto diParentType = mBfIRBuilder->DbgGetTypeInst(mCurTypeInstance);
if (!mBfIRBuilder->mIgnoreWrites)
{
String methodName = "Comptime_Mixin";
mCurMethodState->mCurScope->mDIScope = mBfIRBuilder->DbgCreateFunction(diParentType, methodName, "", mCurFilePosition.mFileInstance->mDIFile,
defLine + 1, diFuncType, false, true, mCurFilePosition.mCurLine + 1, flags, false, BfIRValue());
mCurMethodState->mCurScope->mAltDIFile = mCurFilePosition.mFileInstance->mDIFile;
}
}
UpdateSrcPos(activeTypeDef->mEmitParser->mRootNode);
SetIllegalSrcPos();
Visit(activeTypeDef->mEmitParser->mRootNode);
mBfIRBuilder->RestoreDebugLocation();
mBfIRBuilder->DupDebugLocation();
FinishCEParseContext(refNode, mCurTypeInstance, &ceParseContext);
}
void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCEOnCompileKind onCompileKind)
{
HashSet<BfTypeInstance*> foundAttributes;
@ -2166,7 +2254,12 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance*
auto methodInstance = GetRawMethodInstanceAtIdx(typeInstance, methodDef->mIdx);
auto result = mCompiler->mCEMachine->Call(methodDef->GetRefNode(), this, methodInstance, {}, (CeEvalFlags)(CeEvalFlags_PersistantError | CeEvalFlags_DeferIfNotOnlyError), NULL);
if (!ceEmitContext->mEmitData.IsEmpty())
if (typeInstance->mDefineState != BfTypeDefineState_CETypeInit)
{
// We populated before we could finish
AssertErrorState();
}
else if (!ceEmitContext->mEmitData.IsEmpty())
{
String ctxStr = "OnCompile execution of ";
ctxStr += MethodToString(methodInstance);
@ -2203,6 +2296,113 @@ void BfModule::DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers)
}
}
void BfModule::DoCEEmit(BfMethodInstance* methodInstance)
{
auto customAttributes = methodInstance->GetCustomAttributes();
if (customAttributes == NULL)
return;
auto typeInstance = methodInstance->GetOwner();
CeEmitContext ceEmitContext;
ceEmitContext.mMethodInstance = methodInstance;
BfTypeInstance* iComptimeMethodApply = NULL;
for (auto& customAttribute : customAttributes->mAttributes)
{
auto attrType = customAttribute.mType;
PopulateType(attrType, BfPopulateType_DataAndMethods);
if (attrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
continue;
for (auto& ifaceEntry : attrType->mInterfaces)
{
if (iComptimeMethodApply == NULL)
iComptimeMethodApply = ResolveTypeDef(mCompiler->mIComptimeMethodApply)->ToTypeInstance();
if (ifaceEntry.mInterfaceType != iComptimeMethodApply)
continue;
// if (!foundAttributes.Add(attrType))
// continue;
BfMethodInstance* applyMethodInstance = attrType->mInterfaceMethodTable[ifaceEntry.mStartInterfaceTableIdx].mMethodRef;
if (applyMethodInstance == NULL)
continue;
SetAndRestoreValue<CeEmitContext*> prevEmitContext(mCompiler->mCEMachine->mCurEmitContext, &ceEmitContext);
auto ceContext = mCompiler->mCEMachine->AllocContext();
BfIRValue attrVal = ceContext->CreateAttribute(customAttribute.mRef, this, typeInstance->mConstHolder, &customAttribute);
SizedArray<BfIRValue, 1> args;
if (!attrType->IsValuelessType())
args.Add(attrVal);
args.Add(mBfIRBuilder->CreateConst(BfTypeCode_UInt64, (uint64)(intptr)methodInstance));
mCompiler->mCEMachine->mMethodInstanceSet.Add(methodInstance);
//TESTING
// mCompiler->mCEMachine->ReleaseContext(ceContext);
// ceContext = mCompiler->mCEMachine->AllocContext();
// ceContext->mMemory.mSize = ceContext->mMemory.mAllocSize;
auto activeTypeDef = typeInstance->mTypeDef;
auto result = ceContext->Call(customAttribute.mRef, this, applyMethodInstance, args, CeEvalFlags_None, NULL);
if ((!ceEmitContext.mEmitData.IsEmpty()) || (!ceEmitContext.mExitEmitData.IsEmpty()))
{
String src;
src += "// Code emission in comptime ApplyToMethod of ";
src += TypeToString(attrType);
src += " to ";
src += MethodToString(methodInstance);
src += " ";
src += customAttribute.mRef->LocationToString();
src += "\n";
BfReducer bfReducer;
bfReducer.mSource = activeTypeDef->mEmitParser;
bfReducer.mPassInstance = mCompiler->mPassInstance;
bfReducer.mSystem = mSystem;
bfReducer.mCurTypeDecl = activeTypeDef->mTypeDeclaration;
bfReducer.mCurMethodDecl = BfNodeDynCast<BfMethodDeclaration>(methodInstance->mMethodDef->mMethodDeclaration);
if (!ceEmitContext.mEmitData.IsEmpty())
{
SetAndRestoreValue<BfAstNode*> prevCustomAttribute(mCurMethodState->mEmitRefNode, customAttribute.mRef);
String entrySrc = src;
if (activeTypeDef->mEmitParser != NULL)
entrySrc += "\n\n";
entrySrc += src;
entrySrc += ceEmitContext.mEmitData;
BfCEParseContext ceParseContext = CEEmitParse(typeInstance, activeTypeDef, entrySrc);
bfReducer.mAlloc = activeTypeDef->mEmitParser->mAlloc;
bfReducer.HandleBlock(activeTypeDef->mEmitParser->mRootNode, false);
Visit(activeTypeDef->mEmitParser->mRootNode);
FinishCEParseContext(customAttribute.mRef, typeInstance, &ceParseContext);
}
if (!ceEmitContext.mExitEmitData.IsEmpty())
{
String exitSrc;
if (activeTypeDef->mEmitParser != NULL)
exitSrc += "\n\n";
exitSrc += src;
exitSrc += ceEmitContext.mExitEmitData;
BfCEParseContext ceParseContext = CEEmitParse(typeInstance, activeTypeDef, exitSrc);
bfReducer.mAlloc = activeTypeDef->mEmitParser->mAlloc;
bfReducer.HandleBlock(activeTypeDef->mEmitParser->mRootNode, false);
auto deferredBlock = AddDeferredBlock(activeTypeDef->mEmitParser->mRootNode, &mCurMethodState->mHeadScope);
deferredBlock->mEmitRefNode = customAttribute.mRef;
FinishCEParseContext(customAttribute.mRef, typeInstance, &ceParseContext);
}
}
mCompiler->mCEMachine->ReleaseContext(ceContext);
}
}
}
void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateType)
{
auto typeInstance = resolvedTypeRef->ToTypeInstance();
@ -6316,6 +6516,11 @@ BfPointerType* BfModule::CreatePointerType(BfTypeReference* typeRef)
BfType* BfModule::ResolveTypeDef(BfTypeDef* typeDef, BfPopulateType populateType, BfResolveTypeRefFlags resolveFlags)
{
if (typeDef->mTypeDeclaration == NULL)
{
BF_ASSERT(!typeDef->mIsDelegate && !typeDef->mIsFunction);
}
//BF_ASSERT(typeDef->mTypeCode != BfTypeCode_Extension);
BF_ASSERT(!typeDef->mIsPartial || typeDef->mIsCombinedPartial);

View file

@ -630,6 +630,35 @@ BfImportKind BfMethodInstance::GetImportKind()
return BfMethodDef::GetImportKindFromPath(*filePath);
}
BfMethodFlags BfMethodInstance::GetMethodFlags()
{
BfMethodFlags methodFlags = (BfMethodFlags)0;
if (mMethodDef->mProtection == BfProtection_Protected)
methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_Protected);
if (mMethodDef->mProtection == BfProtection_Public)
methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_Public);
if (mMethodDef->mIsStatic)
methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_Static);
if ((mMethodDef->mIsVirtual) || (mVirtualTableIdx != -1))
methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_Virtual);
if (mMethodDef->mCallingConvention == BfCallingConvention_Fastcall)
methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_FastCall);
if (mMethodDef->mIsMutating)
methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_Mutating);
if (mMethodDef->mMethodType == BfMethodType_Ctor)
methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_Constructor);
auto callingConvention = GetOwner()->mModule->GetIRCallingConvention(this);
if (callingConvention == BfIRCallingConv_ThisCall)
methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_ThisCall);
else if (callingConvention == BfIRCallingConv_StdCall)
methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_StdCall);
else if (callingConvention == BfIRCallingConv_FastCall)
methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_FastCall);
return methodFlags;
}
void BfMethodInstance::UndoDeclaration(bool keepIRFunction)
{

View file

@ -899,6 +899,7 @@ public:
}
BfImportKind GetImportKind();
BfMethodFlags GetMethodFlags();
void UndoDeclaration(bool keepIRFunction = false);
BfTypeInstance* GetOwner();
BfModule* GetModule();

View file

@ -512,13 +512,14 @@ bool BfModule::AddDeferredCallEntry(BfDeferredCallEntry* deferredCallEntry, BfSc
return true;
}
void BfModule::AddDeferredBlock(BfBlock* block, BfScopeData* scopeData, Array<BfDeferredCapture>* captures)
BfDeferredCallEntry* BfModule::AddDeferredBlock(BfBlock* block, BfScopeData* scopeData, Array<BfDeferredCapture>* captures)
{
BfDeferredCallEntry* deferredCallEntry = new BfDeferredCallEntry();
deferredCallEntry->mDeferredBlock = block;
if (captures != NULL)
deferredCallEntry->mCaptures = *captures;
AddDeferredCallEntry(deferredCallEntry, scopeData);
return deferredCallEntry;
}
BfDeferredCallEntry* BfModule::AddDeferredCall(const BfModuleMethodInstance& moduleMethodInstance, SizedArrayImpl<BfIRValue>& llvmArgs, BfScopeData* scopeData, BfAstNode* srcNode, bool bypassVirtual, bool doNullCheck)
@ -826,6 +827,7 @@ void BfModule::EmitDeferredCall(BfDeferredCallEntry& deferredCallEntry, bool mov
AddLocalVariableDef(localVar, true);
}
SetAndRestoreValue<BfAstNode*> prevCustomAttribute(mCurMethodState->mEmitRefNode, deferredCallEntry.mEmitRefNode);
VisitEmbeddedStatement(deferredCallEntry.mDeferredBlock, NULL, BfEmbeddedStatementFlags_IsDeferredBlock);
RestoreScopeState();
return;

View file

@ -187,6 +187,19 @@ enum BfTypeFlags
BfTypeFlags_HasDestructor = 0x40000,
};
enum BfMethodFlags
{
BfMethodFlags_Protected = 3,
BfMethodFlags_Public = 6,
BfMethodFlags_Static = 0x10,
BfMethodFlags_Virtual = 0x40,
BfMethodFlags_StdCall = 0x1000,
BfMethodFlags_FastCall = 0x2000,
BfMethodFlags_ThisCall = 0x3000,
BfMethodFlags_Mutating = 0x4000,
BfMethodFlags_Constructor = 0x8000,
};
enum BfObjectFlags : uint8
{
BfObjectFlag_None = 0,

View file

@ -1172,6 +1172,8 @@ void CeBuilder::HandleParams()
void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance)
{
SetAndRestoreValue<BfMethodState*> prevMethodStateInConstEval(mCeMachine->mCeModule->mCurMethodState, NULL);
auto irCodeGen = mCeMachine->mCeModule->mBfIRBuilder->mBeIRCodeGen;
auto irBuilder = mCeMachine->mCeModule->mBfIRBuilder;
auto beModule = irCodeGen->mBeModule;
@ -2680,7 +2682,7 @@ BfError* CeContext::Fail(const StringImpl& error)
auto bfError = mCurModule->Fail(StrFormat("Unable to comptime %s", mCurModule->MethodToString(mCurMethodInstance).c_str()), mCurTargetSrc, (mCurEvalFlags & CeEvalFlags_PersistantError) != 0);
if (bfError == NULL)
return NULL;
mCeMachine->mCompiler->mPassInstance->MoreInfo(error, mCeMachine->mCeModule->mCompiler->GetAutoComplete() != NULL);
mCeMachine->mCompiler->mPassInstance->MoreInfo(error, mCeMachine->mCompiler->GetAutoComplete() != NULL);
return bfError;
}
@ -3020,6 +3022,12 @@ addr_ce CeContext::GetString(int stringId)
return *ceAddrPtr;
}
addr_ce CeContext::GetString(const StringImpl& str)
{
int stringId = mCeMachine->mCeModule->mContext->GetStringLiteralId(str);
return GetString(stringId);
}
BfType* CeContext::GetBfType(int typeId)
{
if ((uintptr)typeId < (uintptr)mCeMachine->mCeModule->mContext->mTypes.size())
@ -3616,6 +3624,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
AutoTimer autoTimer(mCeMachine->mRevisionExecuteTime);
SetAndRestoreValue<CeContext*> prevContext(mCeMachine->mCurContext, this);
SetAndRestoreValue<CeEvalFlags> prevEvalFlags(mCurEvalFlags, flags);
SetAndRestoreValue<BfAstNode*> prevTargetSrc(mCurTargetSrc, targetSrc);
SetAndRestoreValue<BfModule*> prevModule(mCurModule, module);
@ -3623,7 +3632,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
SetAndRestoreValue<BfType*> prevExpectingType(mCurExpectingType, expectingType);
// Reentrancy may occur as methods need defining
SetAndRestoreValue<BfMethodState*> prevMethodStateInConstEval(module->mCurMethodState, NULL);
//SetAndRestoreValue<BfMethodState*> prevMethodStateInConstEval(module->mCurMethodState, NULL);
if (mCeMachine->mAppendAllocInfo != NULL)
{
@ -3887,7 +3896,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
}
#define CE_CHECKALLOC(SIZE) \
if ((uintptr)memSize + (uintptr)SIZE > BF_CE_MAX_MEMORY) \
if ((SIZE < 0) || (uintptr)memSize + (uintptr)SIZE > BF_CE_MAX_MEMORY) \
{ \
_Fail("Maximum memory size exceeded"); \
}
@ -4006,6 +4015,14 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
instPtr = &ceFunction->mCode[0]; \
CE_CHECKSTACK();
static void CeSetAddrVal(void* ptr, addr_ce val, int32 ptrSize)
{
if (ptrSize == 4)
*(int32*)(ptr) = (int32)val;
else
*(int64*)(ptr) = (int64)val;
}
bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr, BfType*& returnType)
{
auto ceModule = mCeMachine->mCeModule;
@ -4208,7 +4225,119 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_EmitDefinition)
else if (checkFunction->mFunctionKind == CeFunctionKind_GetMethodCount)
{
int32 typeId = *(int32*)((uint8*)stackPtr + 4);
CeTypeInfo* typeInfo = mCeMachine->GetTypeInfo(GetBfType(typeId));
if (typeInfo == NULL)
{
_Fail("Invalid type");
return false;
}
*(int32*)(stackPtr + 0) = (int)typeInfo->mMethodInstances.size();
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_GetMethod)
{
int32 typeId = *(int32*)((uint8*)stackPtr + 8);
int32 methodIdx = *(int32*)((uint8*)stackPtr + 8+4);
CeTypeInfo* typeInfo = mCeMachine->GetTypeInfo(GetBfType(typeId));
if (typeInfo == NULL)
{
_Fail("Invalid type");
return false;
}
if ((methodIdx < 0) || (methodIdx >= typeInfo->mMethodInstances.mSize))
{
_Fail("Method out of bounds");
return false;
}
*(int64*)(stackPtr + 0) = (int64)(intptr)typeInfo->mMethodInstances[methodIdx];
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_Method_ToString)
{
int64 methodHandle = *(int64*)((uint8*)stackPtr + ptrSize);
auto methodInstance = mCeMachine->GetMethodInstance(methodHandle);
if (methodInstance == NULL)
{
_Fail("Invalid method instance");
return false;
}
CeSetAddrVal(stackPtr + 0, GetString(mCeMachine->mCeModule->MethodToString(methodInstance)), ptrSize);
_FixVariables();
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_Method_GetName)
{
int64 methodHandle = *(int64*)((uint8*)stackPtr + ptrSize);
auto methodInstance = mCeMachine->GetMethodInstance(methodHandle);
if (methodInstance == NULL)
{
_Fail("Invalid method instance");
return false;
}
CeSetAddrVal(stackPtr + 0, GetString(methodInstance->mMethodDef->mName), ptrSize);
_FixVariables();
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_Method_GetInfo)
{
// int32 mReturnType
// int32 mParamCount
// int16 mFlags
int64 methodHandle = *(int64*)((uint8*)stackPtr + 4+4+2);
auto methodInstance = mCeMachine->GetMethodInstance(methodHandle);
if (methodInstance == NULL)
{
_Fail("Invalid method instance");
return false;
}
*(int32*)(stackPtr + 0) = methodInstance->mReturnType->mTypeId;
*(int32*)(stackPtr + 4) = methodInstance->GetParamCount();
*(int16*)(stackPtr + 4+4) = methodInstance->GetMethodFlags();
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_Method_GetParamInfo)
{
// int32 mParamType
// int16 mFlags
// str mName
int64 methodHandle = *(int64*)((uint8*)stackPtr + 4+2+ptrSize);
int32 paramIdx = *(int32*)((uint8*)stackPtr + 4+2+ptrSize+8);
auto methodInstance = mCeMachine->GetMethodInstance(methodHandle);
if (methodInstance == NULL)
{
_Fail("Invalid method instance");
return false;
}
*(int32*)(stackPtr + 0) = methodInstance->GetParamType(paramIdx)->mTypeId;
*(int16*)(stackPtr + 4) = 0; // Flags
CeSetAddrVal(stackPtr + 4+2, GetString(methodInstance->GetParamName(paramIdx)), ptrSize);
_FixVariables();
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_EmitTypeBody)
{
int32 typeId = *(int32*)((uint8*)stackPtr);
addr_ce strViewPtr = *(addr_ce*)((uint8*)stackPtr + sizeof(int32));
@ -4226,6 +4355,60 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_EmitMethodEntry)
{
int64 methodHandle = *(int64*)((uint8*)stackPtr);
addr_ce strViewPtr = *(addr_ce*)((uint8*)stackPtr + sizeof(int64));
if ((mCurEmitContext == NULL) || (mCurEmitContext->mMethodInstance == NULL) ||
(methodHandle != (int64)mCurEmitContext->mMethodInstance))
{
_Fail("Code cannot be emitted for this method in this context");
return false;
}
if (!GetStringFromStringView(strViewPtr, mCurEmitContext->mEmitData))
{
_Fail("Invalid StringView");
return false;
}
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_EmitMethodExit)
{
int64 methodHandle = *(int64*)((uint8*)stackPtr);
addr_ce strViewPtr = *(addr_ce*)((uint8*)stackPtr + sizeof(int64));
if ((mCurEmitContext == NULL) || (mCurEmitContext->mMethodInstance == NULL) ||
(methodHandle != (int64)mCurEmitContext->mMethodInstance))
{
_Fail("Code cannot be emitted for this method in this context");
return false;
}
if (!GetStringFromStringView(strViewPtr, mCurEmitContext->mExitEmitData))
{
_Fail("Invalid StringView");
return false;
}
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_EmitMixin)
{
addr_ce strViewPtr = *(addr_ce*)((uint8*)stackPtr);
String emitStr;
if (!GetStringFromStringView(strViewPtr, emitStr))
{
_Fail("Invalid StringView");
return false;
}
mCurModule->CEMixin(mCurTargetSrc, emitStr);
handled = true;
return true;
}
else if (checkFunction->mFunctionKind == CeFunctionKind_Sleep)
{
int32 sleepMS = *(int32*)((uint8*)stackPtr);
@ -4461,7 +4644,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
if (valueAddr == 0)
{
result = 0;
CeSetAddrVal(&result, 0, ptrSize);
}
else
{
@ -4477,9 +4660,10 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
}
if (ceModule->TypeIsSubTypeOf(valueType->ToTypeInstance(), ifaceType->ToTypeInstance(), false))
result = valueAddr;
CeSetAddrVal(&result, valueAddr, ptrSize);
else
result = 0;
CeSetAddrVal(&result, 0, ptrSize);
}
}
break;
@ -4973,7 +5157,15 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
CE_CHECKADDR(valueAddr, sizeof(int32));
int32 objTypeId = *(int32*)(memStart + valueAddr);
auto valueType = ceModule->mContext->mTypes[objTypeId]->ToTypeInstance();
auto bfObjectType = GetBfType(objTypeId);
if ((bfObjectType == NULL) || (!bfObjectType->IsTypeInstance()))
{
_Fail("Invalid object");
return false;
}
auto valueType = bfObjectType->ToTypeInstance();
BfMethodInstance* methodInstance = NULL;
if (valueType != NULL)
@ -5671,8 +5863,10 @@ void CeMachine::CompileStarted()
void CeMachine::CompileDone()
{
// So things like delted local methods get recheckeds
// So things like deleted local methods get recheckeds
mRevision++;
mTypeInfoMap.Clear();
mMethodInstanceSet.Clear();
}
void CeMachine::DerefMethodInfo(CeFunctionInfo* ceFunctionInfo)
@ -6008,12 +6202,48 @@ void CeMachine::PrepareFunction(CeFunction* ceFunction, CeBuilder* parentBuilder
{
ceFunction->mFunctionKind = CeFunctionKind_Type_GetCustomAttribute;
}
else if (methodDef->mName == "Comptime_GetMethod")
{
ceFunction->mFunctionKind = CeFunctionKind_GetMethod;
}
else if (methodDef->mName == "Comptime_GetMethodCount")
{
ceFunction->mFunctionKind = CeFunctionKind_GetMethodCount;
}
else if (methodDef->mName == "Comptime_Method_ToString")
{
ceFunction->mFunctionKind = CeFunctionKind_Method_ToString;
}
else if (methodDef->mName == "Comptime_Method_GetName")
{
ceFunction->mFunctionKind = CeFunctionKind_Method_GetName;
}
else if (methodDef->mName == "Comptime_Method_GetInfo")
{
ceFunction->mFunctionKind = CeFunctionKind_Method_GetInfo;
}
else if (methodDef->mName == "Comptime_Method_GetParamInfo")
{
ceFunction->mFunctionKind = CeFunctionKind_Method_GetParamInfo;
}
}
else if (owner->IsInstanceOf(mCeModule->mCompiler->mCompilerTypeDef))
{
if (methodDef->mName == "Comptime_EmitDefinition")
if (methodDef->mName == "Comptime_EmitTypeBody")
{
ceFunction->mFunctionKind = CeFunctionKind_EmitDefinition;
ceFunction->mFunctionKind = CeFunctionKind_EmitTypeBody;
}
else if (methodDef->mName == "Comptime_EmitMethodEntry")
{
ceFunction->mFunctionKind = CeFunctionKind_EmitMethodEntry;
}
else if (methodDef->mName == "Comptime_EmitMethodExit")
{
ceFunction->mFunctionKind = CeFunctionKind_EmitMethodExit;
}
else if (methodDef->mName == "Comptime_EmitMixin")
{
ceFunction->mFunctionKind = CeFunctionKind_EmitMixin;
}
}
else if (owner->IsInstanceOf(mCeModule->mCompiler->mDiagnosticsDebugTypeDef))
@ -6188,6 +6418,52 @@ CeFunction* CeMachine::GetPreparedFunction(BfMethodInstance* methodInstance)
return ceFunction;
}
CeTypeInfo* CeMachine::GetTypeInfo(BfType* type)
{
if (type == NULL)
return NULL;
auto typeInstance = type->ToTypeInstance();
if (typeInstance == NULL)
return NULL;
CeTypeInfo* ceTypeInfo = NULL;
if (!mTypeInfoMap.TryAdd(type, NULL, &ceTypeInfo))
{
if (ceTypeInfo->mRevision == typeInstance->mRevision)
return ceTypeInfo;
ceTypeInfo->mMethodInstances.Clear();
}
mCeModule->PopulateType(typeInstance, BfPopulateType_DataAndMethods);
ceTypeInfo->mRevision = typeInstance->mRevision;
for (auto& methodGroup : typeInstance->mMethodInstanceGroups)
{
if (methodGroup.mDefault != NULL)
{
mMethodInstanceSet.Add(methodGroup.mDefault);
ceTypeInfo->mMethodInstances.Add(methodGroup.mDefault);
}
if (methodGroup.mMethodSpecializationMap != NULL)
{
for (auto& kv : *methodGroup.mMethodSpecializationMap)
{
mMethodInstanceSet.Add(kv.mValue);
ceTypeInfo->mMethodInstances.Add(kv.mValue);
}
}
}
return ceTypeInfo;
}
BfMethodInstance* CeMachine::GetMethodInstance(int64 methodHandle)
{
BfMethodInstance* methodInstance = (BfMethodInstance*)(intptr)methodHandle;
if (!mMethodInstanceSet.Contains(methodInstance))
return false;
return methodInstance;
}
void CeMachine::QueueMethod(BfMethodInstance* methodInstance, BfIRValue func)
{
if (mPreparingFunction != NULL)

View file

@ -254,7 +254,17 @@ enum CeFunctionKind
CeFunctionKind_GetReflectTypeByName,
CeFunctionKind_GetReflectSpecializedType,
CeFunctionKind_Type_GetCustomAttribute,
CeFunctionKind_EmitDefinition,
CeFunctionKind_GetMethodCount,
CeFunctionKind_GetMethod,
CeFunctionKind_Method_ToString,
CeFunctionKind_Method_GetName,
CeFunctionKind_Method_GetInfo,
CeFunctionKind_Method_GetParamInfo,
CeFunctionKind_EmitTypeBody,
CeFunctionKind_EmitMethodEntry,
CeFunctionKind_EmitMethodExit,
CeFunctionKind_EmitMixin,
CeFunctionKind_Sleep,
CeFunctionKind_Char32_ToLower,
CeFunctionKind_Char32_ToUpper,
@ -613,11 +623,14 @@ class CeEmitContext
{
public:
BfType* mType;
BfMethodInstance* mMethodInstance;
String mEmitData;
String mExitEmitData;
CeEmitContext()
{
mType = NULL;
mMethodInstance = NULL;
}
};
@ -662,6 +675,7 @@ public:
int GetTypeIdFromType(addr_ce typeAddr);
addr_ce GetReflectSpecializedType(addr_ce unspecializedType, addr_ce typeArgsSpanAddr);
addr_ce GetString(int stringId);
addr_ce GetString(const StringImpl& str);
addr_ce GetConstantData(BeConstant* constant);
BfType* GetBfType(int typeId);
void PrepareConstStructEntry(CeConstStructData& constStructData);
@ -677,12 +691,20 @@ public:
BfTypedValue Call(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray<BfIRValue>& args, CeEvalFlags flags, BfType* expectingType);
};
struct CeTypeInfo
{
Array<BfMethodInstance*> mMethodInstances;
int mRevision;
};
class CeMachine
{
public:
Dictionary<BfMethodInstance*, CeFunctionInfo*> mFunctions;
Dictionary<String, CeFunctionInfo*> mNamedFunctionMap;
Dictionary<int, CeFunction*> mFunctionIdMap; // Only used for 32-bit
Dictionary<BfType*, CeTypeInfo> mTypeInfoMap;
HashSet<BfMethodInstance*> mMethodInstanceSet;
Array<CeContext*> mContextList;
@ -722,6 +744,8 @@ public:
void CheckFunctions();
CeFunction* GetFunction(BfMethodInstance* methodInstance, BfIRValue func, bool& added);
CeFunction* GetPreparedFunction(BfMethodInstance* methodInstance);
CeTypeInfo* GetTypeInfo(BfType* type);
BfMethodInstance* GetMethodInstance(int64 methodHandle);
public:
void CompileStarted();

View file

@ -1,4 +1,6 @@
using System;
using System.Diagnostics;
using System.Reflection;
namespace Tests
{
@ -27,11 +29,26 @@ namespace Tests
[Comptime]
public void ApplyToType(Type type)
{
Compiler.EmitDefinition(type, scope $"""
Compiler.EmitTypeBody(type, scope $"""
public int32 m{mMemberName} = {mInitVal};
public int32 GetVal{mMemberName}() => mC;
""");
}
}
[AttributeUsage(.Method)]
struct LogAttribute : Attribute, IComptimeMethodApply
{
public static String gLog = new .() ~ delete _;
[Comptime]
public void ApplyToMethod(ComptimeMethodInfo method)
{
String emit = scope $"LogAttribute.gLog.AppendF($\"Called {method}";
for (var fieldIdx < method.ParamCount)
emit.AppendF($" {{ {method.GetParamName(fieldIdx)} }}");
emit.Append("\");");
Compiler.EmitMethodEntry(method, emit);
}
}
@ -43,13 +60,19 @@ namespace Tests
[OnCompile(.TypeInit), Comptime]
public static void Generate()
{
Compiler.EmitDefinition(typeof(Self), """
Compiler.EmitTypeBody(typeof(Self), """
public int32 mB = 234;
public int32 GetValB() => mB;
""");
}
}
[Log]
public static void MethodA(int a, int b)
{
}
[Test]
public static void TestBasics()
{
@ -59,6 +82,12 @@ namespace Tests
Test.Assert(ca.GetValB() == 234);
Test.Assert(ca.mC == 345);
Test.Assert(ca.GetValC() == 345);
Compiler.Mixin("int val = 99;");
Test.Assert(val == 99);
MethodA(34, 45);
Debug.Assert(LogAttribute.gLog == "Called Tests.Comptime.MethodA(int a, int b) 34 45");
}
}
}