예제 #1
0
        private static void EmitVirtualCallOrJump(ILEmitterCtx context, bool isJump)
        {
            if (context.Tier == TranslationTier.Tier0)
            {
                context.Emit(OpCodes.Ret);
            }
            else
            {
                context.EmitSttmp();
                context.EmitLdarg(TranslatedSub.StateArgIdx);

                context.EmitLdfld(typeof(CpuThreadState).GetField(nameof(CpuThreadState.CurrentTranslator),
                                                                  BindingFlags.Instance |
                                                                  BindingFlags.NonPublic));

                context.EmitLdarg(TranslatedSub.StateArgIdx);
                context.EmitLdtmp();
                context.EmitLdc_I4(isJump
                    ? (int)CallType.VirtualJump
                    : (int)CallType.VirtualCall);

                context.EmitPrivateCall(typeof(Translator), nameof(Translator.GetOrTranslateSubroutine));

                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);
                }
            }
        }
예제 #2
0
        public static void EmitCall(ILEmitterCtx context, long imm)
        {
            if (context.Tier == TranslationTier.Tier0)
            {
                context.EmitStoreContext();

                context.TranslateAhead(imm);

                context.EmitLdc_I8(imm);

                context.Emit(OpCodes.Ret);

                return;
            }

            if (!context.TryOptEmitSubroutineCall())
            {
                context.HasSlowCall = true;

                context.EmitStoreContext();

                context.TranslateAhead(imm);

                context.EmitLdarg(TranslatedSub.StateArgIdx);

                context.EmitLdfld(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);
        }