MemberReference ReplaceMemberRef(MemberReference m)
        {
            if (m is MethodReference)
            {
                // Every instruction is only process once, so nothing should be resolved
                //Debug.Assert(!(m is MethodDefinition));

                var reference = (m as MethodReference);

                var declatingType = AddAndResolveType(reference.DeclaringType);
                var parameters    = reference.Parameters.Select(x => AddAndResolveType(x.ParameterType).Name);
                if (declatingType != null)
                {
                    try {
                        return(m_resolver.GetMethodReference(declatingType, reference.Name, parameters));
                    } catch { }
                }
            }
            if (m is FieldReference)
            {
                var reference = m as FieldReference;
                var resolved  = AddAndResolveType(reference.DeclaringType);
                if (resolved != null)
                {
                    return(m_resolver.GetField(resolved.FullName, reference.Name));
                }
            }
            return(m);
        }
Beispiel #2
0
        private void ReplaceCatch(ILProcessor ilp, ExceptionHandler catchHandler, VariableDefinition exceptionVariable)
        {
            var insts    = ilp.Body.Instructions;
            var tryStart = catchHandler.TryStart;
            var tryEnd   = catchHandler.TryEnd;

            var catchStart   = ilp.Create(OpCodes.Nop);
            var catchEnd     = ilp.Create(OpCodes.Nop);
            var finallyStart = ilp.Create(OpCodes.Nop);

            bool thrown = false;

            // replace throw with jump to catch handler
            for (int idx = insts.IndexOf(tryStart); idx <= insts.IndexOf(tryEnd); idx++)
            {
                var i = insts[idx];
                if (i.OpCode == OpCodes.Throw)
                {
                    //ilp.Replace(i, ilp.Create(OpCodes.Br, catchStart));
                    // need a leave here as there might still be things on the stack
                    ilp.Replace(i, ilp.Create(OpCodes.Leave, catchStart));
                    thrown = true;
                }
            }

            // only use catch block if there is a chance of reaching it
            if (thrown)
            {
                // add labels
                ilp.InsertBefore(tryEnd, catchStart);
                ilp.InsertBefore(tryEnd, catchEnd);

                // add catch check
                var next = ilp.Create(OpCodes.Nop);
                if (catchHandler.CatchType.Name != "EException")
                {
                    ilp.InsertBefore(catchEnd, ilp.Create(OpCodes.Ldloc, exceptionVariable));
                    ilp.InsertBefore(catchEnd, ilp.Create(OpCodes.Call, m_resolver.GetMethodReference(catchHandler.CatchType, "isInstance", after_rename: true)));
                    ilp.InsertBefore(catchEnd, ilp.Create(OpCodes.Brfalse, next));
                }

                // copy catch handler (Excpetion is expected on top of stack)
                ilp.InsertBefore(catchEnd, ilp.Create(OpCodes.Ldloc, exceptionVariable));
                var block = insts.SkipWhile(x => x != catchHandler.HandlerStart).TakeWhile(x => x != catchHandler.HandlerEnd).ToArray();
                foreach (var bi in block)
                {
                    ilp.InsertBefore(catchEnd, CopyInstruction(bi));
                }

                ilp.InsertBefore(catchEnd, next);


                // rethrow uncaught exception
                if (catchHandler.CatchType.Name != "EException")
                {
                    ilp.InsertBefore(next, ilp.Create(OpCodes.Throw));
                }
            }
        }
        // after type rename??
        public void TransformIL(IEnumerable <TypeDefinition> types)
        {
            var resolver = new ReferenceResolver(types);

            var mod = ModuleDefinition.CreateModule("bla", ModuleKind.Dll);

            var m_virtuals = VirtualHelper.VirtualAnalysis(types).Where(x => x.Method.Name != ".ctor").ToArray();
            var toReplace  = new Dictionary <MethodReference, MethodReference>();

            // add a pacleholder for the virtual method
            foreach (var virt in m_virtuals)
            {
                if (!virt.Method.DeclaringType.IsInterface)
                {
                    virt.OverwrittenBy.Add(virt.Method);
                }

                var org           = virt.Method;
                var virtualMethod = new MethodDefinition(org.Name + "_virtual", org.Attributes, org.ReturnType);
                virtualMethod.IsAbstract = false;
                virtualMethod.IsVirtual  = false;
                //Debug.Assert(virtualMethod.IsStatic);

                virtualMethod.CustomAttributes.Add(new CustomAttribute(mod.ImportReference(typeof(ManualRefCounting).GetConstructor(new Type[] { })), new byte[] { 1, 0, 0, 0 }));
                foreach (var p in org.Parameters)
                {
                    virtualMethod.Parameters.Add(p);
                }

                org.DeclaringType.Methods.Add(virtualMethod);
                virt.Method = virtualMethod;


                toReplace.Add(org, virtualMethod);


                // imlement the virtual method
                virtualMethod.Body = new MethodBody(virtualMethod);

                var proc = virtualMethod.Body.GetILProcessor();


                var getHandle = mod.ImportReference(typeof(Type).GetMethod("GetTypeFromHandle"));
                var typeEq    = mod.ImportReference(typeof(Type).GetMethod("op_Equality"));

                var getType = types.Single(x => x.Name == "EObject").Methods.Single(x => x.Name == "GetType");

                var ret = Instruction.Create(OpCodes.Nop);

                foreach (var o in virt.OverwrittenBy)
                {
                    var next = Instruction.Create(OpCodes.Nop);
                    // compare types
                    proc.Emit(OpCodes.Ldarg_0);
                    proc.Emit(OpCodes.Call, getType);
                    proc.Emit(OpCodes.Ldtoken, o.DeclaringType);
                    proc.Emit(OpCodes.Call, getHandle);
                    proc.Emit(OpCodes.Call, typeEq);

                    // call virtual if there is a match
                    proc.Emit(OpCodes.Brfalse, next);

                    Debug.Assert(virt.Method.IsStatic == false);
                    // If this parameter has not been transformed, add one parameter for this.
                    proc.Emit(OpCodes.Ldarg_0);
                    for (var paramIdx = 0; paramIdx < virt.Method.Parameters.Count; paramIdx++)
                    {
                        proc.Emit(OpCodes.Ldarg, paramIdx + 1);
                    }

                    proc.Emit(OpCodes.Call, o);
                    proc.Emit(OpCodes.Br, ret);
                    proc.Append(next);
                }

                // type not found
                proc.Emit(OpCodes.Call, resolver.GetMethodReference(() => ECSharp.Core.ESharpRT.Error()));

                // Make sure the stack is correct
                if (virt.Method.ReturnType.Name != "Void")
                {
                    if (virt.Method.ReturnType.IsValueType)
                    {
                        var variable = new VariableDefinition(virt.Method.ReturnType);
                        virtualMethod.Body.Variables.Add(variable);
                        proc.Emit(OpCodes.Ldloca, variable);
                        proc.Emit(OpCodes.Initobj, virt.Method.ReturnType.Resolve());
                        proc.Emit(OpCodes.Ldloc, variable);
                    }
                    else
                    {
                        proc.Emit(OpCodes.Ldnull);
                    }
                }

                proc.Append(ret);
                proc.Emit(OpCodes.Ret);
            }

            // change the reference to the virtual method
            foreach (var t in types)
            {
                foreach (var m in t.Methods)
                {
                    if (m.Body == null)
                    {
                        continue;
                    }

                    for (int idx = 0; idx < m.Body.Instructions.Count; idx++)
                    {
                        var i    = m.Body.Instructions[idx];
                        var mRef = i.Operand as MethodReference;
                        if (mRef == null)
                        {
                            continue;
                        }

                        // only replace virtual calls
                        if (i.OpCode == OpCodes.Call)
                        {
                            continue;
                        }

                        if (toReplace.ContainsKey(mRef))
                        {
                            i.Operand = toReplace[mRef];
                            Debug.Assert(i.Operand is MethodDefinition);

                            // only use non virtual call instructions
                            if (i.OpCode == OpCodes.Ldvirtftn)
                            {
                                i.OpCode = OpCodes.Ldftn;
                                // make sure the stack is correct.
                                m.Body.GetILProcessor().InsertBefore(i, Instruction.Create(OpCodes.Pop));
                                idx++;
                            }
                            else if (i.OpCode == OpCodes.Callvirt)
                            {
                                i.OpCode = OpCodes.Call;
                            }
                            else
                            {
                                Debug.Assert(false, "Unecpected virtual opcode");
                            }
                        }
                    }
                }
            }
        }