private void ProcessInvoke(RPContext ctx, int instrIndex, int argBeginIndex) { Tuple <FieldDef, MethodDef> tuple2; Instruction instruction = ctx.Body.Instructions[instrIndex]; IMethod operand = (IMethod)instruction.Operand; MethodSig sig = RPMode.CreateProxySignature(ctx, operand, instruction.OpCode.Code == Code.Newobj); TypeDef delegateType = RPMode.GetDelegateType(ctx, sig); Tuple <Code, IMethod, IRPEncoding> key = Tuple.Create <Code, IMethod, IRPEncoding>(instruction.OpCode.Code, operand, ctx.EncodingHandler); if (!this.fields.TryGetValue(key, out tuple2)) { tuple2 = new Tuple <FieldDef, MethodDef>(this.CreateField(ctx, delegateType), null); this.fields[key] = tuple2; } if (argBeginIndex == instrIndex) { ctx.Body.Instructions.Insert(instrIndex + 1, new Instruction(OpCodes.Call, delegateType.FindMethod("Invoke"))); instruction.OpCode = OpCodes.Ldsfld; instruction.Operand = tuple2.Item1; } else { Instruction instruction2 = ctx.Body.Instructions[argBeginIndex]; ctx.Body.Instructions.Insert(argBeginIndex + 1, new Instruction(instruction2.OpCode, instruction2.Operand)); instruction2.OpCode = OpCodes.Ldsfld; instruction2.Operand = tuple2.Item1; instruction.OpCode = OpCodes.Call; instruction.Operand = delegateType.FindMethod("Invoke"); } }
private void ProcessBridge(RPContext ctx, int instrIndex) { Instruction instruction = ctx.Body.Instructions[instrIndex]; IMethod operand = (IMethod)instruction.Operand; TypeDef def = operand.DeclaringType.ResolveTypeDefThrow(); if (def.Module.IsILOnly && !def.IsGlobalModuleType) { Tuple <FieldDef, MethodDef> tuple2; Tuple <Code, IMethod, IRPEncoding> key = Tuple.Create <Code, IMethod, IRPEncoding>(instruction.OpCode.Code, operand, ctx.EncodingHandler); if (this.fields.TryGetValue(key, out tuple2)) { if (tuple2.Item2 != null) { instruction.OpCode = OpCodes.Call; instruction.Operand = tuple2.Item2; return; } } else { tuple2 = new Tuple <FieldDef, MethodDef>(null, null); } MethodSig sig = RPMode.CreateProxySignature(ctx, operand, instruction.OpCode.Code == Code.Newobj); TypeDef delegateType = RPMode.GetDelegateType(ctx, sig); if (tuple2.Item1 == null) { tuple2 = new Tuple <FieldDef, MethodDef>(this.CreateField(ctx, delegateType), tuple2.Item2); } tuple2 = new Tuple <FieldDef, MethodDef>(tuple2.Item1, this.CreateBridge(ctx, delegateType, tuple2.Item1, sig)); this.fields[key] = tuple2; instruction.OpCode = OpCodes.Call; instruction.Operand = tuple2.Item2; } }
public override void ProcessCall(RPContext ctx, int instrIndex) { Instruction instruction = ctx.Body.Instructions[instrIndex]; IMethod operand = (IMethod)instruction.Operand; if (!operand.DeclaringType.ResolveTypeDefThrow().IsValueType&& (operand.ResolveThrow().IsPublic || operand.ResolveThrow().IsAssembly)) { MethodDef def; Tuple <Code, TypeDef, IMethod> key = Tuple.Create <Code, TypeDef, IMethod>(instruction.OpCode.Code, ctx.Method.DeclaringType, operand); if (!this.proxies.TryGetValue(key, out def)) { MethodSig methodSig = RPMode.CreateProxySignature(ctx, operand, instruction.OpCode.Code == Code.Newobj); def = new MethodDefUser(NameService.RandomNameStatic(), methodSig) { Attributes = MethodAttributes.CompilerControlled | MethodAttributes.Static, ImplAttributes = MethodImplAttributes.IL }; ctx.Method.DeclaringType.Methods.Add(def); if ((instruction.OpCode.Code == Code.Call) && operand.ResolveThrow().IsVirtual) { def.IsStatic = false; methodSig.HasThis = true; methodSig.Params.RemoveAt(0); } ctx.Marker.Mark(def, ctx.Protection); /*ctx.Name.Analyze(def); * ctx.Name.SetCanRename(def, false);*/ def.Body = new CilBody(); for (int i = 0; i < def.Parameters.Count; i++) { def.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg, def.Parameters[i])); } def.Body.Instructions.Add(Instruction.Create(instruction.OpCode, operand)); def.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); this.proxies[key] = def; } instruction.OpCode = OpCodes.Call; if (ctx.Method.DeclaringType.HasGenericParameters) { GenericVar[] genArgs = new GenericVar[ctx.Method.DeclaringType.GenericParameters.Count]; for (int j = 0; j < genArgs.Length; j++) { genArgs[j] = new GenericVar(j); } instruction.Operand = new MemberRefUser(ctx.Module, def.Name, def.MethodSig, new GenericInstSig((ClassOrValueTypeSig)ctx.Method.DeclaringType.ToTypeSig(), genArgs).ToTypeDefOrRef()); } else { instruction.Operand = def; } } }