protected internal override void VisitNewObj(NewObj inst) { if (TransformDecimalCtorToConstant(inst, out LdcDecimal decimalConstant)) { context.Step("TransformDecimalCtorToConstant", inst); inst.ReplaceWith(decimalConstant); return; } Block block; if (TransformSpanTCtorContainingStackAlloc(inst, out ILInstruction locallocSpan)) { inst.ReplaceWith(locallocSpan); block = null; ILInstruction stmt = locallocSpan; while (stmt.Parent != null) { if (stmt.Parent is Block b) { block = b; break; } stmt = stmt.Parent; } //ILInlining.InlineIfPossible(block, stmt.ChildIndex - 1, context); return; } if (TransformArrayInitializers.TransformSpanTArrayInitialization(inst, context, out block)) { context.Step("TransformSpanTArrayInitialization: single-dim", inst); inst.ReplaceWith(block); return; } base.VisitNewObj(inst); }
bool ScanCallSiteInitBlock(Block callSiteInitBlock, IField callSiteCacheField, IType callSiteDelegateType, out CallSiteInfo callSiteInfo, out Block blockAfterInit) { callSiteInfo = default(CallSiteInfo); blockAfterInit = null; int instCount = callSiteInitBlock.Instructions.Count; if (callSiteInitBlock.IncomingEdgeCount != 1 || instCount < 2) { return(false); } if (!callSiteInitBlock.Instructions[instCount - 1].MatchBranch(out blockAfterInit)) { return(false); } if (!callSiteInitBlock.Instructions[instCount - 2].MatchStsFld(out var field, out var value) || !field.Equals(callSiteCacheField)) { return(false); } if (!(value is Call createBinderCall) || createBinderCall.Method.TypeArguments.Count != 0 || createBinderCall.Arguments.Count != 1 || createBinderCall.Method.Name != "Create" || createBinderCall.Method.DeclaringType.FullName != CallSiteTypeName || createBinderCall.Method.DeclaringType.TypeArguments.Count != 1) { return(false); } if (!(createBinderCall.Arguments[0] is Call binderCall) || binderCall.Method.DeclaringType.FullName != CSharpBinderTypeName || binderCall.Method.DeclaringType.TypeParameterCount != 0) { return(false); } callSiteInfo.DelegateType = callSiteDelegateType; callSiteInfo.InitBlock = callSiteInitBlock; switch (binderCall.Method.Name) { case "IsEvent": callSiteInfo.Kind = BinderMethodKind.IsEvent; // In the case of Binder.IsEvent all arguments should already be properly inlined, as there is no array initializer: // Scan arguments: binder flags, member name, context type if (binderCall.Arguments.Count != 3) { return(false); } if (!binderCall.Arguments[0].MatchLdcI4(out int binderFlagsInteger)) { return(false); } callSiteInfo.Flags = (CSharpBinderFlags)binderFlagsInteger; if (!binderCall.Arguments[1].MatchLdStr(out string name)) { return(false); } callSiteInfo.MemberName = name; if (!TransformExpressionTrees.MatchGetTypeFromHandle(binderCall.Arguments[2], out var contextType)) { return(false); } callSiteInfo.Context = contextType; return(true); case "Convert": callSiteInfo.Kind = BinderMethodKind.Convert; // In the case of Binder.Convert all arguments should already be properly inlined, as there is no array initializer: // Scan arguments: binder flags, target type, context type if (binderCall.Arguments.Count != 3) { return(false); } if (!binderCall.Arguments[0].MatchLdcI4(out binderFlagsInteger)) { return(false); } callSiteInfo.Flags = (CSharpBinderFlags)binderFlagsInteger; if (!TransformExpressionTrees.MatchGetTypeFromHandle(binderCall.Arguments[1], out var targetType)) { return(false); } callSiteInfo.ConvertTargetType = targetType; if (!TransformExpressionTrees.MatchGetTypeFromHandle(binderCall.Arguments[2], out contextType)) { return(false); } callSiteInfo.Context = contextType; return(true); case "InvokeMember": callSiteInfo.Kind = BinderMethodKind.InvokeMember; if (binderCall.Arguments.Count != 5) { return(false); } // First argument: binder flags // The value must be a single ldc.i4 instruction. if (!binderCall.Arguments[0].MatchLdLoc(out var variable)) { return(false); } if (!callSiteInitBlock.Instructions[0].MatchStLoc(variable, out value)) { return(false); } if (!value.MatchLdcI4(out binderFlagsInteger)) { return(false); } callSiteInfo.Flags = (CSharpBinderFlags)binderFlagsInteger; // Second argument: method name // The value must be a single ldstr instruction. if (!binderCall.Arguments[1].MatchLdLoc(out variable)) { return(false); } if (!callSiteInitBlock.Instructions[1].MatchStLoc(variable, out value)) { return(false); } if (!value.MatchLdStr(out name)) { return(false); } callSiteInfo.MemberName = name; // Third argument: type arguments // The value must be either ldnull (no type arguments) or an array initializer pattern. if (!binderCall.Arguments[2].MatchLdLoc(out variable)) { return(false); } if (!callSiteInitBlock.Instructions[2].MatchStLoc(out var variableOrTemporary, out value)) { return(false); } int numberOfTypeArguments = 0; if (!value.MatchLdNull()) { if (value is NewArr typeArgsNewArr && typeArgsNewArr.Type.IsKnownType(KnownTypeCode.Type) && typeArgsNewArr.Indices.Count == 1 && typeArgsNewArr.Indices[0].MatchLdcI4(out numberOfTypeArguments)) { if (!TransformArrayInitializers.HandleSimpleArrayInitializer(context.Function, callSiteInitBlock, 3, variableOrTemporary, typeArgsNewArr.Type, new[] { numberOfTypeArguments }, out var typeArguments, out _)) { return(false); } int i = 0; callSiteInfo.TypeArguments = new IType[numberOfTypeArguments]; foreach (var(_, typeArg) in typeArguments) { if (!TransformExpressionTrees.MatchGetTypeFromHandle(typeArg, out var type)) { return(false); } callSiteInfo.TypeArguments[i] = type; i++; } } else { return(false); } } int typeArgumentsOffset = numberOfTypeArguments; // Special case for csc array initializers: if (variableOrTemporary != variable) { // store temporary from array initializer in variable if (!callSiteInitBlock.Instructions[3 + typeArgumentsOffset].MatchStLoc(variable, out value)) { return(false); } if (!value.MatchLdLoc(variableOrTemporary)) { return(false); } typeArgumentsOffset++; } // Fourth argument: context type if (!binderCall.Arguments[3].MatchLdLoc(out variable)) { return(false); } if (!callSiteInitBlock.Instructions[3 + typeArgumentsOffset].MatchStLoc(variable, out value)) { return(false); } if (!TransformExpressionTrees.MatchGetTypeFromHandle(value, out contextType)) { return(false); } callSiteInfo.Context = contextType; // Fifth argument: call parameter info if (!binderCall.Arguments[4].MatchLdLoc(out variable)) { return(false); } if (!callSiteInitBlock.Instructions[4 + typeArgumentsOffset].MatchStLoc(variable, out value)) { return(false); } if (!ExtractArgumentInfo(value, ref callSiteInfo, 5 + typeArgumentsOffset, variable)) { return(false); } return(true);