public void Create(Type type)
 {
     if (!type.IsArray)
     {
         var constructor = type.GetConstructor(Type.EmptyTypes);
         if (constructor == null)
         {
             throw new InvalidOperationException("Missing parameterless constructor for type '" + type + "'");
         }
         Il.Newobj(constructor);
     }
     else
     {
         var rank = type.GetArrayRank();
         if (rank == 1)
         {
             Il.Ldc_I4(0);
             Il.Newarr(type.GetElementType());
         }
         else
         {
             var constructor = type.GetConstructor(Enumerable.Repeat(typeof(int), rank).ToArray());
             if (constructor == null)
             {
                 throw new InvalidOperationException(string.Format("Missing constructor accepting {0} integers for type '{1}'", rank, type));
             }
             for (int i = 0; i < rank; ++i)
             {
                 Il.Ldc_I4(0);
             }
             Il.Newobj(constructor);
         }
     }
 }
        /// <summary>
        ///     Asserts that the specified number of bytes can be read from <c>data</c> starting at <c>index</c>
        ///     <para></para>
        ///     The number of bytes must be pushed onto the evaluation stack
        /// </summary>
        public void AssertLength()
        {
            LoadIndex();      // stack: [length, index]
            Il.Add();         // stack: [length + index]
            LoadDataLength(); // stack: [length + index, dataLength]
            var bigEnoughLabel = Il.DefineLabel("bigEnough");

            Il.Ble(bigEnoughLabel, true);
            Il.Ldstr("Unexpected end of data");
            var constructor = typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) });

            if (constructor == null)
            {
                throw new MissingConstructorException(typeof(DataCorruptedException), typeof(string));
            }
            Il.Newobj(constructor);
            Il.Throw();
            Il.MarkLabel(bigEnoughLabel);
        }
        /// <summary>
        ///     Asserts that the specified number of bytes can be written to <c>result</c> starting at <c>index</c>
        ///     <para></para>
        ///     The number of bytes must be pushed onto the evaluation stack
        /// </summary>
        public void AssertLength()
        {
            LoadIndex();        // stack: [length, index]
            Il.Add();           // stack: [length + index]
            LoadResultLength(); // stack: [length + index, resultLength]
            var bigEnoughLabel = Il.DefineLabel("bigEnough");

            Il.Ble(bigEnoughLabel, true);
            Il.Ldstr("Seems like the object being serialized has been changed during serialization");
            var constructor = typeof(InvalidOperationException).GetConstructor(new[] { typeof(string) });

            if (constructor == null)
            {
                throw new MissingConstructorException(typeof(InvalidOperationException), typeof(string));
            }
            Il.Newobj(constructor);
            Il.Throw();
            Il.MarkLabel(bigEnoughLabel);
        }
        /// <summary>
        ///     Checks TypeCode and throws Exception if it is invalid
        /// </summary>
        public void CheckTypeCode()
        {
            LoadField(Context.Lengths);
            Il.Ldloc(TypeCode);     // stack: [lengths, typeCode]
            Il.Ldelem(typeof(int)); // stack: [lengths[typeCode]]
            var okLabel = Il.DefineLabel("ok");

            Il.Brtrue(okLabel); // if(lengths[typeCode] != 0) goto ok;
            Il.Ldstr("Unknown type code: ");
            Il.Ldloca(TypeCode);
            Il.Call(HackHelpers.GetMethodDefinition <int>(x => x.ToString()), typeof(int));
            Il.Call(HackHelpers.GetMethodDefinition <string>(s => s + "zzz"));
            var constructor = typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) });

            if (constructor == null)
            {
                throw new MissingConstructorException(typeof(DataCorruptedException), typeof(string));
            }
            Il.Newobj(constructor);
            Il.Throw();
            Il.MarkLabel(okLabel);
        }
 public void EmitConvert(Type from, Type to, bool check = false)
 {
     if (from == to)
     {
         return;
     }
     if (!from.IsValueType)
     {
         if (!to.IsValueType)
         {
             Il.Castclass(to);
         }
         else
         {
             if (from != typeof(object) && !(from == typeof(Enum) && to.IsEnum))
             {
                 throw new InvalidCastException("Cannot cast an object of type '" + from + "' to type '" + to + "'");
             }
             Il.Unbox_Any(to);
         }
     }
     else
     {
         if (!to.IsValueType)
         {
             if (to != typeof(object) && !(to == typeof(Enum) && from.IsEnum))
             {
                 throw new InvalidCastException("Cannot cast an object of type '" + from + "' to type '" + to + "'");
             }
             Il.Box(from);
         }
         else
         {
             if (to.IsNullable())
             {
                 var toArgument = to.GetGenericArguments()[0];
                 if (from.IsNullable())
                 {
                     var fromArgument = from.GetGenericArguments()[0];
                     using (var temp = DeclareLocal(from))
                     {
                         Il.Stloc(temp);
                         Il.Ldloca(temp);
                         EmitHasValueAccess(from);
                         var valueIsNullLabel = Il.DefineLabel("valueIsNull");
                         Il.Brfalse(valueIsNullLabel);
                         Il.Ldloca(temp);
                         EmitValueAccess(from);
                         if (toArgument != fromArgument)
                         {
                             EmitConvert(fromArgument, toArgument, check);
                         }
                         Il.Newobj(to.GetConstructor(new[] { toArgument }));
                         var doneLabel = Il.DefineLabel("done");
                         Il.Br(doneLabel);
                         MarkLabelAndSurroundWithSP(valueIsNullLabel);
                         EmitLoadDefaultValue(to);
                         MarkLabelAndSurroundWithSP(doneLabel);
                     }
                 }
                 else
                 {
                     if (toArgument != from)
                     {
                         EmitConvert(from, toArgument, check);
                     }
                     Il.Newobj(to.GetConstructor(new[] { toArgument }));
                 }
             }
             else if (from.IsNullable())
             {
                 var fromArgument = from.GetGenericArguments()[0];
                 using (var temp = DeclareLocal(from))
                 {
                     Il.Stloc(temp);
                     Il.Ldloca(temp);
                     var valueIsNullLabel = Il.DefineLabel("valueIsNull");
                     Il.Brfalse(valueIsNullLabel);
                     Il.Ldloca(temp);
                     EmitValueAccess(from);
                     if (to != fromArgument)
                     {
                         EmitConvert(fromArgument, to, check);
                     }
                     var doneLabel = Il.DefineLabel("done");
                     Il.Br(doneLabel);
                     MarkLabelAndSurroundWithSP(valueIsNullLabel);
                     EmitLoadDefaultValue(to);
                     MarkLabelAndSurroundWithSP(doneLabel);
                 }
             }
             else if (to.IsEnum || to == typeof(Enum))
             {
                 EmitConvert(from, typeof(int), check);
             }
             else if (from.IsEnum || from == typeof(Enum))
             {
                 EmitConvert(typeof(int), to, check);
             }
             else
             {
                 if (!check)
                 {
                     EmitConvertValue(Il, from, to);
                 }
                 else
                 {
                     EmitConvertValueChecked(Il, from, to);
                 }
             }
         }
     }
 }
        public void EmitArithmeticOperation(ExpressionType nodeType, Type resultType, Type leftType, Type rightType, MethodInfo method)
        {
            if (!leftType.IsNullable() && !rightType.IsNullable())
            {
                if (method != null)
                {
                    Il.Call(method);
                }
                else
                {
                    if (leftType.IsStruct())
                    {
                        throw new InvalidOperationException("Unable to perfrom operation '" + nodeType + "' to a struct of type '" + leftType + "'");
                    }
                    if (rightType.IsStruct())
                    {
                        throw new InvalidOperationException("Unable to perfrom operation '" + nodeType + "' to a struct of type '" + rightType + "'");
                    }
                    EmitOp(Il, nodeType, resultType);
                }
            }
            else
            {
                using (var localLeft = DeclareLocal(leftType))
                    using (var localRight = DeclareLocal(rightType))
                    {
                        Il.Stloc(localRight);
                        Il.Stloc(localLeft);
                        var returnNullLabel = Il.DefineLabel("returnNull");
                        if (leftType.IsNullable())
                        {
                            Il.Ldloca(localLeft);
                            EmitHasValueAccess(leftType);
                            Il.Brfalse(returnNullLabel);
                        }
                        if (rightType.IsNullable())
                        {
                            Il.Ldloca(localRight);
                            EmitHasValueAccess(rightType);
                            Il.Brfalse(returnNullLabel);
                        }
                        if (!leftType.IsNullable())
                        {
                            Il.Ldloc(localLeft);
                        }
                        else
                        {
                            Il.Ldloca(localLeft);
                            EmitValueAccess(leftType);
                        }
                        if (!rightType.IsNullable())
                        {
                            Il.Ldloc(localRight);
                        }
                        else
                        {
                            Il.Ldloca(localRight);
                            EmitValueAccess(rightType);
                        }
                        Type argumentType = resultType.GetGenericArguments()[0];
                        if (method != null)
                        {
                            Il.Call(method);
                        }
                        else
                        {
                            EmitOp(Il, nodeType, argumentType);
                        }
                        Il.Newobj(resultType.GetConstructor(new[] { argumentType }));

                        var doneLabel = Il.DefineLabel("done");
                        Il.Br(doneLabel);
                        MarkLabelAndSurroundWithSP(returnNullLabel);
                        EmitLoadDefaultValue(resultType);
                        MarkLabelAndSurroundWithSP(doneLabel);
                    }
            }
        }