ILInstruction MakeDynamicInstruction(CallSiteInfo callsite, CallVirt targetInvokeCall, List <ILInstruction> deadArguments) { switch (callsite.Kind) { case BinderMethodKind.BinaryOperation: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicBinaryOperatorInstruction( binderFlags: callsite.Flags, operation: callsite.Operation, context: callsite.Context, leftArgumentInfo: callsite.ArgumentInfos[0], left: targetInvokeCall.Arguments[2], rightArgumentInfo: callsite.ArgumentInfos[1], right: targetInvokeCall.Arguments[3] )); case BinderMethodKind.Convert: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); ILInstruction result = new DynamicConvertInstruction( binderFlags: callsite.Flags, context: callsite.Context, type: callsite.ConvertTargetType, argument: targetInvokeCall.Arguments[2] ); if (result.ResultType == StackType.Unknown) { // if references are missing, we need to coerce the primitive type to None. // Otherwise we will get loads of assertions. result = new Conv(result, PrimitiveType.None, ((DynamicConvertInstruction)result).IsChecked, Sign.None); } return(result); case BinderMethodKind.GetIndex: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicGetIndexInstruction( binderFlags: callsite.Flags, context: callsite.Context, argumentInfo: callsite.ArgumentInfos, arguments: targetInvokeCall.Arguments.Skip(2).ToArray() )); case BinderMethodKind.GetMember: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicGetMemberInstruction( binderFlags: callsite.Flags, name: callsite.MemberName, context: callsite.Context, targetArgumentInfo: callsite.ArgumentInfos[0], target: targetInvokeCall.Arguments[2] )); case BinderMethodKind.Invoke: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicInvokeInstruction( binderFlags: callsite.Flags, context: callsite.Context, argumentInfo: callsite.ArgumentInfos, arguments: targetInvokeCall.Arguments.Skip(2).ToArray() )); case BinderMethodKind.InvokeConstructor: var arguments = targetInvokeCall.Arguments.Skip(2).ToArray(); // Extract type information from targetInvokeCall: // Must either be an inlined type or // a reference to a variable that is initialized with a type. if (!TransformExpressionTrees.MatchGetTypeFromHandle(arguments[0], out var type)) { if (!(arguments[0].MatchLdLoc(out var temp) && temp.IsSingleDefinition && temp.StoreInstructions.FirstOrDefault() is StLoc initStore)) { return(null); } if (!TransformExpressionTrees.MatchGetTypeFromHandle(initStore.Value, out type)) { return(null); } } deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicInvokeConstructorInstruction( binderFlags: callsite.Flags, type: type ?? SpecialType.UnknownType, context: callsite.Context, argumentInfo: callsite.ArgumentInfos, arguments: arguments )); case BinderMethodKind.InvokeMember: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicInvokeMemberInstruction( binderFlags: callsite.Flags, name: callsite.MemberName, typeArguments: callsite.TypeArguments, context: callsite.Context, argumentInfo: callsite.ArgumentInfos, arguments: targetInvokeCall.Arguments.Skip(2).ToArray() )); case BinderMethodKind.IsEvent: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicIsEventInstruction( binderFlags: callsite.Flags, name: callsite.MemberName, context: callsite.Context, argument: targetInvokeCall.Arguments[2] )); case BinderMethodKind.SetIndex: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicSetIndexInstruction( binderFlags: callsite.Flags, context: callsite.Context, argumentInfo: callsite.ArgumentInfos, arguments: targetInvokeCall.Arguments.Skip(2).ToArray() )); case BinderMethodKind.SetMember: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicSetMemberInstruction( binderFlags: callsite.Flags, name: callsite.MemberName, context: callsite.Context, targetArgumentInfo: callsite.ArgumentInfos[0], target: targetInvokeCall.Arguments[2], valueArgumentInfo: callsite.ArgumentInfos[1], value: targetInvokeCall.Arguments[3] )); case BinderMethodKind.UnaryOperation: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicUnaryOperatorInstruction( binderFlags: callsite.Flags, operation: callsite.Operation, context: callsite.Context, operandArgumentInfo: callsite.ArgumentInfos[0], operand: targetInvokeCall.Arguments[2] )); default: throw new ArgumentOutOfRangeException($"Value {callsite.Kind} is not supported!"); } }
ILInstruction MakeDynamicInstruction(CallSiteInfo callsite, CallVirt targetInvokeCall, List <ILInstruction> deadArguments) { switch (callsite.Kind) { case BinderMethodKind.BinaryOperation: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicBinaryOperatorInstruction( binderFlags: callsite.Flags, operation: callsite.Operation, context: callsite.Context, leftArgumentInfo: callsite.ArgumentInfos[0], left: targetInvokeCall.Arguments[2], rightArgumentInfo: callsite.ArgumentInfos[1], right: targetInvokeCall.Arguments[3] )); case BinderMethodKind.Convert: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); ILInstruction result = new DynamicConvertInstruction( binderFlags: callsite.Flags, context: callsite.Context, type: callsite.ConvertTargetType, argument: targetInvokeCall.Arguments[2] ); if (result.ResultType == StackType.Unknown) { // if references are missing, we need to coerce the primitive type to None. // Otherwise we will get loads of assertions. result = new Conv(result, PrimitiveType.None, ((DynamicConvertInstruction)result).IsChecked, Sign.None); } return(result); case BinderMethodKind.GetIndex: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicGetIndexInstruction( binderFlags: callsite.Flags, context: callsite.Context, argumentInfo: callsite.ArgumentInfos, arguments: targetInvokeCall.Arguments.Skip(2).ToArray() )); case BinderMethodKind.GetMember: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicGetMemberInstruction( binderFlags: callsite.Flags, name: callsite.MemberName, context: callsite.Context, targetArgumentInfo: callsite.ArgumentInfos[0], target: targetInvokeCall.Arguments[2] )); case BinderMethodKind.Invoke: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicInvokeInstruction( binderFlags: callsite.Flags, context: callsite.Context, argumentInfo: callsite.ArgumentInfos, arguments: targetInvokeCall.Arguments.Skip(2).ToArray() )); case BinderMethodKind.InvokeConstructor: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicInvokeConstructorInstruction( binderFlags: callsite.Flags, context: callsite.Context, argumentInfo: callsite.ArgumentInfos, arguments: targetInvokeCall.Arguments.Skip(2).ToArray() )); case BinderMethodKind.InvokeMember: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicInvokeMemberInstruction( binderFlags: callsite.Flags, name: callsite.MemberName, typeArguments: callsite.TypeArguments, context: callsite.Context, argumentInfo: callsite.ArgumentInfos, arguments: targetInvokeCall.Arguments.Skip(2).ToArray() )); case BinderMethodKind.IsEvent: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicIsEventInstruction( binderFlags: callsite.Flags, name: callsite.MemberName, context: callsite.Context, argument: targetInvokeCall.Arguments[2] )); case BinderMethodKind.SetIndex: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicSetIndexInstruction( binderFlags: callsite.Flags, context: callsite.Context, argumentInfo: callsite.ArgumentInfos, arguments: targetInvokeCall.Arguments.Skip(2).ToArray() )); case BinderMethodKind.SetMember: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicSetMemberInstruction( binderFlags: callsite.Flags, name: callsite.MemberName, context: callsite.Context, targetArgumentInfo: callsite.ArgumentInfos[0], target: targetInvokeCall.Arguments[2], valueArgumentInfo: callsite.ArgumentInfos[1], value: targetInvokeCall.Arguments[3] )); case BinderMethodKind.UnaryOperation: deadArguments.AddRange(targetInvokeCall.Arguments.Take(2)); return(new DynamicUnaryOperatorInstruction( binderFlags: callsite.Flags, operation: callsite.Operation, context: callsite.Context, operandArgumentInfo: callsite.ArgumentInfos[0], operand: targetInvokeCall.Arguments[2] )); default: throw new ArgumentOutOfRangeException($"Value {callsite.Kind} is not supported!"); } }