Пример #1
0
        private static Func <object, MyClientInfo> GenerateAllocateClientInfo()
        {
            var clientDataType = Type.GetType(ClientData.InternalTypeName);

            if (clientDataType == null)
            {
                throw new InvalidOperationException("Couldn't find " +
                                                    ClientData.InternalTypeName);
            }
            var ctor = typeof(MyClientInfo).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null,
                                                           new[] { clientDataType }, null);

            if (ctor == null)
            {
                throw new InvalidOperationException("Couldn't find MyClientInfo(ClientData)");
            }

            var meth = new DynamicMethod(nameof(AllocateClientInfo), typeof(MyClientInfo), new[] { typeof(object) },
                                         true);
            var gen = new LoggingIlGenerator(meth.GetILGenerator(), _level);

            gen.EmitComment("// Start" + nameof(AllocateClientInfo));
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Castclass, clientDataType);
            gen.Emit(OpCodes.Newobj, ctor);
            gen.Emit(OpCodes.Ret);
            gen.EmitComment("// End" + nameof(AllocateClientInfo));
            Check(meth);
            return(meth.CreateDelegate <Func <object, MyClientInfo> >());
        }
Пример #2
0
        private static Action <object> GenerateCachingIslandDataApplyRemovals()
        {
            var type = Type.GetType(_clientDataIsland);

            if (type == null)
            {
                throw new InvalidOperationException("Couldn't find " + _clientDataIsland);
            }

            var cacheType = typeof(CachingHashSet <>).MakeGenericType(type);
            var backing   = cacheType.GetMethod("ApplyRemovals", BindingFlags.Instance | BindingFlags.Public);

            if (backing == null)
            {
                throw new InvalidOperationException("Couldn't find ApplyRemovals");
            }
            var meth = new DynamicMethod(nameof(ClientDataIslandsApplyRemovals), typeof(void),
                                         new[] { typeof(object) }, true);
            var gen = new LoggingIlGenerator(meth.GetILGenerator(), _level);

            gen.EmitComment("// Start " + meth.Name);
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Castclass, cacheType);
            gen.Emit(OpCodes.Callvirt, backing);
            gen.Emit(OpCodes.Ret);
            gen.EmitComment("// End " + meth.Name);
            Check(meth);
            return(meth.CreateDelegate <Action <object> >());
        }
Пример #3
0
        public DynamicMethod ComposePatchedMethod()
        {
            DynamicMethod          method    = AllocatePatchMethod();
            var                    generator = new LoggingIlGenerator(method.GetILGenerator(), PrintMsil ? LogLevel.Info : LogLevel.Trace);
            List <MsilInstruction> il        = EmitPatched((type, pinned) => new MsilLocal(generator.DeclareLocal(type, pinned))).ToList();

            if (PrintMsil)
            {
                lock (_log)
                {
                    MethodTranspiler.IntegrityAnalysis(LogLevel.Info, il);
                }
            }

            MethodTranspiler.EmitMethod(il, generator);

            try
            {
                PatchUtilities.Compile(method);
            }
            catch
            {
                lock (_log)
                {
                    var ctx = new MethodContext(method);
                    ctx.Read();
                    MethodTranspiler.IntegrityAnalysis(LogLevel.Warn, ctx.Instructions);
                }

                throw;
            }

            return(method);
        }
Пример #4
0
            internal override void Emit(LoggingIlGenerator generator)
            {
                // ReSharper disable once SwitchStatementMissingSomeCases
                switch (Instruction.OpCode.OperandType)
                {
                case OperandType.InlineSig:
                    throw new NotImplementedException();

                default:
                    throw new InvalidBranchException(
                              $"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
                }
            }
Пример #5
0
        GenerateCreateNewCachedIsland()
        {
            var clientDataType = Type.GetType(ClientData.InternalTypeName);

            if (clientDataType == null)
            {
                throw new InvalidOperationException("Couldn't fine " +
                                                    ClientData.InternalTypeName);
            }

            var type = Type.GetType(_clientDataIsland);

            if (type == null)
            {
                throw new InvalidOperationException("Couldn't find " + _clientDataIsland);
            }

            var backing = clientDataType.GetMethod("CreateNewCachedIsland");

            if (backing == null)
            {
                throw new InvalidOperationException("Couldn't find CreateNewCachedIsland");
            }

            var meth = new DynamicMethod(nameof(CreateNewCachedIsland), typeof(IslandData),
                                         new[] { typeof(object), typeof(IMyReplicable), typeof(HashSet <IMyReplicable>), typeof(MyTimeSpan) },
                                         true);

            var gen = new LoggingIlGenerator(meth.GetILGenerator(), _level);

            gen.EmitComment("// Start " + meth.Name);
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Castclass, clientDataType);
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Ldarg_2);
            gen.Emit(OpCodes.Ldarg_3);
            gen.Emit(OpCodes.Callvirt, backing);

            var islandInternal = gen.DeclareLocal(type);
            var islandExternal = gen.DeclareLocal(typeof(IslandData));

            gen.Emit(OpCodes.Stloc, islandInternal);
            EmitCopyAs(gen, islandInternal, islandExternal);
            gen.Emit(OpCodes.Ldloc, islandExternal);
            gen.Emit(OpCodes.Ret);
            gen.EmitComment("// End " + meth.Name);

            Check(meth);
            return(meth.CreateDelegate <Func <object, IMyReplicable, HashSet <IMyReplicable>, MyTimeSpan, IslandData> >());
        }
Пример #6
0
        internal override void Emit(LoggingIlGenerator generator)
        {
            // ReSharper disable once SwitchStatementMissingSomeCases
            switch (Instruction.OpCode.OperandType)
            {
            case OperandType.ShortInlineBrTarget:
            case OperandType.InlineBrTarget:
                generator.Emit(Instruction.OpCode, Target.LabelFor(generator));
                break;

            default:
                throw new InvalidBranchException(
                          $"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
            }
        }
Пример #7
0
        GenerateClientDataReplicableToIslandTryGetValue()
        {
            var type = Type.GetType(_clientDataIsland);

            if (type == null)
            {
                throw new InvalidOperationException("Couldn't find " + _clientDataIsland);
            }

            var cacheType = typeof(Dictionary <,>).MakeGenericType(typeof(IMyStreamableReplicable), type);
            var backing   = cacheType.GetMethod("TryGetValue", BindingFlags.Instance | BindingFlags.Public);

            if (backing == null)
            {
                throw new InvalidOperationException("Couldn't find TryGetValue");
            }
            var meth = new DynamicMethod(nameof(ClientDataReplicableToIslandTryGetValue), typeof(bool),
                                         new[] { typeof(object), typeof(IMyStreamableReplicable), typeof(IslandData).MakeByRefType() }, true);
            var gen = new LoggingIlGenerator(meth.GetILGenerator(), _level);

            gen.EmitComment("// Start " + meth.Name);
            var islandInternal = gen.DeclareLocal(type);
            var islandExternal = gen.DeclareLocal(typeof(IslandData));
            var tmpResult      = gen.DeclareLocal(typeof(bool));

            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Castclass, cacheType);
            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Ldloca, islandInternal);
            gen.Emit(OpCodes.Callvirt, backing);
            gen.Emit(OpCodes.Stloc, tmpResult);

            EmitCopyAs(gen, islandInternal, islandExternal);

            gen.Emit(OpCodes.Ldarg_2);
            gen.Emit(OpCodes.Ldloc, islandExternal);
            gen.Emit(OpCodes.Stobj, typeof(IslandData));

            gen.Emit(OpCodes.Ldloc, tmpResult);
            gen.Emit(OpCodes.Ret);
            gen.EmitComment("// End " + meth.Name);

            Check(meth);
            return((TryGetValueTemplate <IMyStreamableReplicable, IslandData>)meth.CreateDelegate(
                       typeof(TryGetValueTemplate <IMyStreamableReplicable, IslandData>)));
        }
Пример #8
0
            internal override void Emit(LoggingIlGenerator generator)
            {
                // ReSharper disable once SwitchStatementMissingSomeCases
                switch (Instruction.OpCode.OperandType)
                {
                case OperandType.ShortInlineI:
                    generator.Emit(Instruction.OpCode, (byte)Value);
                    return;

                case OperandType.InlineI:
                    generator.Emit(Instruction.OpCode, Value);
                    return;

                default:
                    throw new InvalidBranchException(
                              $"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
                }
            }
Пример #9
0
        private static Action <object, IslandData> GenerateRemoveCachedIsland()
        {
            var clientDataType = Type.GetType(ClientData.InternalTypeName);

            if (clientDataType == null)
            {
                throw new InvalidOperationException("Couldn't fine " +
                                                    ClientData.InternalTypeName);
            }

            var type = Type.GetType(_clientDataIsland);

            if (type == null)
            {
                throw new InvalidOperationException("Couldn't find " + _clientDataIsland);
            }

            var backing = clientDataType.GetMethod("RemoveCachedIsland");

            if (backing == null)
            {
                throw new InvalidOperationException("Couldn't find RemoveCachedIsland");
            }
            var meth = new DynamicMethod(nameof(RemoveCachedIsland), typeof(void),
                                         new[] { typeof(object), typeof(IslandData) }, true);
            var gen = new LoggingIlGenerator(meth.GetILGenerator(), _level);

            gen.EmitComment("// Start " + meth.Name);
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Castclass, clientDataType);
            var islandExternal = gen.DeclareLocal(typeof(IslandData));
            var islandInternal = gen.DeclareLocal(type);

            gen.Emit(OpCodes.Ldarg_1);
            gen.Emit(OpCodes.Stloc, islandExternal);
            EmitCopyAs(gen, islandExternal, islandInternal);
            gen.Emit(OpCodes.Ldloc, islandInternal);
            gen.Emit(OpCodes.Callvirt, backing);
            gen.Emit(OpCodes.Ret);
            gen.EmitComment("// End " + meth.Name);

            Check(meth);
            return(meth.CreateDelegate <Action <object, IslandData> >());
        }
Пример #10
0
            internal override void Emit(LoggingIlGenerator generator)
            {
                switch (Instruction.OpCode.OperandType)
                {
                case OperandType.InlineTok:
                    Debug.Assert(Value is MethodBase || Value is Type || Value is FieldInfo,
                                 $"Value {Value?.GetType()} doesn't match operand type for {Instruction.OpCode}");
                    break;

                case OperandType.InlineType:
                    Debug.Assert(Value is Type, $"Value {Value?.GetType()} doesn't match operand type for {Instruction.OpCode}");
                    break;

                case OperandType.InlineMethod:
                    Debug.Assert(Value is MethodBase, $"Value {Value?.GetType()} doesn't match operand type for {Instruction.OpCode}");
                    break;

                case OperandType.InlineField:
                    Debug.Assert(Value is FieldInfo, $"Value {Value?.GetType()} doesn't match operand type for {Instruction.OpCode}");
                    break;

                default:
                    throw new InvalidBranchException(
                              $"OpCode {Instruction.OpCode}, operand type {Instruction.OpCode.OperandType} doesn't match {GetType().Name}");
                }

                if (Value is ConstructorInfo)
                {
                    generator.Emit(Instruction.OpCode, Value as ConstructorInfo);
                }
                else if (Value is FieldInfo)
                {
                    generator.Emit(Instruction.OpCode, Value as FieldInfo);
                }
                else if (Value is Type)
                {
                    generator.Emit(Instruction.OpCode, Value as Type);
                }
                else if (Value is MethodInfo)
                {
                    generator.Emit(Instruction.OpCode, Value as MethodInfo);
                }
            }
Пример #11
0
        internal Label LabelFor(LoggingIlGenerator gen)
        {
            if (_overrideLabel.HasValue)
            {
                return(_overrideLabel.Value);
            }
            foreach (KeyValuePair <WeakReference <LoggingIlGenerator>, Label> kv in _labelInstances)
            {
                if (kv.Key.TryGetTarget(out LoggingIlGenerator gen2) && gen2 == gen)
                {
                    return(kv.Value);
                }
            }
            Label label = gen.DefineLabel();

            _labelInstances.Add(
                new KeyValuePair <WeakReference <LoggingIlGenerator>, Label>(new WeakReference <LoggingIlGenerator>(gen),
                                                                             label));
            return(label);
        }
Пример #12
0
        private void SavePatchedMethod(string target)
        {
            var asmBuilder =
                AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("SomeName"), AssemblyBuilderAccess.RunAndSave, Path.GetDirectoryName(target));
            var moduleBuilder = asmBuilder.DefineDynamicModule(Path.GetFileNameWithoutExtension(target), Path.GetFileName(target));
            var typeBuilder   = moduleBuilder.DefineType("Test", TypeAttributes.Public);


            var methodName     = _method.Name + $"_{_patchSalt}";
            var returnType     = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
            var parameters     = _method.GetParameters();
            var parameterTypes = (_method.IsStatic ? Enumerable.Empty <Type>() : new[] { _method.DeclaringType })
                                 .Concat(parameters.Select(x => x.ParameterType)).ToArray();

            var patchMethod = typeBuilder.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
                                                       returnType, parameterTypes);

            if (!_method.IsStatic)
            {
                patchMethod.DefineParameter(0, ParameterAttributes.None, INSTANCE_PARAMETER);
            }
            for (var i = 0; i < parameters.Length; i++)
            {
                patchMethod.DefineParameter((patchMethod.IsStatic ? 0 : 1) + i, parameters[i].Attributes, parameters[i].Name);
            }

            var generator             = new LoggingIlGenerator(patchMethod.GetILGenerator(), LogLevel.Trace);
            List <MsilInstruction> il = EmitPatched((type, pinned) => new MsilLocal(generator.DeclareLocal(type, pinned))).ToList();

            MethodTranspiler.EmitMethod(il, generator);

            Type res = typeBuilder.CreateType();

            asmBuilder.Save(Path.GetFileName(target));
            foreach (var method in res.GetMethods(BindingFlags.Public | BindingFlags.Static))
            {
                _log.Info($"Information " + method);
            }
        }
Пример #13
0
        private static DynamicProxyEnumerable <IslandData> GenerateClientDataIslandsEnumerator()
        {
            var type = Type.GetType(_clientDataIsland);

            if (type == null)
            {
                throw new InvalidOperationException("Couldn't find " + _clientDataIsland);
            }

            var meth = new DynamicMethod(nameof(ClientDataIslandsEnumerator) + "_Mapper", typeof(IslandData),
                                         new[] { typeof(IEnumerator) }, true);

            var genericEnumerator = typeof(IEnumerator <>).MakeGenericType(type);
            var currentProp       = genericEnumerator.GetProperty("Current");

            if (currentProp == null)
            {
                throw new InvalidOperationException("Couldn't find Current property on " + genericEnumerator.FullName);
            }

            var gen            = new LoggingIlGenerator(meth.GetILGenerator(), _level);
            var islandInternal = gen.DeclareLocal(type);
            var islandExternal = gen.DeclareLocal(typeof(IslandData));

            gen.EmitComment("// Start " + meth.Name);
            gen.Emit(OpCodes.Ldarg_0);
            gen.Emit(OpCodes.Castclass, genericEnumerator);
            gen.Emit(OpCodes.Callvirt, currentProp.GetMethod);
            gen.Emit(OpCodes.Stloc, islandInternal);
            EmitCopyAs(gen, islandInternal, islandExternal);
            gen.Emit(OpCodes.Ldloc, islandExternal);
            gen.Emit(OpCodes.Ret);
            gen.EmitComment("// End " + meth.Name);

            Check(meth);
            return(new DynamicProxyEnumerable <IslandData>((o) => ((IEnumerable)o).GetEnumerator(),
                                                           meth.CreateDelegate <Func <IEnumerator, IslandData> >()));
        }
Пример #14
0
        private static void EmitCopyAs(LoggingIlGenerator gen, LocalBuilder src, LocalBuilder dst)
        {
            var flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;

            Debug.Assert(src.LocalType != null, "src.LocalType != null");
            Debug.Assert(dst.LocalType != null, "dst.LocalType != null");
            var fields = src.LocalType.GetFields(flags);

            gen.EmitComment($"Copy {src.LocalType} to {dst.LocalType}");
            gen.Emit(OpCodes.Ldloca, dst);
            gen.Emit(OpCodes.Initobj, dst.LocalType);
            foreach (var sf in fields)
            {
                gen.Emit(OpCodes.Ldloca, dst);
                gen.Emit(OpCodes.Ldloca, src);
                var df = dst.LocalType?.GetField(sf.Name, flags);
                Debug.Assert(df != null, $"{dst.LocalType}.{sf.Name} != null");
                gen.Emit(OpCodes.Ldfld, sf);
                gen.Emit(OpCodes.Stfld, df);
            }

            gen.EmitComment("EndCopy");
        }
Пример #15
0
 internal override void Emit(LoggingIlGenerator generator)
 {
     generator.Emit(Instruction.OpCode, Labels?.Select(x => x.LabelFor(generator))?.ToArray() ?? new Label[0]);
 }
Пример #16
0
        public DynamicMethod ComposePatchedMethod()
        {
            DynamicMethod method    = AllocatePatchMethod();
            var           generator = new LoggingIlGenerator(method.GetILGenerator(),
                                                             PrintMode.HasFlag(PrintModeEnum.EmittedReflection) ? LogLevel.Info : LogLevel.Trace);
            List <MsilInstruction> il = EmitPatched((type, pinned) => new MsilLocal(generator.DeclareLocal(type, pinned))).ToList();

            var dumpTarget = DumpTarget != null?File.CreateText(DumpTarget) : null;

            try
            {
                const string gap = "\n\n\n\n\n";

                void LogTarget(PrintModeEnum mode, bool err, string msg)
                {
                    if (DumpMode.HasFlag(mode))
                    {
                        dumpTarget?.WriteLine((err ? "ERROR " : "") + msg);
                    }
                    if (!PrintMode.HasFlag(mode))
                    {
                        return;
                    }
                    if (err)
                    {
                        _log.Error(msg);
                    }
                    else
                    {
                        _log.Info(msg);
                    }
                }

                if (PrintMsil || DumpTarget != null)
                {
                    lock (_log)
                    {
                        var ctx = new MethodContext(_method);
                        ctx.Read();
                        LogTarget(PrintModeEnum.Original, false, "========== Original method ==========");
                        MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Original, a, b), ctx.Instructions, true);
                        LogTarget(PrintModeEnum.Original, false, gap);

                        LogTarget(PrintModeEnum.Emitted, false, "========== Desired method ==========");
                        MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Emitted, a, b), il);
                        LogTarget(PrintModeEnum.Emitted, false, gap);
                    }
                }

                MethodTranspiler.EmitMethod(il, generator);

                try
                {
                    PatchUtilities.Compile(method);
                }
                catch
                {
                    lock (_log)
                    {
                        var ctx = new MethodContext(method);
                        ctx.Read();
                        MethodTranspiler.IntegrityAnalysis((err, msg) => _log.Warn(msg), ctx.Instructions);
                    }

                    throw;
                }

                if (PrintMsil || DumpTarget != null)
                {
                    lock (_log)
                    {
                        var ctx = new MethodContext(method);
                        ctx.Read();
                        LogTarget(PrintModeEnum.Patched, false, "========== Patched method ==========");
                        MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Patched, a, b), ctx.Instructions, true);
                        LogTarget(PrintModeEnum.Patched, false, gap);
                    }
                }
            }
            finally
            {
                dumpTarget?.Close();
            }

            return(method);
        }
Пример #17
0
 internal abstract void Emit(LoggingIlGenerator generator);
Пример #18
0
 /// <summary>
 ///     Creates a label that supplies the given <see cref="Label" /> when a label for the given generator is requested,
 ///     otherwise it creates a new label.
 /// </summary>
 /// <param name="generator">Generator to register the label on</param>
 /// <param name="label">Label to register</param>
 public MsilLabel(LoggingIlGenerator generator, Label label)
 {
     _labelInstances.Add(
         new KeyValuePair <WeakReference <LoggingIlGenerator>, Label>(
             new WeakReference <LoggingIlGenerator>(generator), label));
 }
Пример #19
0
 /// <summary>
 /// Writes the given instruction stream to the given IL generator, fixing short branch instructions.
 /// </summary>
 /// <param name="insn">Instruction stream</param>
 /// <param name="generator">Output</param>
 public static void EmitInstructions(IEnumerable <MsilInstruction> insn, LoggingIlGenerator generator)
 {
     MethodTranspiler.EmitMethod(insn.ToList(), generator);
 }