zoukankan      html  css  js  c++  java
  • 【Emit基础】OpCodes.Ldind_Ref 和 OpCodes.Ldind_I*

    一.OpCodes.Ldind_Ref

    OpCodes.Ldind_Ref ,MSDN的解释是:将对象引用作为 O(对象引用)类型间接加载到计算堆栈上。

         比较拗口,我对OpCodes.Ldind_Ref 的理解是,当前计算堆栈顶部的值是一个(对象引用的)地址(即指针的指针),而OpCodes.Ldind_Ref 就是要把这个地址处的对象引用加载到计算堆栈上。具体过程如下:

    1. 将地址推送到堆栈上。

    2. 从堆栈中弹出地址;获取位于此地址的对象引用。

    3. 将获取的引用推送到堆栈上。

         什么时候用到它了?通常是Emit加载方法的out/ref参数时。举个例子:

         我们需要Emit一个这样的动作,为方法的第一个参数(自定义引用类型,使用out修饰)调用ToString方法:     

        ldarg.1 
        ldind.
    ref 
        callvirt instance 
    string [mscorlib]System.Object::ToString()

         由于第一个参数使用了out修饰符,说明传入方法的实际上是对象引用的地址(即地址的地址),而该地址并不是一个对象引用,所以必须通过Ldind_Ref将该地址处的对象引用加载到计算堆栈,而后才能对其调用ToString()方法。

     二.OpCodes.Ldind_I

         如果ref/out参数是一个值类型,也是类似的情况,这时我们就需要使用OpCodes.Ldind_I*系列的字段。比如,将一个int类型的out参数间接加载到计算堆栈:

        ldarg.2 
        ldind.
    i4     

         i4表示目标类型是Int32,而对于不同的值类型,会有不同的操作符字段,使用下面的方法,可以简化调用:

            /// <summary>
            
    /// Ldind 间接加载。(即从地址加载)
             
    /// </summary>       
            public static void Ldind(ILGenerator ilGenerator, Type type)
            {
                
    if (!type.IsValueType)
                {
                    ilGenerator.Emit(OpCodes.Ldind_Ref);
                    
    return;
                }

                
    if (type.IsEnum)
                {
                    Type underType 
    = Enum.GetUnderlyingType(type);
                    EmitHelper.Ldind(ilGenerator, underType);
                    
    return;
                }

                
    if (type == typeof(Int64))
                {
                    ilGenerator.Emit(OpCodes.Ldind_I8);
                    
    return;
                }

                
    if (type == typeof(Int32))
                {
                    ilGenerator.Emit(OpCodes.Ldind_I4);
                    
    return;
                }

                
    if (type == typeof(Int16))
                {
                    ilGenerator.Emit(OpCodes.Ldind_I2);
                    
    return;
                }

                
    if (type == typeof(Byte))
                {
                    ilGenerator.Emit(OpCodes.Ldind_U1);
                    
    return;
                }

                
    if (type == typeof(SByte))
                {
                    ilGenerator.Emit(OpCodes.Ldind_I1);
                    
    return;
                }

                
    if (type == typeof(Boolean))
                {
                    ilGenerator.Emit(OpCodes.Ldind_I1);
                    
    return;
                }

                
    if (type == typeof(UInt64))
                {
                    ilGenerator.Emit(OpCodes.Ldind_I8);
                    
    return;
                }

                
    if (type == typeof(UInt32))
                {
                    ilGenerator.Emit(OpCodes.Ldind_U4);
                    
    return;
                }

                
    if (type == typeof(UInt16))
                {
                    ilGenerator.Emit(OpCodes.Ldind_U2);
                    
    return;
                }

                
    if (type == typeof(Single))
                {
                    ilGenerator.Emit(OpCodes.Ldind_R4);
                    
    return;
                }

                
    if (type == typeof(Double))
                {
                    ilGenerator.Emit(OpCodes.Ldind_R8);
                    
    return;
                }

                
    if (type == typeof(System.IntPtr))
                {
                    ilGenerator.Emit(OpCodes.Ldind_I4);
                    
    return;
                }

                
    if (type == typeof(System.UIntPtr))
                {
                    ilGenerator.Emit(OpCodes.Ldind_I4);
                    
    return;
                }

                
    throw new Exception(string.Format("The target type:{0} is not supported by EmitHelper.Ldind()" ,type));
            } 

    三.OpCodes.Stind_Ref 与 OpCodes.Stind_I*

        与OpCodes.Ldind_Ref  和 OpCodes.Ldind_I* 的间接加载相反,OpCodes.Stind_Ref 与 OpCodes.Stind_I* 是间接存储,即

    1. 将地址推送到堆栈上。

    2. 将值推送到堆栈上。

    3. 从堆栈中弹出值和地址;将值存储在该地址。

         为了简化调用,封装下面的Helper方法:

            /// <summary>
            
    /// Stind 间接存储
             
    /// </summary>      
            public static void Stind(ILGenerator ilGenerator, Type type)
            {
                
    if (!type.IsValueType)
                {
                    ilGenerator.Emit(OpCodes.Stind_Ref);
                    
    return;
                }

                
    if (type.IsEnum)
                {
                    Type underType 
    = Enum.GetUnderlyingType(type);
                    EmitHelper.Stind(ilGenerator, underType);
                    
    return;
                }

                
    if (type == typeof(Int64))
                {
                    ilGenerator.Emit(OpCodes.Stind_I8);
                    
    return;
                }

                
    if (type == typeof(Int32))
                {
                    ilGenerator.Emit(OpCodes.Stind_I4);
                    
    return;
                }

                
    if (type == typeof(Int16))
                {
                    ilGenerator.Emit(OpCodes.Stind_I2);
                    
    return;
                }

                
    if (type == typeof(Byte))
                {
                    ilGenerator.Emit(OpCodes.Stind_I1);
                    
    return;
                }

                
    if (type == typeof(SByte))
                {
                    ilGenerator.Emit(OpCodes.Stind_I1);
                    
    return;
                }

                
    if (type == typeof(Boolean))
                {
                    ilGenerator.Emit(OpCodes.Stind_I1);
                    
    return;
                }

                
    if (type == typeof(UInt64))
                {
                    ilGenerator.Emit(OpCodes.Stind_I8);
                    
    return;
                }

                
    if (type == typeof(UInt32))
                {
                    ilGenerator.Emit(OpCodes.Stind_I4);
                    
    return;
                }

                
    if (type == typeof(UInt16))
                {
                    ilGenerator.Emit(OpCodes.Stind_I2);
                    
    return;
                }

                
    if (type == typeof(Single))
                {
                    ilGenerator.Emit(OpCodes.Stind_R4);
                    
    return;
                }

                
    if (type == typeof(Double))
                {
                    ilGenerator.Emit(OpCodes.Stind_R8);
                    
    return;
                }

                
    if (type == typeof(System.IntPtr))
                {
                    ilGenerator.Emit(OpCodes.Stind_I4);
                    
    return;
                }

                
    if (type == typeof(System.UIntPtr))
                {
                    ilGenerator.Emit(OpCodes.Stind_I4);
                    
    return;
                }

                
    throw new Exception(string.Format("The target type:{0} is not supported by EmitHelper.Stind_ForValueType()", type));
            } 

     

  • 相关阅读:
    176. Second Highest Salary
    175. Combine Two Tables
    172. Factorial Trailing Zeroes
    171. Excel Sheet Column Number
    169. Majority Element
    168. Excel Sheet Column Title
    167. Two Sum II
    160. Intersection of Two Linked Lists
    个人博客记录
    <meta>标签
  • 原文地址:https://www.cnblogs.com/zhuweisky/p/1294274.html
Copyright © 2011-2022 走看看