private WriteBack AddressOfWriteBackCore(IndexExpression node)
        {
            // emit instance, if any
            LocalBuilder?instanceLocal = null;
            Type?        instanceType  = null;

            if (node.Object != null)
            {
                EmitInstance(node.Object, out instanceType);

                // store in local
                IL.Emit(OpCodes.Dup);
                IL.Emit(OpCodes.Stloc, instanceLocal = GetInstanceLocal(instanceType));
            }

            // Emit indexes. We don't allow byref args, so no need to worry
            // about write-backs or EmitAddress
            var n    = node.ArgumentCount;
            var args = new LocalBuilder[n];

            for (var i = 0; i < n; i++)
            {
                var arg = node.GetArgument(i);
                EmitExpression(arg);

                var argLocal = GetLocal(arg.Type);
                IL.Emit(OpCodes.Dup);
                IL.Emit(OpCodes.Stloc, argLocal);
                args[i] = argLocal;
            }

            // emit the get
            EmitGetIndexCall(node, instanceType);

            // emit the address of the value
            var valueLocal = GetLocal(node.Type);

            IL.Emit(OpCodes.Stloc, valueLocal);
            IL.Emit(OpCodes.Ldloca, valueLocal);

            // Set the property after the method call
            // don't re-evaluate anything
            return(@this =>
            {
                if (instanceLocal != null)
                {
                    @this.IL.Emit(OpCodes.Ldloc, instanceLocal);
                    @this.FreeLocal(instanceLocal);
                }
                foreach (var arg in args)
                {
                    @this.IL.Emit(OpCodes.Ldloc, arg);
                    @this.FreeLocal(arg);
                }
                @this.IL.Emit(OpCodes.Ldloc, valueLocal);
                @this.FreeLocal(valueLocal);

                @this.EmitSetIndexCall(node, instanceLocal?.LocalType);
            });
        }
Beispiel #2
0
        private LocalBuilder Imitate(Object obj, ILGenerator il)
        {
            var type = obj.GetType();
            var bldr = Construct(type, il);

            var node = new ValueNode(obj);

            var props = _objectManipulator.GetPropertyResults(node, _settings);

            foreach (var prop in props)
            {
                LocalBuilder?liveLocal = null;

                switch (prop.Value)
                {
                case String str:
                    il.Emit(OpCodes.Ldstr, str);
                    liveLocal = il.DeclareLocal(typeof(String));
                    break;

                case Int32 i32:
                    il.Emit(OpCodes.Ldind_I4, i32);
                    liveLocal = il.DeclareLocal(typeof(Int32));
                    break;
                }

                if (liveLocal != null)
                {
                    il.Emit(OpCodes.Stloc, liveLocal);
                    SetPropertyValue(bldr, prop, liveLocal, il);
                }
            }

            return(bldr);
        }
Beispiel #3
0
            private int WriteMembers(ClassDataContract classContract, LocalBuilder?extensionDataLocal, ClassDataContract derivedMostClassContract)
            {
                int memberCount = (classContract.BaseContract == null) ? 0 :
                                  WriteMembers(classContract.BaseContract, extensionDataLocal, derivedMostClassContract);

                int classMemberCount = classContract.Members !.Count;

                _ilg.Call(thisObj: _contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, classMemberCount);

                for (int i = 0; i < classMemberCount; i++, memberCount++)
                {
                    DataMember   member      = classContract.Members[i];
                    Type         memberType  = member.MemberType;
                    LocalBuilder?memberValue = null;

                    _ilg.Load(_contextArg);
                    _ilg.Call(methodInfo: member.IsGetOnlyCollection ?
                              XmlFormatGeneratorStatics.StoreIsGetOnlyCollectionMethod :
                              XmlFormatGeneratorStatics.ResetIsGetOnlyCollectionMethod);

                    if (!member.EmitDefaultValue)
                    {
                        memberValue = LoadMemberValue(member);
                        _ilg.IfNotDefaultValue(memberValue);
                    }

                    bool requiresNameAttribute = DataContractJsonSerializerImpl.CheckIfXmlNameRequiresMapping(classContract.MemberNames ![i]);
Beispiel #4
0
 public unsafe DeserializeStaticMutableArguments(ArrayPool <byte> pool)
 {
     this.pool = pool;
     deserializeDictionaryEntrySegments = pool.Rent(sizeof(DeserializeDictionaryEntrySegment) * 64);
     used          = default;
     ByteVariable  = default;
     ULongVariable = default;
     Length        = default;
     Position      = default;
     Rest          = default;
 }
            private int ReadMembers(ClassDataContract classContract, bool[] requiredMembers, Label[] memberLabels, LocalBuilder memberIndexLocal, LocalBuilder?requiredIndexLocal)
            {
                Debug.Assert(_objectLocal != null);
                Debug.Assert(_objectType != null);

                int memberCount = (classContract.BaseContract == null) ? 0 : ReadMembers(classContract.BaseContract, requiredMembers,
                                                                                         memberLabels, memberIndexLocal, requiredIndexLocal);

                for (int i = 0; i < classContract.Members !.Count; i++, memberCount++)
                {
                    DataMember dataMember = classContract.Members[i];
                    Type       memberType = dataMember.MemberType;
                    _ilg.Case(memberLabels[memberCount], dataMember.Name);
                    if (dataMember.IsRequired)
                    {
                        int nextRequiredIndex = memberCount + 1;
                        for (; nextRequiredIndex < requiredMembers.Length; nextRequiredIndex++)
                        {
                            if (requiredMembers[nextRequiredIndex])
                            {
                                break;
                            }
                        }
                        _ilg.Set(requiredIndexLocal !, nextRequiredIndex);
                    }

                    LocalBuilder?value = null;

                    if (dataMember.IsGetOnlyCollection)
                    {
                        _ilg.LoadAddress(_objectLocal);
                        _ilg.LoadMember(dataMember.MemberInfo);
                        value = _ilg.DeclareLocal(memberType, dataMember.Name + "Value");
                        _ilg.Stloc(value);
                        _ilg.Call(_contextArg, XmlFormatGeneratorStatics.StoreCollectionMemberInfoMethod, value);
                        ReadValue(memberType, dataMember.Name, classContract.StableName.Namespace);
                    }
                    else
                    {
                        _ilg.Call(_contextArg, XmlFormatGeneratorStatics.ResetCollectionMemberInfoMethod);
                        value = ReadValue(memberType, dataMember.Name, classContract.StableName.Namespace);
                        _ilg.LoadAddress(_objectLocal);
                        _ilg.ConvertAddress(_objectLocal.LocalType, _objectType);
                        _ilg.Ldloc(value);
                        _ilg.StoreMember(dataMember.MemberInfo);
                    }

                    _ilg.Set(memberIndexLocal, memberCount);

                    _ilg.EndCase();
                }
                return(memberCount);
            }
Beispiel #6
0
 private void EnsureLabelAndValue()
 {
     if (!_labelDefined)
     {
         _labelDefined = true;
         _label        = _ilg.DefineLabel();
         if (_node != null && _node.Type != typeof(void))
         {
             _value = _ilg.DeclareLocal(_node.Type);
         }
     }
 }
            private void WriteClass(ClassDataContract classContract)
            {
                InvokeOnSerializing(classContract);

                if (classContract.IsISerializable)
                {
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.WriteISerializableMethod, _xmlWriterArg, _objectLocal);
                }
                else
                {
                    if (classContract.ContractNamespaces!.Length > 1)
                    {
                        _contractNamespacesLocal = _ilg.DeclareLocal(typeof(XmlDictionaryString[]), "contractNamespaces");
                        _ilg.Load(_dataContractArg);
                        _ilg.LoadMember(XmlFormatGeneratorStatics.ContractNamespacesField);
                        _ilg.Store(_contractNamespacesLocal);
                    }

                    _memberNamesLocal = _ilg.DeclareLocal(typeof(XmlDictionaryString[]), "memberNames");
                    _ilg.Load(_dataContractArg);
                    _ilg.LoadMember(XmlFormatGeneratorStatics.MemberNamesField);
                    _ilg.Store(_memberNamesLocal);

                    for (int i = 0; i < classContract.ChildElementNamespaces!.Length; i++)
                    {
                        if (classContract.ChildElementNamespaces[i] != null)
                        {
                            _childElementNamespacesLocal = _ilg.DeclareLocal(typeof(XmlDictionaryString[]), "childElementNamespaces");
                            _ilg.Load(_dataContractArg);
                            _ilg.LoadMember(XmlFormatGeneratorStatics.ChildElementNamespacesProperty);
                            _ilg.Store(_childElementNamespacesLocal);
                        }
                    }

                    if (classContract.HasExtensionData)
                    {
                        LocalBuilder extensionDataLocal = _ilg.DeclareLocal(Globals.TypeOfExtensionDataObject, "extensionData");
                        _ilg.Load(_objectLocal);
                        _ilg.ConvertValue(_objectLocal.LocalType, Globals.TypeOfIExtensibleDataObject);
                        _ilg.LoadMember(XmlFormatGeneratorStatics.ExtensionDataProperty);
                        _ilg.Store(extensionDataLocal);
                        _ilg.Call(_contextArg, XmlFormatGeneratorStatics.WriteExtensionDataMethod, _xmlWriterArg, extensionDataLocal, -1);
                        WriteMembers(classContract, extensionDataLocal, classContract);
                    }
                    else
                    {
                        WriteMembers(classContract, null, classContract);
                    }
                }
                InvokeOnSerialized(classContract);
            }
Beispiel #8
0
            private void ReadMembers(ClassDataContract classContract, LocalBuilder?extensionDataLocal)
            {
                int memberCount = classContract.MemberNames !.Length;

                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, memberCount);

                BitFlagsGenerator expectedElements = new BitFlagsGenerator(memberCount, _ilg, classContract.UnderlyingType.Name + "_ExpectedElements");

                byte[] requiredElements = new byte[expectedElements.GetLocalCount()];
                SetRequiredElements(classContract, requiredElements);
                SetExpectedElements(expectedElements, 0 /*startIndex*/);

                LocalBuilder memberIndexLocal                 = _ilg.DeclareLocal(Globals.TypeOfInt, "memberIndex", -1);
                Label        throwDuplicateMemberLabel        = _ilg.DefineLabel();
                Label        throwMissingRequiredMembersLabel = _ilg.DefineLabel();

                object forReadElements = _ilg.For(null, null, null);

                _ilg.Call(null, XmlFormatGeneratorStatics.MoveToNextElementMethod, _xmlReaderArg);
                _ilg.IfFalseBreak(forReadElements);
                _ilg.Call(_contextArg, JsonFormatGeneratorStatics.GetJsonMemberIndexMethod, _xmlReaderArg, _memberNamesArg, memberIndexLocal, extensionDataLocal);
                if (memberCount > 0)
                {
                    Label[] memberLabels = _ilg.Switch(memberCount);
                    ReadMembers(classContract, expectedElements, memberLabels, throwDuplicateMemberLabel, memberIndexLocal);
                    _ilg.EndSwitch();
                }
                else
                {
                    _ilg.Pop();
                }
                _ilg.EndFor();
                CheckRequiredElements(expectedElements, requiredElements, throwMissingRequiredMembersLabel);
                Label endOfTypeLabel = _ilg.DefineLabel();

                _ilg.Br(endOfTypeLabel);

                _ilg.MarkLabel(throwDuplicateMemberLabel);
                _ilg.Call(null, JsonFormatGeneratorStatics.ThrowDuplicateMemberExceptionMethod, _objectLocal, _memberNamesArg, memberIndexLocal);

                _ilg.MarkLabel(throwMissingRequiredMembersLabel);
                _ilg.Load(_objectLocal);
                _ilg.ConvertValue(_objectLocal.LocalType, Globals.TypeOfObject);
                _ilg.Load(_memberNamesArg);
                expectedElements.LoadArray();
                LoadArray(requiredElements, "requiredElements");
                _ilg.Call(JsonFormatGeneratorStatics.ThrowMissingRequiredMembersMethod);

                _ilg.MarkLabel(endOfTypeLabel);
            }
Beispiel #9
0
        private void EmitMemberAssignment(AssignBinaryExpression node, CompilationFlags flags)
        {
            Debug.Assert(!node.IsByRef);

            var lvalue = (MemberExpression)node.Left;
            var member = lvalue.Member;

            // emit "this", if any
            Type?objectType = null;

            if (lvalue.Expression != null)
            {
                EmitInstance(lvalue.Expression, out objectType);
            }

            // emit value
            EmitExpression(node.Right);

            LocalBuilder?temp = null;

            var emitAs = flags & CompilationFlags.EmitAsTypeMask;

            if (emitAs != CompilationFlags.EmitAsVoidType)
            {
                // save the value so we can return it
                IL.Emit(OpCodes.Dup);
                temp = GetLocal(node.Type);
                IL.Emit(OpCodes.Stloc, temp);
            }

            if (member is FieldInfo info)
            {
                IL.EmitFieldSet(info);
            }
            else
            {
                // MemberExpression.Member can only be a FieldInfo or a PropertyInfo
                Debug.Assert(member is PropertyInfo);
                var prop = (PropertyInfo)member;
                EmitCall(objectType, prop.GetSetMethod(true));
            }

            if (temp == null)
            {
                return;
            }

            IL.Emit(OpCodes.Ldloc, temp);
            FreeLocal(temp);
        }
Beispiel #10
0
        internal object For(LocalBuilder?local, object?start, object?end)
        {
            ForState forState = new ForState(local, DefineLabel(), DefineLabel(), end);

            if (forState.Index != null)
            {
                Load(start);
                Stloc(forState.Index);
                Br(forState.TestLabel);
            }
            MarkLabel(forState.BeginLabel);
            _blockStack.Push(forState);
            return(forState);
        }
Beispiel #11
0
        private void EmitIndexAssignment(AssignBinaryExpression node, CompilationFlags flags)
        {
            Debug.Assert(!node.IsByRef);

            var index = (IndexExpression)node.Left;

            var emitAs = flags & CompilationFlags.EmitAsTypeMask;

            // Emit instance, if calling an instance method
            Type?objectType = null;

            if (index.Object != null)
            {
                EmitInstance(index.Object, out objectType);
            }

            // Emit indexes. We don't allow byref args, so no need to worry
            // about writebacks or EmitAddress
            for (int i = 0, n = index.ArgumentCount; i < n; i++)
            {
                var arg = index.GetArgument(i);
                EmitExpression(arg);
            }

            // Emit value
            EmitExpression(node.Right);

            // Save the expression value, if needed
            LocalBuilder?temp = null;

            if (emitAs != CompilationFlags.EmitAsVoidType)
            {
                IL.Emit(OpCodes.Dup);
                temp = GetLocal(node.Type);
                IL.Emit(OpCodes.Stloc, temp);
            }

            EmitSetIndexCall(index, objectType);

            // Restore the value
            if (temp == null)
            {
                return;
            }

            IL.Emit(OpCodes.Ldloc, temp);
            FreeLocal(temp);
        }
            private bool InvokeFactoryMethod(ClassDataContract classContract, LocalBuilder?objectId)
            {
                Debug.Assert(_objectLocal != null);

                if (HasFactoryMethod(classContract))
                {
                    _ilg.Load(_contextArg);
                    _ilg.LoadAddress(_objectLocal);
                    _ilg.ConvertAddress(_objectLocal.LocalType, Globals.TypeOfIObjectReference);
                    _ilg.Load(objectId);
                    _ilg.Call(XmlFormatGeneratorStatics.GetRealObjectMethod);
                    _ilg.ConvertValue(Globals.TypeOfObject, _ilg.CurrentMethod.ReturnType);
                    return(true);
                }

                return(false);
            }
Beispiel #13
0
        public void EmittedDeserializeIsValid(Type emitterType, Type valueType, string testLiteral, object expectedResult)
        {
            if (valueType == typeof(decimal))
            {
                expectedResult = (decimal)(double)expectedResult;
            }
            else if (valueType == typeof(decimal?))
            {
                expectedResult = (decimal?)(double?)expectedResult;
            }
            IConverterEmitter emitter     = (IConverterEmitter)Activator.CreateInstance(emitterType) !;
            DynamicMethod     deserialize = new DynamicMethod("Deserialize", valueType, new Type[] { typeof(ReadOnlyMemory <char>), typeof(IFormatProvider) }, typeof(NumberConverterTests));
            LocalBuilder?     local       = null;

            deserialize.GetILGenerator()
            .Emit(gen => Nullable.GetUnderlyingType(valueType) switch {
                { } => gen.DeclareLocal(valueType, out local),
Beispiel #14
0
        private void EmitListInit(ListInitExpression init)
        {
            EmitExpression(init.NewExpression);
            LocalBuilder?loc = null;

            if (init.NewExpression.Type.IsValueType)
            {
                loc = GetLocal(init.NewExpression.Type);
                _ilg.Emit(OpCodes.Stloc, loc);
                _ilg.Emit(OpCodes.Ldloca, loc);
            }
            EmitListInit(init.Initializers, loc == null, init.NewExpression.Type);
            if (loc != null)
            {
                _ilg.Emit(OpCodes.Ldloc, loc);
                FreeLocal(loc);
            }
        }
Beispiel #15
0
        private void EmitMemberInit(MemberInitExpression init)
        {
            EmitExpression(init.NewExpression);
            LocalBuilder?loc = null;

            if (init.NewExpression.Type.IsValueType && init.Bindings.Count > 0)
            {
                loc = GetLocal(init.NewExpression.Type);
                _ilg.Emit(OpCodes.Stloc, loc);
                _ilg.Emit(OpCodes.Ldloca, loc);
            }
            EmitMemberInit(init.Bindings, loc == null, init.NewExpression.Type);
            if (loc != null)
            {
                _ilg.Emit(OpCodes.Ldloc, loc);
                FreeLocal(loc);
            }
        }
            private void ReadMembers(ClassDataContract classContract, LocalBuilder?extensionDataLocal)
            {
                int memberCount = classContract.MemberNames !.Length;

                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, memberCount);

                LocalBuilder memberIndexLocal = _ilg.DeclareLocal(Globals.TypeOfInt, "memberIndex", -1);

                int firstRequiredMember;

                bool[]       requiredMembers    = GetRequiredMembers(classContract, out firstRequiredMember);
                bool         hasRequiredMembers = (firstRequiredMember < memberCount);
                LocalBuilder?requiredIndexLocal = hasRequiredMembers ? _ilg.DeclareLocal(Globals.TypeOfInt, "requiredIndex", firstRequiredMember) : null;

                object forReadElements = _ilg.For(null, null, null);

                _ilg.Call(null, XmlFormatGeneratorStatics.MoveToNextElementMethod, _xmlReaderArg);
                _ilg.IfFalseBreak(forReadElements);
                if (hasRequiredMembers)
                {
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetMemberIndexWithRequiredMembersMethod, _xmlReaderArg, _memberNamesArg, _memberNamespacesArg, memberIndexLocal, requiredIndexLocal, extensionDataLocal);
                }
                else
                {
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetMemberIndexMethod, _xmlReaderArg, _memberNamesArg, _memberNamespacesArg, memberIndexLocal, extensionDataLocal);
                }
                if (memberCount > 0)
                {
                    Label[] memberLabels = _ilg.Switch(memberCount);
                    ReadMembers(classContract, requiredMembers, memberLabels, memberIndexLocal, requiredIndexLocal);
                    _ilg.EndSwitch();
                }
                else
                {
                    _ilg.Pop();
                }
                _ilg.EndFor();
                if (hasRequiredMembers)
                {
                    _ilg.If(requiredIndexLocal !, Cmp.LessThan, memberCount);
                    _ilg.Call(null, XmlFormatGeneratorStatics.ThrowRequiredMemberMissingExceptionMethod, _xmlReaderArg, memberIndexLocal, requiredIndexLocal, _memberNamesArg);
                    _ilg.EndIf();
                }
            }
            private int WriteMembers(ClassDataContract classContract, LocalBuilder?extensionDataLocal, ClassDataContract derivedMostClassContract)
            {
                int memberCount = (classContract.BaseContract == null) ? 0 :
                                  WriteMembers(classContract.BaseContract, extensionDataLocal, derivedMostClassContract);

                LocalBuilder namespaceLocal = _ilg.DeclareLocal(typeof(XmlDictionaryString), "ns");

                if (_contractNamespacesLocal == null)
                {
                    _ilg.Load(_dataContractArg);
                    _ilg.LoadMember(XmlFormatGeneratorStatics.NamespaceProperty);
                }
                else
                {
                    _ilg.LoadArrayElement(_contractNamespacesLocal, _typeIndex - 1);
                }

                _ilg.Store(namespaceLocal);

                int classMemberCount = classContract.Members !.Count;

                _ilg.Call(thisObj: _contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, classMemberCount);

                for (int i = 0; i < classMemberCount; i++, memberCount++)
                {
                    DataMember   member      = classContract.Members[i];
                    Type         memberType  = member.MemberType;
                    LocalBuilder?memberValue = null;

                    _ilg.Load(_contextArg);
                    _ilg.Call(methodInfo: member.IsGetOnlyCollection ?
                              XmlFormatGeneratorStatics.StoreIsGetOnlyCollectionMethod :
                              XmlFormatGeneratorStatics.ResetIsGetOnlyCollectionMethod);

                    if (!member.EmitDefaultValue)
                    {
                        memberValue = LoadMemberValue(member);
                        _ilg.IfNotDefaultValue(memberValue);
                    }
                    bool writeXsiType = CheckIfMemberHasConflict(member, classContract, derivedMostClassContract);
                    if (writeXsiType || !TryWritePrimitive(memberType, memberValue, member.MemberInfo, arrayItemIndex: null, ns: namespaceLocal, name: null, nameIndex: i + _childElementIndex))
                    {
                        WriteStartElement(memberType, classContract.Namespace, namespaceLocal, nameLocal: null, nameIndex: i + _childElementIndex);
                        if (classContract.ChildElementNamespaces ![i + _childElementIndex] != null)
Beispiel #18
0
        public void EmittedAppendToStringBuilderIsValid(Type emitterType, Type valueType, object testValue, string expectedResult)
        {
            if (valueType == typeof(decimal))
            {
                testValue = (decimal)(double)testValue;
            }
            else if (valueType == typeof(decimal?))
            {
                testValue = (decimal?)(double?)testValue;
            }
            IConverterEmitter emitter        = (IConverterEmitter)Activator.CreateInstance(emitterType) !;
            DynamicMethod     serialize      = new DynamicMethod("Serialize", typeof(string), new Type[] { valueType, typeof(IFormatProvider), typeof(char) }, typeof(NumberConverterTests));
            LocalBuilder?     local          = null;
            LocalBuilder?     secondaryLocal = null;

            serialize.GetILGenerator()
            .Emit(gen => {
                if (valueType == typeof(float) || valueType == typeof(double) || valueType == typeof(decimal))
                {
                    gen.DeclareLocal(valueType, out local);
                }
                else if (Nullable.GetUnderlyingType(valueType) is Type underlyingType)
                {
                    if (underlyingType == typeof(float) || underlyingType == typeof(double) || underlyingType == typeof(decimal))
                    {
                        gen.DeclareLocal(typeof(Nullable <>).MakeGenericType(underlyingType), out local);
                        gen.DeclareLocal(valueType, out secondaryLocal);
                    }
                    else
                    {
                        gen.DeclareLocal(typeof(Nullable <>).MakeGenericType(underlyingType), out local);
                    }
                }
            })
            .Newobj <StringBuilder>()
            .Ldarg_0()
            .Emit(gen => emitter.EmitAppendToStringBuilder(gen, local, secondaryLocal, null))
            .Callvirt <StringBuilder>("ToString")
            .Ret();
            string serialized = (string)serialize.Invoke(null, new[] { testValue, CultureInfo.InvariantCulture, ',' }) !;

            serialized.Should().Be(expectedResult);
        }
Beispiel #19
0
        private Action <LambdaCompiler> AddressOfWriteBackCore(MemberExpression node)
        {
            // emit instance, if any
            LocalBuilder?instanceLocal = null;
            Type?        instanceType  = null;

            if (node.Expression != null)
            {
                EmitInstance(node.Expression, out instanceType);

                // store in local
                IL.Emit(OpCodes.Dup);
                instanceLocal = GetInstanceLocal(instanceType);
                IL.Emit(OpCodes.Stloc, instanceLocal);
            }

            var pi = (PropertyInfo)node.Member;

            // emit the get
            EmitCall(instanceType, pi.GetGetMethod(true));

            // emit the address of the value
            var valueLocal = GetLocal(node.Type);

            IL.Emit(OpCodes.Stloc, valueLocal);
            IL.Emit(OpCodes.Ldloca, valueLocal);

            // Set the property after the method call
            // don't re-evaluate anything
            return(@this =>
            {
                if (instanceLocal != null)
                {
                    @this.IL.Emit(OpCodes.Ldloc, instanceLocal);
                    @this.FreeLocal(instanceLocal);
                }

                @this.IL.Emit(OpCodes.Ldloc, valueLocal);
                @this.FreeLocal(valueLocal);
                @this.EmitCall(instanceLocal?.LocalType, pi.GetSetMethod(true));
            });
        }
Beispiel #20
0
            private int ReadMembers(ClassDataContract classContract, BitFlagsGenerator expectedElements,
                                    Label[] memberLabels, Label throwDuplicateMemberLabel, LocalBuilder memberIndexLocal)
            {
                int memberCount = (classContract.BaseContract == null) ? 0 :
                                  ReadMembers(classContract.BaseContract, expectedElements, memberLabels, throwDuplicateMemberLabel, memberIndexLocal);

                for (int i = 0; i < classContract.Members !.Count; i++, memberCount++)
                {
                    DataMember dataMember = classContract.Members[i];
                    Type       memberType = dataMember.MemberType;
                    _ilg.Case(memberLabels[memberCount], dataMember.Name);
                    _ilg.Set(memberIndexLocal, memberCount);
                    expectedElements.Load(memberCount);
                    _ilg.Brfalse(throwDuplicateMemberLabel);
                    LocalBuilder?value = null;
                    if (dataMember.IsGetOnlyCollection)
                    {
                        _ilg.LoadAddress(_objectLocal);
                        _ilg.LoadMember(dataMember.MemberInfo);
                        value = _ilg.DeclareLocal(memberType, dataMember.Name + "Value");
                        _ilg.Stloc(value);
                        _ilg.Call(_contextArg, XmlFormatGeneratorStatics.StoreCollectionMemberInfoMethod, value);
                        ReadValue(memberType, dataMember.Name);
                    }
                    else
                    {
                        _ilg.Call(_contextArg, XmlFormatGeneratorStatics.ResetCollectionMemberInfoMethod);
                        value = ReadValue(memberType, dataMember.Name);
                        _ilg.LoadAddress(_objectLocal);
                        _ilg.ConvertAddress(_objectLocal.LocalType, _objectType !);
                        _ilg.Ldloc(value);
                        _ilg.StoreMember(dataMember.MemberInfo);
                    }
                    ResetExpectedElements(expectedElements, memberCount);
                    _ilg.EndCase();
                }
                return(memberCount);
            }
            private void CreateObject(ClassDataContract classContract)
            {
                Type type = _objectType = classContract.UnderlyingType;

                if (type.IsValueType && !classContract.IsNonAttributedType)
                {
                    type = Globals.TypeOfValueType;
                }

                _objectLocal = _ilg.DeclareLocal(type, "objectDeserialized");

                if (classContract.UnderlyingType == Globals.TypeOfDBNull)
                {
                    _ilg.LoadMember(Globals.TypeOfDBNull.GetField("Value") !);
                    _ilg.Stloc(_objectLocal);
                }
                else if (classContract.IsNonAttributedType)
                {
                    if (type.IsValueType)
                    {
                        _ilg.Ldloca(_objectLocal);
                        _ilg.InitObj(type);
                    }
                    else
                    {
                        _ilg.New(classContract.GetNonAttributedTypeConstructor() !);
                        _ilg.Stloc(_objectLocal);
                    }
                }
                else
                {
                    _ilg.Call(null, XmlFormatGeneratorStatics.GetUninitializedObjectMethod, DataContract.GetIdForInitialization(classContract));
                    _ilg.ConvertValue(Globals.TypeOfObject, type);
                    _ilg.Stloc(_objectLocal);
                }
            }
            private void ReadCollection(CollectionDataContract collectionContract)
            {
                Type            type        = collectionContract.UnderlyingType;
                Type            itemType    = collectionContract.ItemType;
                bool            isArray     = (collectionContract.Kind == CollectionKind.Array);
                ConstructorInfo constructor = collectionContract.Constructor !;

                if (type.IsInterface)
                {
                    switch (collectionContract.Kind)
                    {
                    case CollectionKind.GenericDictionary:
                        type        = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments());
                        constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.EmptyTypes) !;
                        break;

                    case CollectionKind.Dictionary:
                        type        = Globals.TypeOfHashtable;
                        constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.EmptyTypes) !;
                        break;

                    case CollectionKind.Collection:
                    case CollectionKind.GenericCollection:
                    case CollectionKind.Enumerable:
                    case CollectionKind.GenericEnumerable:
                    case CollectionKind.List:
                    case CollectionKind.GenericList:
                        type    = itemType.MakeArrayType();
                        isArray = true;
                        break;
                    }
                }

                _objectLocal = _ilg.DeclareLocal(type, "objectDeserialized");
                if (!isArray)
                {
                    if (type.IsValueType)
                    {
                        _ilg.Ldloca(_objectLocal);
                        _ilg.InitObj(type);
                    }
                    else
                    {
                        _ilg.New(constructor);
                        _ilg.Stloc(_objectLocal);
                        _ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, _objectLocal);
                    }
                }

                bool canReadSimpleDictionary = collectionContract.Kind == CollectionKind.Dictionary ||
                                               collectionContract.Kind == CollectionKind.GenericDictionary;

                if (canReadSimpleDictionary)
                {
                    _ilg.Load(_contextArg);
                    _ilg.LoadMember(JsonFormatGeneratorStatics.UseSimpleDictionaryFormatReadProperty);
                    _ilg.If();

                    ReadSimpleDictionary(collectionContract, itemType);

                    _ilg.Else();
                }

                LocalBuilder objectId = _ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");

                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
                _ilg.Stloc(objectId);

                bool canReadPrimitiveArray = false;

                if (isArray && TryReadPrimitiveArray(itemType))
                {
                    canReadPrimitiveArray = true;
                    _ilg.IfNot();
                }

                LocalBuilder?growingCollection = null;

                if (isArray)
                {
                    growingCollection = _ilg.DeclareLocal(type, "growingCollection");
                    _ilg.NewArray(itemType, 32);
                    _ilg.Stloc(growingCollection);
                }
                LocalBuilder i       = _ilg.DeclareLocal(Globals.TypeOfInt, "i");
                object       forLoop = _ilg.For(i, 0, int.MaxValue);

                // Empty namespace
                IsStartElement(_memberNamesArg, _emptyDictionaryStringArg);
                _ilg.If();
                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
                LocalBuilder value = ReadCollectionItem(collectionContract, itemType);

                if (isArray)
                {
                    Debug.Assert(growingCollection != null);
                    MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod(itemType);
                    _ilg.Call(null, ensureArraySizeMethod, growingCollection, i);
                    _ilg.Stloc(growingCollection);
                    _ilg.StoreArrayElement(growingCollection, i, value);
                }
                else
                {
                    StoreCollectionValue(_objectLocal, value, collectionContract);
                }
                _ilg.Else();
                IsEndElement();
                _ilg.If();
                _ilg.Break(forLoop);
                _ilg.Else();
                HandleUnexpectedItemInCollection(i);
                _ilg.EndIf();
                _ilg.EndIf();

                _ilg.EndFor();
                if (isArray)
                {
                    MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod(itemType);
                    _ilg.Call(null, trimArraySizeMethod, growingCollection, i);
                    _ilg.Stloc(_objectLocal);
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, _objectLocal);
                }

                if (canReadPrimitiveArray)
                {
                    _ilg.Else();
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, _objectLocal);
                    _ilg.EndIf();
                }

                if (canReadSimpleDictionary)
                {
                    _ilg.EndIf();
                }
            }
 public void EmitDeserialize(ILGenerator gen, LocalBuilder?nullableLocal, LocalBuilder?secondaryLocal, CsvColumnAttribute?attribute) => gen
 .Dup()
 .CallPropertyGet <ReadOnlyMemory <char> >("Length")
 .Brfalse_S(out Label @else)
            public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
            {
                if (DataContractSerializer.Option == SerializationOption.ReflectionOnly)
                {
                    return(CreateReflectionXmlClassReader(classContract));
                }
                else
                {
                    _ilg = new CodeGenerator();
                    bool memberAccessFlag = classContract.RequiresMemberAccessForRead(null);
                    try
                    {
                        _ilg.BeginMethod("Read" + classContract.StableName.Name + "FromXml", Globals.TypeOfXmlFormatClassReaderDelegate, memberAccessFlag);
                    }
                    catch (SecurityException securityException)
                    {
                        if (memberAccessFlag)
                        {
                            classContract.RequiresMemberAccessForRead(securityException);
                        }
                        else
                        {
                            throw;
                        }
                    }

                    InitArgs();
                    CreateObject(classContract);
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, _objectLocal);
                    InvokeOnDeserializing(classContract);
                    LocalBuilder?objectId = null;
                    if (HasFactoryMethod(classContract))
                    {
                        objectId = _ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
                        _ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
                        _ilg.Stloc(objectId);
                    }

                    if (classContract.IsISerializable)
                    {
                        ReadISerializable(classContract);
                    }
                    else
                    {
                        ReadClass(classContract);
                    }

                    _ = InvokeFactoryMethod(classContract, objectId);
                    if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom(classContract.UnderlyingType))
                    {
                        _ilg.Call(_objectLocal, XmlFormatGeneratorStatics.OnDeserializationMethod, null);
                    }

                    InvokeOnDeserialized(classContract);
                    if (objectId == null)
                    {
                        _ilg.Load(_objectLocal);

                        // Do a conversion back from DateTimeOffsetAdapter to DateTimeOffset after deserialization.
                        // DateTimeOffsetAdapter is used here for deserialization purposes to bypass the ISerializable implementation
                        // on DateTimeOffset; which does not work in partial trust.

                        if (classContract.UnderlyingType == Globals.TypeOfDateTimeOffsetAdapter)
                        {
                            _ilg.ConvertValue(_objectLocal.LocalType, Globals.TypeOfDateTimeOffsetAdapter);
                            _ilg.Call(XmlFormatGeneratorStatics.GetDateTimeOffsetMethod);
                            _ilg.ConvertValue(Globals.TypeOfDateTimeOffset, _ilg.CurrentMethod.ReturnType);
                        }
                        //Copy the KeyValuePairAdapter<K,T> to a KeyValuePair<K,T>.
                        else if (classContract.IsKeyValuePairAdapter)
                        {
                            _ilg.Call(classContract.GetKeyValuePairMethodInfo);
                            _ilg.ConvertValue(Globals.TypeOfKeyValuePair.MakeGenericType(classContract.KeyValuePairGenericArguments), _ilg.CurrentMethod.ReturnType);
                        }
                        else
                        {
                            _ilg.ConvertValue(_objectLocal.LocalType, _ilg.CurrentMethod.ReturnType);
                        }
                    }
                    return((XmlFormatClassReaderDelegate)_ilg.EndMethod());
                }
            }
            private void ReadGetOnlyCollection(CollectionDataContract collectionContract)
            {
                Type   type     = collectionContract.UnderlyingType;
                Type   itemType = collectionContract.ItemType;
                bool   isArray  = (collectionContract.Kind == CollectionKind.Array);
                string itemName = collectionContract.ItemName;
                string itemNs   = collectionContract.StableName.Namespace;

                _objectLocal = _ilg.DeclareLocal(type, "objectDeserialized");
                _ilg.Load(_contextArg);
                _ilg.LoadMember(XmlFormatGeneratorStatics.GetCollectionMemberMethod);
                _ilg.ConvertValue(Globals.TypeOfObject, type);
                _ilg.Stloc(_objectLocal);

                //check that items are actually going to be deserialized into the collection
                IsStartElement(_memberNamesArg, _memberNamespacesArg);
                _ilg.If();
                _ilg.If(_objectLocal, Cmp.EqualTo, null);
                _ilg.Call(null, XmlFormatGeneratorStatics.ThrowNullValueReturnedForGetOnlyCollectionExceptionMethod, type);

                _ilg.Else();
                LocalBuilder size = _ilg.DeclareLocal(Globals.TypeOfInt, "arraySize");

                if (isArray)
                {
                    _ilg.Load(_objectLocal);
                    _ilg.Call(XmlFormatGeneratorStatics.GetArrayLengthMethod);
                    _ilg.Stloc(size);
                }

                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, _objectLocal);

                LocalBuilder i       = _ilg.DeclareLocal(Globals.TypeOfInt, "i");
                object       forLoop = _ilg.For(i, 0, int.MaxValue);

                IsStartElement(_memberNamesArg, _memberNamespacesArg);
                _ilg.If();
                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
                LocalBuilder value = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);

                if (isArray)
                {
                    _ilg.If(size, Cmp.EqualTo, i);
                    _ilg.Call(null, XmlFormatGeneratorStatics.ThrowArrayExceededSizeExceptionMethod, size, type);
                    _ilg.Else();
                    _ilg.StoreArrayElement(_objectLocal, i, value);
                    _ilg.EndIf();
                }
                else
                {
                    StoreCollectionValue(_objectLocal, value, collectionContract);
                }
                _ilg.Else();
                IsEndElement();
                _ilg.If();
                _ilg.Break(forLoop);
                _ilg.Else();
                HandleUnexpectedItemInCollection(i);
                _ilg.EndIf();
                _ilg.EndIf();
                _ilg.EndFor();
                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, _xmlReaderArg, size, _memberNamesArg, _memberNamespacesArg);

                _ilg.EndIf();
                _ilg.EndIf();
            }
            private void ReadCollection(CollectionDataContract collectionContract)
            {
                Type type     = collectionContract.UnderlyingType;
                Type itemType = collectionContract.ItemType;
                bool isArray  = (collectionContract.Kind == CollectionKind.Array);

                ConstructorInfo constructor = collectionContract.Constructor !;

                if (type.IsInterface)
                {
                    switch (collectionContract.Kind)
                    {
                    case CollectionKind.GenericDictionary:
                        type        = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments());
                        constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Array.Empty <Type>()) !;
                        break;

                    case CollectionKind.Dictionary:
                        type        = Globals.TypeOfHashtable;
                        constructor = XmlFormatGeneratorStatics.HashtableCtor;
                        break;

                    case CollectionKind.Collection:
                    case CollectionKind.GenericCollection:
                    case CollectionKind.Enumerable:
                    case CollectionKind.GenericEnumerable:
                    case CollectionKind.List:
                    case CollectionKind.GenericList:
                        type    = itemType.MakeArrayType();
                        isArray = true;
                        break;
                    }
                }
                string itemName = collectionContract.ItemName;
                string itemNs   = collectionContract.StableName.Namespace;

                _objectLocal = _ilg.DeclareLocal(type, "objectDeserialized");
                if (!isArray)
                {
                    if (type.IsValueType)
                    {
                        _ilg.Ldloca(_objectLocal);
                        _ilg.InitObj(type);
                    }
                    else
                    {
                        _ilg.New(constructor);
                        _ilg.Stloc(_objectLocal);
                        _ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, _objectLocal);
                    }
                }

                LocalBuilder size = _ilg.DeclareLocal(Globals.TypeOfInt, "arraySize");

                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetArraySizeMethod);
                _ilg.Stloc(size);

                LocalBuilder objectId = _ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");

                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
                _ilg.Stloc(objectId);

                bool canReadPrimitiveArray = false;

                if (isArray && TryReadPrimitiveArray(type, itemType, size))
                {
                    canReadPrimitiveArray = true;
                    _ilg.IfNot();
                }

                _ilg.If(size, Cmp.EqualTo, -1);

                LocalBuilder?growingCollection = null;

                if (isArray)
                {
                    growingCollection = _ilg.DeclareLocal(type, "growingCollection");
                    _ilg.NewArray(itemType, 32);
                    _ilg.Stloc(growingCollection);
                }
                LocalBuilder i       = _ilg.DeclareLocal(Globals.TypeOfInt, "i");
                object       forLoop = _ilg.For(i, 0, int.MaxValue);

                IsStartElement(_memberNamesArg, _memberNamespacesArg);
                _ilg.If();
                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
                LocalBuilder value = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);

                if (isArray)
                {
                    Debug.Assert(growingCollection != null);
                    MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod(itemType);
                    _ilg.Call(null, ensureArraySizeMethod, growingCollection, i);
                    _ilg.Stloc(growingCollection);
                    _ilg.StoreArrayElement(growingCollection, i, value);
                }
                else
                {
                    StoreCollectionValue(_objectLocal, value, collectionContract);
                }
                _ilg.Else();
                IsEndElement();
                _ilg.If();
                _ilg.Break(forLoop);
                _ilg.Else();
                HandleUnexpectedItemInCollection(i);
                _ilg.EndIf();
                _ilg.EndIf();

                _ilg.EndFor();
                if (isArray)
                {
                    MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod(itemType);
                    _ilg.Call(null, trimArraySizeMethod, growingCollection, i);
                    _ilg.Stloc(_objectLocal);
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, _objectLocal);
                }
                _ilg.Else();

                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, size);
                if (isArray)
                {
                    _ilg.NewArray(itemType, size);
                    _ilg.Stloc(_objectLocal);
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, _objectLocal);
                }
                LocalBuilder j = _ilg.DeclareLocal(Globals.TypeOfInt, "j");

                _ilg.For(j, 0, size);
                IsStartElement(_memberNamesArg, _memberNamespacesArg);
                _ilg.If();
                LocalBuilder itemValue = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);

                if (isArray)
                {
                    _ilg.StoreArrayElement(_objectLocal, j, itemValue);
                }
                else
                {
                    StoreCollectionValue(_objectLocal, itemValue, collectionContract);
                }
                _ilg.Else();
                HandleUnexpectedItemInCollection(j);
                _ilg.EndIf();
                _ilg.EndFor();
                _ilg.Call(_contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, _xmlReaderArg, size, _memberNamesArg, _memberNamespacesArg);
                _ilg.EndIf();

                if (canReadPrimitiveArray)
                {
                    _ilg.Else();
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, _objectLocal);
                    _ilg.EndIf();
                }
            }
            private LocalBuilder ReadValue(Type type, string name, string ns)
            {
                LocalBuilder value         = _ilg.DeclareLocal(type, "valueRead");
                LocalBuilder?nullableValue = null;
                int          nullables     = 0;

                while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable)
                {
                    nullables++;
                    type = type.GetGenericArguments()[0];
                }

                PrimitiveDataContract?primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);

                if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType)
                {
                    LocalBuilder objectId = _ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.ReadAttributesMethod, _xmlReaderArg);
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.ReadIfNullOrRefMethod, _xmlReaderArg, type, DataContract.IsTypeSerializable(type));
                    _ilg.Stloc(objectId);
                    // Deserialize null
                    _ilg.If(objectId, Cmp.EqualTo, Globals.NullObjectId);
                    if (nullables != 0)
                    {
                        _ilg.LoadAddress(value);
                        _ilg.InitObj(value.LocalType);
                    }
                    else if (type.IsValueType)
                    {
                        ThrowValidationException(SR.Format(SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName(type)));
                    }
                    else
                    {
                        _ilg.Load(null);
                        _ilg.Stloc(value);
                    }

                    // Deserialize value

                    // Compare against Globals.NewObjectId, which is set to string.Empty
                    _ilg.ElseIfIsEmptyString(objectId);
                    _ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
                    _ilg.Stloc(objectId);
                    if (type.IsValueType)
                    {
                        _ilg.IfNotIsEmptyString(objectId);
                        ThrowValidationException(SR.Format(SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type)));
                        _ilg.EndIf();
                    }
                    if (nullables != 0)
                    {
                        nullableValue = value;
                        value         = _ilg.DeclareLocal(type, "innerValueRead");
                    }

                    if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject)
                    {
                        _ilg.Call(_xmlReaderArg, primitiveContract.XmlFormatReaderMethod);
                        _ilg.Stloc(value);
                        if (!type.IsValueType)
                        {
                            _ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, value);
                        }
                    }
                    else
                    {
                        InternalDeserialize(value, type, name, ns);
                    }
                    // Deserialize ref
                    _ilg.Else();
                    if (type.IsValueType)
                    {
                        ThrowValidationException(SR.Format(SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName(type)));
                    }
                    else
                    {
                        _ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetExistingObjectMethod, objectId, type, name, ns);
                        _ilg.ConvertValue(Globals.TypeOfObject, type);
                        _ilg.Stloc(value);
                    }
                    _ilg.EndIf();

                    if (nullableValue != null)
                    {
                        _ilg.If(objectId, Cmp.NotEqualTo, Globals.NullObjectId);
                        WrapNullableObject(value, nullableValue, nullables);
                        _ilg.EndIf();
                        value = nullableValue;
                    }
                }
                else
                {
                    InternalDeserialize(value, type, name, ns);
                }

                return(value);
            }
Beispiel #28
0
        /// <summary>
        /// create a method implementation that uses GetDelegateForFunctionPointer internally
        /// </summary>
        private static Action <object, IImportResolver, ICallingConventionAdapter> ImplementMethodDelegate(
            TypeBuilder type,
            MethodInfo baseMethod,
            CallingConvention nativeCall,
            string entryPointName,
            FieldInfo?monitorField,
            bool nonTrivialAdapter)
        {
            // create the delegate type
            var delegateType = BizInvokeUtilities.CreateDelegateType(baseMethod, nativeCall, type, out var delegateInvoke);

            var paramInfos = baseMethod.GetParameters();
            var paramTypes = paramInfos.Select(p => p.ParameterType).ToArray();
            var returnType = baseMethod.ReturnType;

            if (paramTypes.Concat(new[] { returnType }).Any(typeof(Delegate).IsAssignableFrom))
            {
                // this isn't a problem if CallingConventionAdapters.Waterbox is a no-op, but it is otherwise:  we don't
                // have a custom marshaller set up so the user needs to manually pump the callingconventionadapter
                if (nonTrivialAdapter)
                {
                    throw new InvalidOperationException(
                              "Compatibility call mode cannot use ICallingConventionAdapters for automatically marshalled delegate types!");
                }
            }

            // define a field on the class to hold the delegate
            var field = type.DefineField(
                $"DelegateField{baseMethod.Name}",
                delegateType,
                FieldAttributes.Public);

            var method = type.DefineMethod(
                baseMethod.Name,
                MethodAttributes.Virtual | MethodAttributes.Public,
                CallingConventions.HasThis,
                returnType,
                paramTypes);

            var il = method.GetILGenerator();

            Label exc = new Label();

            if (monitorField != null)             // monitor: enter and then begin try
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, monitorField);
                il.Emit(OpCodes.Callvirt, MInfo_IMonitor_Enter);
                exc = il.BeginExceptionBlock();
            }

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, field);
            for (int i = 0; i < paramTypes.Length; i++)
            {
                il.Emit(OpCodes.Ldarg, (short)(i + 1));
            }

            il.Emit(OpCodes.Callvirt, delegateInvoke);

            if (monitorField != null)             // monitor: finally exit
            {
                LocalBuilder?loc = null;
                if (returnType != typeof(void))
                {
                    loc = il.DeclareLocal(returnType);
                    il.Emit(OpCodes.Stloc, loc);
                }

                il.Emit(OpCodes.Leave, exc);
                il.BeginFinallyBlock();
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, monitorField);
                il.Emit(OpCodes.Callvirt, MInfo_IMonitor_Exit);
                il.EndExceptionBlock();

                if (returnType != typeof(void))
                {
                    il.Emit(OpCodes.Ldloc, loc !);
                }
            }

            il.Emit(OpCodes.Ret);

            type.DefineMethodOverride(method, baseMethod);

            return((o, dll, adapter) =>
            {
                var entryPtr = dll.GetProcAddrOrThrow(entryPointName);
                var interopDelegate = adapter.GetDelegateForFunctionPointer(entryPtr, delegateType.CreateType());
                o.GetType().GetField(field.Name).SetValue(o, interopDelegate);
            });
        }
Beispiel #29
0
        /// <summary>
        /// create a method implementation that uses calli internally
        /// </summary>
        private static Action <object, IImportResolver, ICallingConventionAdapter> ImplementMethodCalli(
            TypeBuilder type,
            MethodInfo baseMethod,
            CallingConvention nativeCall,
            string entryPointName,
            FieldInfo?monitorField,
            FieldInfo adapterField)
        {
            var paramInfos     = baseMethod.GetParameters();
            var paramTypes     = paramInfos.Select(p => p.ParameterType).ToArray();
            var paramLoadInfos = new List <ParameterLoadInfo>();
            var returnType     = baseMethod.ReturnType;

            if (returnType != typeof(void) && !returnType.IsPrimitive && !returnType.IsPointer && !returnType.IsEnum)
            {
                throw new InvalidOperationException("Only primitive return types are supported");
            }

            // define a field on the type to hold the entry pointer
            var field = type.DefineField(
                $"EntryPtrField{baseMethod.Name}",
                typeof(IntPtr),
                FieldAttributes.Public);

            var method = type.DefineMethod(
                baseMethod.Name,
                MethodAttributes.Virtual | MethodAttributes.Public,
                CallingConventions.HasThis,
                returnType,
                paramTypes);

            var il = method.GetILGenerator();

            Label exc = new Label();

            if (monitorField != null)             // monitor: enter and then begin try
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, monitorField);
                il.Emit(OpCodes.Callvirt, MInfo_IMonitor_Enter);
                exc = il.BeginExceptionBlock();
            }

            // phase 1:  empty eval stack and each parameter load thunk does any prep work it needs to do
            for (int i = 0; i < paramTypes.Length; i++)
            {
                // arg 0 is this, so + 1
                paramLoadInfos.Add(EmitParamterLoad(il, i + 1, paramTypes[i], adapterField));
            }
            // phase 2:  actually load the individual params, leaving each one on the stack
            foreach (var pli in paramLoadInfos)
            {
                pli.EmitLoad();
            }

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, field);
            il.EmitCalli(
                OpCodes.Calli,
                nativeCall,
                returnType == typeof(bool) ? typeof(byte) : returnType,                 // undo winapi style bool garbage
                paramLoadInfos.Select(p => p.NativeType).ToArray());

            if (monitorField != null)             // monitor: finally exit
            {
                LocalBuilder?loc = null;
                if (returnType != typeof(void))
                {
                    loc = il.DeclareLocal(returnType);
                    il.Emit(OpCodes.Stloc, loc);
                }

                il.Emit(OpCodes.Leave, exc);
                il.BeginFinallyBlock();
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, monitorField);
                il.Emit(OpCodes.Callvirt, MInfo_IMonitor_Exit);
                il.EndExceptionBlock();

                if (returnType != typeof(void))
                {
                    il.Emit(OpCodes.Ldloc, loc !);
                }
            }

            // either there's a primitive on the stack and we're expected to return that primitive,
            // or there's nothing on the stack and we're expected to return nothing
            il.Emit(OpCodes.Ret);

            type.DefineMethodOverride(method, baseMethod);

            return((o, dll, adapter) =>
            {
                var entryPtr = dll.GetProcAddrOrThrow(entryPointName);
                o.GetType().GetField(field.Name).SetValue(
                    o, adapter.GetDepartureFunctionPointer(entryPtr, new ParameterInfo(returnType, paramTypes), o));
            });
        }
 public void EmitAppendToStringBuilder(ILGenerator gen, LocalBuilder?nullableLocal, LocalBuilder?_, CsvColumnAttribute?attribute) => gen
 .Stloc(nullableLocal !)