Example #1
0
        /// <summary>
        /// Introduce a named argument for 'arg' and evaluate it before the other arguments
        /// (except for the "this" pointer)
        /// </summary>
        internal static void IntroduceNamedArgument(ILInstruction arg, ILTransformContext context)
        {
            var call = (CallInstruction)arg.Parent;

            Debug.Assert(context.Function == call.Ancestors.OfType <ILFunction>().First());
            var v = context.Function.RegisterVariable(VariableKind.NamedArgument, arg.InferType(context.TypeSystem));

            context.Step($"Introduce named argument '{v.Name}'", arg);
            if (!(call.Parent is Block namedArgBlock) || namedArgBlock.Kind != BlockKind.CallWithNamedArgs)
            {
                // create namedArgBlock:
                namedArgBlock = new Block(BlockKind.CallWithNamedArgs);
                call.ReplaceWith(namedArgBlock);
                namedArgBlock.FinalInstruction = call;
                if (call.IsInstanceCall)
                {
                    IType thisVarType = call.Method.DeclaringType;
                    if (CallInstruction.ExpectedTypeForThisPointer(thisVarType) == StackType.Ref)
                    {
                        thisVarType = new ByReferenceType(thisVarType);
                    }
                    var thisArgVar = context.Function.RegisterVariable(VariableKind.NamedArgument, thisVarType, "this_arg");
                    namedArgBlock.Instructions.Add(new StLoc(thisArgVar, call.Arguments[0]));
                    call.Arguments[0] = new LdLoc(thisArgVar);
                }
            }
            int argIndex = arg.ChildIndex;

            Debug.Assert(call.Arguments[argIndex] == arg);
            namedArgBlock.Instructions.Insert(call.IsInstanceCall ? 1 : 0, new StLoc(v, arg));
            call.Arguments[argIndex] = new LdLoc(v);
        }
Example #2
0
        /// <summary>
        /// Gets whether 'stobj type(..., value)' would evaluate to a different value than 'value'
        /// due to implicit truncation.
        /// </summary>
        static internal bool IsImplicitTruncation(ILInstruction value, IType type, bool allowNullableValue = false)
        {
            if (!type.IsSmallIntegerType())
            {
                // Implicit truncation in ILAst only happens for small integer types;
                // other types of implicit truncation in IL cause the ILReader to insert
                // conv instructions.
                return(false);
            }
            // With small integer types, test whether the value might be changed by
            // truncation (based on type.GetSize()) followed by sign/zero extension (based on type.GetSign()).
            // (it's OK to have false-positives here if we're unsure)
            if (value.MatchLdcI4(out int val))
            {
                switch (type.GetEnumUnderlyingType().GetDefinition()?.KnownTypeCode)
                {
                case KnownTypeCode.Boolean:
                    return(!(val == 0 || val == 1));

                case KnownTypeCode.Byte:
                    return(!(val >= byte.MinValue && val <= byte.MaxValue));

                case KnownTypeCode.SByte:
                    return(!(val >= sbyte.MinValue && val <= sbyte.MaxValue));

                case KnownTypeCode.Int16:
                    return(!(val >= short.MinValue && val <= short.MaxValue));

                case KnownTypeCode.UInt16:
                case KnownTypeCode.Char:
                    return(!(val >= ushort.MinValue && val <= ushort.MaxValue));
                }
            }
            else if (value is Conv conv)
            {
                return(conv.TargetType != type.ToPrimitiveType());
            }
            else if (value is Comp)
            {
                return(false);                // comp returns 0 or 1, which always fits
            }
            else if (value is IfInstruction ifInst)
            {
                return(IsImplicitTruncation(ifInst.TrueInst, type, allowNullableValue) ||
                       IsImplicitTruncation(ifInst.FalseInst, type, allowNullableValue));
            }
            else
            {
                IType inferredType = value.InferType();
                if (allowNullableValue)
                {
                    inferredType = NullableType.GetUnderlyingType(inferredType);
                }
                if (inferredType.Kind != TypeKind.Unknown)
                {
                    return(!(inferredType.GetSize() <= type.GetSize() && inferredType.GetSign() == type.GetSign()));
                }
            }
            return(true);
        }
Example #3
0
        internal static IType GuessType(IType variableType, ILInstruction inst, ILTransformContext context)
        {
            if (!variableType.IsKnownType(KnownTypeCode.Object))
                return variableType;

            IType inferredType = inst.InferType(context.TypeSystem);
            if (inferredType.Kind != TypeKind.Unknown)
                return inferredType;
            else
                return variableType;
        }
Example #4
0
        internal static IType GuessType(IType variableType, ILInstruction inst, ILTransformContext context)
        {
            if (!variableType.IsKnownType(KnownTypeCode.Object))
            {
                return(variableType);
            }

            IType inferredType = inst.InferType();

            if (inferredType.Kind != TypeKind.Unknown)
            {
                return(inferredType);
            }
            else
            {
                return(variableType);
            }
        }