Beispiel #1
0
            internal override void EmitLoadTypeDesc(DirectTypeRef node, CodeGenerator codeGenerator, ResolveTypeFlags flags)
            {
                Debug.Assert(resolvedType != null);

                // disallow generic parameters on generic type which already has generic arguments:
                resolvedType.EmitLoadTypeDesc(codeGenerator, flags |
                                              ((node.GenericParams.Count > 0) ? ResolveTypeFlags.SkipGenericNameParsing : 0));

                // constructed type already emited its generic parameters:
                if (!(resolvedType is ConstructedType))
                {
                    EmitMakeGenericInstantiation(node, codeGenerator, flags);
                }
            }
Beispiel #2
0
		internal void EmitGetConstantValueOperator(DType type, string/*!*/ constantFullName, string constantFallbackName)
		{
			if (type != null)
			{
                Debug.Assert(constantFallbackName == null);

				// CALL Operators.GetClassConstant(<type desc>, <constant name>, <type context>, <script context>);
				type.EmitLoadTypeDesc(this, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);

				il.Emit(OpCodes.Ldstr, constantFullName);

				EmitLoadClassContext();
				EmitLoadScriptContext();

				il.EmitCall(OpCodes.Call, Methods.Operators.GetClassConstant, null);
			}
			else
			{
				// CALL context.GetConstantValue(name);
				EmitLoadScriptContext();
				il.Emit(OpCodes.Ldstr, constantFullName);
                if (constantFallbackName != null) il.Emit(OpCodes.Ldstr, constantFallbackName); else il.Emit(OpCodes.Ldnull);
				il.Emit(OpCodes.Call, Methods.ScriptContext.GetConstantValue);
			}
		}
Beispiel #3
0
		internal void EmitUnsetStaticPropertyOperator(DType/*!*/ type, string propertyFullName,
			Expression propertyNameExpr)
		{
			Debug.Assert(type != null && (propertyFullName != null ^ propertyNameExpr != null));

			// CALL Operators.UnsetStaticProperty(<type desc>, <field name>, <type desc>, <context>) 
			type.EmitLoadTypeDesc(this, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);

			EmitName(propertyFullName, propertyNameExpr, false);
			EmitLoadClassContext();
			EmitLoadScriptContext();

			il.Emit(OpCodes.Call, Methods.Operators.UnsetStaticProperty);
		}
Beispiel #4
0
		internal AssignmentCallback/*!*/ EmitSetStaticPropertyOperator(DType/*!*/ type,
			string propertyFullName, Expression propertyNameExpr, bool setReference)
		{
			Debug.Assert(type != null && (propertyFullName != null ^ propertyNameExpr != null));

			// we need to check the visibility => invoke the operator:
			type.EmitLoadTypeDesc(this, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
			EmitName(propertyFullName, propertyNameExpr, false);

			return delegate(CodeGenerator/*!*/ codeGen, PhpTypeCode stackTypeCode)
			{
				codeGen.EmitLoadClassContext();
				codeGen.EmitLoadScriptContext();

				// invoke the operator
				codeGen.IL.Emit(OpCodes.Call, Methods.Operators.SetStaticProperty);
			};
		}
Beispiel #5
0
		internal PhpTypeCode EmitGetStaticPropertyOperator(DType/*!*/ type,
			string propertyFullName, Expression propertyNameExpr, bool getReference)
		{
			Debug.Assert(type != null && (propertyFullName != null ^ propertyNameExpr != null));

			// LOAD GetStaticProperty[Ref](<type name>, <field name>, <type desc>, <context>, [quiet]);
			type.EmitLoadTypeDesc(this, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
			EmitName(propertyFullName, propertyNameExpr, false);
			EmitLoadClassContext();
			EmitLoadScriptContext();

			// invoke the operator
			if (getReference)
			{
				il.Emit(OpCodes.Call, Methods.Operators.GetStaticPropertyRef);
				return PhpTypeCode.PhpReference;
			}
			else
			{
				il.LdcI4(this.ChainBuilder.QuietRead ? 1 : 0);
				il.Emit(OpCodes.Call, Methods.Operators.GetStaticProperty);
				return PhpTypeCode.Object;
			}
		}
Beispiel #6
0
		private void EmitLoadTypeDesc(string typeFullName, TypeRef typeNameRef, DType type, ResolveTypeFlags flags)
		{
            DebugHelper.AssertNonNull(1, typeFullName, typeNameRef, type);

			if (typeFullName != null)
				EmitLoadTypeDescOperator(typeFullName, null, flags);
			else if (typeNameRef != null)
				typeNameRef.EmitLoadTypeDesc(this, flags);
			else
				type.EmitLoadTypeDesc(this, flags);
		}
Beispiel #7
0
		/// <summary>
		/// Emits a call to a routine with specified name using an operator.
		/// </summary>
        internal PhpTypeCode EmitRoutineOperatorCall(DType type, Expression targetExpr,
            string routineFullName, string fallbackRoutineFullname, Expression routineNameExpr, CallSignature callSignature, AccessType access)
        {
            Debug.Assert(routineFullName != null ^ routineNameExpr != null);

            MethodInfo operator_method;
            PhpTypeCode return_type_code;

            // (J) use call sites to call the method:
            if (targetExpr != null /*|| type != null*/)
            {
                Debug.Assert(fallbackRoutineFullname == null);

                return this.CallSitesBuilder.EmitMethodCall(this, CallSitesBuilder.AccessToReturnType(access), targetExpr, type, routineFullName, routineNameExpr, callSignature);
            }
            else if (targetExpr != null)
            {
                Debug.Assert(fallbackRoutineFullname == null);

                // LOAD Operators.InvokeMethod(<target>, <method name>, <type desc>, <context>);

                // start a new operators chain (as the rest of chain is read)
                this.ChainBuilder.Create();
                this.ChainBuilder.Begin();
                this.ChainBuilder.Lengthen(); // for hop over ->

                // prepare for operator invocation
                this.EmitBoxing(targetExpr.Emit(this));
                this.ChainBuilder.End();

                this.EmitName(routineFullName, routineNameExpr, true);
                this.EmitLoadClassContext();
                this.EmitLoadScriptContext();

                if (routineFullName != null)
                    operator_method = Methods.Operators.InvokeMethodStr;
                else
                    operator_method = Methods.Operators.InvokeMethodObj;

                return_type_code = PhpTypeCode.PhpReference;
            }
            else if (type != null)
            {
                Debug.Assert(fallbackRoutineFullname == null);

                // LOAD Operators.InvokeStaticMethod(<type desc>, <method name>, <self>, <type desc>, context);
                type.EmitLoadTypeDesc(this, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);

                this.EmitName(routineFullName, routineNameExpr, true);

                this.EmitLoadSelf();
                this.EmitLoadClassContext();
                this.EmitLoadScriptContext();

                operator_method = Methods.Operators.InvokeStaticMethod;
                return_type_code = PhpTypeCode.PhpReference;
            }
            else
            {
                Debug.Assert(routineNameExpr == null || fallbackRoutineFullname == null);   // (routineNameExpr != null) => (fallbackRoutineFullName == null)

                // DRoutineDesc <callHint>;
                FieldInfo hintField = this.CallSitesBuilder.DefineField(
                    "<callHint>'" + (routineFullName ?? "indirect"),
                    typeof(PHP.Core.Reflection.DRoutineDesc),
                    FieldAttributes.Static | FieldAttributes.Assembly);

                // LOAD ScriptContext.Call{|Void|Value}(<local variables>, <naming context>, <function name>, ref <hint>, context);
                this.EmitLoadRTVariablesTable();
                this.EmitLoadNamingContext();
                this.EmitName(routineFullName, routineNameExpr, true);
                if (fallbackRoutineFullname != null) il.Emit(OpCodes.Ldstr, fallbackRoutineFullname); else il.Emit(OpCodes.Ldnull); // fallback fcn name
                il.Emit(OpCodes.Ldsflda, hintField);
                this.EmitLoadScriptContext();

                // (J) only necessary copying, dereferencing or reference making:
                if (access == AccessType.None)
                {
                    operator_method = Methods.ScriptContext.CallVoid;
                    return_type_code = PhpTypeCode.Void;
                }
                else if (access == AccessType.Read)
                {
                    operator_method = Methods.ScriptContext.CallValue;
                    return_type_code = PhpTypeCode.Object;
                }
                else
                {
                    operator_method = Methods.ScriptContext.Call;
                    return_type_code = PhpTypeCode.PhpReference;
                }
            }

            // emits load of parameters to the PHP stack:
            callSignature.EmitLoadOnPhpStack(this);

            // marks transient sequence point just before the call:
            this.MarkTransientSequencePoint();

            il.Emit(OpCodes.Call, operator_method);

            // marks transient sequence point just after the call:
            this.MarkTransientSequencePoint();

            return return_type_code;
        }
Beispiel #8
0
        /// <summary>
        /// Create and call <see cref="CallSite"/> for getting property.
        /// </summary>
        /// <param name="cg"><see cref="CodeGenerator"/>.</param>
        /// <param name="wantRef">Wheter <see cref="PhpReference"/> is expected as the result.</param>
        /// <param name="targetExpr">The expression representing the target (object).</param>
        /// <param name="targetObjectPlace">The place representing the target (<see cref="DObject"/>) iff <paramref name="targetExpr"/> is not provided.</param>
        /// <param name="targetPlace">The place representing the target (object) iff <paramref name="targetExpr"/> and <paramref name="targetObjectPlace"/> are not provided.</param>
        /// <param name="targetType">Type of target iff we are getting property statically.</param>
        /// <param name="fieldName">The name of the field. Can be null if the name is not known at compile time (indirect).</param>
        /// <param name="fieldNameExpr">The expression used to get field name in run time (iff <paramref name="fieldName"/> is <c>null</c>.</param>
        /// <param name="issetSemantics">Wheter we are only checking if the property exists. If true, no warnings are thrown during run time.</param>
        /// <returns>Type code of the value that is pushed onto the top of the evaluation stack.</returns>
        public PhpTypeCode EmitGetProperty(
            PHP.Core.CodeGenerator /*!*/ cg, bool wantRef,
            Expression targetExpr, IPlace targetObjectPlace, IPlace targetPlace, DType targetType,
            string fieldName, Expression fieldNameExpr,
            bool issetSemantics)
        {
            Debug.Assert(fieldName != null ^ fieldNameExpr != null);
            Debug.Assert(targetExpr != null || targetObjectPlace != null || targetPlace != null || targetType != null);

            //
            bool staticCall          = (targetExpr == null && targetObjectPlace == null && targetPlace == null); // we are going to access static property
            bool fieldNameIsKnown    = (fieldName != null);
            bool classContextIsKnown = (this.classContextPlace != null);

            //
            // binder flags:
            //
            Type returnType = wantRef ? Types.PhpReference[0] : Types.Object[0];

            //
            // define the call site:
            //

            //
            List <Type> additionalArgs = new List <Type>();

            if (!classContextIsKnown)
            {
                additionalArgs.Add(Types.DTypeDesc[0]);
            }
            if (!fieldNameIsKnown)
            {
                additionalArgs.Add(Types.String[0]);
            }

            var delegateTypeArgs = GetPropertyDelegateTypeArgs(
                staticCall ? Types.DTypeDesc[0] : ((targetObjectPlace != null) ? Types.DObject[0] : Types.Object[0]),   // DTypeDesc of static field's declaring type || DObject if field called on DObject known at compile time || otherwise object
                additionalArgs.ToArray(),
                returnType);

            var delegateType = /*System.Linq.Expressions.Expression.*/ delegateBuilder.GetDelegateType(delegateTypeArgs, callSitesCount);    // (J) do not create dynamic delegates in dynamic modules, so they can be referenced from non-transient assemblies

            //
            var field = DefineCallSite(cg.IL, string.Format("get{0}_{1}", wantRef ? "ref" : string.Empty, fieldName ?? "$"), delegateType, (il) =>
            {
                // <LOAD> Binder.{GetProperty|GetStaticProperty}( fieldName, classContext, issetSemantics, <returnType> )
                if (fieldName != null)
                {
                    il.Emit(OpCodes.Ldstr, fieldName);
                }
                else
                {
                    il.Emit(OpCodes.Ldnull);
                }
                if (this.classContextPlace != null)
                {
                    this.classContextPlace.EmitLoad(il);
                }
                else
                {
                    il.Emit(OpCodes.Ldsfld, Fields.UnknownTypeDesc.Singleton);
                }
                il.LoadBool(issetSemantics);

                il.Emit(OpCodes.Ldtoken, returnType);
                il.Emit(OpCodes.Call, Methods.GetTypeFromHandle);

                il.Emit(OpCodes.Call, staticCall ? Methods.Binder.StaticGetProperty : Methods.Binder.GetProperty);
            });

            //
            // call the CallSite:
            //

            // <field>.Target( <field>, <targetExpr|targetType>, (classContext)?, <methodNameExpr>? ):

            cg.IL.Emit(OpCodes.Ldsfld, field);
            cg.IL.Emit(OpCodes.Ldfld, field.FieldType.GetField("Target"));
            cg.IL.Emit(OpCodes.Ldsfld, field);
            if (staticCall)
            {
                targetType.EmitLoadTypeDesc(cg, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
            }
            else if (targetExpr != null)
            {
                cg.ChainBuilder.Lengthen();         // for hop over ->
                cg.EmitBoxing(targetExpr.Emit(cg)); // prepare for operator invocation
            }
            else if (targetObjectPlace != null)
            {
                targetObjectPlace.EmitLoad(cg.IL);
            }
            else if (targetPlace != null)
            {
                targetPlace.EmitLoad(cg.IL);
            }
            else
            {
                Debug.Fail();
            }
            if (!classContextIsKnown)
            {
                cg.EmitLoadClassContext();
            }
            if (!fieldNameIsKnown)
            {
                cg.EmitName(fieldName /*null*/, fieldNameExpr, true, PhpTypeCode.String);
            }

            cg.MarkTransientSequencePoint();
            cg.IL.Emit(OpCodes.Callvirt, delegateType.GetMethod("Invoke"));

            cg.MarkTransientSequencePoint();

            //
            return(PhpTypeCodeEnum.FromType(returnType));
        }
Beispiel #9
0
        /// <summary>
        /// Emit call of the instance/static method. This defines the call site and call it using given parameters.
        /// </summary>
        /// <param name="cg">Current code <see cref="CodeGenerator"/>.</param>
        /// <param name="returnType">Return type of the method call determined by current access of the method call.</param>
        /// <param name="targetExpr">The method call instance expression (the target) if it is an instance method call.</param>
        /// <param name="targetType">The target type if it is a static method call.</param>
        /// <param name="methodFullName">If known at compile time, the method name. Otherwise <c>null</c>.</param>
        /// <param name="methodNameExpr">If the <paramref name="methodFullName"/> is null, this will be the expression giving the method name in run time.</param>
        /// <param name="callSignature">The call signature of the method call.</param>
        /// <returns>The resulting value type code. This value will be pushed onto the evaluation stack.</returns>
        public PhpTypeCode EmitMethodCall(
            PHP.Core.CodeGenerator /*!*/ cg, Type returnType,
            Expression /*!*/ targetExpr, DType /*!*/ targetType,
            string methodFullName, Expression methodNameExpr, CallSignature callSignature)
        {
            Debug.Assert(methodFullName != null ^ methodNameExpr != null);

            //
            bool staticCall = (targetExpr == null); // we are going to emit static method call
            //bool methodNameIsKnown = (methodFullName != null);
            //bool classContextIsKnown = (this.classContextPlace != null);

            //
            // define the call site:
            //
            var delegateType = /*System.Linq.Expressions.Expression.*/ delegateBuilder.GetDelegateType(
                MethodCallDelegateTypeArgs(
                    callSignature,
                    staticCall ? Types.DObject[0] : Types.Object[0],
                    MethodCallDelegateAdditionalArguments(staticCall, methodFullName != null, this.classContextPlace != null),
                    returnType),
                callSitesCount);    // (J) do not create dynamic delegates in dynamic modules, so they can be referenced from non-transient assemblies

            //
            var field = DefineCallSite(cg.IL, string.Format("call_{0}", methodFullName ?? "$"), delegateType, (il) =>
            {
                // <LOAD> Binder.{MethodCall|StaticMethodCall}( methodFullName, genericParamsCount, paramsCount, classContext, <returnType> )
                if (methodFullName != null)
                {
                    il.Emit(OpCodes.Ldstr, methodFullName);
                }
                else
                {
                    il.Emit(OpCodes.Ldnull);
                }
                il.LdcI4(callSignature.GenericParams.Count);
                il.LdcI4(callSignature.Parameters.Count);
                if (this.classContextPlace != null)
                {
                    this.classContextPlace.EmitLoad(il);
                }
                else
                {
                    il.Emit(OpCodes.Ldsfld, Fields.UnknownTypeDesc.Singleton);
                }

                il.Emit(OpCodes.Ldtoken, returnType);
                il.Emit(OpCodes.Call, Methods.GetTypeFromHandle);

                il.Emit(OpCodes.Call, staticCall ? Methods.Binder.StaticMethodCall : Methods.Binder.MethodCall);
            });

            //
            // call the CallSite:
            //

            // <field>.Target( <field>, <targetExpr|self>, <scriptContext>, <callSignature.EmitLoadOnEvalStack>, <targetType>?, (classContext)?, <methodNameExpr>? ):

            cg.IL.Emit(OpCodes.Ldsfld, field);
            cg.IL.Emit(OpCodes.Ldfld, field.FieldType.GetField("Target"));
            cg.IL.Emit(OpCodes.Ldsfld, field);
            if (staticCall)
            {
                cg.EmitLoadSelf();
            }
            else
            {
                EmitMethodTargetExpr(cg, targetExpr);
            }
            cg.EmitLoadScriptContext();
            EmitMethodCallParameters(cg, callSignature);
            if (staticCall)
            {
                targetType.EmitLoadTypeDesc(cg, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
            }
            if (/*!classContextIsKnown*/ this.classContextPlace == null)
            {
                cg.EmitLoadClassContext();
            }
            if (/*!methodNameIsKnown*/ methodFullName == null)
            {
                cg.EmitName(methodFullName /*null*/, methodNameExpr, true);
            }

            cg.MarkTransientSequencePoint();
            cg.IL.Emit(OpCodes.Callvirt, delegateType.GetMethod("Invoke"));

            cg.MarkTransientSequencePoint();

            //
            return(PhpTypeCodeEnum.FromType(returnType));
        }
Beispiel #10
0
        /// <summary>
        /// Create and call <see cref="CallSite"/> for getting property.
        /// </summary>
        /// <param name="cg"><see cref="CodeGenerator"/>.</param>
        /// <param name="wantRef">Wheter <see cref="PhpReference"/> is expected as the result.</param>
        /// <param name="targetExpr">The expression representing the target (object).</param>
        /// <param name="targetObjectPlace">The place representing the target (<see cref="DObject"/>) iff <paramref name="targetExpr"/> is not provided.</param>
        /// <param name="targetPlace">The place representing the target (object) iff <paramref name="targetExpr"/> and <paramref name="targetObjectPlace"/> are not provided.</param>
        /// <param name="targetType">Type of target iff we are getting property statically.</param>
        /// <param name="fieldName">The name of the field. Can be null if the name is not known at compile time (indirect).</param>
        /// <param name="fieldNameExpr">The expression used to get field name in run time (iff <paramref name="fieldName"/> is <c>null</c>.</param>
        /// <param name="issetSemantics">Wheter we are only checking if the property exists. If true, no warnings are thrown during run time.</param>
        /// <returns>Type code of the value that is pushed onto the top of the evaluation stack.</returns>
        public PhpTypeCode EmitGetProperty(
            PHP.Core.CodeGenerator/*!*/cg, bool wantRef,
            Expression targetExpr, IPlace targetObjectPlace, IPlace targetPlace, DType targetType,
            string fieldName, Expression fieldNameExpr,
            bool issetSemantics)
        {
            Debug.Assert(fieldName != null ^ fieldNameExpr != null);
            Debug.Assert(targetExpr != null || targetObjectPlace != null || targetPlace != null || targetType != null);
            
            //
            bool staticCall = (targetExpr == null && targetObjectPlace == null && targetPlace == null); // we are going to access static property
            bool fieldNameIsKnown = (fieldName != null);
            bool classContextIsKnown = (this.classContextPlace != null);

            //
            // binder flags:
            //
            Type returnType = wantRef ? Types.PhpReference[0] : Types.Object[0];
            
            //
            // define the call site:
            //

            //
            List<Type> additionalArgs = new List<Type>();
            if (!classContextIsKnown) additionalArgs.Add(Types.DTypeDesc[0]);
            if (!fieldNameIsKnown) additionalArgs.Add(Types.String[0]);

            var delegateTypeArgs = GetPropertyDelegateTypeArgs(
                staticCall ? Types.DTypeDesc[0] : ((targetObjectPlace != null) ? Types.DObject[0] : Types.Object[0]),   // DTypeDesc of static field's declaring type || DObject if field called on DObject known at compile time || otherwise object
                additionalArgs.ToArray(),
                returnType);

            var delegateType = /*System.Linq.Expressions.Expression.*/delegateBuilder.GetDelegateType(delegateTypeArgs, callSitesCount);    // (J) do not create dynamic delegates in dynamic modules, so they can be referenced from non-transient assemblies

            //
            var field = DefineCallSite(cg.IL, string.Format("get{0}_{1}", wantRef ? "ref" : string.Empty, fieldName ?? "$"), delegateType, (il) =>
            {
                // <LOAD> Binder.{GetProperty|GetStaticProperty}( fieldName, classContext, issetSemantics, <returnType> )
                if (fieldName != null) il.Emit(OpCodes.Ldstr, fieldName); else il.Emit(OpCodes.Ldnull);
                if (this.classContextPlace != null) this.classContextPlace.EmitLoad(il); else il.Emit(OpCodes.Ldsfld, Fields.UnknownTypeDesc.Singleton);
                il.LoadBool(issetSemantics);

                il.Emit(OpCodes.Ldtoken, returnType);
                il.Emit(OpCodes.Call, Methods.GetTypeFromHandle);

                il.Emit(OpCodes.Call, staticCall ? Methods.Binder.StaticGetProperty : Methods.Binder.GetProperty);
            });

            //
            // call the CallSite:
            //

            // <field>.Target( <field>, <targetExpr|targetType>, (classContext)?, <methodNameExpr>? ):

            cg.IL.Emit(OpCodes.Ldsfld, field);
            cg.IL.Emit(OpCodes.Ldfld, field.FieldType.GetField("Target"));
            cg.IL.Emit(OpCodes.Ldsfld, field);
            if (staticCall) targetType.EmitLoadTypeDesc(cg, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
            else if (targetExpr != null)
            {
                cg.ChainBuilder.Lengthen(); // for hop over ->
                cg.EmitBoxing(targetExpr.Emit(cg)); // prepare for operator invocation
            }
            else if (targetObjectPlace != null) targetObjectPlace.EmitLoad(cg.IL);
            else if (targetPlace != null) targetPlace.EmitLoad(cg.IL);
            else Debug.Fail();
            if (!classContextIsKnown) cg.EmitLoadClassContext();
            if (!fieldNameIsKnown) cg.EmitName(fieldName/*null*/, fieldNameExpr, true, PhpTypeCode.String);

            cg.MarkTransientSequencePoint();
            cg.IL.Emit(OpCodes.Callvirt, delegateType.GetMethod("Invoke"));

            cg.MarkTransientSequencePoint();
            
            //
            return PhpTypeCodeEnum.FromType(returnType);
        }
Beispiel #11
0
        /// <summary>
        /// Emit call of the instance/static method. This defines the call site and call it using given parameters.
        /// </summary>
        /// <param name="cg">Current code <see cref="CodeGenerator"/>.</param>
        /// <param name="returnType">Return type of the method call determined by current access of the method call.</param>
        /// <param name="targetExpr">The method call instance expression (the target) if it is an instance method call.</param>
        /// <param name="targetType">The target type if it is a static method call.</param>
        /// <param name="methodFullName">If known at compile time, the method name. Otherwise <c>null</c>.</param>
        /// <param name="methodNameExpr">If the <paramref name="methodFullName"/> is null, this will be the expression giving the method name in run time.</param>
        /// <param name="callSignature">The call signature of the method call.</param>
        /// <returns>The resulting value type code. This value will be pushed onto the evaluation stack.</returns>
        public PhpTypeCode EmitMethodCall(
            PHP.Core.CodeGenerator/*!*/cg, Type returnType,
            Expression/*!*/targetExpr, DType/*!*/targetType,
            string methodFullName, Expression methodNameExpr, CallSignature callSignature)
        {
            Debug.Assert(methodFullName != null ^ methodNameExpr != null);          

            //
            bool staticCall = (targetExpr == null); // we are going to emit static method call
            //bool methodNameIsKnown = (methodFullName != null);
            //bool classContextIsKnown = (this.classContextPlace != null);

            //
            // define the call site:
            //
            var delegateType = /*System.Linq.Expressions.Expression.*/delegateBuilder.GetDelegateType(
                MethodCallDelegateTypeArgs(
                    callSignature,
                    staticCall ? Types.DObject[0] : Types.Object[0],
                    MethodCallDelegateAdditionalArguments(staticCall, methodFullName != null, this.classContextPlace != null),
                    returnType),
                callSitesCount);    // (J) do not create dynamic delegates in dynamic modules, so they can be referenced from non-transient assemblies

            //
            var field = DefineCallSite(cg.IL, string.Format("call_{0}", methodFullName ?? "$"), delegateType, (il) =>
            {
                // <LOAD> Binder.{MethodCall|StaticMethodCall}( methodFullName, genericParamsCount, paramsCount, classContext, <returnType> )
                if (methodFullName != null) il.Emit(OpCodes.Ldstr, methodFullName); else il.Emit(OpCodes.Ldnull);
                il.LdcI4(callSignature.GenericParams.Count);
                il.LdcI4(callSignature.Parameters.Count);
                if (this.classContextPlace != null) this.classContextPlace.EmitLoad(il); else il.Emit(OpCodes.Ldsfld, Fields.UnknownTypeDesc.Singleton);

                il.Emit(OpCodes.Ldtoken, returnType);
                il.Emit(OpCodes.Call, Methods.GetTypeFromHandle);
                
                il.Emit(OpCodes.Call, staticCall ? Methods.Binder.StaticMethodCall : Methods.Binder.MethodCall);
            });

            //
            // call the CallSite:
            //

            // <field>.Target( <field>, <targetExpr|self>, <scriptContext>, <callSignature.EmitLoadOnEvalStack>, <targetType>?, (classContext)?, <methodNameExpr>? ):

            cg.IL.Emit(OpCodes.Ldsfld, field);
            cg.IL.Emit(OpCodes.Ldfld, field.FieldType.GetField("Target"));
            cg.IL.Emit(OpCodes.Ldsfld, field);
            if (staticCall) cg.EmitLoadSelf(); else EmitMethodTargetExpr(cg, targetExpr);
            cg.EmitLoadScriptContext();
            EmitMethodCallParameters(cg, callSignature);
            if (staticCall) targetType.EmitLoadTypeDesc(cg, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
            if (/*!classContextIsKnown*/this.classContextPlace == null) cg.EmitLoadClassContext();
            if (/*!methodNameIsKnown*/methodFullName == null) cg.EmitName(methodFullName/*null*/, methodNameExpr, true);
            
            cg.MarkTransientSequencePoint();
            cg.IL.Emit(OpCodes.Callvirt, delegateType.GetMethod("Invoke"));
            
            cg.MarkTransientSequencePoint();
            
            //
            return PhpTypeCodeEnum.FromType(returnType);
        }
Beispiel #12
0
        internal override PhpTypeCode EmitCall(CodeGenerator/*!*/ codeGenerator, string fallbackQualifiedName, CallSignature callSignature,
            IPlace instance, bool runtimeVisibilityCheck, int overloadIndex, DType type, Position position,
            AccessType access, bool callVirt)
		{
            if (IsStatic != (instance == null) || runtimeVisibilityCheck)
			{
                Expression targetExpression = null;
                if (instance != null)
                {
                    targetExpression = ExpressionPlace.GetExpression(instance); // the instance expression, $this would be determined in runtime
                    Debug.Assert(targetExpression != null || instance == IndexedPlace.ThisArg,
                        "Unexpected instance IPlace type" + this.Name.Value);
                }

                // call the operator if we could not provide an appropriate instance or the visibility has to be checked:
                return codeGenerator.EmitRoutineOperatorCall(this.UsesLateStaticBinding ? type : this.DeclaringType, targetExpression, this.FullName, fallbackQualifiedName, null, callSignature, access);
			}

            Debug.Assert(IsStatic == (instance == null));

            if (IsStatic) callVirt = false; // never call static method virtually
            
			ILEmitter il = codeGenerator.IL;
			bool args_aware = (Properties & RoutineProperties.IsArgsAware) != 0;
            var constructedType = type as ConstructedType;

            // load the instance reference if we have one:
            // Just here we need RealObject if possible. When calling CLR method on $this,
            // Phalanger has "this.<proxy>" in "codeGenerator.SelfPlace". We need just "this".
			EmitLoadInstanceUnwrapped(codeGenerator, instance);

            // arg-full overload may not be present in the case of classes declared Class Library where
			// we do not require the user to specify both overloads
			if (args_aware || ArgFullInfo == null)
			{
				// args-aware routines //
                Debug.Assert(callVirt == false, "Cannot call ArgLess stub virtually!");

				// all arg-less stubs have the 'instance' parameter
				if (instance == null) il.Emit(OpCodes.Ldnull);

				// emits load of parameters to the PHP stack:
				callSignature.EmitLoadOnPhpStack(codeGenerator);

                // CALL <routine>(context.Stack)
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Ldfld, Fields.ScriptContext_Stack);

                if (this.UsesLateStaticBinding)
                {
                    // <stack>.LateStaticBindType = <type>
                    il.Emit(OpCodes.Dup);
                    type.EmitLoadTypeDesc(codeGenerator, ResolveTypeFlags.None);
                    il.Emit(OpCodes.Stfld, Fields.PhpStack_LateStaticBindType);
                }

                il.Emit(OpCodes.Call, DType.MakeConstructed(ArgLessInfo, constructedType));

				// arg-less overload's return value has to be type-cast to a reference if it returns one:
				if (signature == null || signature.AliasReturn)
					codeGenerator.IL.Emit(OpCodes.Castclass, typeof(PhpReference));
			}
			else
			{
				// args-unaware routines //

				// CALL <routine>(context, <argumens>)
				codeGenerator.EmitLoadScriptContext();
				callSignature.EmitLoadOnEvalStack(codeGenerator, this);
                il.Emit(callVirt ? OpCodes.Callvirt : OpCodes.Call, DType.MakeConstructed(ArgFullInfo, constructedType));
			}

			// marks transient sequence point just after the call:
			codeGenerator.MarkTransientSequencePoint();

			return ((signature == null || signature.AliasReturn) ? PhpTypeCode.PhpReference : PhpTypeCode.Object);
		}