public void EmitDecode(ILGenerator il, ILocalVariableCollection locals, bool doNotCheckBounds) { var enoughBytesForLengthLabel = il.DefineLabel(); var enoughBytesForDataLabel = il.DefineLabel(); var lengthIsMinusOneLabel = il.DefineLabel(); var lengthIsZeroLabel = il.DefineLabel(); var labelGroup = new[] {lengthIsMinusOneLabel, lengthIsZeroLabel}; var lengthIsPositiveLabel = il.DefineLabel(); var endOfMethodLabel = il.DefineLabel(); if (!doNotCheckBounds) { il.Emit(OpCodes.Ldloc, locals.RemainingBytes); // if (remainingBytes >= sizeof(int)) il.Emit_Ldc_I4(sizeof(int)); // goto enoughBytesForLengthLabel il.Emit(OpCodes.Bge, enoughBytesForLengthLabel); // not enough bytes for length il.Emit_ThrowUnexpectedEndException(); // throw new InvalidDataException(...) } // enough bytes for length il.MarkLabel(enoughBytesForLengthLabel); var lengthVar = locals.GetOrAdd("length", // var length = *(int*)data lil => lil.DeclareLocal(typeof(int))); il.Emit(OpCodes.Ldloc, locals.DataPointer); il.Emit(OpCodes.Ldind_I4); il.Emit(OpCodes.Stloc, lengthVar); il.Emit_IncreasePointer(locals.DataPointer, sizeof(int)); // data += sizeof(int) il.Emit_DecreaseInteger(locals.RemainingBytes, sizeof(int));// remainingBytes -= sizeof(int) il.Emit(OpCodes.Ldloc, lengthVar); // switch(length + 1) il.Emit_Ldc_I4(1); // case 0: goto lengthIsMinusOneLabel il.Emit(OpCodes.Add); // case 1: goto lengthIsZeroLabel il.Emit(OpCodes.Switch, labelGroup); // default: goto lengthIsPositiveLabel il.Emit(OpCodes.Br, lengthIsPositiveLabel); // length is -1 il.MarkLabel(lengthIsMinusOneLabel); il.Emit(OpCodes.Ldnull); // stack_0 = null il.Emit(OpCodes.Br, endOfMethodLabel); // goto endOfMethodLabel // length is 0 il.MarkLabel(lengthIsZeroLabel); il.Emit_Ldc_I4(0); // stack_0 = new T[0] il.Emit(OpCodes.Newarr, typeOfStruct); il.Emit(OpCodes.Br, endOfMethodLabel); // goto endOfMethodLabel // length is positive il.MarkLabel(lengthIsPositiveLabel); var sizeVar = locals.GetOrAdd("sizeInBytes", // var sizeInBytes = length * sizeOfStruct lil => lil.DeclareLocal(typeof(int))); il.Emit(OpCodes.Ldloc, lengthVar); il.Emit_Ldc_I4(sizeOfStruct); il.Emit(OpCodes.Mul); il.Emit(OpCodes.Stloc, sizeVar); if (!doNotCheckBounds) { il.Emit(OpCodes.Ldloc, locals.RemainingBytes); // if (remainingBytes >= sizeInBytes) il.Emit(OpCodes.Ldloc, sizeVar); // goto enoughBytesForDataLabel il.Emit(OpCodes.Bge, enoughBytesForDataLabel); // not enough bytes for data il.Emit_ThrowUnexpectedEndException(); // throw new InvalidDataException(...) } // enough bytes for data il.MarkLabel(enoughBytesForDataLabel); var resultVar = locals.GetOrAdd( // var result = new T[length] "arrayOf" + typeOfStruct.FullName, lil => lil.DeclareLocal(typeOfStruct.MakeArrayType())); il.Emit(OpCodes.Ldloc, lengthVar); il.Emit(OpCodes.Newarr, typeOfStruct); il.Emit(OpCodes.Stloc, resultVar); var arrayPointerVar = il.Emit_PinArray( // var pinned arrayPointer = pin(value) typeOfStruct, locals, resultVar); il.Emit(OpCodes.Ldloc, arrayPointerVar); // cpblk((byte*)arrayPointer, data, sizeInBytes) il.Emit(OpCodes.Conv_I); il.Emit(OpCodes.Ldloc, locals.DataPointer); il.Emit(OpCodes.Ldloc, sizeVar); il.Emit(OpCodes.Cpblk); il.Emit_UnpinArray(arrayPointerVar); // unpin(arrayPointer) il.Emit_IncreasePointer(locals.DataPointer, sizeVar); // data += size il.Emit_DecreaseInteger(locals.RemainingBytes, sizeVar); // remainingBytes -= size il.Emit(OpCodes.Ldloc, resultVar); // stack_0 = result il.MarkLabel(endOfMethodLabel); }
public void EmitDecode(ILGenerator il, ILocalVariableCollection locals, bool doNotCheckBounds) { var strIsNotNullLabel = il.DefineLabel(); var endOfSubmethodLabel = il.DefineLabel(); if (!doNotCheckBounds) { var canReadSizeLabel = il.DefineLabel(); il.Emit(OpCodes.Ldloc, locals.RemainingBytes); // if (remainingBytes >= sizeof(int)) il.Emit_Ldc_I4(sizeof(int)); // goto canReadSizeLabel il.Emit(OpCodes.Bge, canReadSizeLabel); il.Emit_ThrowUnexpectedEndException(); // throw new InvalidDataException("...") il.MarkLabel(canReadSizeLabel); // label canReadSizeLabel } il.Emit(OpCodes.Ldloc, locals.DataPointer); // stack_0 = *(int*) data il.Emit(OpCodes.Ldind_I4); var tempInteger = locals.GetOrAdd("tempInteger", // var tempInteger = stack_0 g => g.DeclareLocal(typeof(int))); il.Emit(OpCodes.Stloc, tempInteger); il.Emit_IncreasePointer(locals.DataPointer, sizeof(int)); // data += sizeof(int) il.Emit_DecreaseInteger(locals.RemainingBytes, sizeof(int));// remainingBytes -= sizeof(int) il.Emit(OpCodes.Ldloc, tempInteger); il.Emit_Ldc_I4(-1); il.Emit(OpCodes.Bne_Un, strIsNotNullLabel); // String is null branch il.Emit(OpCodes.Ldnull); // stack_0 = null il.Emit(OpCodes.Br, endOfSubmethodLabel); // goto endOfSubmethodLabel // String is not null branch il.MarkLabel(strIsNotNullLabel); // label strIsNotNullLabel if (!doNotCheckBounds) { var canReadDataLabel = il.DefineLabel(); il.Emit(OpCodes.Ldloc, locals.RemainingBytes); // if (remainingBytes >= tempInteger) il.Emit(OpCodes.Ldloc, tempInteger); // goto canReadDataLabel il.Emit(OpCodes.Bge, canReadDataLabel); il.Emit_ThrowUnexpectedEndException(); // throw new InvalidDataException("...") il.MarkLabel(canReadDataLabel); // label canReadDataLabel } il.Emit(OpCodes.Ldloc, locals.DataPointer); // stack_0 = data il.Emit_Ldc_I4(0); // stack_1 = 0 il.Emit(OpCodes.Ldloc, tempInteger); // stack_2 = tempInteger >> 1 il.Emit_Ldc_I4(1); il.Emit(OpCodes.Shr); il.Emit(OpCodes.Newobj, NewString); // stack_0 = new string(stack_0, stack_1, stack_2) il.Emit_IncreasePointer(locals.DataPointer, tempInteger); // data += tempInteger il.Emit_DecreaseInteger(locals.RemainingBytes, tempInteger);// remainingBytes -= tempInteger il.MarkLabel(endOfSubmethodLabel); // label endOfSubmethodLabel }
public void EmitDecode(ILGenerator il, ILocalVariableCollection locals, bool doNotCheckBounds) { var valueIsNotNullLabel = il.DefineLabel(); var loopStartLabel = il.DefineLabel(); var loopConditionLabel = il.DefineLabel(); var endOfMethodLabel = il.DefineLabel(); var resultVar = il.DeclareLocal(type.MakeArrayType()); // T[] result var iVar = il.DeclareLocal(typeof(int)); // int i if (!doNotCheckBounds) { var canReadLengthLabel = il.DefineLabel(); il.Emit(OpCodes.Ldloc, locals.RemainingBytes); // if (remainingBytes >= sizeof(int)) il.Emit_Ldc_I4(sizeof(int)); // goto canReadLengthLabel il.Emit(OpCodes.Bge, canReadLengthLabel); il.Emit_ThrowUnexpectedEndException(); // throw new InvalidDataException("...") il.MarkLabel(canReadLengthLabel); // label canReadLengthLabel } var lengthVar = locals.GetOrAdd("refArrayLength", lil => lil.DeclareLocal(typeof(int))); il.Emit(OpCodes.Ldloc, locals.DataPointer); // var length = *(int*) data il.Emit(OpCodes.Ldind_I4); il.Emit(OpCodes.Stloc, lengthVar); il.Emit_IncreasePointer(locals.DataPointer, sizeof(int)); // data += sizeof(int) il.Emit_DecreaseInteger(locals.RemainingBytes, sizeof(int));// remainingBytes -= sizeof(int) il.Emit(OpCodes.Ldloc, lengthVar); // if (length == -1) il.Emit_Ldc_I4(-1); // goto valueIsNotNullLabel il.Emit(OpCodes.Bne_Un, valueIsNotNullLabel); // value is null branch il.Emit(OpCodes.Ldnull); // stack_0 = null il.Emit(OpCodes.Br, endOfMethodLabel); // goto endOfMethodLabel // value is not null branch il.MarkLabel(valueIsNotNullLabel); // label valueIsNotNullLabel il.Emit(OpCodes.Ldloc, lengthVar); // result = new T[length] il.Emit(OpCodes.Newarr, type); il.Emit(OpCodes.Stloc, resultVar); il.Emit_Ldc_I4(0); // i = 0 il.Emit(OpCodes.Stloc, iVar); il.Emit(OpCodes.Br, loopConditionLabel); // goto loopConditionLabel // loop start il.MarkLabel(loopStartLabel); // label loopStartLabel il.Emit(OpCodes.Ldloc, resultVar); // result[i] = decode(data, remainingBytes) il.Emit(OpCodes.Ldloc, iVar); EmitDecodeAndStore(il, locals, doNotCheckBounds); il.Emit(OpCodes.Ldloc, iVar); // i++ il.Emit_Ldc_I4(1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc, iVar); // loop condition il.MarkLabel(loopConditionLabel); // label loopConditionLabel il.Emit(OpCodes.Ldloc, iVar); // if (i < (int)result.Length) il.Emit(OpCodes.Ldloc, resultVar); // goto loopStartLabel il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Blt, loopStartLabel); il.Emit(OpCodes.Ldloc, resultVar); // stack_0 = result il.MarkLabel(endOfMethodLabel); // label endOfMethodLabel }
public void EmitDecode(ILGenerator il, ILocalVariableCollection locals, bool doNotCheckBounds) { var resultIsNotNullLabel = il.DefineLabel(); var endOfSubmethodLabel = il.DefineLabel(); if (!doNotCheckBounds) { var canReadFlagLabel = il.DefineLabel(); il.Emit(OpCodes.Ldloc, locals.RemainingBytes); // if (remainingBytes >= sizeof(int)) il.Emit_Ldc_I4(sizeof(int)); // goto canReadFlagLabel il.Emit(OpCodes.Bge, canReadFlagLabel); il.Emit_ThrowUnexpectedEndException(); // throw new InvalidDataException("...") il.MarkLabel(canReadFlagLabel); // label canReadFlagLabel } var flagVar = locals.GetOrAdd("existanceFlag", lil => lil.DeclareLocal(typeof(int))); il.Emit(OpCodes.Ldloc, locals.DataPointer); // flag = *(int*) data il.Emit(OpCodes.Ldind_I4); il.Emit(OpCodes.Stloc, flagVar); il.Emit_IncreasePointer(locals.DataPointer, sizeof(int)); // data += sizeof(int) il.Emit_DecreaseInteger(locals.RemainingBytes, sizeof(int)); // remainingBytes -= sizeof(int) il.Emit(OpCodes.Ldloc, flagVar); // if (flag) il.Emit(OpCodes.Brtrue, resultIsNotNullLabel); // goto resultIsNotNullLabel // Result is null branch il.Emit(OpCodes.Ldnull); // stack_0 = null il.Emit(OpCodes.Br, endOfSubmethodLabel); // goto endOfSubmethodLabel // Result is not null branch il.MarkLabel(resultIsNotNullLabel); // label resultIsNotNullLabel il.Emit(OpCodes.Ldtoken, type); // stack_0 = (T)FormatterServices.GetUninitializedObject(typeof(T)) il.Emit(OpCodes.Call, GetTypeFromHandleMethod); il.Emit(OpCodes.Call, GetUninitializedObject); il.Emit(OpCodes.Castclass, type); foreach (var memberInfo in memberInfos) // foreach (Prop) { // { il.Emit(OpCodes.Dup); // stack_0.Prop = decode() memberInfo.Codec.EmitDecode(il, locals, doNotCheckBounds); il.Emit(OpCodes.Call, memberInfo.Property.GetSetMethod(true)); } // } il.MarkLabel(endOfSubmethodLabel); // label endOfSubmethodLabel }