Example #1
0
        /// <summary>
        /// Sets the given local to its default value in the given IL generator.
        /// </summary>
        /// <param name="local">Local to set to default</param>
        /// <returns>Instructions</returns>
        public static IEnumerable <MsilInstruction> SetToDefault(this MsilLocal local)
        {
            Debug.Assert(local.Type != null);
            if (local.Type.IsEnum || local.Type.IsPrimitive)
            {
                if (local.Type == typeof(float))
                {
                    yield return(new MsilInstruction(OpCodes.Ldc_R4).InlineValue(0f));
                }
                else if (local.Type == typeof(double))
                {
                    yield return(new MsilInstruction(OpCodes.Ldc_R8).InlineValue(0d));
                }
                else if (local.Type == typeof(long) || local.Type == typeof(ulong))
                {
                    yield return(new MsilInstruction(OpCodes.Ldc_I8).InlineValue(0L));
                }
                else
                {
                    yield return(new MsilInstruction(OpCodes.Ldc_I4).InlineValue(0));
                }
                yield return(new MsilInstruction(OpCodes.Stloc).InlineValue(local));
            }
            else if (local.Type.IsValueType) // struct
            {
                yield return(new MsilInstruction(OpCodes.Ldloca).InlineValue(local));

                yield return(new MsilInstruction(OpCodes.Initobj).InlineValue(local.Type));
            }
            else // class
            {
                yield return(new MsilInstruction(OpCodes.Ldnull));

                yield return(new MsilInstruction(OpCodes.Stloc).InlineValue(local));
            }
        }
Example #2
0
        private IEnumerable <MsilInstruction> EmitPatched(Func <Type, bool, MsilLocal> declareLocal)
        {
            var methodBody = _method.GetMethodBody();

            Debug.Assert(methodBody != null, "Method body is null");
            foreach (var localVar in methodBody.LocalVariables)
            {
                Debug.Assert(localVar.LocalType != null);
                declareLocal(localVar.LocalType, localVar.IsPinned);
            }

            var instructions     = new List <MsilInstruction>();
            var specialVariables = new Dictionary <string, MsilLocal>();

            var labelAfterOriginalContent = new MsilLabel();
            var labelSkipMethodContent    = new MsilLabel();


            Type      returnType     = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
            MsilLocal resultVariable = null;

            if (returnType != typeof(void))
            {
                if (Prefixes.Concat(Suffixes).SelectMany(x => x.GetParameters()).Any(x => x.Name == RESULT_PARAMETER) ||
                    Prefixes.Any(x => x.ReturnType == typeof(bool)))
                {
                    resultVariable = declareLocal(returnType, false);
                }
            }

            if (resultVariable != null)
            {
                instructions.AddRange(resultVariable.SetToDefault());
            }
            MsilLocal prefixSkippedVariable = null;

            if (Prefixes.Count > 0 && Suffixes.Any(x => x.GetParameters()
                                                   .Any(y => y.Name.Equals(PREFIX_SKIPPED_PARAMETER))))
            {
                prefixSkippedVariable = declareLocal(typeof(bool), false);
                specialVariables.Add(PREFIX_SKIPPED_PARAMETER, prefixSkippedVariable);
            }

            if (resultVariable != null)
            {
                specialVariables.Add(RESULT_PARAMETER, resultVariable);
            }

            // Create special variables
            foreach (var m in Prefixes.Concat(Suffixes))
            {
                foreach (var param in m.GetParameters())
                {
                    if (param.Name.StartsWith(LOCAL_PARAMETER))
                    {
                        var requiredType = param.ParameterType.IsByRef ? param.ParameterType.GetElementType() : param.ParameterType;
                        if (specialVariables.TryGetValue(param.Name, out var existingParam))
                        {
                            if (existingParam.Type != requiredType)
                            {
                                throw new ArgumentException(
                                          $"Trying to use injected local {param.Name} for {m.DeclaringType?.FullName}#{m.ToString()} with type {requiredType} but a local with the same name already exists with type {existingParam.Type}",
                                          param.Name);
                            }
                        }
                        else
                        {
                            specialVariables.Add(param.Name, declareLocal(requiredType, false));
                        }
                    }
                }
            }

            foreach (MethodInfo prefix in Prefixes)
            {
                instructions.AddRange(EmitMonkeyCall(prefix, specialVariables));
                if (prefix.ReturnType == typeof(bool))
                {
                    instructions.Add(new MsilInstruction(OpCodes.Brfalse).InlineTarget(labelSkipMethodContent));
                }
                else if (prefix.ReturnType != typeof(void))
                {
                    throw new Exception(
                              $"Prefixes must return void or bool.  {prefix.DeclaringType?.FullName}.{prefix.Name} returns {prefix.ReturnType}");
                }
            }

            instructions.AddRange(MethodTranspiler.Transpile(_method, (x) => declareLocal(x, false), Transpilers, labelAfterOriginalContent));

            instructions.Add(new MsilInstruction(OpCodes.Nop).LabelWith(labelAfterOriginalContent));
            if (resultVariable != null)
            {
                instructions.Add(new MsilInstruction(OpCodes.Stloc).InlineValue(resultVariable));
            }
            var notSkip = new MsilLabel();

            instructions.Add(new MsilInstruction(OpCodes.Br).InlineTarget(notSkip));
            instructions.Add(new MsilInstruction(OpCodes.Nop).LabelWith(labelSkipMethodContent));
            if (prefixSkippedVariable != null)
            {
                instructions.Add(new MsilInstruction(OpCodes.Ldc_I4_1));
                instructions.Add(new MsilInstruction(OpCodes.Stloc).InlineValue(prefixSkippedVariable));
            }

            instructions.Add(new MsilInstruction(OpCodes.Nop).LabelWith(notSkip));

            foreach (MethodInfo suffix in Suffixes)
            {
                instructions.AddRange(EmitMonkeyCall(suffix, specialVariables));
                if (suffix.ReturnType != typeof(void))
                {
                    throw new Exception($"Suffixes must return void.  {suffix.DeclaringType?.FullName}.{suffix.Name} returns {suffix.ReturnType}");
                }
            }

            if (resultVariable != null)
            {
                instructions.Add(new MsilInstruction(OpCodes.Ldloc).InlineValue(resultVariable));
            }
            instructions.Add(new MsilInstruction(OpCodes.Ret));

            var result = MethodTranspiler.Transpile(_method, instructions, (x) => declareLocal(x, false), PostTranspilers, null).ToList();

            if (result.Last().OpCode != OpCodes.Ret)
            {
                result.Add(new MsilInstruction(OpCodes.Ret));
            }
            return(result);
        }
Example #3
0
        private static IEnumerable <MsilInstruction> TranspilerForUpdate <T>(IEnumerable <MsilInstruction> insn, Func <Type, MsilLocal> __localCreator, MethodBase __methodBase)
        {
            MethodInfo profilerCall = null;

            if (typeof(IMyEntity).IsAssignableFrom(typeof(T)))
            {
                profilerCall = ProfilerData.GetEntityProfiler;
            }
            else if (typeof(MyEntityComponentBase).IsAssignableFrom(typeof(T)) || typeof(T) == typeof(IMyGameLogicComponent))
            {
                profilerCall = ProfilerData.GetEntityComponentProfiler;
            }
            else if (typeof(MyCubeGridSystems) == typeof(T))
            {
                profilerCall = ProfilerData.GetGridSystemProfiler;
            }
            else if (typeof(MySessionComponentBase) == typeof(T))
            {
                profilerCall = ProfilerData.GetSessionComponentProfiler;
            }
            else
            {
                _log.Warn($"Trying to profile unknown target {typeof(T)}");
            }

            MsilLocal profilerEntry = profilerCall != null
                ? __localCreator(typeof(SlimProfilerEntry))
                : null;

            var usedLocals  = new List <MsilLocal>();
            var tmpArgument = new Dictionary <Type, Stack <MsilLocal> >();

            var foundAny = false;

            foreach (MsilInstruction i in insn)
            {
                if (profilerCall != null && (i.OpCode == OpCodes.Call || i.OpCode == OpCodes.Callvirt) &&
                    ShouldProfileMethodCall <T>((i.Operand as MsilOperandInline <MethodBase>)?.Value))
                {
                    MethodBase      target = ((MsilOperandInline <MethodBase>)i.Operand).Value;
                    ParameterInfo[] pams   = target.GetParameters();
                    usedLocals.Clear();
                    foreach (ParameterInfo pam in pams)
                    {
                        if (!tmpArgument.TryGetValue(pam.ParameterType, out var stack))
                        {
                            tmpArgument.Add(pam.ParameterType, stack = new Stack <MsilLocal>());
                        }
                        MsilLocal local = stack.Count > 0 ? stack.Pop() : __localCreator(pam.ParameterType);
                        usedLocals.Add(local);
                        yield return(local.AsValueStore());
                    }

                    _log.Debug($"Attaching profiling to {target?.DeclaringType?.FullName}#{target?.Name} in {__methodBase.DeclaringType?.FullName}#{__methodBase.Name} targeting {typeof(T)}");
                    yield return(new MsilInstruction(OpCodes.Dup)); // duplicate the object the update is called on

                    if (typeof(MyCubeGridSystems) == typeof(T) && __methodBase.DeclaringType == typeof(MyCubeGridSystems))
                    {
                        yield return(new MsilInstruction(OpCodes.Ldarg_0));

                        yield return(new MsilInstruction(OpCodes.Ldfld).InlineValue(_gridSystemsCubeGrid));
                    }

                    yield return(new MsilInstruction(OpCodes.Call).InlineValue(profilerCall)); // consume object the update is called on

                    yield return(new MsilInstruction(OpCodes.Dup));                            // Duplicate profiler entry for brnull

                    yield return(profilerEntry.AsValueStore());                                // store the profiler entry for later

                    var skipProfilerOne = new MsilLabel();
                    yield return(new MsilInstruction(OpCodes.Brfalse).InlineTarget(skipProfilerOne)); // Brfalse == Brnull

                    {
                        yield return(profilerEntry.AsValueLoad()); // start the profiler

                        yield return(new MsilInstruction(OpCodes.Call).InlineValue(ProfilerData.ProfilerEntryStart));
                    }

                    // consumes from the first Dup
                    yield return(new MsilInstruction(OpCodes.Nop).LabelWith(skipProfilerOne));

                    for (int j = usedLocals.Count - 1; j >= 0; j--)
                    {
                        yield return(usedLocals[j].AsValueLoad());

                        tmpArgument[usedLocals[j].Type].Push(usedLocals[j]);
                    }
                    yield return(i);

                    var skipProfilerTwo = new MsilLabel();
                    yield return(profilerEntry.AsValueLoad());

                    yield return(new MsilInstruction(OpCodes.Brfalse).InlineTarget(skipProfilerTwo)); // Brfalse == Brnull

                    {
                        yield return(profilerEntry.AsValueLoad()); // stop the profiler

                        yield return(new MsilInstruction(OpCodes.Call).InlineValue(ProfilerData.ProfilerEntryStop));
                    }
                    yield return(new MsilInstruction(OpCodes.Nop).LabelWith(skipProfilerTwo));

                    foundAny = true;
                    continue;
                }
                yield return(i);
            }
            if (!foundAny)
            {
                _log.Warn($"Didn't find any update profiling targets for target {typeof(T)} in {__methodBase.DeclaringType?.FullName}#{__methodBase.Name}");
            }
        }