diff options
Diffstat (limited to 'ChocolArm64/Instructions/InstEmitFlowHelper.cs')
-rw-r--r-- | ChocolArm64/Instructions/InstEmitFlowHelper.cs | 122 |
1 files changed, 115 insertions, 7 deletions
diff --git a/ChocolArm64/Instructions/InstEmitFlowHelper.cs b/ChocolArm64/Instructions/InstEmitFlowHelper.cs index cf093bb3..e93ef426 100644 --- a/ChocolArm64/Instructions/InstEmitFlowHelper.cs +++ b/ChocolArm64/Instructions/InstEmitFlowHelper.cs @@ -1,4 +1,6 @@ +using ChocolArm64.State; using ChocolArm64.Translation; +using System.Reflection; using System.Reflection.Emit; namespace ChocolArm64.Instructions @@ -7,12 +9,120 @@ namespace ChocolArm64.Instructions { public static void EmitCall(ILEmitterCtx context, long imm) { - if (context.TryOptEmitSubroutineCall()) + if (context.Tier == TranslationTier.Tier0) + { + context.TranslateAhead(imm); + + context.EmitLdc_I8(imm); + + context.Emit(OpCodes.Ret); + + return; + } + + if (!context.TryOptEmitSubroutineCall()) + { + context.TranslateAhead(imm); + + context.EmitLdarg(TranslatedSub.StateArgIdx); + + context.EmitFieldLoad(typeof(CpuThreadState).GetField(nameof(CpuThreadState.CurrentTranslator), + BindingFlags.Instance | + BindingFlags.NonPublic)); + + context.EmitLdarg(TranslatedSub.StateArgIdx); + context.EmitLdc_I8(imm); + + context.EmitPrivateCall(typeof(Translator), nameof(Translator.GetOrTranslateSubroutine)); + + context.EmitLdarg(TranslatedSub.StateArgIdx); + context.EmitLdarg(TranslatedSub.MemoryArgIdx); + + context.EmitCall(typeof(TranslatedSub), nameof(TranslatedSub.Execute)); + } + + EmitContinueOrReturnCheck(context); + } + + public static void EmitVirtualCall(ILEmitterCtx context) + { + EmitVirtualCallOrJump(context, isJump: false); + } + + public static void EmitVirtualJump(ILEmitterCtx context) + { + EmitVirtualCallOrJump(context, isJump: true); + } + + private static void EmitVirtualCallOrJump(ILEmitterCtx context, bool isJump) + { + if (context.Tier == TranslationTier.Tier0) + { + context.Emit(OpCodes.Dup); + + context.EmitSttmp(); + context.EmitLdarg(TranslatedSub.StateArgIdx); + + context.EmitFieldLoad(typeof(CpuThreadState).GetField(nameof(CpuThreadState.CurrentTranslator), + BindingFlags.Instance | + BindingFlags.NonPublic)); + + context.EmitLdarg(TranslatedSub.StateArgIdx); + context.EmitLdtmp(); + + context.EmitPrivateCall(typeof(Translator), nameof(Translator.TranslateVirtualSubroutine)); + + context.Emit(OpCodes.Ret); + } + else + { + context.EmitSttmp(); + context.EmitLdarg(TranslatedSub.StateArgIdx); + + context.EmitFieldLoad(typeof(CpuThreadState).GetField(nameof(CpuThreadState.CurrentTranslator), + BindingFlags.Instance | + BindingFlags.NonPublic)); + + context.EmitLdarg(TranslatedSub.StateArgIdx); + context.EmitLdtmp(); + + context.EmitPrivateCall(typeof(Translator), nameof(Translator.GetOrTranslateVirtualSubroutine)); + + context.EmitLdarg(TranslatedSub.StateArgIdx); + context.EmitLdarg(TranslatedSub.MemoryArgIdx); + + if (isJump) + { + //The tail prefix allows the JIT to jump to the next function, + //while releasing the stack space used by the current one. + //This is ideal for BR ARM instructions, which are + //basically indirect tail calls. + context.Emit(OpCodes.Tailcall); + } + + MethodInfo mthdInfo = typeof(ArmSubroutine).GetMethod("Invoke"); + + context.EmitCall(mthdInfo, isVirtual: true); + + if (!isJump) + { + EmitContinueOrReturnCheck(context); + } + else + { + context.Emit(OpCodes.Ret); + } + } + } + + private static void EmitContinueOrReturnCheck(ILEmitterCtx context) + { + //Note: The return value of the called method will be placed + //at the Stack, the return value is always a Int64 with the + //return address of the function. We check if the address is + //correct, if it isn't we keep returning until we reach the dispatcher. + if (context.CurrBlock.Next != null) { - //Note: the return value of the called method will be placed - //at the Stack, the return value is always a Int64 with the - //return address of the function. We check if the address is - //correct, if it isn't we keep returning until we reach the dispatcher. context.Emit(OpCodes.Dup); context.EmitLdc_I8(context.CurrOp.Position + 4); @@ -30,8 +140,6 @@ namespace ChocolArm64.Instructions } else { - context.EmitLdc_I8(imm); - context.Emit(OpCodes.Ret); } } |