public static string GetName(this VariableReference self, MethodDebugInformation debugInfo)
        {
            if (self == null)
            {
                return(String.Empty);
            }

            // as per commit 7cde491752861a331e091dca601748e9f0741e95 of Mono.Cecil, VariableReference do not have Name anymore
            if (debugInfo != null)
            {
                if (debugInfo.TryGetName((VariableDefinition)self, out var name))
                {
                    return(name);
                }
            }

            return(self.ToString());
        }
Пример #2
0
        public static void Generate(DynamicMethodDefinition dmd, MethodBase _mb, ILGenerator il)
        {
            MethodDefinition def = dmd.Definition;
            DynamicMethod    dm  = _mb as DynamicMethod;

#if !NETSTANDARD
            MethodBuilder mb            = _mb as MethodBuilder;
            ModuleBuilder moduleBuilder = mb?.Module as ModuleBuilder;
            // moduleBuilder.Assembly sometimes avoids the .Assembly override under mysterious circumstances.
            AssemblyBuilder    assemblyBuilder     = (mb?.DeclaringType as TypeBuilder)?.Assembly as AssemblyBuilder;
            HashSet <Assembly> accessChecksIgnored = null;
            if (mb != null)
            {
                accessChecksIgnored = new HashSet <Assembly>();
            }
#endif

#if !CECIL0_9
            MethodDebugInformation defInfo = dmd.Debug ? def.DebugInformation : null;
#endif

            if (dm != null)
            {
                foreach (ParameterDefinition param in def.Parameters)
                {
                    dm.DefineParameter(param.Index + 1, (System.Reflection.ParameterAttributes)param.Attributes, param.Name);
                }
            }
#if !NETSTANDARD
            if (mb != null)
            {
                foreach (ParameterDefinition param in def.Parameters)
                {
                    mb.DefineParameter(param.Index + 1, (System.Reflection.ParameterAttributes)param.Attributes, param.Name);
                }
            }
#endif

            LocalBuilder[] locals = def.Body.Variables.Select(
                var => {
                LocalBuilder local = il.DeclareLocal(var.VariableType.ResolveReflection(), var.IsPinned);
#if !NETSTANDARD && !CECIL0_9
                if (mb != null && defInfo != null && defInfo.TryGetName(var, out string name))
                {
                    local.SetLocalSymInfo(name);
                }
#endif
                return(local);
            }
                ).ToArray();

            // Pre-pass - Set up label map.
            Dictionary <Instruction, Label> labelMap = new Dictionary <Instruction, Label>();
            foreach (Instruction instr in def.Body.Instructions)
            {
                if (instr.Operand is Instruction[] targets)
                {
                    foreach (Instruction target in targets)
                    {
                        if (!labelMap.ContainsKey(target))
                        {
                            labelMap[target] = il.DefineLabel();
                        }
                    }
                }
                else if (instr.Operand is Instruction target)
                {
                    if (!labelMap.ContainsKey(target))
                    {
                        labelMap[target] = il.DefineLabel();
                    }
                }
            }

#if !NETSTANDARD && !CECIL0_9
            Dictionary <Document, ISymbolDocumentWriter> infoDocCache = mb == null ? null : new Dictionary <Document, ISymbolDocumentWriter>();
#endif

            int      paramOffs        = def.HasThis ? 1 : 0;
            object[] emitArgs         = new object[2];
            bool     checkTryEndEarly = false;
            foreach (Instruction instr in def.Body.Instructions)
            {
                if (labelMap.TryGetValue(instr, out Label label))
                {
                    il.MarkLabel(label);
                }

#if !NETSTANDARD && !CECIL0_9
                SequencePoint instrInfo = defInfo?.GetSequencePoint(instr);
                if (mb != null && instrInfo != null)
                {
                    if (!infoDocCache.TryGetValue(instrInfo.Document, out ISymbolDocumentWriter infoDoc))
                    {
                        infoDocCache[instrInfo.Document] = infoDoc = moduleBuilder.DefineDocument(
                            instrInfo.Document.Url,
                            instrInfo.Document.LanguageGuid,
                            instrInfo.Document.LanguageVendorGuid,
                            instrInfo.Document.TypeGuid
                            );
                    }
                    il.MarkSequencePoint(infoDoc, instrInfo.StartLine, instrInfo.StartColumn, instrInfo.EndLine, instrInfo.EndColumn);
                }
#endif

                foreach (ExceptionHandler handler in def.Body.ExceptionHandlers)
                {
                    if (checkTryEndEarly && handler.HandlerEnd == instr)
                    {
                        il.EndExceptionBlock();
                    }

                    if (handler.TryStart == instr)
                    {
                        il.BeginExceptionBlock();
                    }
                    else if (handler.FilterStart == instr)
                    {
                        il.BeginExceptFilterBlock();
                    }
                    else if (handler.HandlerStart == instr)
                    {
                        switch (handler.HandlerType)
                        {
                        case ExceptionHandlerType.Filter:
                            il.BeginCatchBlock(null);
                            break;

                        case ExceptionHandlerType.Catch:
                            il.BeginCatchBlock(handler.CatchType.ResolveReflection());
                            break;

                        case ExceptionHandlerType.Finally:
                            il.BeginFinallyBlock();
                            break;

                        case ExceptionHandlerType.Fault:
                            il.BeginFaultBlock();
                            break;
                        }
                    }

                    // Avoid duplicate endfilter / endfinally
                    if (handler.HandlerStart == instr.Next)
                    {
                        switch (handler.HandlerType)
                        {
                        case ExceptionHandlerType.Filter:
                            if (instr.OpCode == Mono.Cecil.Cil.OpCodes.Endfilter)
                            {
                                goto SkipEmit;
                            }
                            break;

                        case ExceptionHandlerType.Finally:
                            if (instr.OpCode == Mono.Cecil.Cil.OpCodes.Endfinally)
                            {
                                goto SkipEmit;
                            }
                            break;
                        }
                    }
                }

                if (instr.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineNone)
                {
                    il.Emit(_ReflOpCodes[instr.OpCode.Value]);
                }
                else
                {
                    object operand = instr.Operand;

                    if (operand is Instruction[] targets)
                    {
                        operand = targets.Select(target => labelMap[target]).ToArray();
                        // Let's hope that the JIT treats the long forms identically to the short forms.
                        instr.OpCode = instr.OpCode.ToLongOp();
                    }
                    else if (operand is Instruction target)
                    {
                        operand = labelMap[target];
                        // Let's hope that the JIT treats the long forms identically to the short forms.
                        instr.OpCode = instr.OpCode.ToLongOp();
                    }
                    else if (operand is VariableDefinition var)
                    {
                        operand = locals[var.Index];
                    }
                    else if (operand is ParameterDefinition param)
                    {
                        operand = param.Index + paramOffs;
                    }
                    else if (operand is MemberReference mref)
                    {
                        MemberInfo member = mref.ResolveReflection();
                        operand = member;
#if !NETSTANDARD
                        if (mb != null && member != null)
                        {
                            Assembly asm = member.Module?.Assembly;
                            if (asm != null && !accessChecksIgnored.Contains(asm))
                            {
                                // while (member.DeclaringType != null)
                                //     member = member.DeclaringType;
                                assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(DynamicMethodDefinition.c_IgnoresAccessChecksToAttribute, new object[] {
                                    asm.GetName().Name
                                }));
                                accessChecksIgnored.Add(asm);
                            }
                        }
#endif
                    }
                    else if (operand is CallSite csite)
                    {
                        if (dm != null)
                        {
                            // SignatureHelper in unmanaged contexts cannot be fully made use of for DynamicMethods.
                            _EmitCallSite(dm, il, _ReflOpCodes[instr.OpCode.Value], csite);
                            continue;
                        }
#if !NETSTANDARD
                        operand = csite.ResolveReflection(mb.Module);
#else
                        throw new NotSupportedException();
#endif
                    }

#if !NETSTANDARD
                    if (mb != null && operand is MethodBase called && called.DeclaringType == null)
                    {
                        // "Global" methods (f.e. DynamicMethods) cannot be tokenized.
                        if (instr.OpCode == Mono.Cecil.Cil.OpCodes.Call)
                        {
                            if (operand is DynamicMethod target)
                            {
                                // This should be heavily optimizable.
                                operand = _CreateMethodProxy(mb, target);
                            }
                            else
                            {
                                IntPtr ptr = called.GetLdftnPointer();
                                if (IntPtr.Size == 4)
                                {
                                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)ptr);
                                }
                                else
                                {
                                    il.Emit(System.Reflection.Emit.OpCodes.Ldc_I8, (long)ptr);
                                }
                                il.Emit(System.Reflection.Emit.OpCodes.Conv_I);
                                instr.OpCode = Mono.Cecil.Cil.OpCodes.Calli;
                                operand      = ((MethodReference)instr.Operand).ResolveReflectionSignature(mb.Module);
                            }
                        }
                        else
                        {
                            throw new NotSupportedException($"Unsupported global method operand on opcode {instr.OpCode.Name}");
                        }
                    }
#endif

                    if (operand == null)
                    {
                        throw new NullReferenceException($"Unexpected null in {def} @ {instr}");
                    }

                    il.DynEmit(_ReflOpCodes[instr.OpCode.Value], operand);
                }

                if (!checkTryEndEarly)
                {
                    foreach (ExceptionHandler handler in def.Body.ExceptionHandlers)
                    {
                        if (handler.HandlerEnd == instr.Next)
                        {
                            il.EndExceptionBlock();
                        }
                    }
                }

                checkTryEndEarly = false;
                continue;

SkipEmit:
                checkTryEndEarly = true;
                continue;
            }
        }