protected override void ReadNotEmpty(ReaderMethodBuilderContext context) { var customSerializerField = context.Context.InitConstField(Type, 0, customSerializer); var il = context.Il; context.IncreaseIndexBy1(); // index = index + 1 context.AssertTypeCode(GroBufTypeCode.CustomData); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [(uint)data[index]] context.IncreaseIndexBy4(); // index = index + 4; stack: [(uint)data[index]] context.AssertLength(); // stack: [] var local = il.DeclareLocal(typeof(object)); context.LoadField(customSerializerField); // stack: [customSerializer] context.LoadData(); // stack: [customSerializer, data] context.LoadIndexByRef(); // stack: [customSerializer, data, ref index] il.Ldloca(local); // stack: [customSerializer, data, ref index, ref local] context.LoadContext(); // stack: [customSerializer, data, ref index, ref local, context] int dummy = 0; object dummyObj = null; var readMethod = HackHelpers.GetMethodDefinition <IGroBufCustomSerializer>(serializer => serializer.Read(IntPtr.Zero, ref dummy, ref dummyObj, null)); il.Call(readMethod); // customSerializer.Read(data, ref index, length, ref local); stack: [] context.LoadResultByRef(); // stack: [ref result] il.Ldloc(local); // stack: [ref result, ref local] if (!Type.IsValueType) { il.Castclass(Type); il.Stind(Type); } else { il.Unbox_Any(Type); // stack: [ref result, (Type)local] il.Stobj(Type); // result = (Type)local } context.StoreObject(Type); }
protected override void ReadNotEmpty(ReaderMethodBuilderContext context) { var il = context.Il; context.AssertTypeCode(GroBufTypeCode.Tuple); context.IncreaseIndexBy1(); var length = context.Length; il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [data length] context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] il.Stloc(length); // length = array length; stack: [] context.LoadResultByRef(); // stack: [ref result] var genericArguments = Type.GetGenericArguments(); // stack: [ref result, args] for (int i = 0; i < genericArguments.Length; ++i) { context.LoadData(); // stack: [ref result, args, data] context.LoadIndexByRef(); // stack: [ref result, args, data, ref index] var arg = il.DeclareLocal(genericArguments[i]); il.Ldloca(arg); // stack: [ref result, args, data, ref index, ref arg] context.LoadContext(); // stack: [ref result, args, data, ref index, ref arg, context] context.CallReader(genericArguments[i]); // reader(pinnedData, ref index, ref arg, context); stack: [ref result, args] il.Ldloc(arg); // stack: [ref result, {args, arg} => args] } il.Newobj(Type.GetConstructor(genericArguments)); // stack: [ref result, new Tuple(args)] il.Stind(Type); // result = new Tuple(args); stack: [] context.StoreObject(Type); }
protected override void ReadNotEmpty(ReaderMethodBuilderContext context) { var il = context.Il; il.Ldloc(context.TypeCode); // stack: [type code] il.Ldc_I4((int)GroBufTypeCode.Array); // stack: [type code, GroBufTypeCode.Array] var tryReadArrayElementLabel = il.DefineLabel("tryReadArrayElement"); il.Bne_Un(tryReadArrayElementLabel); // if(type code != GroBufTypeCode.Array) goto tryReadArrayElement; stack: [] context.IncreaseIndexBy1(); var length = context.Length; il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [data length] context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] context.AssertLength(); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [array length] context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] il.Stloc(length); // length = array length; stack: [] if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) { var createArrayLabel = il.DefineLabel("createArray"); context.LoadResult(Type); // stack: [result] il.Brfalse(createArrayLabel); // if(result == null) goto createArray; context.LoadResult(Type); // stack: [result] il.Ldlen(); // stack: [result.Length] il.Ldloc(length); // stack: [result.Length, length] var arrayCreatedLabel = il.DefineLabel("arrayCreated"); il.Bge(arrayCreatedLabel, false); // if(result.Length >= length) goto arrayCreated; context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) il.Br(arrayCreatedLabel); // goto arrayCreated il.MarkLabel(createArrayLabel); context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Newarr(elementType); // stack: [ref result, new type[length]] il.Stind(Type); // result = new type[length]; stack: [] il.MarkLabel(arrayCreatedLabel); } else { context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Newarr(elementType); // stack: [ref result, new type[length]] il.Stind(Type); // result = new type[length]; stack: [] } context.StoreObject(Type); il.Ldloc(length); // stack: [length] var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] var i = il.DeclareLocal(typeof(uint)); il.Ldc_I4(0); // stack: [0] il.Stloc(i); // i = 0; stack: [] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); context.LoadData(); // stack: [pinnedData] context.LoadIndexByRef(); // stack: [pinnedData, ref index] context.LoadResult(Type); // stack: [pinnedData, ref index, result] il.Ldloc(i); // stack: [pinnedData, ref index, result, i] il.Ldelema(elementType); // stack: [pinnedData, ref index, ref result[i]] context.LoadContext(); // stack: [pinnedData, ref index, ref result[i], context] context.CallReader(elementType); // reader(pinnedData, ref index, ref result[i], context); stack: [] il.Ldloc(i); // stack: [i] il.Ldc_I4(1); // stack: [i, 1] il.Add(); // stack: [i + 1] il.Dup(); // stack: [i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [i] il.Ldloc(length); // stack: [i, length] il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart il.Br(doneLabel); il.MarkLabel(tryReadArrayElementLabel); if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) { var createArrayLabel = il.DefineLabel("createArray"); context.LoadResult(Type); // stack: [result] il.Brfalse(createArrayLabel); // if(result == null) goto createArray; context.LoadResult(Type); // stack: [result] il.Ldlen(); // stack: [result.Length] il.Ldc_I4(1); // stack: [result.Length, 1] var arrayCreatedLabel = il.DefineLabel("arrayCreated"); il.Bge(arrayCreatedLabel, false); // if(result.Length >= 1) goto arrayCreated; context.LoadResultByRef(); // stack: [ref result] il.Ldc_I4(1); // stack: [ref result, 1] il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) il.Br(arrayCreatedLabel); // goto arrayCreated il.MarkLabel(createArrayLabel); context.LoadResultByRef(); // stack: [ref result] il.Ldc_I4(1); // stack: [ref result, 1] il.Newarr(elementType); // stack: [ref result, new type[1]] il.Stind(Type); // result = new type[1]; stack: [] il.MarkLabel(arrayCreatedLabel); } else { context.LoadResultByRef(); // stack: [ref result] il.Ldc_I4(1); // stack: [ref result, 1] il.Newarr(elementType); // stack: [ref result, new type[1]] il.Stind(Type); // result = new type[1]; stack: [] } context.StoreObject(Type); context.LoadData(); // stack: [pinnedData] context.LoadIndexByRef(); // stack: [pinnedData, ref index] context.LoadResult(Type); // stack: [pinnedData, ref index, result] il.Ldc_I4(0); // stack: [pinnedData, ref index, result, 0] il.Ldelema(elementType); // stack: [pinnedData, ref index, ref result[0]] context.LoadContext(); // stack: [pinnedData, ref index, ref result[0], context] context.CallReader(elementType); // reader(pinnedData, ref index, ref result[0], context); stack: [] il.MarkLabel(doneLabel); // stack: [] }
protected override void ReadNotEmpty(ReaderMethodBuilderContext context) { MemberInfo[] dataMembers; ulong[] hashCodes; BuildMembersTable(context.Context, out hashCodes, out dataMembers); var il = context.Il; var end = context.Length; var typeCode = context.TypeCode; var setters = dataMembers.Select(member => member == null ? default(KeyValuePair <Delegate, IntPtr>) : GetMemberSetter(context.Context, member)).ToArray(); var settersField = context.Context.InitConstField(Type, 0, setters.Select(pair => pair.Value).ToArray()); context.Context.InitConstField(Type, 1, setters.Select(pair => pair.Key).ToArray()); var hashCodesField = context.Context.InitConstField(Type, 2, hashCodes); context.IncreaseIndexBy1(); // index = index + 1 context.AssertTypeCode(GroBufTypeCode.Object); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [(uint)data[index] = data length] context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] il.Dup(); // stack: [data length, data length] il.Stloc(end); // end = data length; stack: [data length] if (!Type.IsValueType) { context.LoadResultByRef(); // stack: [data length, ref result] il.Ldind(Type); // stack: [data length, result] var notNullLabel = il.DefineLabel("notNull"); il.Brtrue(notNullLabel); // if(result != null) goto notNull; stack: [data length] context.LoadResultByRef(); // stack: [data length, ref result] ObjectConstructionHelper.EmitConstructionOfType(Type, il); il.Stind(Type); // result = new type(); stack: [data length] il.MarkLabel(notNullLabel); } context.StoreObject(Type); var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(data length == 0) goto done; stack: [] il.Ldloc(end); // stack: [data length] context.AssertLength(); // stack: [] il.Ldloc(end); // stack: [data length] context.LoadIndex(); // stack: [data length, index] il.Add(); // stack: [data length + index] il.Stloc(end); // end = data length + index var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldc_I4(9); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(long)); // stack: [*(int64*)&data[index] = hashCode] context.IncreaseIndexBy8(); // index = index + 8; stack: [*(int64*)&data[index] = hashCode] il.Dup(); // stack: [hashCode, hashCode] il.Ldc_I8(dataMembers.Length); // stack: [hashCode, hashCode, (int64)hashCodes.Length] il.Rem(true); // stack: [hashCode, hashCode % hashCodes.Length] il.Conv <int>(); // stack: [hashCode, (int)(hashCode % hashCodes.Length)] var idx = il.DeclareLocal(typeof(int)); il.Stloc(idx); // idx = (int)(hashCode % hashCodes.Length); stack: [hashCode] context.LoadField(hashCodesField); // stack: [hashCode, hashCodes] il.Ldloc(idx); // stack: [hashCode, hashCodes, idx] il.Ldelem(typeof(long)); // stack: [hashCode, hashCodes[idx]] var skipDataLabel = il.DefineLabel("skipData"); il.Bne_Un(skipDataLabel); // if(hashCode != hashCodes[idx]) goto skipData; stack: [] // Read data context.LoadData(); // stack: [pinnedData] context.LoadIndexByRef(); // stack: [pinnedData, ref index] context.LoadResultByRef(); // stack: [pinnedData, ref index, ref result] context.LoadContext(); // stack: [pinnedData, ref index, ref result, context] context.LoadField(settersField); // stack: [pinnedData, ref index, ref result, context, setters] il.Ldloc(idx); // stack: [pinnedData, ref index, ref result, context, setters, idx] il.Ldelem(typeof(IntPtr)); // stack: [pinnedData, ref index, ref result, context, setters[idx]] var parameterTypes = new[] { typeof(byte *), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext) }; il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // setters[idx](pinnedData, ref index, ref result, context); stack: [] var checkIndexLabel = il.DefineLabel("checkIndex"); il.Br(checkIndexLabel); // goto checkIndex il.MarkLabel(skipDataLabel); // Skip data context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(byte)); // stack: [data[index]] il.Stloc(typeCode); // typeCode = data[index]; stack: [] context.IncreaseIndexBy1(); // index = index + 1 context.CheckTypeCode(); context.SkipValue(); il.MarkLabel(checkIndexLabel); context.LoadIndex(); // stack: [index] il.Ldloc(end); // stack: [index, end] il.Blt(cycleStartLabel, true); // if(index < end) goto cycleStart; stack: [] var onDeserializedMethod = Type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .SingleOrDefault(method => method.GetCustomAttribute <OnDeserializedAttribute>() != null); if (onDeserializedMethod != null) { var parameters = onDeserializedMethod.GetParameters(); if (parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext)) { throw new InvalidOperationException(string.Format("The method '{0}' marked with 'OnDeserialized' attribute must accept exactly one parameter of type '{1}'", onDeserializedMethod, typeof(StreamingContext).FullName)); } context.LoadResult(Type); il.Ldc_I4((int)StreamingContextStates.Other); il.Newobj(typeof(StreamingContext).GetConstructor(new[] { typeof(StreamingContextStates) })); il.Call(onDeserializedMethod); } il.MarkLabel(doneLabel); }
protected override void ReadNotEmpty(ReaderMethodBuilderContext context) { context.IncreaseIndexBy1(); context.AssertTypeCode(GroBufTypeCode.Array); var il = context.Il; var length = context.Length; il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [data length] context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] context.AssertLength(); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [array length] context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] il.Stloc(length); // length = array length; stack: [] if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) { var createArrayLabel = il.DefineLabel("createArray"); context.LoadResult(Type); // stack: [result] il.Brfalse(createArrayLabel); // if(result == null) goto createArray; context.LoadResult(Type); // stack: [result] il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] il.Ldlen(); // stack: [result._items.Length] il.Ldloc(length); // stack: [result._items.Length, length] var arrayCreatedLabel = il.DefineLabel("arrayCreated"); il.Bge(arrayCreatedLabel, false); // if(result._items.Length >= length) goto arrayCreated; context.LoadResult(Type); // stack: [result] il.Ldflda(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [ref result._items] il.Ldloc(length); // stack: [ref result, length] il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result._items, length) il.Br(arrayCreatedLabel); // goto arrayCreated il.MarkLabel(createArrayLabel); context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Newobj(Type.GetConstructor(new[] { typeof(int) })); // stack: [ref result, new List(length)] il.Stind(Type); // result = new List(length); stack: [] il.MarkLabel(arrayCreatedLabel); } else { context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Newobj(Type.GetConstructor(new[] { typeof(int) })); // stack: [ref result, new List(length)] il.Stind(Type); // result = new List(length); stack: [] } context.StoreObject(Type); il.Ldloc(length); // stack: [length] var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] context.LoadResult(Type); // stack: [result] il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] var items = il.DeclareLocal(elementType.MakeArrayType()); il.Stloc(items); // items = result._items; stack: [] var i = il.DeclareLocal(typeof(uint)); il.Ldc_I4(0); // stack: [0] il.Stloc(i); // i = 0; stack: [] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); context.LoadData(); // stack: [pinnedData] context.LoadIndexByRef(); // stack: [pinnedData, ref index] il.Ldloc(items); // stack: [pinnedData, ref index, items] il.Ldloc(i); // stack: [pinnedData, ref index, items, i] il.Ldelema(elementType); // stack: [pinnedData, ref index, ref items[i]] context.LoadContext(); // stack: [pinnedData, ref index, ref items[i], context] context.CallReader(elementType); // reader(pinnedData, ref index, ref result[i], context); stack: [] il.Ldloc(i); // stack: [i] il.Ldc_I4(1); // stack: [i, 1] il.Add(); // stack: [i + 1] il.Dup(); // stack: [i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [i] il.Ldloc(length); // stack: [i, length] il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) { context.LoadResult(Type); // stack: [result] il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result.Count] il.Ldloc(length); // stack: [result.Count, length] il.Bge(doneLabel, false); // if(result.Count >= length) goto done; stack: [] } context.LoadResult(Type); // stack: [result] il.Ldloc(length); // stack: [result.Count, length] il.Stfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // result._size = length; stack: [] il.MarkLabel(doneLabel); // stack: [] }
protected override void ReadNotEmpty(ReaderMethodBuilderContext context) { context.IncreaseIndexBy1(); context.AssertTypeCode(GroBufTypeCode.Array); var il = context.Il; var length = context.Length; il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [data length] context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] context.AssertLength(); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [array length] context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] il.Stloc(length); // length = array length; stack: [] context.LoadResultByRef(); // stack: [ref result] il.Newobj(Type.GetConstructor(Type.EmptyTypes)); // stack: [ref result, new HashSet() = hashSet] il.Dup(); // stack: [ref result, hashSet, hashSet] il.Ldloc(length); // stack: [ref result, hashSet, hashSet, length] var initializeMethod = Type.GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic); il.Call(initializeMethod); // hashSet.Initialize(length); stack: [ref result, hashSet] or [ref result, hashSet, actualHashSetSize] if (initializeMethod.ReturnType != typeof(void)) { il.Pop(); // stack: [ref result, hashSet] } il.Stind(Type); // result = hashSet; stack: [] context.StoreObject(Type); il.Ldloc(length); // stack: [length] var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] var i = il.DeclareLocal(typeof(uint)); il.Ldc_I4(0); // stack: [0] il.Stloc(i); // i = 0; stack: [] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); context.LoadData(); // stack: [pinnedData] context.LoadIndexByRef(); // stack: [pinnedData, ref index] var value = il.DeclareLocal(elementType); il.Ldloca(value); // stack: [pinnedData, ref index, ref value] context.LoadContext(); // stack: [pinnedData, ref index, ref value, context] context.CallReader(elementType); // reader(pinnedData, ref index, ref value, context); stack: [] context.LoadResult(Type); // stack: [result] il.Ldloc(value); // stack: [result, value] il.Call(Type.GetMethod("Add")); // stack: [result.Add(value)] il.Pop(); // stack: [] if (!elementType.IsValueType) { il.Ldnull(); il.Stloc(value); } il.Ldloc(i); // stack: [i] il.Ldc_I4(1); // stack: [i, 1] il.Add(); // stack: [i + 1] il.Dup(); // stack: [i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [i] il.Ldloc(length); // stack: [i, length] il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart il.MarkLabel(doneLabel); // stack: [] }
protected override void ReadNotEmpty(ReaderMethodBuilderContext context) { context.IncreaseIndexBy1(); context.AssertTypeCode(GroBufTypeCode.Dictionary); var il = context.Il; var length = context.Length; il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [data length] context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] context.AssertLength(); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [array length] context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] il.Stloc(length); // length = array length; stack: [] context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Newobj(Type.GetConstructor(new[] { typeof(int) })); // stack: [ref result, new Dictionary(length)] il.Stind(Type); // result = new Dictionary(length); stack: [] context.StoreObject(Type); il.Ldloc(length); // stack: [length] var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] var i = il.DeclareLocal(typeof(uint)); il.Ldc_I4(0); // stack: [0] il.Stloc(i); // i = 0; stack: [] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); context.LoadData(); // stack: [pinnedData] context.LoadIndexByRef(); // stack: [pinnedData, ref index] var key = il.DeclareLocal(Type.GetGenericArguments()[0]); var value = il.DeclareLocal(Type.GetGenericArguments()[1]); il.Ldloca(key); // stack: [pinnedData, ref index, ref key] context.LoadContext(); // stack: [pinnedData, ref index, ref key, context] context.CallReader(keyType); // reader(pinnedData, ref index, ref key, context); stack: [] context.LoadData(); // stack: [pinnedData] context.LoadIndexByRef(); // stack: [pinnedData, ref index] il.Ldloca(value); // stack: [pinnedData, ref index, ref value] context.LoadContext(); // stack: [pinnedData, ref index, ref value, context] context.CallReader(valueType); // reader(pinnedData, ref index, ref value, context); stack: [] context.LoadResult(Type); il.Ldloc(key); il.Ldloc(value); il.Call(Type.GetMethod("Add")); if (!keyType.IsValueType) { il.Ldnull(); il.Stloc(key); } if (!valueType.IsValueType) { il.Ldnull(); il.Stloc(value); } il.Ldloc(i); // stack: [i] il.Ldc_I4(1); // stack: [i, 1] il.Add(); // stack: [i + 1] il.Dup(); // stack: [i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [i] il.Ldloc(length); // stack: [i, length] il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart il.MarkLabel(doneLabel); // stack: [] }