public void TestFarsh() { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(int) }, typeof(Test)); using (var il = new GroboIL(method)) { var temp = il.DeclareLocal(typeof(int)); il.Ldarg(0); // stack: [x] var label0 = il.DefineLabel("L"); il.Br(label0); // goto L_0; stack: [x] il.Ldstr("zzz"); il.Ldobj(typeof(DateTime)); il.Mul(); il.Initobj(typeof(int)); var label1 = il.DefineLabel("L"); il.MarkLabel(label1); // stack: [x, 2] il.Stloc(temp); // temp = 2; stack: [x] var label2 = il.DefineLabel("L"); il.MarkLabel(label2); // stack: [cur] il.Ldarg(0); // stack: [cur, x] il.Mul(); // stack: [cur * x = cur] il.Ldloc(temp); // stack: [cur, temp] il.Ldc_I4(1); // stack: [cur, temp, 1] il.Sub(); // stack: [cur, temp - 1] il.Stloc(temp); // temp = temp - 1; stack: [cur] il.Ldloc(temp); // stack: [cur, temp] il.Ldc_I4(0); // stack: [cur, temp, 0] il.Bgt(label2, false); // if(temp > 0) goto L_2; stack: [cur] var label3 = il.DefineLabel("L"); il.Br(label3); // goto L_3; stack: [cur] il.MarkLabel(label0); // stack: [x] il.Ldc_I4(2); // stack: [x, 2] il.Br(label1); // goto L_1; stack: [x, 2] il.MarkLabel(label3); // stack: [cur] il.Ret(); // return cur; stack: [] Console.Write(il.GetILCode()); } }
public void Test1() { var overflow = typeof(OverflowException); var exCtorInfo = overflow.GetConstructor(new[] { typeof(string) }); var exToStrMI = overflow.GetMethod("ToString"); var writeLineMI = typeof(Console).GetMethod("WriteLine", new[] { typeof(string), typeof(object) }); var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] { typeof(int), typeof(int) }, typeof(TestTryCatch)); using (var il = new GroboIL(method)) { GroboIL.Local tmp1 = il.DeclareLocal(typeof(int)); GroboIL.Local tmp2 = il.DeclareLocal(overflow); // In order to successfully branch, we need to create labels // representing the offset IL instruction block to branch to. // These labels, when the MarkLabel(Label) method is invoked, // will specify the IL instruction to branch to. // GroboIL.Label failed = il.DefineLabel("failed"); GroboIL.Label endOfMthd = il.DefineLabel("end"); // Begin the try block. il.BeginExceptionBlock(); // First, load argument 0 and the integer value of "100" onto the // stack. If arg0 > 100, branch to the label "failed", which is marked // as the address of the block that throws an exception. // il.Ldarg(0); il.Ldc_I4(100); il.Bgt(failed, false); // Now, check to see if argument 1 was greater than 100. If it was, // branch to "failed." Otherwise, fall through and perform the addition, // branching unconditionally to the instruction at the label "endOfMthd". // il.Ldarg(1); il.Ldc_I4(100); il.Bgt(failed, false); il.Ldarg(0); il.Ldarg(1); il.Add_Ovf(true); // Store the result of the addition. il.Stloc(tmp1); il.Leave(endOfMthd); // If one of the arguments was greater than 100, we need to throw an // exception. We'll use "OverflowException" with a customized message. // First, we load our message onto the stack, and then create a new // exception object using the constructor overload that accepts a // string message. // il.MarkLabel(failed); il.Ldstr("Cannot accept values over 100 for add."); il.Newobj(exCtorInfo); // We're going to need to refer to that exception object later, so let's // store it in a temporary variable. Since the store function pops the // the value/reference off the stack, and we'll need it to throw the // exception, we will subsequently load it back onto the stack as well. il.Stloc(tmp2); il.Ldloc(tmp2); // Throw the exception now on the stack. il.Throw(); // Start the catch block for OverflowException. // il.BeginCatchBlock(overflow); // When we enter the catch block, the thrown exception // is on the stack. Store it, then load the format string // for WriteLine. // il.Stloc(tmp2); il.Ldstr("Caught {0}"); // Push the thrown exception back on the stack, then // call its ToString() method. Note that if this catch block // were for a more general exception type, like Exception, // it would be necessary to use the ToString for that type. // il.Ldloc(tmp2); il.Call(exToStrMI); // The format string and the return value from ToString() are // now on the stack. Call WriteLine(string, object). // il.Call(writeLineMI); // Since our function has to return an integer value, we'll load -1 onto // the stack to indicate an error, and store it in local variable tmp1. // il.Ldc_I4(-1); il.Stloc(tmp1); // End the exception handling block. il.EndExceptionBlock(); // The end of the method. If no exception was thrown, the correct value // will be saved in tmp1. If an exception was thrown, tmp1 will be equal // to -1. Either way, we'll load the value of tmp1 onto the stack and return. // il.MarkLabel(endOfMthd); il.Ldloc(tmp1); il.Ret(); Console.WriteLine(il.GetILCode()); } }
public void Test2() { AssemblyName myAssemblyName = new AssemblyName(); myAssemblyName.Name = "AdderExceptionAsm"; // Create dynamic assembly. AppDomain myAppDomain = Thread.GetDomain(); AssemblyBuilder myAssemblyBuilder = myAppDomain.DefineDynamicAssembly(myAssemblyName, AssemblyBuilderAccess.RunAndSave); // Create a dynamic module. ModuleBuilder myModuleBuilder = myAssemblyBuilder.DefineDynamicModule("AdderExceptionMod", true); var symbolDocumentWriter = myModuleBuilder.GetSymWriter().DefineDocument("AdderException.cil", Guid.Empty, Guid.Empty, Guid.Empty); TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("Adder"); Type[] adderParams = { typeof(int), typeof(int) }; ConstructorInfo myConstructorInfo = typeof(OverflowException).GetConstructor(new[] { typeof(string) }); MethodInfo myExToStrMI = typeof(OverflowException).GetMethod("ToString"); MethodInfo myWriteLineMI = typeof(Console).GetMethod("WriteLine", new[] { typeof(string), typeof(object) }); // Define method to add two numbers. MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("DoAdd", MethodAttributes.Public | MethodAttributes.Static, typeof(int), adderParams); using (var il = new GroboIL(myMethodBuilder, symbolDocumentWriter)) { // Declare local variable. GroboIL.Local myLocalBuilder1 = il.DeclareLocal(typeof(int)); GroboIL.Local myLocalBuilder2 = il.DeclareLocal(typeof(OverflowException)); // Define label. GroboIL.Label myFailedLabel = il.DefineLabel("failed"); GroboIL.Label myEndOfMethodLabel = il.DefineLabel("end"); // Begin exception block. il.BeginExceptionBlock(); il.Ldarg(0); il.Ldc_I4(10); il.Bgt(myFailedLabel, false); il.Ldarg(1); il.Ldc_I4(10); il.Bgt(myFailedLabel, false); il.Ldarg(0); il.Ldarg(1); il.Add_Ovf(true); il.Stloc(myLocalBuilder1); il.Leave(myEndOfMethodLabel); il.MarkLabel(myFailedLabel); il.Ldstr("Cannot accept values over 10 for add."); il.Newobj(myConstructorInfo); il.Stloc(myLocalBuilder2); il.Ldloc(myLocalBuilder2); // Throw the exception. il.Throw(); // Call 'BeginExceptFilterBlock'. il.BeginExceptFilterBlock(); il.WriteLine("Except filter block called."); // Call catch block. il.BeginCatchBlock(null); // Call other catch block. il.BeginCatchBlock(typeof(OverflowException)); il.Ldstr("{0}"); il.Ldloc(myLocalBuilder2); il.Call(myExToStrMI); il.Call(myWriteLineMI); il.Ldc_I4(-1); il.Stloc(myLocalBuilder1); // Call finally block. il.BeginFinallyBlock(); il.WriteLine("Finally block called."); // End the exception block. il.EndExceptionBlock(); il.MarkLabel(myEndOfMethodLabel); il.Ldloc(myLocalBuilder1); il.Ret(); Console.WriteLine(il.GetILCode()); } }
public static TryGetValueDelegate <T> Build <T>(char[] keys, T[] values, int numberOfSegments, int numberOfKeysPerSegment) { var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(bool), new[] { typeof(Closure <T>), typeof(char), typeof(T).MakeByRefType() }, typeof(string), true); var indices = new List <int>(); using (var il = new GroboIL(method)) { var idx = il.DeclareLocal(typeof(int), "idx"); var retFalseLabel = il.DefineLabel("retFalse"); for (int i = 0; i < numberOfSegments; ++i) { var firstKeyInSegment = keys[i * numberOfKeysPerSegment]; var lastKeyInSegment = keys[numberOfKeysPerSegment - 1 + i * numberOfKeysPerSegment]; il.Ldarg(1); // stack: [key] il.Ldc_I4(firstKeyInSegment); // stack: [key, firstKey] var nextSegmentLabel = il.DefineLabel("nextSegment"); il.Blt(nextSegmentLabel, false); // if(key < firstKey) goto nextSegment; stack: [] il.Ldarg(1); // stack: [key] il.Ldc_I4(lastKeyInSegment); // stack: [key, lastKey] il.Bgt(nextSegmentLabel, false); // if(key > lastKey) goto nextSegment; stack: [] il.Ldarg(0); // stack: [closure] il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.indices)); // stack: [closure.indices] il.Ldarg(1); // stack: [closure.indices, key] il.Ldc_I4(firstKeyInSegment - indices.Count); // stack: [closure.indices, key, diff] il.Sub(); // stack: [closure.indices, key - diff] il.Ldelem(typeof(int)); // stack: [closure.indices[key - diff]] il.Dup(); il.Stloc(idx); // idx = closure.indices[key - diff]; stack: [idx] il.Ldc_I4(0); // stack: [idx, 0] il.Blt(retFalseLabel, false); // if(idx < 0) goto retFalse; stack: [] il.Ldarg(2); // stack: [ref value] il.Ldarg(0); // stack: [ref value, closure] il.Ldfld(HackHelpers.GetField <Closure <T> >(x => x.values)); // stack: [ref value, closure.values] il.Ldloc(idx); // stack: [ref value, closure.values, idx] il.Ldelem(typeof(T)); // stack: [ref value, closure.values[idx]] il.Stind(typeof(T)); // value = closure.values[idx]; stack: [] il.Ldc_I4(1); // stack: [true] il.Ret(); il.MarkLabel(nextSegmentLabel); var segmentLength = lastKeyInSegment - firstKeyInSegment + 1; int start = indices.Count; for (int j = 0; j < segmentLength; ++j) { indices.Add(-1); } for (int j = 0; j < numberOfKeysPerSegment; ++j) { indices[start + keys[i * numberOfKeysPerSegment + j] - firstKeyInSegment] = i * numberOfKeysPerSegment + j; } } il.MarkLabel(retFalseLabel); il.Ldarg(2); // stack: [ref value] if (typeof(T).IsValueType) { il.Initobj(typeof(T)); // value = default(T); stack: [] } else { il.Ldnull(); // stack: [ref value, null] il.Stind(typeof(T)); // value = null; stack: [] } il.Ldc_I4(0); // stack: [false] il.Ret(); } var closure = new Closure <T> { indices = indices.ToArray(), values = values }; return((TryGetValueDelegate <T>)method.CreateDelegate(typeof(TryGetValueDelegate <T>), closure)); }
public void BuildReader(ReaderTypeBuilderContext readerTypeBuilderContext) { var method = new DynamicMethod("Read_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), new[] { typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext) }, readerTypeBuilderContext.Module, true); readerTypeBuilderContext.SetReaderMethod(Type, method); using (var il = new GroboIL(method)) { var context = new ReaderMethodBuilderContext(readerTypeBuilderContext, il, !Type.IsValueType && IsReference); ReadTypeCodeAndCheck(context); // Read TypeCode and check if (!Type.IsValueType && IsReference) { // Read reference context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] var notReadLabel = il.DefineLabel("notRead"); il.Brfalse(notReadLabel); context.LoadIndex(); // stack: [external index] context.LoadContext(); // stack: [external index, context] il.Ldfld(ReaderContext.StartField); // stack: [external index, context.start] il.Sub(); // stack: [external index - context.start] il.Stloc(context.Index); // index = external index - context.start; stack: [] context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] il.Ldloc(context.Index); // stack: [context.objects, index] var obj = il.DeclareLocal(typeof(object)); il.Ldloca(obj); object dummy; il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(index, out obj)] il.Brfalse(notReadLabel); // if(!context.objects.TryGetValue(index, out obj)) goto notRead; context.LoadResultByRef(); // stack: [ref result] il.Ldloc(obj); // stack: [ref result, obj] il.Castclass(Type); // stack: [ref result, (Type)obj] il.Stind(Type); // result = (Type)obj; stack: [] context.IncreaseIndexBy1(); // Skip type code context.SkipValue(); // Skip value - it has already been read il.Ret(); il.MarkLabel(notReadLabel); il.Ldloc(context.TypeCode); // stack: [typeCode] il.Ldc_I4((int)GroBufTypeCode.Reference); // stack: [typeCode, GroBufTypeCode.Reference] var readUsualLabel = il.DefineLabel("readUsual"); il.Bne_Un(readUsualLabel); // if(typeCode != GroBufTypeCode.Reference) goto readUsual; stack: [] context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] var objectsIsNotNullLabel = il.DefineLabel("objectsIsNotNull"); il.Brtrue(objectsIsNotNullLabel); // if(context.objects != null) goto objectsIsNotNull; stack: [context.objects] il.Ldstr("Reference is not valid at this point"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(objectsIsNotNullLabel); context.IncreaseIndexBy1(); // index = index + 1; stack: [] il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); var reference = il.DeclareLocal(typeof(int)); il.Ldind(typeof(int)); // stack: [*(int*)data[index]] il.Stloc(reference); // reference = *(int*)data[index]; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] il.Ldloc(context.Index); // stack: [index] il.Ldloc(reference); // stack: [index, reference] var goodReferenceLabel = il.DefineLabel("goodReference"); il.Bgt(goodReferenceLabel, false); // if(index > reference) goto goodReference; stack: [] il.Ldstr("Bad reference"); il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) })); il.Throw(); il.MarkLabel(goodReferenceLabel); context.LoadContext(); // stack: [context] il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] il.Ldloc(reference); // stack: [context.objects, reference] il.Ldloca(obj); // stack: [context.objects, reference, ref obj] il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(reference, out obj)] var readObjectLabel = il.DefineLabel("readObject"); il.Brfalse(readObjectLabel); // if(!context.objects.TryGetValue(reference, out obj)) goto readObjects; stack: [] context.LoadResultByRef(); // stack: [ref result] il.Ldloc(obj); // stack: [ref result, obj] il.Castclass(Type); // stack: [ref result, (Type)obj] il.Stind(Type); // result = (Type)obj; stack: [] il.Ret(); il.MarkLabel(readObjectLabel); // Referenced object has not been read - this means that the object reference belongs to is a property that had been deleted context.LoadData(); // stack: [data] il.Ldloc(reference); // stack: [data, reference] context.LoadContext(); // stack: [data, reference, context] il.Ldfld(ReaderContext.StartField); // stack: [data, reference, context.start] il.Add(); // stack: [data, reference + context.start] il.Stloc(reference); // reference += context.start; stack: [data] il.Ldloca(reference); // stack: [data, ref reference] context.LoadResultByRef(); // stack: [data, ref reference, ref result] context.LoadContext(); // stack: [data, ref reference, ref result, context] context.CallReader(Type); il.Ret(); il.MarkLabel(readUsualLabel); } ReadNotEmpty(context); // Read obj il.Ret(); } var @delegate = method.CreateDelegate(typeof(ReaderDelegate <>).MakeGenericType(Type)); var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); readerTypeBuilderContext.SetReaderPointer(Type, pointer, @delegate); }
public void Test3() { // Create an assembly. AssemblyName myAssemblyName = new AssemblyName(); myAssemblyName.Name = "AdderExceptionAsm"; // Create dynamic assembly. AppDomain myAppDomain = Thread.GetDomain(); AssemblyBuilder myAssemblyBuilder = myAppDomain.DefineDynamicAssembly(myAssemblyName, AssemblyBuilderAccess.Run); // Create a dynamic module. ModuleBuilder myModuleBuilder = myAssemblyBuilder.DefineDynamicModule("AdderExceptionMod", true); var symbolDocumentWriter = myModuleBuilder.GetSymWriter().DefineDocument("AdderException.cil", Guid.Empty, Guid.Empty, Guid.Empty); TypeBuilder myTypeBuilder = myModuleBuilder.DefineType("Adder"); Type[] myAdderParams = new Type[] { typeof(int), typeof(int) }; // Create constructor. ConstructorInfo myConstructorInfo = typeof(OverflowException).GetConstructor( new Type[] { typeof(string) }); MethodInfo myExToStrMI = typeof(OverflowException).GetMethod("ToString"); MethodInfo myWriteLineMI = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string), typeof(object) }); // Method to add two numbers. MethodBuilder myMethodBuilder = myTypeBuilder.DefineMethod("DoAdd", MethodAttributes.Public | MethodAttributes.Static, typeof(int), myAdderParams); using (var il = new GroboIL(myMethodBuilder, symbolDocumentWriter)) { // Declare local variable. GroboIL.Local myLocalBuilder1 = il.DeclareLocal(typeof(int)); GroboIL.Local myLocalBuilder2 = il.DeclareLocal(typeof(OverflowException)); // Define label. GroboIL.Label myFailedLabel = il.DefineLabel("failed"); GroboIL.Label myEndOfMethodLabel = il.DefineLabel("end"); // Begin exception block. il.BeginExceptionBlock(); il.Ldarg(0); il.Ldc_I4(10); il.Bgt(myFailedLabel, false); il.Ldarg(1); il.Ldc_I4(10); il.Bgt(myFailedLabel, false); il.Ldarg(0); il.Ldarg(1); il.Add_Ovf(true); il.Stloc(myLocalBuilder1); il.Br(myEndOfMethodLabel); il.MarkLabel(myFailedLabel); il.Ldstr("Cannot accept values over 10 for addition."); il.Newobj(myConstructorInfo); il.Stloc(myLocalBuilder2); il.Ldloc(myLocalBuilder2); // Call fault block. il.BeginFaultBlock(); //Throw exception. il.Newobj(typeof(NotSupportedException).GetConstructor(Type.EmptyTypes)); il.Throw(); // Call finally block. il.BeginFinallyBlock(); il.Ldstr("{0}"); il.Ldloc(myLocalBuilder2); il.Call(myExToStrMI); il.Call(myWriteLineMI); il.Ldc_I4(-1); il.Stloc(myLocalBuilder1); // End exception block. il.EndExceptionBlock(); il.MarkLabel(myEndOfMethodLabel); il.Ldloc(myLocalBuilder1); il.Ret(); Console.WriteLine(il.GetILCode()); } Type adderType = myTypeBuilder.CreateType(); object addIns = Activator.CreateInstance(adderType); object[] addParams = new object[2]; addParams[0] = 20; addParams[1] = 10; Console.WriteLine("{0} + {1} = {2}", addParams[0], addParams[1], adderType.InvokeMember("DoAdd", BindingFlags.InvokeMethod, null, addIns, addParams)); }
public static bool Emit(Expression zarr, Expression zindex, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType) { var arrayType = zarr.Type; var isArray = arrayType.IsArray; if (!isArray && !arrayType.IsList()) { throw new InvalidOperationException("Unable to perform array index operator to type '" + arrayType + "'"); } var itemType = isArray ? arrayType.GetElementType() : arrayType.GetGenericArguments()[0]; GroboIL il = context.Il; EmittingContext.LocalHolder arrayIndex = null; bool extendArray = extend && (CanAssign(zarr) || !isArray); bool extendArrayElement = extend && itemType.IsClass; var result = false; if (!extendArray) { result |= ExpressionEmittersCollection.Emit(zarr, context, returnDefaultValueLabel, ResultType.Value, extend, out arrayType); // stack: [array] if (context.Options.HasFlag(CompilerOptions.CheckNullReferences)) { result = true; il.Dup(); // stack: [array, array] il.Brfalse(returnDefaultValueLabel); // if(array == null) goto returnDefaultValue; stack: [array] } EmitLoadIndex(zindex, context, arrayType); // stack: [array, arrayIndex] if (context.Options.HasFlag(CompilerOptions.CheckArrayIndexes)) { result = true; arrayIndex = context.DeclareLocal(typeof(int)); il.Stloc(arrayIndex); // arrayIndex = index; stack: [array] il.Dup(); // stack: [array, array] if (isArray) { il.Ldlen(); // stack: [array, array.Length] } else { EmitLoadField(context, arrayType, arrayType.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); } il.Ldloc(arrayIndex); // stack: [array, array.Length, arrayIndex] il.Ble(returnDefaultValueLabel, false); // if(array.Length <= arrayIndex) goto returnDefaultValue; stack: [array] il.Ldloc(arrayIndex); // stack: [array, arrayIndex] il.Ldc_I4(0); // stack: [array, arrayIndex, 0] il.Blt(returnDefaultValueLabel, false); // if(arrayIndex < 0) goto returnDefaultValue; stack: [array] } else if (extendArrayElement || !isArray) { arrayIndex = context.DeclareLocal(typeof(int)); il.Stloc(arrayIndex); // arrayIndex = index; stack: [array] } } else { EmittingContext.LocalHolder arrayOwner = null; switch (zarr.NodeType) { case ExpressionType.Parameter: case ExpressionType.ArrayIndex: case ExpressionType.Index: Type type; ExpressionEmittersCollection.Emit(zarr, context, returnDefaultValueLabel, ResultType.ByRefAll, true, out type); // stack: [ref array] arrayOwner = context.DeclareLocal(type); il.Dup(); // stack: [ref array, ref array] il.Stloc(arrayOwner); // arrayOwner = ref array; stack: [ref array] il.Ldind(zarr.Type); // stack: [array] break; case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)zarr; Type memberType; context.EmitMemberAccess(memberExpression, returnDefaultValueLabel, context.Options.HasFlag(CompilerOptions.CheckNullReferences), true, ResultType.ByRefValueTypesOnly, out memberType, out arrayOwner); // stack: [array] break; default: throw new InvalidOperationException("Cannot extend array for expression with node type '" + zarr.NodeType + "'"); } if (context.Options.HasFlag(CompilerOptions.CheckNullReferences)) { il.Dup(); // stack: [array, array] il.Brfalse(returnDefaultValueLabel); // if(array == null) goto returnDefaultValue; stack: [array] } EmitLoadIndex(zindex, context, arrayType); result = true; arrayIndex = context.DeclareLocal(typeof(int)); il.Stloc(arrayIndex); // arrayIndex = index; stack: [array] il.Ldloc(arrayIndex); // stack: [array, arrayIndex] il.Ldc_I4(0); // stack: [array, arrayIndex, 0] il.Blt(returnDefaultValueLabel, false); // if(arrayIndex < 0) goto returnDefaultValue; stack: [array] il.Dup(); // stack: [array, array] if (isArray) { il.Ldlen(); // stack: [array, array.Length] } else { EmitLoadField(context, arrayType, arrayType.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); } il.Ldloc(arrayIndex); // stack: [array, array.Length, arrayIndex] var bigEnoughLabel = il.DefineLabel("bigEnough"); il.Bgt(bigEnoughLabel, false); // if(array.Length > arrayIndex) goto bigEnough; stack: [array] using (var array = context.DeclareLocal(arrayType)) { il.Stloc(array); // stack: [] if (!isArray) { EnsureCount(context, array, arrayIndex, arrayType); } else { il.Ldloca(array); // stack: [ref array] il.Ldloc(arrayIndex); // stack: [ref array, arrayIndex] il.Ldc_I4(1); // stack: [ref array, arrayIndex, 1] il.Add(); // stack: [ref array, arrayIndex + 1] il.Call(arrayResizeMethod.MakeGenericMethod(arrayType.GetElementType())); // Array.Resize(ref array, 1 + arrayIndex); stack: [] switch (zarr.NodeType) { case ExpressionType.Parameter: case ExpressionType.ArrayIndex: case ExpressionType.Index: il.Ldloc(arrayOwner); // stack: [ref parameter] il.Ldloc(array); // stack: [ref parameter, array] il.Stind(arrayType); // parameter = array; stack: [] break; case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)zarr; if (memberExpression.Expression != null) { il.Ldloc(arrayOwner); } il.Ldloc(array); switch (memberExpression.Member.MemberType) { case MemberTypes.Field: il.Stfld((FieldInfo)memberExpression.Member); break; case MemberTypes.Property: var propertyInfo = (PropertyInfo)memberExpression.Member; var setter = propertyInfo.GetSetMethod(context.SkipVisibility); if (setter == null) { throw new MissingMethodException(propertyInfo.ReflectedType.ToString(), "set_" + propertyInfo.Name); } il.Call(setter, memberExpression.Expression == null ? null : memberExpression.Expression.Type); break; default: throw new NotSupportedException("Member type '" + memberExpression.Member.MemberType + "' is not supported"); } break; default: throw new InvalidOperationException("Unable to assign array to an expression with node type '" + zarr.NodeType); } } il.Ldloc(array); context.MarkLabelAndSurroundWithSP(bigEnoughLabel); } } if (!isArray) { // TODO: это злобно, лист при всех операциях меняет _version, а мы нет EmitLoadField(context, arrayType, arrayType.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); arrayType = itemType.MakeArrayType(); } if (extendArrayElement) { // stack: [array] var constructor = itemType.GetConstructor(Type.EmptyTypes); if (itemType.IsArray || constructor != null) { using (var array = context.DeclareLocal(arrayType)) { il.Dup(); // stack: [array, array] il.Stloc(array); // stack: [array] il.Ldloc(arrayIndex); // stack: [array, arrayIndex] il.Ldelem(itemType); // stack: [array[arrayIndex]] var elementIsNotNullLabel = il.DefineLabel("elementIsNotNull"); il.Brtrue(elementIsNotNullLabel); il.Ldloc(array); il.Ldloc(arrayIndex); context.Create(itemType); il.Stelem(itemType); context.MarkLabelAndSurroundWithSP(elementIsNotNullLabel); il.Ldloc(array); } } } if (arrayIndex != null) { il.Ldloc(arrayIndex); arrayIndex.Dispose(); } switch (whatReturn) { case ResultType.ByRefAll: il.Ldelema(itemType); resultType = itemType.MakeByRefType(); break; case ResultType.ByRefValueTypesOnly: if (itemType.IsValueType) { il.Ldelema(itemType); resultType = itemType.MakeByRefType(); } else { il.Ldelem(itemType); // stack: [array[arrayIndex]] resultType = itemType; } break; default: il.Ldelem(itemType); // stack: [array[arrayIndex]] resultType = itemType; break; } return(result); }