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);
        }
Beispiel #2
0
        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))
            {
                context.Step("new Span<T>(stackalloc) -> stackalloc Span<T>", inst);
                inst.ReplaceWith(locallocSpan);
                block = null;
                ILInstruction stmt = locallocSpan;
                while (stmt.Parent != null)
                {
                    if (stmt.Parent is Block b)
                    {
                        block = b;
                        break;
                    }
                    stmt = stmt.Parent;
                }
                // Special case to eliminate extra store
                if (stmt.GetNextSibling() is StLoc storeStmt && storeStmt.Value is LdLoc)
                {
                    ILInlining.InlineIfPossible(block, stmt.ChildIndex, context);
                }
                return;
            }
            if (TransformArrayInitializers.TransformSpanTArrayInitialization(inst, context, out block))
            {
                context.Step("TransformSpanTArrayInitialization: single-dim", inst);
                inst.ReplaceWith(block);
                return;
            }
            if (TransformDelegateCtorLdVirtFtnToLdVirtDelegate(inst, out LdVirtDelegate ldVirtDelegate))
            {
                context.Step("new Delegate(target, ldvirtftn Method) -> ldvirtdelegate Delegate Method(target)", inst);
                inst.ReplaceWith(ldVirtDelegate);
                return;
            }
            base.VisitNewObj(inst);
        }
Beispiel #3
0
        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);