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> >()); }
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> >()); }
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); }
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}"); } }
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> >()); }
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}"); } }
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>))); }
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}"); } }
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> >()); }
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); } }
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); }
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); } }
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> >())); }
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"); }
internal override void Emit(LoggingIlGenerator generator) { generator.Emit(Instruction.OpCode, Labels?.Select(x => x.LabelFor(generator))?.ToArray() ?? new Label[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); }
internal abstract void Emit(LoggingIlGenerator generator);
/// <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)); }
/// <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); }