/// <summary> /// Emits 'foreach' statement on the IL stream. /// </summary> /// <param name="il">IL generator to be emitted to.</param> /// <param name="traits"><see cref="CollectionTraits"/> which contains traits of the iterating collection.</param> /// <param name="collection">'collection' argument index.</param> /// <param name="bodyEmitter">Delegate to emit body statement.</param> public static void EmitForEach( TracingILGenerator il, CollectionTraits traits, LocalBuilder collection, Action<TracingILGenerator, Action> bodyEmitter ) { Contract.Requires( il != null ); Contract.Requires( collection != null ); Contract.Requires( bodyEmitter != null ); var enumerator = il.DeclareLocal( traits.GetEnumeratorMethod.ReturnType, "enumerator" ); // gets enumerator if ( collection.LocalType.IsValueType ) { il.EmitAnyLdloca( collection ); } else { il.EmitAnyLdloc( collection ); } il.EmitAnyCall( traits.GetEnumeratorMethod ); il.EmitAnyStloc( enumerator ); if ( typeof( IDisposable ).IsAssignableFrom( traits.GetEnumeratorMethod.ReturnType ) ) { il.BeginExceptionBlock(); } var startLoop = il.DefineLabel( "START_LOOP" ); il.MarkLabel( startLoop ); var endLoop = il.DefineLabel( "END_LOOP" ); var enumeratorType = traits.GetEnumeratorMethod.ReturnType; MethodInfo moveNextMethod = enumeratorType.GetMethod( "MoveNext", Type.EmptyTypes ); PropertyInfo currentProperty = traits.GetEnumeratorMethod.ReturnType.GetProperty( "Current" ); if ( moveNextMethod == null ) { moveNextMethod = Metadata._IEnumerator.MoveNext; } if ( currentProperty == null ) { if ( enumeratorType == typeof( IDictionaryEnumerator ) ) { currentProperty = Metadata._IDictionaryEnumerator.Current; } else if ( enumeratorType.IsInterface ) { if ( enumeratorType.IsGenericType && enumeratorType.GetGenericTypeDefinition() == typeof( IEnumerator<> ) ) { currentProperty = typeof( IEnumerator<> ).MakeGenericType( traits.ElementType ).GetProperty( "Current" ); } else { currentProperty = Metadata._IEnumerator.Current; } } } Contract.Assert( currentProperty != null, enumeratorType.ToString() ); // iterates if ( traits.GetEnumeratorMethod.ReturnType.IsValueType ) { il.EmitAnyLdloca( enumerator ); } else { il.EmitAnyLdloc( enumerator ); } il.EmitAnyCall( moveNextMethod ); il.EmitBrfalse( endLoop ); bodyEmitter( il, () => { if ( traits.GetEnumeratorMethod.ReturnType.IsValueType ) { il.EmitAnyLdloca( enumerator ); } else { il.EmitAnyLdloc( enumerator ); } il.EmitGetProperty( currentProperty ); } ); il.EmitBr( startLoop ); il.MarkLabel( endLoop ); // Dispose if ( typeof( IDisposable ).IsAssignableFrom( traits.GetEnumeratorMethod.ReturnType ) ) { il.BeginFinallyBlock(); if ( traits.GetEnumeratorMethod.ReturnType.IsValueType ) { var disposeMethod = traits.GetEnumeratorMethod.ReturnType.GetMethod( "Dispose" ); if ( disposeMethod != null && disposeMethod.GetParameters().Length == 0 && disposeMethod.ReturnType == typeof( void ) ) { il.EmitAnyLdloca( enumerator ); il.EmitAnyCall( disposeMethod ); } else { il.EmitAnyLdloc( enumerator ); il.EmitBox( traits.GetEnumeratorMethod.ReturnType ); il.EmitAnyCall( Metadata._IDisposable.Dispose ); } } else { il.EmitAnyLdloc( enumerator ); il.EmitAnyCall( Metadata._IDisposable.Dispose ); } il.EndExceptionBlock(); } }
private static void EmitNewDelegate( TracingILGenerator il, Type targetType, MethodInfo method, Action<TracingILGenerator> loadTargetEmitting, Type delegateType ) { loadTargetEmitting( il ); if ( targetType.IsValueType ) { il.EmitBox( targetType ); } if ( method.IsStatic || method.IsFinal || !method.IsVirtual ) { il.EmitLdftn( method ); } else { il.EmitDup(); il.EmitLdvirtftn( method ); } il.EmitNewobj( delegateType.GetConstructor( _delegateConstructorParameterTypes ) ); }
private static void EmitInvokeMapUnpackToHelper( Type targetType, SerializerEmitter emitter, CollectionTraits traits, TracingILGenerator il, int unpackerArgumentIndex, Action<TracingILGenerator> loadCollectionEmitting ) { il.EmitAnyLdarg( unpackerArgumentIndex ); if ( traits.ElementType.IsGenericType ) { var keyType = traits.ElementType.GetGenericArguments()[ 0 ]; var valueType = traits.ElementType.GetGenericArguments()[ 1 ]; var keySerializerGetting = emitter.RegisterSerializer( keyType ); var valueSerializerGetting = emitter.RegisterSerializer( valueType ); keySerializerGetting( il, 0 ); valueSerializerGetting( il, 0 ); loadCollectionEmitting( il ); if ( targetType.IsValueType ) { il.EmitBox( targetType ); } il.EmitAnyCall( Metadata._UnpackHelpers.UnpackMapTo_2.MakeGenericMethod( keyType, valueType ) ); } else { loadCollectionEmitting( il ); if ( targetType.IsValueType ) { il.EmitBox( targetType ); } il.EmitAnyCall( Metadata._UnpackHelpers.UnpackNonGenericMapTo ); } }
private static void EmitInvokeArrayUnpackToHelper( Type targetType, SerializerEmitter emitter, CollectionTraits traits, TracingILGenerator il, int unpackerArgumentIndex, Action<TracingILGenerator> loadCollectionEmitting ) { il.EmitAnyLdarg( unpackerArgumentIndex ); var serializerGetting = emitter.RegisterSerializer( traits.ElementType ); if ( targetType.IsArray ) { // Array /* * UnpackHelpers.UnpackArrayTo( unpacker, GET_SERIALIZER, collection ); */ serializerGetting( il, 0 ); loadCollectionEmitting( il ); il.EmitAnyCall( Metadata._UnpackHelpers.UnpackArrayTo_1.MakeGenericMethod( traits.ElementType ) ); } else if ( targetType.IsGenericType ) { serializerGetting( il, 0 ); loadCollectionEmitting( il ); if ( targetType.IsValueType ) { il.EmitBox( targetType ); } if ( traits.AddMethod.ReturnType == null || traits.AddMethod.ReturnType == typeof( void ) ) { // with void Add( T item ) /* * Action<T> addition = TCollection.Add * UnpackHelpers.UnpackCollectionTo( unpacker, GET_SERIALIZER, collection, addition ); */ var itemType = traits.AddMethod.GetParameters()[ 0 ].ParameterType; EmitNewDelegate( il, targetType, traits.AddMethod, loadCollectionEmitting, typeof( Action<> ).MakeGenericType( itemType ) ); il.EmitAnyCall( Metadata._UnpackHelpers.UnpackCollectionTo_1.MakeGenericMethod( itemType ) ); } else { // with TDiscarded Add( T item ) /* * Func<T, TDiscarded> addition = TCollection.Add * UnpackHelpers.UnpackCollectionTo( unpacker, GET_SERIALIZER, collection, addition ); */ var itemType = traits.AddMethod.GetParameters()[ 0 ].ParameterType; var discardingType = traits.AddMethod.ReturnType; EmitNewDelegate( il, targetType, traits.AddMethod, loadCollectionEmitting, typeof( Func<,> ).MakeGenericType( itemType, discardingType ) ); il.EmitAnyCall( Metadata._UnpackHelpers.UnpackCollectionTo_2.MakeGenericMethod( itemType, discardingType ) ); } } else { loadCollectionEmitting( il ); if ( targetType.IsValueType ) { il.EmitBox( targetType ); } if ( traits.AddMethod.ReturnType == null || traits.AddMethod.ReturnType == typeof( void ) ) { // with void Add( object item ) /* * Action<object> addition = TCollection.Add * UnpackHelpers.UnpackCollectionTo( unpacker, collection, addition ); */ EmitNewDelegate( il, targetType, traits.AddMethod, loadCollectionEmitting, typeof( Action<object> ) ); il.EmitAnyCall( Metadata._UnpackHelpers.UnpackNonGenericCollectionTo ); } else { // with TDiscarded Add( object item ) /* * Func<TDiscarded> addition = TCollection.Add * UnpackHelpers.UnpackCollectionTo( unpacker, collection, addition ); */ var discardingType = traits.AddMethod.ReturnType; EmitNewDelegate( il, targetType, traits.AddMethod, loadCollectionEmitting, typeof( Func<,> ).MakeGenericType( typeof( object ), discardingType ) ); il.EmitAnyCall( Metadata._UnpackHelpers.UnpackNonGenericCollectionTo_1.MakeGenericMethod( discardingType ) ); } } }