예제 #1
0
 internal Delegate GetDelegate()
 {
     _method = CreateDynamicMethod();
     _emit = new EmitHelper(Method.GetILGenerator());
     Delegate @delegate = CreateDelegate();
     return @delegate;
 }
        protected virtual ReadDataInvoker CreateReadDataMethod(Type type, AMFReader reader, object instance)
        {
#if !(MONO) && !(NET_2_0) && !(NET_3_5) && !(SILVERLIGHT)
            bool canSkipChecks = _ps.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet);
#else
            bool canSkipChecks = SecurityManager.IsGranted(new ReflectionPermission(ReflectionPermissionFlag.MemberAccess));
#endif

            DynamicMethod method = new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(AMFReader), typeof(ClassDefinition) }, this.GetType(), canSkipChecks);
            ILGenerator il = method.GetILGenerator();

            LocalBuilder instanceLocal = il.DeclareLocal(type);//[0] instance
            LocalBuilder typeCodeLocal = il.DeclareLocal(typeof(byte));//[1] uint8 typeCode
            LocalBuilder keyLocal = il.DeclareLocal(typeof(string));//[2] string key
            LocalBuilder objTmp = il.DeclareLocal(typeof(object));//[3] temp object store
            LocalBuilder intTmp1 = il.DeclareLocal(typeof(int));//[4] temp int store, length
            LocalBuilder intTmp2 = il.DeclareLocal(typeof(int));//[5] temp int store, index
            LocalBuilder objTmp2 = il.DeclareLocal(typeof(object));//[6] temp object store
            LocalBuilder typeTmp = il.DeclareLocal(typeof(Type));//[7] temp Type store

            EmitHelper emit = new EmitHelper(il);
            ConstructorInfo typeConstructor = type.GetConstructor(EmitHelper.AnyVisibilityInstance, null, CallingConventions.HasThis, System.Type.EmptyTypes, null);
            MethodInfo miAddReference = typeof(AMFReader).GetMethod("AddReference");
            MethodInfo miReadString = typeof(AMFReader).GetMethod("ReadString");
            MethodInfo miReadByte = typeof(AMFReader).GetMethod("ReadByte");
            emit
                //object instance = new object();
                .newobj(typeConstructor) //Create the new instance and push the object reference onto the evaluation stack
                .stloc_0 //Pop from the top of the evaluation stack and store it in a the local variable list at index 0
                //reader.AddReference(instance);
                .ldarg_0 //Push the argument indexed at 1 onto the evaluation stack 'reader'
                .ldloc_0 //Loads the local variable at index 0 onto the evaluation stack 'instance'
                .callvirt(miAddReference) //Arguments are popped from the stack, the method call is performed, return value is pushed onto the stack
                //typeCode = 0;
                .ldc_i4_0 //Push the integer value of 0 onto the evaluation stack as an int32
                .stloc_1 //Pop and store it in a the local variable list at index 1
                //string key = null;
                .ldnull //Push a null reference onto the evaluation stack
                .stloc_2 //Pop and store it in a the local variable list at index 2 'key'
                .end()
            ;

			string key = reader.ReadString();
            for (byte typeCode = reader.ReadByte(); typeCode != AMF0TypeCode.EndOfObject; typeCode = reader.ReadByte())
            {
                emit
                    .ldarg_0
                    .callvirt(miReadString)
                    .stloc_2
                    .ldarg_0
                    .callvirt(miReadByte)
                    .stloc_1
                    .end()
                ;

                object value = reader.ReadData(typeCode);
                reader.SetMember(instance, key, value);

                MemberInfo[] memberInfos = type.GetMember(key);
                if (memberInfos != null && memberInfos.Length > 0)
                    GeneratePropertySet(emit, typeCode, memberInfos[0]);
                else
                {
                    //Log this error (do not throw exception), otherwise our current AMF stream becomes unreliable
                    log.Warn(__Res.GetString(__Res.Optimizer_Warning));
                    string msg = __Res.GetString(__Res.Reflection_MemberNotFound, string.Format("{0}.{1}", type.FullName, key));
                    log.Warn(msg);
                    //reader.ReadAMF3Data(typeCode);
                    emit
                        .ldarg_0 //Push 'reader'
                        .ldloc_1 //Push 'typeCode'
                        .callvirt(typeof(AMFReader).GetMethod("ReadData", new Type[] { typeof(byte) }))
                        .pop
                        .end()
                    ;
                }

                key = reader.ReadString();
            }
            Label labelExit = emit.DefineLabel();
            ConstructorInfo exceptionConstructor = typeof(UnexpectedAMF).GetConstructor(EmitHelper.AnyVisibilityInstance, null, CallingConventions.HasThis, Type.EmptyTypes, null);
            //key = reader.ReadString();
            emit
                .ldarg_0 //Push 'reader'
                .callvirt(miReadString)
                .stloc_2 //Pop 'key'
                //typeCode = reader.ReadByte();
                .ldarg_0 //Push 'reader'
                .callvirt(miReadByte)
                .stloc_1 //Pop 'typeCode'
                .ldloc_1
                .ldc_i4_s(AMF0TypeCode.EndOfObject)
                .ceq
                .brtrue_s(labelExit)
                //if( typeCode != AMF0TypeCode.EndOfObject ) throw new UnexpectedAMF();
                .newobj(exceptionConstructor)
                .@throw
                .end()
            ;
            emit
                .MarkLabel(labelExit)
                //return instance;
                .ldloc_0 //Load the local variable at index 0 onto the evaluation stack
                .ret() //Return
            ;

            return (ReadDataInvoker)method.CreateDelegate(typeof(ReadDataInvoker));
        }
        private void GeneratePropertySet(EmitHelper emit, int typeCode, MemberInfo memberInfo)
        {
            Type memberType = null;
            if (memberInfo.MemberType == MemberTypes.Property)
            {
                PropertyInfo propertyInfo = memberInfo.DeclaringType.GetProperty(memberInfo.Name);
                memberType = propertyInfo.PropertyType;
            }
            if (memberInfo is FieldInfo)
            {
                FieldInfo fieldInfo = memberInfo.DeclaringType.GetField(memberInfo.Name);
                memberType = fieldInfo.FieldType;
            }
            if (memberType == null)
                throw new ArgumentNullException(memberInfo.Name);

            //The primitive types are: Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Char, Double, Single
            //We handle here Decimal types too
            if (memberType.IsPrimitive || memberType == typeof(decimal))
            {
                TypeCode primitiveTypeCode = Type.GetTypeCode(memberType);
                switch (primitiveTypeCode)
                {
                    case TypeCode.Byte:
                    case TypeCode.Decimal:
                    case TypeCode.Int16:
                    case TypeCode.Int32:
                    case TypeCode.Int64:
                    case TypeCode.SByte:
                    case TypeCode.UInt16:
                    case TypeCode.UInt32:
                    case TypeCode.UInt64:
                    case TypeCode.Single:
                    case TypeCode.Double:
                        {
                            #region Primitive numeric
                            Label labelNotNumber = emit.ILGenerator.DefineLabel();
                            Label labelExit = emit.ILGenerator.DefineLabel();

                            //if( typeCode == AMF0TypeCode.Number )
                            emit
                                .ldloc_1 //Push 'typeCode'
                                .ldc_i4(AMF0TypeCode.Number)
                                .ceq
                                .brfalse_s(labelNotNumber)
                                //instance.{0} = ({1})reader.ReadDouble();
                                .ldloc_0 //Push 'instance'
                                .ldarg_0 //Push 'reader'
                                .callvirt(typeof(AMFReader).GetMethod("ReadDouble"))
                                .GeneratePrimitiveCast(primitiveTypeCode)
                                .GenerateSetMember(memberInfo)
                                .br_s(labelExit)
                                .MarkLabel(labelNotNumber)
                                .GenerateThrowUnexpectedAMFException(memberInfo)
                                .MarkLabel(labelExit)
                                //.nop
                                .end()
                            ;
                            #endregion Primitive numeric
                        }
                        break;
                    case TypeCode.Boolean:
                        {
                            #region Primitive boolean
                            Label labelNotBoolean = emit.ILGenerator.DefineLabel();
                            Label labelExit = emit.ILGenerator.DefineLabel();

                            //if( typeCode == AMF0TypeCode.Boolean )
                            emit
                                .ldloc_1 //Push 'typeCode'
                                .ldc_i4(AMF0TypeCode.Boolean)
                                .ceq
                                .brfalse_s(labelNotBoolean)
                                //instance.{0} = ({1})reader.ReadBoolean();
                                .ldloc_0 //Push 'instance'
                                .ldarg_0 //Push 'reader'
                                .callvirt(typeof(AMFReader).GetMethod("ReadBoolean"))
                                .GeneratePrimitiveCast(primitiveTypeCode)
                                .GenerateSetMember(memberInfo)
                                .br_s(labelExit)
                                .MarkLabel(labelNotBoolean)
                                .GenerateThrowUnexpectedAMFException(memberInfo)
                                .MarkLabel(labelExit)
                                .end()
                            ;
                            #endregion Primitive boolean
                        }
                        break;
                    case TypeCode.Char:
                        {
                            #region Primitive Char
                            {
                                Label labelNotString = emit.ILGenerator.DefineLabel();
                                Label labelExit = emit.ILGenerator.DefineLabel();
                                //if( typeCode == AMF0TypeCode.String )
                                emit
                                    .ldloc_1 //Push 'typeCode'
                                    .ldc_i4(AMF0TypeCode.String)
                                    .ceq
                                    .brfalse_s(labelNotString)
                                    //instance.member = reader.ReadString()[0];
                                    .ldarg_0 //Push 'reader'
                                    .callvirt(typeof(AMFReader).GetMethod("ReadString"))
                                    .stloc_2
                                    .ldloc_2 //Push 'key'
                                    .brfalse_s(labelNotString) // Branch if 'key' is null
                                    .ldloc_2 //Push strTmp
                                    .ldsfld(typeof(string).GetField("Empty"))
                                    .call(typeof(string).GetMethod("op_Inequality", new Type[] { typeof(string), typeof(string) }))
                                    .brfalse_s(labelNotString)
                                    .ldloc_0 //Push 'instance'
                                    .ldloc_2 //Push 'key'
                                    .ldc_i4_0 //Push char index 0
                                    .callvirt(typeof(string).GetMethod("get_Chars", new Type[] { typeof(Int32) }))
                                    .GenerateSetMember(memberInfo)
                                    .br_s(labelExit)
                                    .MarkLabel(labelNotString)
                                    .GenerateThrowUnexpectedAMFException(memberInfo)
                                    .MarkLabel(labelExit)
                                    .end()
                                ;
                            }
                            #endregion Primitive Char
                        }
                        break;
                }
                return;
            }
            if (memberType.IsEnum)
            {
                #region Enum
                    Label labelNotStringOrNumber = emit.ILGenerator.DefineLabel();
                    Label labelExit = emit.ILGenerator.DefineLabel();
                    Label labelReadDouble = emit.ILGenerator.DefineLabel();
                    //if( typeCode == AMF0TypeCode.String || typeCode == AMF0TypeCode.Number )
                    emit
                        .ldloc_1 //Push 'typeCode'
                        .brfalse_s(labelReadDouble) //Branch if 0 (AMF0TypeCode.Number)
                        .ldloc_1 //Push 'typeCode'
                        .ldc_i4(AMF0TypeCode.String)
                        .ceq
                        .brfalse_s(labelNotStringOrNumber)
                        //we have a string
                        .ldloc_0 //Push 'instance'
                        .ldtoken(memberType)
                        .call(typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }))
                        .ldarg_0 //Push 'reader'
                        .callvirt(typeof(AMFReader).GetMethod("ReadString"))
                        .ldc_i4_1
                        .call(typeof(Enum).GetMethod("Parse", new Type[] { typeof(Type), typeof(string), typeof(bool) }))
                        .unbox_any(memberType)
                        .GenerateSetMember(memberInfo)
                        .br_s(labelExit)
                        .MarkLabel(labelReadDouble)
                        //we have a number
                        .ldloc_0 //Push 'instance'
                        .ldtoken(memberType)
                        .call(typeof(Type).GetMethod("GetTypeFromHandle"))
                        .ldarg_0 //Push 'reader'
                        .callvirt(typeof(AMFReader).GetMethod("ReadDouble"))
                        .conv_i4
                        .call(typeof(Enum).GetMethod("ToObject", new Type[] { typeof(Type), typeof(Int32) }))
                        .unbox_any(memberType)
                        .GenerateSetMember(memberInfo)
                        .br_s(labelExit)
                        .MarkLabel(labelNotStringOrNumber)
                        .GenerateThrowUnexpectedAMFException(memberInfo)
                        .MarkLabel(labelExit)
                        .end()
                    ;
                    return;
                #endregion Enum
            }
            if (memberType == typeof(DateTime))
            {
                #region DateTime
                Label labelNotDate = emit.ILGenerator.DefineLabel();
                Label labelExit = emit.ILGenerator.DefineLabel();
                //if( typeCode == AMF0TypeCode.DateTime )
                emit
                    .ldloc_1 //Push 'typeCode'
                    .ldc_i4(AMF0TypeCode.DateTime)
                    .ceq
                    .brfalse_s(labelNotDate)
                    .ldloc_0 //Push 'instance'
                    .ldarg_0 //Push 'reader'
                    .callvirt(typeof(AMFReader).GetMethod("ReadDateTime"))
                    .GenerateSetMember(memberInfo)
                    .br_s(labelExit)
                    .MarkLabel(labelNotDate)
                    .GenerateThrowUnexpectedAMFException(memberInfo)
                    .MarkLabel(labelExit)
                    .end()
                ;
                return;
                #endregion DateTime
            }
            if (memberType == typeof(string))
            {
                #region String
                Label labelNotStringOrNull = emit.ILGenerator.DefineLabel();
                Label labelSetNull = emit.ILGenerator.DefineLabel();
                Label labelExit = emit.ILGenerator.DefineLabel();
                Label labelReadString = emit.ILGenerator.DefineLabel();
                Label labelReadLongString = emit.ILGenerator.DefineLabel();
                emit
                    //if( typeCode == AMF0TypeCode.String || typeCode == AMF0TypeCode.LongString || typeCode == AMF0TypeCode.Null || typeCode == AMF0TypeCode.Undefined )
                    .ldloc_1 //Push 'typeCode'
                    .ldc_i4(AMF0TypeCode.String)
                    .ceq
                    .brtrue_s(labelReadString)
                    .ldloc_1 //Push 'typeCode'
                    .ldc_i4(AMF0TypeCode.LongString)
                    .ceq
                    .brtrue_s(labelReadLongString)
                    .ldloc_1 //Push 'typeCode'
                    .ldc_i4(AMF0TypeCode.Null)
                    .ceq
                    .brtrue_s(labelSetNull)
                    .ldloc_1 //Push 'typeCode'
                    .ldc_i4(AMF0TypeCode.Undefined)
                    .ceq
                    .brtrue_s(labelSetNull)
                    .br_s(labelNotStringOrNull)
                    .MarkLabel(labelReadString)
                    .ldloc_0 //Push 'instance'
                    .ldarg_0 //Push 'reader'
                    .callvirt(typeof(AMFReader).GetMethod("ReadString"))
                    .GenerateSetMember(memberInfo)
                    .br_s(labelExit)
                    .MarkLabel(labelReadLongString)
                    .ldloc_0 //Push 'instance'
                    .ldarg_0 //Push 'reader'
                    .callvirt(typeof(AMFReader).GetMethod("ReadLongString"))
                    .GenerateSetMember(memberInfo)
                    .br_s(labelExit)
                    .MarkLabel(labelSetNull)
                    .ldloc_0 //Push 'instance'
                    .ldc_i4_0
                    .GenerateSetMember(memberInfo)
                    .br_s(labelExit)
                    .MarkLabel(labelNotStringOrNull)
                    .GenerateThrowUnexpectedAMFException(memberInfo)
                    .MarkLabel(labelExit)
                    .end()
                ;
                return;
                #endregion String
            }
            if (memberType == typeof(Guid))
            {
                #region Guid
                Label labelNotString = emit.ILGenerator.DefineLabel();
                Label labelExit = emit.ILGenerator.DefineLabel();
                emit
                    //if( typeCode == AMF0TypeCode.String )
                    .ldloc_1 //Push 'typeCode'
                    .ldc_i4(AMF0TypeCode.String)
                    .ceq
                    .brfalse_s(labelNotString)
                    .ldloc_0 //Push 'instance'
                    .ldarg_0 //Push 'reader'
                    .callvirt(typeof(AMFReader).GetMethod("ReadString"))
                    .newobj(typeof(Guid).GetConstructor(EmitHelper.AnyVisibilityInstance, null, CallingConventions.HasThis, new Type[] { typeof(string) }, null))
                    .GenerateSetMember(memberInfo)
                    .br_s(labelExit)
                    .MarkLabel(labelNotString)
                    .GenerateThrowUnexpectedAMFException(memberInfo)
                    .MarkLabel(labelExit)
                    .end()
                ;
                return;
                #endregion Guid
            }
            if (memberType.IsValueType)
            {
                //structs are not handled
                throw new FluorineException("Struct value types are not supported");
            }

            //instance.member = (type)TypeHelper.ChangeType(reader.ReadData(typeCode), typeof(member));
            emit
                .ldloc_0 //Push 'instance'
                .ldarg_0 //Push 'reader'
                .ldloc_1 //Push 'typeCode'
                .callvirt(typeof(AMFReader).GetMethod("ReadData", new Type[] { typeof(byte) }))
                .ldtoken(memberType)
                .call(typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }))
                .call(typeof(TypeHelper).GetMethod("ChangeType", new Type[] { typeof(object), typeof(Type) }))
                .CastFromObject(memberType)
                .GenerateSetMember(memberInfo)
                .end()
            ;
        }