public void AssertTypeCode(GroBufTypeCode expectedTypeCode)
        {
            Il.Ldloc(TypeCode);               // stack: [typeCode]
            Il.Ldc_I4((int)expectedTypeCode); // stack: [typeCode, expectedTypeCode]

            var okLabel = Il.DefineLabel("ok");

            Il.Beq(okLabel);

            SkipValue();
            Il.Ret();

            Il.MarkLabel(okLabel);
        }
        public void SkipValue()
        {
            LoadIndexByRef(); // stack: [ref index]
            LoadIndex();      // stack: [ref index, index]

            // todo: сделать switch
            Il.Ldloc(TypeCode);                         // stack: [ref index, index, TypeCode]
            Il.Ldc_I4((int)GroBufTypeCode.DateTimeOld); // stack: [ref index, index, TypeCode, GroBufTypeCode.DateTimeOld]
            var notDateTimeLabel = Il.DefineLabel("notDateTime");

            Il.Bne_Un(notDateTimeLabel); // if(TypeCode != GroBufTypeCode.DateTimeOld) goto notDateTime; stack: [ref index, index]
            Il.Ldc_I4(8);                // stack: [ref index, index, 8]
            AssertLength();
            GoToCurrentLocation();       // stack: [ref index, index, &data[index]]
            Il.Ldc_I4(4);
            Il.Add();
            Il.Ldind(typeof(int)); // stack: [ref index, index, (int)(&data[index])]
            Il.Ldc_I4(31);         // stack: [ref index, index, (int)&data[index], 31]
            Il.Shr(true);          // stack: [ref index, index, (int)&data[index] >> 31]
            Il.Ldc_I4(8);          // stack: [ref index, index, (int)&data[index] >> 31, 8]
            Il.Add();              // stack: [ref index, index, (int)&data[index] >> 31 + 8]
            var increaseLabel = Il.DefineLabel("increase");

            Il.Br(increaseLabel);

            Il.MarkLabel(notDateTimeLabel);
            LoadField(Context.Lengths);

            Il.Ldloc(TypeCode);       // stack: [ref index, index, lengths, typeCode]
            Il.Ldelem(typeof(int));   // stack: [ref index, index, lengths[typeCode]]
            Il.Dup();                 // stack: [ref index, index, lengths[typeCode], lengths[typeCode]]
            Il.Ldc_I4(-1);            // stack: [ref index, index, lengths[typeCode], lengths[typeCode], -1]
            Il.Bne_Un(increaseLabel); // if(lengths[typeCode] != -1) goto increase;

            Il.Ldc_I4(4);
            AssertLength();
            Il.Pop();               // stack: [ref index, index]
            Il.Dup();               // stack: [ref index, index, index]
            LoadData();             // stack: [ref index, index, index, pinnedData]
            Il.Add();               // stack: [ref index, index, index + pinnedData]
            Il.Ldind(typeof(uint)); // stack: [ref index, index, *(uint*)(pinnedData + index)]
            Il.Ldc_I4(4);           // stack: [ref index, index, *(uint*)(pinnedData + index), 4]
            Il.Add();               // stack: [ref index, *(uint*)(pinnedData + index) + 4]

            Il.MarkLabel(increaseLabel);
            Il.Dup();              // stack: [ref index, length, length]
            AssertLength();        // stack: [ref index, length]
            Il.Add();              // stack: [ref index, index + length]
            Il.Stind(typeof(int)); // index = index + length
        }
 public void EmitLoadDefaultValue(Type type)
 {
     if (type == typeof(void))
     {
         return;
     }
     if (!type.IsValueType)
     {
         Il.Ldnull();
     }
     else
     {
         using (var temp = DeclareLocal(type))
         {
             Il.Ldloca(temp);
             Il.Initobj(type);
             Il.Ldloc(temp);
         }
     }
 }
        /// <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 StoreObject(Type type)
        {
            if (Index == null)
            {
                return;
            }
            if (type.IsValueType)
            {
                throw new InvalidOperationException("A reference type expected");
            }
            // Store in array of all references
            LoadContext();                        // stack: [context]
            Il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects]
            var doneLabel = Il.DefineLabel("done");

            Il.Brfalse(doneLabel);                                                                           // if(context.objects == null) goto done; stack: []

            LoadContext();                                                                                   // stack: [context]
            Il.Ldfld(ReaderContext.ObjectsField);                                                            // stack: [context.objects]
            Il.Ldloc(Index);                                                                                 // stack: [context.objects, index]
            LoadResult(type);                                                                                // stack: [context.objects, index, result]
            Il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.Add(0, null))); // context.objects.Add(index, result)
            Il.MarkLabel(doneLabel);
        }
 public bool EmitNullChecking(Type type, GroboIL.Label objIsNullLabel)
 {
     if (!type.IsValueType)
     {
         Il.Dup();                   // stack: [obj, obj]
         Il.Brfalse(objIsNullLabel); // if(obj == null) goto returnDefaultValue; stack: [obj]
         return(true);
     }
     if (type.IsNullable())
     {
         using (var temp = DeclareLocal(type.MakeByRefType()))
         {
             Il.Stloc(temp);
             Il.Ldnull();
             Il.Ldloc(temp);
             EmitHasValueAccess(type);
             Il.Brfalse(objIsNullLabel);
             Il.Pop();
             Il.Ldloc(temp);
         }
         return(true);
     }
     return(false);
 }
        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);
                    }
            }
        }