System.Xml.Xsl.IlGen.XmlILVisitor.VisitXsltInvokeEarlyBound C# (CSharp) Method

VisitXsltInvokeEarlyBound() protected method

Generate code for for QilNodeType.XsltInvokeEarlyBound.
protected VisitXsltInvokeEarlyBound ( QilInvokeEarlyBound ndInvoke ) : QilNode
ndInvoke QilInvokeEarlyBound
return QilNode
        protected override QilNode VisitXsltInvokeEarlyBound(QilInvokeEarlyBound ndInvoke) {
            QilName ndName = ndInvoke.Name;
            XmlExtensionFunction extFunc;
            Type clrTypeRetSrc, clrTypeRetDst;

            // Retrieve metadata from the extension function
            extFunc = new XmlExtensionFunction(ndName.LocalName, ndName.NamespaceUri, ndInvoke.ClrMethod);
            clrTypeRetSrc = extFunc.ClrReturnType;
            clrTypeRetDst = GetStorageType(ndInvoke);

            // Prepare to call runtime.ChangeTypeXsltResult
            if (clrTypeRetSrc != clrTypeRetDst && !ndInvoke.XmlType.IsEmpty) {
                this.helper.LoadQueryRuntime();
                this.helper.LoadInteger(this.helper.StaticData.DeclareXmlType(ndInvoke.XmlType));
            }

            // If this is not a static method, then get the instance object
            if (!extFunc.Method.IsStatic) {
                // Special-case the XsltLibrary object
                if (ndName.NamespaceUri.Length == 0)
                    this.helper.LoadXsltLibrary();
                else
                    this.helper.CallGetEarlyBoundObject(this.helper.StaticData.DeclareEarlyBound(ndName.NamespaceUri, extFunc.Method), extFunc.Method.DeclaringType);
            }

            // Generate code to push each Invoke argument onto the stack
            for (int iArg = 0; iArg < ndInvoke.Arguments.Count; iArg++) {
                QilNode ndActualArg;
                XmlQueryType xmlTypeFormalArg;
                Type clrTypeActualArg, clrTypeFormalArg;

                ndActualArg = ndInvoke.Arguments[iArg];

                // Infer Xml type and Clr type of formal argument
                xmlTypeFormalArg = extFunc.GetXmlArgumentType(iArg);
                clrTypeFormalArg = extFunc.GetClrArgumentType(iArg);

                Debug.Assert(ndActualArg.XmlType.IsSubtypeOf(xmlTypeFormalArg), "Xml type of actual arg must be a subtype of the Xml type of the formal arg");

                // Use different conversion rules for internal Xslt libraries.  If the actual argument is
                // stored using Clr type T, then library must use type T, XPathItem, IList<T>, or IList<XPathItem>.
                // If the actual argument is stored using Clr type IList<T>, then library must use type
                // IList<T> or IList<XPathItem>.  This is to ensure that there will not be unnecessary
                // conversions that take place when calling into an internal library.
                if (ndName.NamespaceUri.Length == 0) {
                    Type itemType = GetItemStorageType(ndActualArg);

                    if (clrTypeFormalArg == XmlILMethods.StorageMethods[itemType].IListType) {
                        // Formal type is IList<T>
                        NestedVisitEnsureStack(ndActualArg, itemType, true);
                    }
                    else if (clrTypeFormalArg == XmlILMethods.StorageMethods[typeof(XPathItem)].IListType) {
                        // Formal type is IList<XPathItem>
                        NestedVisitEnsureStack(ndActualArg, typeof(XPathItem), true);
                    }
                    else if ((ndActualArg.XmlType.IsSingleton && clrTypeFormalArg == itemType) || ndActualArg.XmlType.TypeCode == XmlTypeCode.None) {
                        // Formal type is T
                        NestedVisitEnsureStack(ndActualArg, itemType, false);
                    }
                    else if (ndActualArg.XmlType.IsSingleton && clrTypeFormalArg == typeof(XPathItem)) {
                        // Formal type is XPathItem
                        NestedVisitEnsureStack(ndActualArg, typeof(XPathItem), false);
                    }
                    else
                        Debug.Fail("Internal Xslt library may not use parameters of type " + clrTypeFormalArg);
                }
                else {
                    // There is an implicit upcast to the Xml type of the formal argument.  This can change the Clr storage type.
                    clrTypeActualArg = GetStorageType(xmlTypeFormalArg);

                    // If the formal Clr type is typeof(object) or if it is not a supertype of the actual Clr type, then call ChangeTypeXsltArgument
                    if (xmlTypeFormalArg.TypeCode == XmlTypeCode.Item || !clrTypeFormalArg.IsAssignableFrom(clrTypeActualArg)) {
                        // (clrTypeFormalArg) runtime.ChangeTypeXsltArgument(xmlTypeFormalArg, (object) value, clrTypeFormalArg);
                        this.helper.LoadQueryRuntime();
                        this.helper.LoadInteger(this.helper.StaticData.DeclareXmlType(xmlTypeFormalArg));
                        NestedVisitEnsureStack(ndActualArg, GetItemStorageType(xmlTypeFormalArg), !xmlTypeFormalArg.IsSingleton);
                        this.helper.TreatAs(clrTypeActualArg, typeof(object));
                        this.helper.LoadType(clrTypeFormalArg);
                        this.helper.Call(XmlILMethods.ChangeTypeXsltArg);
                        this.helper.TreatAs(typeof(object), clrTypeFormalArg);
                    }
                    else {
                        NestedVisitEnsureStack(ndActualArg, GetItemStorageType(xmlTypeFormalArg), !xmlTypeFormalArg.IsSingleton);
                    }
                }
            }

            // Invoke the target method
            this.helper.Call(extFunc.Method);

            // Return value is on the stack; convert it to canonical ILGen storage type
            if (ndInvoke.XmlType.IsEmpty) {
                this.helper.Emit(OpCodes.Ldsfld, XmlILMethods.StorageMethods[typeof(XPathItem)].SeqEmpty);
            }
            else if (clrTypeRetSrc != clrTypeRetDst) {
                // (T) runtime.ChangeTypeXsltResult(idxType, (object) value);
                this.helper.TreatAs(clrTypeRetSrc, typeof(object));
                this.helper.Call(XmlILMethods.ChangeTypeXsltResult);
                this.helper.TreatAs(typeof(object), clrTypeRetDst);
            }
            else if (ndName.NamespaceUri.Length != 0 && !clrTypeRetSrc.IsValueType){
                // Check for null if a user-defined extension function returns a reference type
                Label lblSkip = this.helper.DefineLabel();
                this.helper.Emit(OpCodes.Dup);
                this.helper.Emit(OpCodes.Brtrue, lblSkip);
                this.helper.LoadQueryRuntime();
                this.helper.Emit(OpCodes.Ldstr, Res.GetString(Res.Xslt_ItemNull));
                this.helper.Call(XmlILMethods.ThrowException);
                this.helper.MarkLabel(lblSkip);
            }

            this.iterCurr.Storage = StorageDescriptor.Stack(GetItemStorageType(ndInvoke), !ndInvoke.XmlType.IsSingleton);

            return ndInvoke;
        }
XmlILVisitor