コード例 #1
0
        internal static IEnumerable <MsilInstruction> Transpile(MethodBase baseMethod, Func <Type, MsilLocal> localCreator, IEnumerable <MethodInfo> transpilers,
                                                                MsilLabel retLabel)
        {
            var context = new MethodContext(baseMethod);

            context.Read();
            // IntegrityAnalysis(LogLevel.Trace, context.Instructions);
            return(Transpile(baseMethod, context.Instructions, localCreator, transpilers, retLabel));
        }
コード例 #2
0
 internal MsilLabel LabelAt(int i)
 {
     if (Labels.TryGetValue(i, out MsilLabel label))
     {
         return(label);
     }
     Labels.Add(i, label = new MsilLabel());
     return(label);
 }
コード例 #3
0
        private static IEnumerable <MsilInstruction> FoliageRenderFix(IEnumerable <MsilInstruction> src)
        {
            foreach (var call in src)
            {
                if ((call.OpCode == OpCodes.Callvirt || call.OpCode == OpCodes.Call) && call.Operand is MsilOperandInline <MethodBase> op &&
                    op.Value == _rcDrawAuto)
                {
                    var end      = new MsilLabel();
                    var noStereo = new MsilLabel();
                    yield return(new MsilInstruction(OpCodes.Call).InlineValue(_stereoRenderEnable.GetMethod));

                    yield return(new MsilInstruction(OpCodes.Brfalse).InlineTarget(noStereo));

                    yield return(new MsilInstruction(OpCodes.Dup));                                      // [... RC, RC]

                    yield return(new MsilInstruction(OpCodes.Call).InlineValue(_beginDrawGBufferPass));  // [... RC]

                    yield return(new MsilInstruction(OpCodes.Dup));                                      // [... RC, RC]

                    yield return(new MsilInstruction(call.OpCode).InlineValue(_rcDrawAuto));             // [... RC]

                    yield return(new MsilInstruction(OpCodes.Dup));                                      // [... RC, RC]

                    yield return(new MsilInstruction(OpCodes.Call).InlineValue(_switchDrawGBufferPass)); // [... RC]

                    yield return(new MsilInstruction(OpCodes.Dup));                                      // [... RC, RC]

                    yield return(new MsilInstruction(call.OpCode).InlineValue(_rcDrawAuto));             // [... RC]

                    yield return(new MsilInstruction(OpCodes.Call).InlineValue(_endDrawGBufferPass));    // [...]

                    yield return(new MsilInstruction(OpCodes.Br).InlineTarget(end));

                    call.Labels.Add(noStereo);
                    yield return(call);

                    var t = new MsilInstruction(OpCodes.Nop);
                    t.Labels.Add(end);
                    yield return(t);
                }
                else
                {
                    yield return(call);
                }
            }
        }
コード例 #4
0
        private static IEnumerable <MsilInstruction> FixDrawCalls(IEnumerable <MsilInstruction> src)
        {
            foreach (var call in src)
            {
                if ((call.OpCode == OpCodes.Callvirt || call.OpCode == OpCodes.Call) && call.Operand is MsilOperandInline <MethodBase> op &&
                    _stereoCallReplace.TryGetValue(op.Value, out MethodBase replaceTarget))
                {
                    var end      = new MsilLabel();
                    var noStereo = new MsilLabel();
                    yield return(new MsilInstruction(OpCodes.Call).InlineValue(_stereoRenderEnable.GetMethod));

                    yield return(new MsilInstruction(OpCodes.Brfalse).InlineTarget(noStereo));

                    yield return(new MsilInstruction(OpCodes.Call).InlineValue(replaceTarget));

                    yield return(new MsilInstruction(OpCodes.Br).InlineTarget(end));

                    call.Labels.Add(noStereo);
                    yield return(call);

                    var t = new MsilInstruction(OpCodes.Nop);
                    t.Labels.Add(end);
                    yield return(t);
                }
コード例 #5
0
ファイル: DecoratedMethod.cs プロジェクト: raydleemsc/Torch
        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);
        }
コード例 #6
0
 private static IEnumerable <MsilInstruction> FixBranchAndReturn(IEnumerable <MsilInstruction> insn, MsilLabel retTarget)
 {
     foreach (MsilInstruction i in insn)
     {
         if (retTarget != null && i.OpCode == OpCodes.Ret)
         {
             var j = i.CopyWith(OpCodes.Br).InlineTarget(retTarget);
             _log.Trace($"Replacing {i} with {j}");
             yield return(j);
         }
         else if (_shortToLongBranch.TryGetValue(i.OpCode, out OpCode replaceOpcode))
         {
             var result = i.CopyWith(replaceOpcode);
             _log.Trace($"Replacing {i} with {result}");
             yield return(result);
         }
         else
         {
             yield return(i);
         }
     }
 }
コード例 #7
0
        internal static IEnumerable <MsilInstruction> Transpile(MethodBase baseMethod, IEnumerable <MsilInstruction> methodContent,
                                                                Func <Type, MsilLocal> localCreator, IEnumerable <MethodInfo> transpilers, MsilLabel retLabel)
        {
            foreach (MethodInfo transpiler in transpilers)
            {
                var paramList = new List <object>();
                foreach (var parameter in transpiler.GetParameters())
                {
                    if (parameter.Name.Equals("__methodBody"))
                    {
                        paramList.Add(baseMethod.GetMethodBody());
                    }
                    else if (parameter.Name.Equals("__methodBase"))
                    {
                        paramList.Add(baseMethod);
                    }
                    else if (parameter.Name.Equals("__localCreator"))
                    {
                        paramList.Add(localCreator);
                    }
                    else if (parameter.ParameterType == typeof(IEnumerable <MsilInstruction>))
                    {
                        paramList.Add(methodContent);
                    }
                    else
                    {
                        throw new ArgumentException(
                                  $"Bad transpiler parameter type {parameter.ParameterType.FullName} {parameter.Name}");
                    }
                }

                methodContent = (IEnumerable <MsilInstruction>)transpiler.Invoke(null, paramList.ToArray());
            }

            return(FixBranchAndReturn(methodContent, retLabel));
        }
コード例 #8
0
        private static IEnumerable <MsilInstruction> TranspileDrawF(IEnumerable <MsilInstruction> stream, Func <Type, MsilLocal> __localCreator)
        {
            var replaced = false;

            foreach (var insn in stream)
            {
                if (AllowUiHack && insn.Operand is MsilOperandInline <MethodBase> mtarget && mtarget.Value == _drawSprites)
                {
                    var stereoMode   = new MsilLabel();
                    var endOfSprites = new MsilLabel();
                    yield return(new MsilInstruction(OpCodes.Call).InlineValue(_stereoRenderEnable.GetMethod));

                    yield return(new MsilInstruction(OpCodes.Brtrue).InlineTarget(stereoMode));

                    // if (!Stereo.Enable)
                    {
                        yield return(insn);

                        yield return(new MsilInstruction(OpCodes.Br).InlineTarget(endOfSprites));
                    }
                    // else
                    {
                        yield return(new MsilInstruction(OpCodes.Nop).LabelWith(stereoMode));

                        // Clear out arguments
                        if (!_drawSprites.IsStatic)
                        {
                            yield return(new MsilInstruction(OpCodes.Pop));
                        }
                        foreach (var k in _drawSprites.GetParameters())
                        {
                            yield return(new MsilInstruction(OpCodes.Pop));
                        }

                        // Create the RTV
                        var uiRtv = __localCreator.Invoke(_drawSpritesOffscreen.ReturnType);
                        yield return(new MsilInstruction(OpCodes.Ldstr).InlineValue("VR.Overlay"));

                        #region viewport.X / 2
                        yield return(new MsilInstruction(OpCodes.Call).InlineValue(_viewportResolution.GetMethod));

                        yield return(new MsilInstruction(OpCodes.Ldfld).InlineValue(_vector2IX));

                        yield return(new MsilInstruction(OpCodes.Ldc_I4_2));

                        yield return(new MsilInstruction(OpCodes.Div));

                        #endregion
                        #region viewport.Y
                        yield return(new MsilInstruction(OpCodes.Call).InlineValue(_viewportResolution.GetMethod));

                        yield return(new MsilInstruction(OpCodes.Ldfld).InlineValue(_vector2IY));

                        #endregion
                        yield return(new MsilInstruction(OpCodes.Ldc_I4).InlineValue((int)SharpDX.DXGI.Format
                                                                                     .B8G8R8A8_UNorm));

                        #region (SharpDX.Color?)null
                        var tmpColorNullable = __localCreator.Invoke(typeof(SharpDX.Color?));
                        yield return(tmpColorNullable.AsReferenceLoad());

                        yield return(new MsilInstruction(OpCodes.Initobj).InlineValue(tmpColorNullable.Type));

                        yield return(tmpColorNullable.AsValueLoad());

                        #endregion
                        yield return(new MsilInstruction(OpCodes.Call).InlineValue(_drawSpritesOffscreen));

                        yield return(uiRtv.AsValueStore());

                        var tmpViewportNullable = __localCreator.Invoke(typeof(MyViewport?));
                        yield return(tmpViewportNullable.AsReferenceLoad());

                        yield return(new MsilInstruction(OpCodes.Initobj).InlineValue(tmpViewportNullable.Type));

                        foreach (var region in new[]
                                 { Types.StereoRenderRegion.Left, Types.StereoRenderRegion.Right })
                        {
                            yield return(new MsilInstruction(OpCodes.Call).InlineValue(_backbuffer.GetMethod));

                            yield return(uiRtv.AsValueLoad());

                            yield return(new MsilInstruction(OpCodes.Ldc_I4_1));

                            yield return(tmpViewportNullable.AsValueLoad());

                            // MyStereoRender.RenderRegion = region
                            yield return(new MsilInstruction(OpCodes.Ldc_I4).InlineValue((int)region));

                            yield return(new MsilInstruction(OpCodes.Stsfld).InlineValue(_stereoRenderRegion));

                            // MyCopyToRtv.Run(MyRender11.Backbuffer, tempBindable, true, null)
                            yield return(new MsilInstruction(OpCodes.Call).InlineValue(_copyToRtv));
                        }

                        // MyStereoRender.RenderRegion = StereoRenderRegion.Fullscreen
                        yield return(new MsilInstruction(OpCodes.Ldc_I4).InlineValue((int)Types.StereoRenderRegion
                                                                                     .Fullscreen));

                        yield return(new MsilInstruction(OpCodes.Stsfld).InlineValue(_stereoRenderRegion));

                        yield return(uiRtv.AsValueLoad());

                        yield return(new MsilInstruction(OpCodes.Callvirt).InlineValue(_releaseTexture));
                    }
                    yield return(new MsilInstruction(OpCodes.Nop).LabelWith(endOfSprites));
                }
                else if (!replaced && insn.Operand is MsilOperandInline <FieldInfo> target && target.Value == _renderScreenshot)
                {
                    var endOfDisplay = new MsilLabel();
                    yield return(new MsilInstruction(OpCodes.Call).InlineValue(_openvrStatic.GetMethod));

                    yield return(new MsilInstruction(OpCodes.Brfalse).InlineTarget(endOfDisplay));

                    // if (OpenVR.Static != null)
                    {
                        yield return(new MsilInstruction(OpCodes.Ldsfld).InlineValue(_gbufferMain));

                        yield return(new MsilInstruction(OpCodes.Call).InlineValue(_colorBlack.GetMethod));

                        yield return(new MsilInstruction(OpCodes.Callvirt).InlineValue(_gbufferClear));

                        // GBuffer.Main.Clear(Color.Black);

                        yield return(new MsilInstruction(OpCodes.Call).InlineValue(_openvrStatic.GetMethod));

                        yield return(new MsilInstruction(OpCodes.Call).InlineValue(_backbuffer.GetMethod));

                        yield return(new MsilInstruction(OpCodes.Callvirt).InlineValue(_backbufferResource.GetMethod));

                        yield return(new MsilInstruction(OpCodes.Callvirt).InlineValue(_resourcePointer.GetMethod));

                        yield return(new MsilInstruction(OpCodes.Callvirt).InlineValue(_openvrDisplayEye));
                        // OpenVR.Static.DisplayEye(Backbuffer.Resource.NativePointer);
                    }
                    replaced = true;
                    var copy = insn.CopyWith(insn.OpCode);
                    copy.Labels.Add(endOfDisplay);
                    yield return(copy);
                }
                else
                {
                    yield return(insn);
                }
            }
        }
コード例 #9
0
        private static IEnumerable <MsilInstruction> MoveAmbientOcclusionOutOfLoop(
            IEnumerable <MsilInstruction> instructionStream)
        {
            var labelPosition        = new Dictionary <MsilLabel, int>();
            var body                 = instructionStream.ToList();
            var positionBeginAo      = -1;
            var positionEndAo        = -1;
            var positionAsFullscreen = -1;

            for (var i = 0; i < body.Count; i++)
            {
                var ins = body[i];
                foreach (var k in ins.Labels)
                {
                    labelPosition.Add(k, i);
                }
                if (ins.OpCode == OpCodes.Stsfld && ins.Operand is MsilOperandInline <FieldInfo> fieldInfo && fieldInfo.Value == _stereoRenderRegion &&
                    i > 0 && body[i - 1].IsConstIntLoad() && body[i - 1].GetConstInt() == (int)Types.StereoRenderRegion.Fullscreen)
                {
                    positionAsFullscreen = i;
                }
                if (ins.OpCode == OpCodes.Ldstr && ins.Operand is MsilOperandInline <string> inStr &&
                    inStr.Value.Equals("SSAO"))
                {
                    // Advance back up until we find the end of the previous block.
                    var j = i;
                    while (j-- > 0)
                    {
                        if (body[j].Operand is MsilOperandInline <MethodBase> operand &&
                            operand.Value == _gpuProfilerEndBlock)
                        {
                            positionBeginAo = j + 1;
                            break;
                        }
                    }
                    j = i;
                    MsilLabel endLabel = null;
                    while (++j < body.Count)
                    {
                        if (body[j].OpCode == OpCodes.Br || body[j].OpCode == OpCodes.Br_S)
                        {
                            endLabel = ((MsilOperandBrTarget)body[j].Operand).Target;
                            break;
                        }
                    }
                    while (++j < body.Count)
                    {
                        if (body[j].Labels.Contains(endLabel))
                        {
                            positionEndAo = j;
                        }
                    }
                }
            }
            if (positionEndAo == -1 || positionBeginAo == -1 || positionAsFullscreen == -1)
            {
                foreach (var k in body)
                {
                    yield return(k);
                }
                yield break;
            }

            for (var i = 0; i < body.Count; i++)
            {
                if (i < positionBeginAo)
                {
                    yield return(body[i]);
                }
                else if (i >= positionEndAo)
                {
                    yield return(body[i]);
                }
                if (i == positionAsFullscreen)
                {
                    var endOfAo = new MsilLabel();
                    for (var j = positionBeginAo; j < positionEndAo; j++)
                    {
                        if (body[j].Operand is MsilOperandBrTarget target)
                        {
                            var tiv = labelPosition[target.Target];
                            if (tiv == positionEndAo)
                            {
                                yield return(body[j].CopyWith(body[j].OpCode).InlineTarget(endOfAo));

                                continue;
                            }
                            else if (tiv > positionEndAo || tiv < positionBeginAo)
                            {
                                _log.Warn($"Unable to figure out how to deal with label {target.Target} at {tiv}.  AO data is from {positionBeginAo}-{positionEndAo}");
                            }
                        }
                        yield return(body[j]);
                    }
                    var temp = new MsilInstruction(OpCodes.Nop);
                    temp.Labels.Add(endOfAo);
                    yield return(temp);
                }
            }
        }
コード例 #10
0
ファイル: ProfilerPatch.cs プロジェクト: jimmble/Profiler
        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}");
            }
        }
コード例 #11
0
ファイル: ProfilerPatch.cs プロジェクト: jimmble/Profiler
        private static IEnumerable <MsilInstruction> TranspileSingleMethod(IEnumerable <MsilInstruction> insn, Func <Type, MsilLocal> __localCreator, MethodBase __methodBase)
        {
            MethodInfo profilerCall = null;

            foreach (var method in typeof(ProfilerData).GetMethods(BindingFlags.Static | BindingFlags.NonPublic |
                                                                   BindingFlags.Public))
            {
                if (IsSingleMethodProfilerCall(__methodBase, method))
                {
                    profilerCall = method;
                    break;
                }
            }
            if (profilerCall == null)
            {
                foreach (var method in typeof(ProfilerPatch).GetMethods(BindingFlags.Static | BindingFlags.NonPublic |
                                                                        BindingFlags.Public))
                {
                    if (IsSingleMethodProfilerCall(__methodBase, method))
                    {
                        profilerCall = method;
                        break;
                    }
                }
            }
            if (profilerCall == null)
            {
                _log.Warn($"Single method profiler for {__methodBase.DeclaringType?.FullName}#{__methodBase.Name} couldn't find a profiler call; will not operate");
            }

            FieldInfo stringPool = typeof(ProfilerPatch).GetField(nameof(_keyedStringPool),
                                                                  BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            if (stringPool == null)
            {
                _log.Warn($"Single method profiler for {__methodBase.DeclaringType?.FullName}#{__methodBase.Name} couldn't file string pool; will not operate");
            }


            if (profilerCall == null || stringPool == null)
            {
                foreach (var i in insn)
                {
                    yield return(i);
                }
                yield break;
            }

            // Reserve a keyed string.
            int stringKey = 0;

            lock (_keyedStringPoolLock)
            {
                while (_usedStrings >= _keyedStringPool.Length)
                {
                    Array.Resize(ref _keyedStringPool, Math.Max(64, _keyedStringPool.Length * 2));
                }
                stringKey = _usedStrings;
                _keyedStringPool[stringKey] = __methodBase.Name;
                _usedStrings++;
            }

            var profilerLocal = __localCreator(typeof(SlimProfilerEntry));

            _log.Debug($"Attaching profiling to {__methodBase?.DeclaringType?.FullName}#{__methodBase?.Name} with profiler call {profilerCall.DeclaringType?.FullName}#{profilerCall}");


            var labelNoProfiling    = new MsilLabel();
            var labelStoreProfiling = new MsilLabel();

            yield return(new MsilInstruction(OpCodes.Ldsfld).InlineValue(ProfilerData.FieldProfileSingleMethods));

            yield return(new MsilInstruction(OpCodes.Brfalse).InlineTarget(labelNoProfiling));

            { // if (ProfilerData.FieldProfileSingleMethods)
                foreach (var stub in EmitSingleMethodProfilerCall(__methodBase, profilerCall, stringPool, stringKey))
                {
                    yield return(stub);
                }
                yield return(new MsilInstruction(OpCodes.Br).InlineTarget(labelStoreProfiling));
            }
            { // else
                yield return(new MsilInstruction(OpCodes.Ldnull).LabelWith(labelNoProfiling));
            }
            yield return(new MsilInstruction(OpCodes.Dup).LabelWith(labelStoreProfiling)); // Duplicate profiler entry for brnull

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

            var skipProfilerOne = new MsilLabel();

            yield return(new MsilInstruction(OpCodes.Brfalse).InlineTarget(skipProfilerOne));

            { // if (profiler != null)
                yield return(profilerLocal.AsValueLoad());

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

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

            var skipMainMethod = new MsilLabel();

            foreach (var i in insn)
            {
                if (i.OpCode == OpCodes.Ret)
                {
                    MsilInstruction j = new MsilInstruction(OpCodes.Br).InlineTarget(skipMainMethod);
                    foreach (MsilLabel l in i.Labels)
                    {
                        j.Labels.Add(l);
                    }
                    yield return(j);
                }
                else
                {
                    yield return(i);
                }
            }

            var skipProfilerTwo = new MsilLabel();

            yield return(profilerLocal.AsValueLoad().LabelWith(skipMainMethod));

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

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

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