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()}"); } }
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); } }
public SwitchInstruction(ILInstruction value) : base(OpCode.SwitchInstruction) { this.Value = value; this.Sections = new InstructionCollection <SwitchSection>(this, 1); }
public static IfInstruction LogicAnd(ILInstruction lhs, ILInstruction rhs) { return(new IfInstruction(lhs, rhs, new LdcI4(0))); }
public static IfInstruction LogicOr(ILInstruction lhs, ILInstruction?rhs) { return(new IfInstruction(lhs, new LdcI4(1), rhs)); }
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)); }
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; }
/// <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]); }
public NullCoalescingInstruction(NullCoalescingKind kind, ILInstruction valueInst, ILInstruction fallbackInst) : base(OpCode.NullCoalescingInstruction) { this.Kind = kind; this.ValueInst = valueInst; this.FallbackInst = fallbackInst; }
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); } }
public BitNot(ILInstruction arg, bool isLifted, StackType stackType) : base(OpCode.BitNot, arg) { this.IsLifted = isLifted; this.UnderlyingResultType = stackType; }
public BinaryNumericInstruction(BinaryNumericOperator op, ILInstruction left, ILInstruction right, bool checkForOverflow, Sign sign) : this(op, left, right, left.ResultType, right.ResultType, checkForOverflow, sign) { }
public BitNot(ILInstruction arg) : base(OpCode.BitNot, arg) { this.UnderlyingResultType = arg.ResultType; }
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); }
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); }
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; }
public Conv(ILInstruction argument, PrimitiveType targetType, bool checkForOverflow, Sign inputSign) : this(argument, argument.ResultType, inputSign, targetType, checkForOverflow) { }
public static Comp LogicNot(ILInstruction arg) { return(new Comp(ComparisonKind.Equality, Sign.None, arg, new LdcI4(0))); }
public static IL.ILInstruction AccessMember(this IL.ILInstruction target, IMember p) => p is IProperty property ? new IL.Call(property.Getter)
public Block(BlockType type = BlockType.ControlFlow) : base(OpCode.Block) { this.Type = type; this.Instructions = new InstructionCollection <ILInstruction>(this, 0); this.FinalInstruction = new Nop(); }
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."); } }
protected abstract void SetChild(int index, ILInstruction value);
public CompoundAssignmentInstruction(OpCode opCode, CompoundAssignmentType compoundAssignmentType, ILInstruction target, ILInstruction value) : base(opCode) { this.CompoundAssignmentType = compoundAssignmentType; this.Target = target; this.Value = value; }
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); }
/// <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);
public IfInstruction(ILInstruction condition, ILInstruction trueInst, ILInstruction?falseInst = null) : base(OpCode.IfInstruction) { this.Condition = condition; this.TrueInst = trueInst; this.FalseInst = falseInst ?? new Nop(); }
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)); }