Beispiel #1
0
        public static IType GetObjectResultType(this IL.ILInstruction instruction)
        {
            // if (instruction.ResultType != IL.StackType.O && instruction.ResultType != IL.StackType.Ref)
            //     throw new InvalidOperationException($"Can't get result type of non-object expression.");

            switch (instruction)
            {
            case IL.Call call: return(call.Method.ReturnType);

            case IL.CallVirt callv: return(callv.Method.ReturnType);

            case IL.NewObj newobj: return(newobj.Method.DeclaringType);

            case IL.IInstructionWithFieldOperand field: return(field.Field.ReturnType);

            case IL.ILoadInstruction load: return(load.Variable.Type);

            case IL.IAddressInstruction addrLoad: return(addrLoad.Variable.Type);

            case IL.AddressOf addrOf: return(addrOf.Value.GetObjectResultType());

            case IL.LdObj ldobj: return(ldobj.Target.GetObjectResultType());

            case IL.Box box: return(box.Type);

            default: throw new NotSupportedException($"Can't get result type from instruction {instruction.GetType()}");
            }
        }
Beispiel #2
0
        static IL.ILInstruction GetHashCodeExpression(IType propertyType, IL.ILInstruction prop)
        {
            var eqInterface         = propertyType.GetAllBaseTypes().FirstOrDefault(t => t.FullName == "System.IEquatable") as IType;
            var seqInterface        = propertyType.GetAllBaseTypes().FirstOrDefault(t => t.FullName == "System.Collections.IStructuralEquatable") as IType;
            var enumerableInterface = propertyType.GetAllBaseTypes().FirstOrDefault(t => t.FullName == "System.Collections.IEnumerable") as IType;
            var eqOperator          = propertyType.GetMethods(options: GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(t => t.IsOperator && t.Name == "op_Equality");

            // enumerable types tend to be reference-equality even though they have IStructuralEquality overridden
            if (seqInterface != null && (enumerableInterface != null || eqInterface == null))
            {
                return(InvokeInterfaceMethod(propertyType.GetDefinition().Compilation.FindType(typeof(System.Collections.IEqualityComparer)).GetMethods(options: GetMemberOptions.IgnoreInheritedMembers).Single(m => m.Name == "GetHashCode"), seqInterface,
                                             new IL.CallVirt(propertyType.GetDefinition().Compilation.FindType(typeof(System.Collections.StructuralComparisons)).GetProperties().Single(p => p.Name == "StructuralEqualityComparer").Getter),
                                             new IL.Box(prop, propertyType)
                                             ));
            }
            else
            {
                // var method = propertyType.GetDefinition().Compilation.FindType(typeof(object)).GetMethods().Single(m => m.Name == "GetHashCode");
                return(prop);
            }
        }
Beispiel #3
0
 public SwitchInstruction(ILInstruction value)
     : base(OpCode.SwitchInstruction)
 {
     this.Value    = value;
     this.Sections = new InstructionCollection <SwitchSection>(this, 1);
 }
Beispiel #4
0
 public static IfInstruction LogicAnd(ILInstruction lhs, ILInstruction rhs)
 {
     return(new IfInstruction(lhs, rhs, new LdcI4(0)));
 }
Beispiel #5
0
 public static IfInstruction LogicOr(ILInstruction lhs, ILInstruction?rhs)
 {
     return(new IfInstruction(lhs, new LdcI4(1), rhs));
 }
Beispiel #6
0
 public NumericCompoundAssign(BinaryNumericInstruction binary, ILInstruction target, ILInstruction value, IType type, CompoundAssignmentType compoundAssignmentType)
     : base(OpCode.NumericCompoundAssign, compoundAssignmentType, target, value)
 {
     Debug.Assert(IsBinaryCompatibleWithType(binary, type));
     this.CheckForOverflow     = binary.CheckForOverflow;
     this.Sign                 = binary.Sign;
     this.LeftInputType        = binary.LeftInputType;
     this.RightInputType       = binary.RightInputType;
     this.UnderlyingResultType = binary.UnderlyingResultType;
     this.Operator             = binary.Operator;
     this.IsLifted             = binary.IsLifted;
     this.type                 = type;
     this.AddILRange(binary);
     Debug.Assert(compoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub));
     Debug.Assert(IsValidCompoundAssignmentTarget(Target));
     Debug.Assert(this.ResultType == (IsLifted ? StackType.O : UnderlyingResultType));
 }
Beispiel #7
0
 public DynamicCompoundAssign(ExpressionType op, CSharpBinderFlags binderFlags, ILInstruction target, CSharpArgumentInfo targetArgumentInfo, ILInstruction value, CSharpArgumentInfo valueArgumentInfo)
     : base(OpCode.DynamicCompoundAssign, CompoundAssignmentTypeFromOperation(op), target, value)
 {
     if (!IsExpressionTypeSupported(op))
     {
         throw new ArgumentOutOfRangeException("op");
     }
     this.BinderFlags        = binderFlags;
     this.Operation          = op;
     this.TargetArgumentInfo = targetArgumentInfo;
     this.ValueArgumentInfo  = valueArgumentInfo;
 }
Beispiel #8
0
 /// <summary>
 /// Gets the predecessor of the given instruction.
 /// Returns null if inst.Parent is not a block.
 /// </summary>
 public static ILInstruction GetPredecessor(ILInstruction inst)
 {
     if (inst.Parent is Block block && inst.ChildIndex > 0)
     {
         return(block.Instructions[inst.ChildIndex - 1]);
     }
Beispiel #9
0
 public NullCoalescingInstruction(NullCoalescingKind kind, ILInstruction valueInst, ILInstruction fallbackInst) : base(OpCode.NullCoalescingInstruction)
 {
     this.Kind         = kind;
     this.ValueInst    = valueInst;
     this.FallbackInst = fallbackInst;
 }
Beispiel #10
0
 public BinaryNumericInstruction(BinaryNumericOperator op, ILInstruction left, ILInstruction right, StackType leftInputType, StackType rightInputType, bool checkForOverflow, Sign sign, bool isLifted = false)
     : base(OpCode.BinaryNumericInstruction, left, right)
 {
     this.CheckForOverflow = checkForOverflow;
     this.Sign             = sign;
     this.Operator         = op;
     this.LeftInputType    = leftInputType;
     this.RightInputType   = rightInputType;
     this.IsLifted         = isLifted;
     this.resultType       = ComputeResultType(op, LeftInputType, RightInputType);
     Debug.Assert(resultType != StackType.Unknown);
 }
        internal static bool IsAssignment(ILInstruction inst, ICompilation typeSystem, out IType expectedType, out ILInstruction value)
        {
            expectedType = null;
            value        = null;
            switch (inst)
            {
            case CallInstruction call:
                if (call.Method.AccessorKind != System.Reflection.MethodSemanticsAttributes.Setter)
                {
                    return(false);
                }
                for (int i = 0; i < call.Arguments.Count - 1; i++)
                {
                    ILInstruction arg = call.Arguments[i];
                    if (arg.Flags == InstructionFlags.None)
                    {
                        // OK - we accept integer literals, etc.
                    }
                    else if (arg.MatchLdLoc(out var v))
                    {
                    }
                    else
                    {
                        return(false);
                    }
                }
                expectedType = call.Method.Parameters.Last().Type;
                value        = call.Arguments.Last();
                return(true);

            case StLoc stloc:
                expectedType = stloc.Variable.Type;
                value        = stloc.Value;
                return(true);

            case StObj stobj:
                var target = stobj.Target;
                while (target.MatchLdFlda(out var nestedTarget, out _))
                {
                    target = nestedTarget;
                }
                if (target.Flags == InstructionFlags.None)
                {
                    // OK - we accept integer literals, etc.
                }
                else if (target.MatchLdLoc(out var v))
                {
                }
                else
                {
                    return(false);
                }
                if (stobj.Target.InferType(typeSystem) is ByReferenceType brt)
                {
                    expectedType = brt.ElementType;
                }
                else
                {
                    expectedType = SpecialType.UnknownType;
                }
                value = stobj.Value;
                return(true);

            default:
                return(false);
            }
        }
Beispiel #12
0
 public BitNot(ILInstruction arg, bool isLifted, StackType stackType) : base(OpCode.BitNot, arg)
 {
     this.IsLifted             = isLifted;
     this.UnderlyingResultType = stackType;
 }
Beispiel #13
0
 public BinaryNumericInstruction(BinaryNumericOperator op, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign)
     : this(op, left, right, left.ResultType, right.ResultType, checkForOverflow, sign)
 {
 }
Beispiel #14
0
 public BitNot(ILInstruction arg) : base(OpCode.BitNot, arg)
 {
     this.UnderlyingResultType = arg.ResultType;
 }
Beispiel #15
0
 public bool MatchIfInstructionPositiveCondition(out ILInstruction condition, out ILInstruction trueInst, out ILInstruction falseInst)
 {
     if (MatchIfInstruction(out condition, out trueInst, out falseInst))
     {
         // Swap trueInst<>falseInst for every logic.not in the condition.
         while (condition.MatchLogicNot(out var arg))
         {
             condition = arg;
             ILInstruction tmp = trueInst;
             trueInst  = falseInst;
             falseInst = tmp;
         }
         return(true);
     }
     return(false);
 }
Beispiel #16
0
        public bool MatchIfInstruction(out ILInstruction condition, out ILInstruction trueInst, out ILInstruction falseInst)
        {
            var inst = this as IfInstruction;

            if (inst != null)
            {
                condition = inst.Condition;
                trueInst  = inst.TrueInst;
                falseInst = inst.FalseInst;
                return(true);
            }
            condition = null;
            trueInst  = null;
            falseInst = null;
            return(false);
        }
Beispiel #17
0
 public Comp(ComparisonKind kind, ComparisonLiftingKind lifting, StackType inputType, Sign sign, ILInstruction left, ILInstruction right) : base(OpCode.Comp, left, right)
 {
     this.kind        = kind;
     this.LiftingKind = lifting;
     this.InputType   = inputType;
     this.Sign        = sign;
 }
Beispiel #18
0
 public Conv(ILInstruction argument, PrimitiveType targetType, bool checkForOverflow, Sign inputSign)
     : this(argument, argument.ResultType, inputSign, targetType, checkForOverflow)
 {
 }
Beispiel #19
0
 public static Comp LogicNot(ILInstruction arg)
 {
     return(new Comp(ComparisonKind.Equality, Sign.None, arg, new LdcI4(0)));
 }
Beispiel #20
0
 public static IL.ILInstruction AccessMember(this IL.ILInstruction target, IMember p) =>
 p is IProperty property ? new IL.Call(property.Getter)
Beispiel #21
0
 public Block(BlockType type = BlockType.ControlFlow) : base(OpCode.Block)
 {
     this.Type             = type;
     this.Instructions     = new InstructionCollection <ILInstruction>(this, 0);
     this.FinalInstruction = new Nop();
 }
Beispiel #22
0
        public static IL.ILInstruction EqualsExpression(IType propertyType, IL.ILInstruction @this, IL.ILInstruction other)
        {
            var  originalPropertyType = propertyType;
            bool needsBoxing;

            (propertyType, needsBoxing) =
                propertyType.FullName == "System.Nullable" ?
                (((ParameterizedType)propertyType).TypeArguments.Single(), true) :
                (propertyType, false);

            var eqInterface         = propertyType.GetAllBaseTypes().FirstOrDefault(t => t.FullName == "System.IEquatable") as IType;
            var seqInterface        = propertyType.GetAllBaseTypes().FirstOrDefault(t => t.FullName == "System.Collections.IStructuralEquatable") as IType;
            var enumerableInterface = propertyType.GetAllBaseTypes().FirstOrDefault(t => t.FullName == "System.Collections.IEnumerable") as IType;
            var eqOperator          = propertyType.GetMethods(options: GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(t => t.IsOperator && t.Name == "op_Equality");
            var compilation         = propertyType.GetDefinition().Compilation;

            if (propertyType.GetStackType() != IL.StackType.O)
            {
                return(new IL.Comp(IL.ComparisonKind.Equality, needsBoxing ? IL.ComparisonLiftingKind.CSharp : IL.ComparisonLiftingKind.None, propertyType.GetStackType(), Sign.None, @this, other));
            }
            // enumerable types tend to be reference-equality even though they have IStructuralEquality overridden
            else if (seqInterface != null && (enumerableInterface != null || eqInterface == null))
            {
                return(InvokeInterfaceMethod(compilation.FindType(typeof(System.Collections.IEqualityComparer)).GetMethods(options: GetMemberOptions.IgnoreInheritedMembers).Single(m => m.Name == "Equals"), seqInterface,
                                             new IL.CallVirt(compilation.FindType(typeof(System.Collections.StructuralComparisons)).GetProperties().Single(p => p.Name == "StructuralEqualityComparer").Getter),
                                             new IL.Box(@this, originalPropertyType),
                                             new IL.Box(other, originalPropertyType)
                                             ));
            }
            else if (eqOperator != null)
            {
                if (needsBoxing)
                {
                    eqOperator = CSharpOperators.LiftUserDefinedOperator(eqOperator);
                }
                return(new IL.Call(eqOperator)
                {
                    Arguments = { @this, other }
                });
            }
            else if (eqInterface != null && !needsBoxing)
            {
                return(InvokeInterfaceMethod(
                           eqInterface.GetMethods(options: GetMemberOptions.IgnoreInheritedMembers).Single(m => m.Name == "Equals"),
                           propertyType,
                           @this,
                           other
                           ));
            }
            else if (propertyType.Kind == TypeKind.Interface || true)
            {
                Debug.Assert(!needsBoxing); // interface should not be in Nullable<_>
                // if the type is a interface, let's compare it using the object.Equals method and hope that it will be implemented correctly in the implementation
                var objectEqualsMethod = compilation.FindType(KnownTypeCode.Object).GetMethods(m => m.Parameters.Count == 2 && m.Name == "Equals" && m.IsStatic).Single();
                return(new IL.Call(objectEqualsMethod)
                {
                    Arguments = { @this, other }
                });
            }
            else
            {
                throw new NotSupportedException($"Can't compare {originalPropertyType.ReflectionName}, it does not implement IEquatable.");
            }
        }
Beispiel #23
0
 protected abstract void SetChild(int index, ILInstruction value);
Beispiel #24
0
 public CompoundAssignmentInstruction(OpCode opCode, CompoundAssignmentType compoundAssignmentType, ILInstruction target, ILInstruction value)
     : base(opCode)
 {
     this.CompoundAssignmentType = compoundAssignmentType;
     this.Target = target;
     this.Value  = value;
 }
Beispiel #25
0
        public static IL.ILInstruction InvokeInterfaceMethod(IMethod method, IType targetType, IL.ILInstruction @this, params IL.ILInstruction[] args)
        {
            var explicitImplementation = targetType.GetMethods().FirstOrDefault(m => m.ExplicitlyImplementedInterfaceMembers.Contains(method));
            // var implicitImplementation = propertyType.GetMethods().FirstOrDefault(m => m.
            var usedMethod = explicitImplementation?.Accessibility == Accessibility.Public ? explicitImplementation : method;
            // TODO: call the method directly if there is some
            var call = new IL.CallVirt(usedMethod);

            if ((bool)targetType.IsReferenceType)
            {
                call.Arguments.Add(@this);
            }
            else
            {
                call.ConstrainedTo = targetType;
                call.Arguments.Add(new IL.AddressOf(@this, targetType));
            }
            call.Arguments.AddRange(args);
            return(call);
        }
Beispiel #26
0
 /// <summary>
 /// Attempts matching this instruction against the other instruction.
 /// </summary>
 /// <param name="other">The instruction to compare with.</param>
 /// <param name="match">The match object, used to store global state during the match (such as the results of capture groups).</param>
 /// <returns>Returns whether the (partial) match was successful.
 /// If the method returns true, it adds the capture groups (if any) to the match.
 /// If the method returns false, the match object may remain in a partially-updated state and
 /// needs to be restored before it can be reused.</returns>
 protected internal abstract bool PerformMatch(ILInstruction other, ref Match match);
Beispiel #27
0
 public IfInstruction(ILInstruction condition, ILInstruction trueInst, ILInstruction?falseInst = null) : base(OpCode.IfInstruction)
 {
     this.Condition = condition;
     this.TrueInst  = trueInst;
     this.FalseInst = falseInst ?? new Nop();
 }
Beispiel #28
0
        public bool IsLifted => false;         // TODO: implement lifted user-defined compound assignments

        public UserDefinedCompoundAssign(IMethod method, CompoundAssignmentType compoundAssignmentType, ILInstruction target, ILInstruction value)
            : base(OpCode.UserDefinedCompoundAssign, compoundAssignmentType, target, value)
        {
            this.Method = method;
            Debug.Assert(Method.IsOperator || IsStringConcat(method));
            Debug.Assert(compoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue || (Method.Name == "op_Increment" || Method.Name == "op_Decrement"));
            Debug.Assert(IsValidCompoundAssignmentTarget(Target));
        }