コード例 #1
0
 /// <summary>
 ///   Generates the code to restrict the values contained in ranged array fields.
 /// </summary>
 private void RestrictFields(StateSlotMetadata metadata)
 {
     for (var i = 0; i < metadata.ElementCount; ++i)
     {
         RestrictField(metadata, i);
     }
 }
コード例 #2
0
        /// <summary>
        ///   Generates the code to serialize a reference field.
        /// </summary>
        private void SerializeReferenceField(StateSlotMetadata metadata)
        {
            // s = state
            _il.Emit(OpCodes.Ldloc_0);

            // *s = objs.GetObjectIdentifier(o.field)
            _il.Emit(OpCodes.Ldarg_0);
            PrepareFieldAccess(metadata);
            AccessField(metadata, OpCodes.Ldfld);
            _il.Emit(OpCodes.Call, _getObjectIdentifierMethod);
            _il.Emit(OpCodes.Stind_I2);
        }
コード例 #3
0
        /// <summary>
        ///   Generates the code to serialize the state slot described by the <paramref name="metadata" />.
        /// </summary>
        /// <param name="metadata">The metadata of the state slot the code should be generated for.</param>
        private void SerializeField(StateSlotMetadata metadata)
        {
            LoadObject(metadata.ObjectIdentifier);

            if (IsReferenceType(metadata.DataType))
            {
                SerializeReferenceField(metadata);
            }
            else
            {
                SerializePrimitiveTypeField(metadata);
            }
        }
コード例 #4
0
        /// <summary>
        ///   Generates the code to deserialize a reference field.
        /// </summary>
        private void DeserializeReferenceField(StateSlotMetadata metadata)
        {
            // o = objs.GetObject(identifier)
            PrepareFieldAccess(metadata);

            // v = objs.GetObject(*state)
            _il.Emit(OpCodes.Ldarg_0);
            _il.Emit(OpCodes.Ldloc_0);
            _il.Emit(OpCodes.Ldind_I2);
            _il.Emit(OpCodes.Call, _getObjectMethod);

            // o.field = v
            AccessField(metadata, OpCodes.Stfld);
        }
コード例 #5
0
        /// <summary>
        ///   Generates the code to deserialize the array state slot described by the <paramref name="metadata" />.
        /// </summary>
        /// <param name="metadata">The metadata of the state slot the code should be generated for.</param>
        private void DeserializeArray(StateSlotMetadata metadata)
        {
            var isReferenceType = metadata.DataType.IsReferenceType();
            var loadCode        = _bitLevelAddressing
                                ? default(OpCode)
                                : GetLoadElementOpCode(metadata.ElementSizeInBits / 8, metadata.EffectiveType.IsUnsignedNumericType());
            var storeCode = isReferenceType ? OpCodes.Stelem_Ref : GetStoreArrayElementOpCode(GetUnmanagedSize(metadata.DataType));

            LoadObject(metadata.ObjectIdentifier);

            for (var i = 0; i < metadata.ElementCount; ++i)
            {
                // o = &objs.GetObject(identifier)[i]
                _il.Emit(OpCodes.Ldloc_1);
                PrepareElementAccess(metadata, i);

                if (isReferenceType)
                {
                    // v = objs.GetObject(*state)
                    _il.Emit(OpCodes.Ldarg_0);
                    _il.Emit(OpCodes.Ldloc_0);
                    _il.Emit(OpCodes.Ldind_I2);
                    _il.Emit(OpCodes.Call, _getObjectMethod);
                }
                else if (_bitLevelAddressing)
                {
                    LoadBooleanValue();
                }
                else
                {
                    // v = *state
                    _il.Emit(OpCodes.Ldloc_0);
                    _il.Emit(loadCode);
                }

                // *o = v
                if (metadata.ContainedInStruct)
                {
                    AccessField(metadata, OpCodes.Stfld);
                }
                else
                {
                    _il.Emit(storeCode);
                }

                Advance(metadata.ElementSizeInBits / 8);
            }
        }
コード例 #6
0
        /// <summary>
        ///   Prepares the access to the field referenced by the <paramref name="metadata" /> of an object.
        /// </summary>
        private void PrepareFieldAccess(StateSlotMetadata metadata)
        {
            _il.Emit(OpCodes.Ldloc_1);

            if (!metadata.ContainedInStruct)
            {
                return;
            }

            _il.Emit(OpCodes.Ldflda, metadata.Field);

            for (var i = 0; i < metadata.FieldChain.Length - 1; ++i)
            {
                _il.Emit(OpCodes.Ldflda, metadata.FieldChain[i]);
            }
        }
コード例 #7
0
        /// <summary>
        ///   Prepares the access to the field referenced by the <paramref name="metadata" /> of an element contained in an array.
        /// </summary>
        private void PrepareElementAccess(StateSlotMetadata metadata, int elementIndex)
        {
            _il.Emit(OpCodes.Ldc_I4, elementIndex);

            if (!metadata.ContainedInStruct)
            {
                return;
            }

            _il.Emit(OpCodes.Ldelema, metadata.ObjectType.GetElementType());

            for (var i = 0; i < metadata.FieldChain.Length - 1; ++i)
            {
                _il.Emit(OpCodes.Ldflda, metadata.FieldChain[i]);
            }
        }
コード例 #8
0
        /// <summary>
        ///   Generates the code to deserialize the state slot described by the <paramref name="metadata" /> of the object stored in the
        ///   local variable.
        /// </summary>
        /// <param name="metadata">The metadata of the state slot the code should be generated for.</param>
        private void DeserializePrimitiveTypeField(StateSlotMetadata metadata)
        {
            // o = objs.GetObject(identifier)
            PrepareFieldAccess(metadata);

            if (_bitLevelAddressing)
            {
                LoadBooleanValue();
            }
            else
            {
                // v = *state
                _il.Emit(OpCodes.Ldloc_0);
                _il.Emit(GetLoadElementOpCode(metadata.ElementSizeInBits / 8, metadata.EffectiveType.IsUnsignedNumericType()));
            }

            // o.field = v
            AccessField(metadata, OpCodes.Stfld);
        }
コード例 #9
0
        /// <summary>
        ///   Generates the code to serialize the state slot described by the <paramref name="metadata" /> of the object stored in the
        ///   local variable.
        /// </summary>
        /// <param name="metadata">The metadata of the state slot the code should be generated for.</param>
        private void SerializePrimitiveTypeField(StateSlotMetadata metadata)
        {
            if (_bitLevelAddressing)
            {
                StoreBooleanValue(() =>
                {
                    PrepareFieldAccess(metadata);
                    AccessField(metadata, OpCodes.Ldfld);
                });
                return;
            }

            // s = state
            _il.Emit(OpCodes.Ldloc_0);

            // v = o.field
            PrepareFieldAccess(metadata);
            AccessField(metadata, OpCodes.Ldfld);

            // *s = v
            _il.Emit(GetStoreElementOpCode(metadata.ElementSizeInBits / 8));
        }
コード例 #10
0
        /// <summary>
        ///   Accesses the field on the object currently on the stack.
        /// </summary>
        private void AccessField(StateSlotMetadata metadata, OpCode accessCode)
        {
            var field = metadata.ContainedInStruct ? metadata.FieldChain.Last() : metadata.Field;

            _il.Emit(accessCode, field);
        }
コード例 #11
0
        /// <summary>
        ///   Generates the code to serialize the array state slot described by the <paramref name="metadata" />.
        /// </summary>
        /// <param name="metadata">The metadata of the state slot the code should be generated for.</param>
        private void SerializeArray(StateSlotMetadata metadata)
        {
            var isReferenceType = metadata.DataType.IsReferenceType();
            var storeCode       = _bitLevelAddressing ? default(OpCode) : GetStoreElementOpCode(metadata.ElementSizeInBits / 8);
            var loadCode        = isReferenceType
                                ? OpCodes.Ldelem_Ref
                                : GetLoadArrayElementOpCode(GetUnmanagedSize(metadata.DataType), metadata.EffectiveType.IsUnsignedNumericType());

            LoadObject(metadata.ObjectIdentifier);

            for (var i = 0; i < metadata.ElementCount; ++i)
            {
                if (_bitLevelAddressing)
                {
                    StoreBooleanValue(() =>
                    {
                        // o = objs.GetObject(identifier)
                        _il.Emit(OpCodes.Ldloc_1);

                        // v = o[i]
                        PrepareElementAccess(metadata, i);
                        if (metadata.ContainedInStruct)
                        {
                            AccessField(metadata, OpCodes.Ldfld);
                        }
                        else
                        {
                            _il.Emit(loadCode);
                        }
                    });
                }
                else
                {
                    // s = state
                    _il.Emit(OpCodes.Ldloc_0);

                    // o = objs.GetObject(identifier)
                    if (isReferenceType)
                    {
                        _il.Emit(OpCodes.Ldarg_0);
                    }

                    _il.Emit(OpCodes.Ldloc_1);

                    // v = o[i]
                    PrepareElementAccess(metadata, i);
                    if (metadata.ContainedInStruct)
                    {
                        AccessField(metadata, OpCodes.Ldfld);
                    }
                    else
                    {
                        _il.Emit(loadCode);
                    }

                    // v = objs.GetObjectIdentifier(o[i])
                    if (isReferenceType)
                    {
                        _il.Emit(OpCodes.Call, _getObjectIdentifierMethod);
                    }

                    // *s = v
                    _il.Emit(storeCode);
                }

                Advance(metadata.ElementSizeInBits / 8);
            }
        }
コード例 #12
0
        /// <summary>
        ///   Generates the code to restrict the values contained in ranged object fields.
        /// </summary>
        private void RestrictField(StateSlotMetadata metadata, int elementIndex = 0)
        {
            var exceedsFourBytes = metadata.ElementSizeInBits > 32;
            var continueLabel    = _il.DefineLabel();

            switch (metadata.Range.OverflowBehavior)
            {
            case OverflowBehavior.Error:
                // if (v < lower | v > upper) throw
                PrepareAccess(metadata, elementIndex);
                AccessField(metadata, OpCodes.Ldfld);
                LoadConstant(metadata.Range.LowerBound, exceedsFourBytes);
                _il.Emit(metadata.DataType.IsUnsignedNumericType() ? OpCodes.Clt_Un : OpCodes.Clt);

                PrepareAccess(metadata, elementIndex);
                AccessField(metadata, OpCodes.Ldfld);
                LoadConstant(metadata.Range.UpperBound, exceedsFourBytes);
                _il.Emit(metadata.DataType.IsUnsignedNumericType() ? OpCodes.Cgt_Un : OpCodes.Cgt);

                _il.Emit(OpCodes.Or);
                _il.Emit(OpCodes.Brfalse, continueLabel);

                // throw new RangeViolationException(obj, field)
                _il.Emit(OpCodes.Ldloc_0);
                var field = metadata.ContainedInStruct ? metadata.FieldChain.Last() : metadata.Field;
                _il.Emit(OpCodes.Ldtoken, field);
                _il.Emit(OpCodes.Ldtoken, field.DeclaringType);
                var parameters = new[] { typeof(RuntimeFieldHandle), typeof(RuntimeTypeHandle) };
                _il.Emit(OpCodes.Call, typeof(FieldInfo).GetMethod("GetFieldFromHandle", parameters));
                LoadConstant(metadata.Range.LowerBound, exceedsFourBytes);
                _il.Emit(OpCodes.Box, metadata.EffectiveType);
                LoadConstant(metadata.Range.UpperBound, exceedsFourBytes);
                _il.Emit(OpCodes.Box, metadata.EffectiveType);
                _il.Emit(OpCodes.Ldc_I4, (int)OverflowBehavior.Error);
                _il.Emit(OpCodes.Newobj, typeof(RangeAttribute).GetConstructors().Single());
                _il.Emit(OpCodes.Newobj, typeof(RangeViolationException).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).Single());
                _il.Emit(OpCodes.Throw);
                break;

            case OverflowBehavior.Clamp:
                var clampLabel = _il.DefineLabel();

                PrepareAccess(metadata, elementIndex);
                AccessField(metadata, OpCodes.Ldfld);
                _il.Emit(OpCodes.Dup);

                // if (v < lower) v = lower
                LoadConstant(metadata.Range.LowerBound, exceedsFourBytes);
                _il.Emit(metadata.DataType.IsUnsignedNumericType() ? OpCodes.Bge_Un_S : OpCodes.Bge_S, clampLabel);
                _il.Emit(OpCodes.Pop);
                PrepareAccess(metadata, elementIndex);
                LoadConstant(metadata.Range.LowerBound, exceedsFourBytes);
                AccessField(metadata, OpCodes.Stfld);
                _il.Emit(OpCodes.Br, continueLabel);

                // else if (v > upper) v = upper
                _il.MarkLabel(clampLabel);
                LoadConstant(metadata.Range.UpperBound, exceedsFourBytes);
                _il.Emit(metadata.DataType.IsUnsignedNumericType() ? OpCodes.Ble_Un_S : OpCodes.Ble_S, continueLabel);
                PrepareAccess(metadata, elementIndex);
                LoadConstant(metadata.Range.UpperBound, exceedsFourBytes);
                AccessField(metadata, OpCodes.Stfld);
                break;

            case OverflowBehavior.WrapClamp:
                var wrapLabel = _il.DefineLabel();

                PrepareAccess(metadata, elementIndex);
                AccessField(metadata, OpCodes.Ldfld);
                _il.Emit(OpCodes.Dup);

                // if (v < lower) v = upper
                LoadConstant(metadata.Range.LowerBound, exceedsFourBytes);
                _il.Emit(metadata.DataType.IsUnsignedNumericType() ? OpCodes.Bge_Un_S : OpCodes.Bge_S, wrapLabel);
                _il.Emit(OpCodes.Pop);
                PrepareAccess(metadata, elementIndex);
                LoadConstant(metadata.Range.UpperBound, exceedsFourBytes);
                AccessField(metadata, OpCodes.Stfld);
                _il.Emit(OpCodes.Br, continueLabel);

                // else if (v > upper) v = lower
                _il.MarkLabel(wrapLabel);
                LoadConstant(metadata.Range.UpperBound, exceedsFourBytes);
                _il.Emit(metadata.DataType.IsUnsignedNumericType() ? OpCodes.Ble_Un_S : OpCodes.Ble_S, continueLabel);
                PrepareAccess(metadata, elementIndex);
                LoadConstant(metadata.Range.LowerBound, exceedsFourBytes);
                AccessField(metadata, OpCodes.Stfld);
                break;

            default:
                Assert.NotReached("Unknown overflow behavior.");
                break;
            }

            _il.MarkLabel(continueLabel);
        }