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); } } }
public static void EmitCall(ILEmitterCtx context, long imm) { if (context.Tier == TranslationTier.Tier0) { context.EmitStoreState(); context.TranslateAhead(imm); context.EmitLdc_I8(imm); context.Emit(OpCodes.Ret); return; } if (!context.TryOptEmitSubroutineCall()) { context.HasSlowCall = true; context.EmitStoreState(); 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.EmitLdc_I4((int)CallType.Call); context.EmitPrivateCall(typeof(Translator), nameof(Translator.GetOrTranslateSubroutine)); context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitCall(typeof(TranslatedSub), nameof(TranslatedSub.Execute)); } EmitContinueOrReturnCheck(context); }