Beispiel #1
0
        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());
            }
        }
Beispiel #2
0
        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());
            }
        }
Beispiel #3
0
        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());
            }
        }
Beispiel #4
0
        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));
        }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        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);
        }