Example #1
0
		public NewEx(Position position, TypeRef/*!*/ classNameRef, List<ActualParam>/*!*/ parameters)
			: base(position)
		{
			Debug.Assert(classNameRef != null && parameters != null);
			this.classNameRef = classNameRef;
			this.callSignature = new CallSignature(parameters, TypeRef.EmptyList);
		}
Example #2
0
		public FunctionCall(Position position, List<ActualParam>/*!*/ parameters, List<TypeRef>/*!*/ genericParams)
			: base(position)
		{
			Debug.Assert(parameters != null);

			this.callSignature = new CallSignature(parameters, genericParams);
		}
Example #3
0
        public FunctionCall(Text.Span span, Text.Span nameSpan, List<ActualParam>/*!*/ parameters, List<TypeRef>/*!*/ genericParams)
			: base(span)
		{
			Debug.Assert(parameters != null);

			this.callSignature = new CallSignature(parameters, genericParams);
            this.NameSpan = nameSpan;
		}
Example #4
0
            public void Analyze(CallSignature/*!*/node, Analyzer/*!*/ analyzer, RoutineSignature/*!*/ signature, ExInfoFromParent info, bool isBaseCtorCallConstrained)
            {
                // generic:

                foreach (var p in node.GenericParams)
                    TypeRefHelper.Analyze(p, analyzer);

                // regular:

                analyzer.EnterActualParams(signature, node.Parameters.Count);

                foreach (var p in node.Parameters)
                    p.NodeCompiler<ActualParamCompiler>().Analyze(p, analyzer, isBaseCtorCallConstrained);

                analyzer.LeaveActualParams();
            }
Example #5
0
		internal override int ResolveOverload(Analyzer/*!*/ analyzer, CallSignature callSignature, Position position,
			out RoutineSignature overloadSignature)
		{
			if (callSignature.GenericParams.Count > 0)
			{
				analyzer.ErrorSink.Add(Errors.GenericCallToLibraryFunction, analyzer.SourceUnit, position);
				callSignature = new CallSignature(callSignature.Parameters, TypeRef.EmptyList);
			}

			bool exact_match;
			int result = ResolveOverload(callSignature.Parameters.Count, out exact_match);

			if (!exact_match)
			{
				// library function with wrong number of actual arguments:
				analyzer.ErrorSink.Add(Errors.InvalidArgumentCountForFunction, analyzer.SourceUnit, position, FullName);
			}

			overloadSignature = overloads[result];
			return result;
		}
Example #6
0
		internal void EmitNewOperator(string typeFullName, TypeRef typeNameRef, DType type, CallSignature callSignature)
		{
            DebugHelper.AssertNonNull(1, typeFullName, typeNameRef, type);

			// prepare stack frame for the constructor:
			callSignature.EmitLoadOnPhpStack(this);

			// CALL Operators.New(<type desc>, <context type desc>, <context>);
			EmitLoadTypeDesc(typeFullName, typeNameRef, type, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
			this.EmitLoadClassContext();
			this.EmitLoadScriptContext();
			this.EmitLoadNamingContext();
			il.Emit(OpCodes.Call, Methods.Operators.New);
		}
Example #7
0
            /// <summary>
            /// Emits load of optional parameters array on the evaluation stack.
            /// </summary>
            /// <param name="node">Instance.</param>
            /// <param name="builder">An overloads builder.</param>
            /// <param name="start">An index of the first optional parameter to be loaded into the array (indices start from 0).</param>
            /// <param name="param">
            /// A <see cref="ParameterInfo"/> of the formal parameter of the target method where the array will be passed.
            /// This information influences conversions all optional parameters.
            /// </param>
            /// <param name="optArgCount">Optional argument count (unused).</param>
            public void EmitLibraryLoadOptArguments(CallSignature/*!*/node, OverloadsBuilder/*!*/ builder, int start, ParameterInfo/*!*/ param, IPlace optArgCount)
            {
                Debug.Assert(start >= 0 && builder != null && param != null && builder.Aux is CodeGenerator);

                ILEmitter il = builder.IL;
                Type elem_type = param.ParameterType.GetElementType();
                Type array_type = elem_type.MakeArrayType();

                // NEW <alem_type>[<parameters count - start>]
                il.LdcI4(node.Parameters.Count - start);
                il.Emit(OpCodes.Newarr, elem_type);

                // loads each optional parameter into the appropriate bucket of the array:
                for (int i = start; i < node.Parameters.Count; i++)
                {
                    // <arr>[i - start]
                    il.Emit(OpCodes.Dup);
                    il.LdcI4(i - start);

                    // <parameter value>
                    object type_or_value = EmitLibraryLoadArgument(node, il, i, builder.Aux, param);
                    builder.EmitArgumentConversion(elem_type, type_or_value, false, param, 3);

                    // <arr>[i - start] = <parameter value>;
                    il.Stelem(elem_type);
                }

                // <arr>
            }
Example #8
0
 /// <summary>
 /// Emits IL instructions that load actual parameters on the evaluation stack.
 /// </summary>
 /// <param name="node">Instance.</param>
 /// <param name="codeGenerator">Code generator.</param>
 /// <param name="routine">PHP method being called.</param>
 /// <remarks>
 /// <para>
 /// The function has mandatory and optional formal arguments.
 /// Mandatory arguments are those formal arguments which are not preceded by 
 /// any formal argument with default value. The others are optional.
 /// If a formal argument without default value is declared beyond the last mandatory argument
 /// it is treated as optional one by the caller. The callee checks this and throws warning.
 /// </para>
 /// Missing arguments handling:
 /// <list type="bullet">
 ///   <item>missing mandatory argument - WARNING; LOAD(null);</item>
 ///   <item>missing optional argument - LOAD(Arg.Default);</item>
 ///   <item>superfluous arguments are ignored</item>
 /// </list>
 /// </remarks>
 public void EmitLoadOnEvalStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
 {
     EmitLoadTypeArgsOnEvalStack(node, codeGenerator, routine);
     EmitLoadArgsOnEvalStack(node, codeGenerator, routine);
 }
Example #9
0
            internal void EmitLoadArgsOnEvalStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
            {
                ILEmitter il = codeGenerator.IL;

                int mandatory_count = (routine.Signature != null) ? routine.Signature.MandatoryParamCount : 0;
                int formal_count = (routine.Signature != null) ? routine.Signature.ParamCount : 0;
                int actual_count = node.Parameters.Count;
                PhpTypeCode param_type;

                // loads all actual parameters which are not superfluous:
                for (int i = 0; i < Math.Min(actual_count, formal_count); i++)
                {
                    var p = node.Parameters[i];
                    codeGenerator.EmitBoxing(param_type = p.NodeCompiler<ActualParamCompiler>().Emit(p, codeGenerator));

                    // Actual param emitter should emit "boxing" to a reference if its access type is ReadRef.
                    // That's why no operation is needed here and references should match.
                    Debug.Assert((routine.Signature == null || routine.Signature.IsAlias(i)) == (param_type == PhpTypeCode.PhpReference));
                }

                // loads missing mandatory arguments:
                for (int i = actual_count; i < mandatory_count; i++)
                {
                    // CALL PhpException.MissingArgument(<i+1>,<name>);
                    il.LdcI4(i + 1);
                    il.Emit(OpCodes.Ldstr, routine.FullName);
                    codeGenerator.EmitPhpException(Methods.PhpException.MissingArgument);

                    // LOAD null;
                    if (routine.Signature.IsAlias(i))
                        il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
                    else
                        il.Emit(OpCodes.Ldnull);
                }

                // loads missing optional arguments:
                for (int i = Math.Max(mandatory_count, actual_count); i < formal_count; i++)
                {
                    // LOAD Arg.Default;
                    il.Emit(OpCodes.Ldsfld, Fields.Arg_Default);
                }
            }
Example #10
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)
		{
			return codeGenerator.EmitRoutineOperatorCall(null, null, FullName, fallbackQualifiedName, null, callSignature, access);
		}
Example #11
0
		internal override int ResolveOverload(Analyzer/*!*/ analyzer, CallSignature callSignature, Position position,
			out RoutineSignature overloadSignature)
		{
			// no ctor defined => default is to be used => should have no parameters;
			// do not report errors if the declaring type is open type (constructed or a generic parameter);
			if (declaringType.IsDefinite && IsConstructor && declaringType.IsClosed && callSignature.Parameters.Count > 0)
			{
				analyzer.ErrorSink.Add(Warnings.NoCtorDefined, analyzer.SourceUnit, position, declaringType.FullName);
				declaringType.ReportError(analyzer.ErrorSink, Warnings.RelatedLocation);
			}

			overloadSignature = UnknownSignature.Default;
			return 0;
		}
Example #12
0
 internal override int ResolveOverload(Analyzer analyzer, CallSignature callSignature, Position position, out RoutineSignature overloadSignature)
 {
     overloadSignature = signature;
     return 0;
 }
Example #13
0
		internal override int ResolveOverload(Analyzer/*!*/ analyzer, CallSignature callSignature, Position position,
			out RoutineSignature overloadSignature)
		{
			overloadSignature = UnknownSignature.Default;
			return 0;
		}
Example #14
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 DEBUG_DYNAMIC_STUBS
			
			MethodBuilder mb = codeGenerator.IL.TypeBuilder.DefineMethod(DeclaringType.FullName + "::" + FullName,
				MethodAttributes.PrivateScope | MethodAttributes.Static, typeof(object), Types.Object_PhpStack);

			ILEmitter il = new ILEmitter(mb);
			IndexedPlace instance2 = new IndexedPlace(PlaceHolder.Argument, 0);
			IndexedPlace stack = new IndexedPlace(PlaceHolder.Argument, 1);

			EmitArglessStub(il, stack, instance2);
			
#endif
            Debug.Assert(instance == null || instance is ExpressionPlace || instance == IndexedPlace.ThisArg);
            Debug.Assert(fallbackQualifiedName == null);
			return codeGenerator.EmitRoutineOperatorCall(DeclaringType, ExpressionPlace.GetExpression(instance), this.FullName, null, null, callSignature, access);
		}
Example #15
0
		internal override int ResolveOverload(Analyzer/*!*/ analyzer, CallSignature callSignature, Position position,
			out RoutineSignature/*!*/ overloadSignature)
		{
			if (overloads.Count == 0)
			{
				if (DeclaringType.TypeDesc is ClrDelegateDesc)
				{
					overloadSignature = UnknownSignature.Delegate;
					return 0;
				}

				// structures without ctor:
				if (DeclaringType.TypeDesc.RealType.IsValueType)
				{
					overloadSignature = UnknownSignature.Default;
					return 0;
				}

				Debug.Assert(this.IsConstructor, "Only constructors can have no overload.");
				overloadSignature = UnknownSignature.Default;
				return DRoutine.InvalidOverloadIndex;
			}

			int i = 0;
			bool found = false;

			Overload overload;
			while (i < overloads.Count && (overload = overloads[i]).MandatoryParamCount <= callSignature.Parameters.Count)
			{
				if (overload.MandatoryParamCount == callSignature.Parameters.Count ||
					(overload.Flags & OverloadFlags.IsVararg) != 0)
				{
					found = true;
					break;
				}

				i++;
			}

			// TODO: by type resolving
			// evaluate arguments?

			if (!found)
			{
				analyzer.ErrorSink.Add(Warnings.InvalidArgumentCountForMethod, analyzer.SourceUnit, position,
					this.DeclaringType.FullName, this.FullName);

				if (i > 0) i--;
				overloadSignature = overloads[i];
				return i;
			}

			overloadSignature = overloads[i];
			return i;
		}
Example #16
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)
		{
			Overload overload = overloads[overloadIndex];
			Statistics.AST.AddLibraryFunctionCall(FullName, overload.ParamCount);

            if ((overload.Flags & OverloadFlags.NotSupported) != 0)
            {
                codeGenerator.IL.Emit(OpCodes.Ldstr, FullName);
                codeGenerator.IL.Emit(OpCodes.Call, Methods.PhpException.FunctionNotSupported_String);
                if (codeGenerator.Context.Config.Compiler.Debug)
                    codeGenerator.IL.Emit(OpCodes.Nop);

                return OverloadsBuilder.EmitLoadDefault(codeGenerator.IL, overload.Method);
            }

            //IPlace return_value;
            IPlace script_context = null;
			IPlace opt_arg_count = null;
            IPlace self_ref = null;
            IPlace rt_variables = null;
			IPlace naming_context = null;
            IPlace class_context = null;

            // 

			// captures eval info:
			if ((options & FunctionImplOptions.CaptureEvalInfo) != 0)
			{
				codeGenerator.EmitEvalInfoCapture(position.FirstLine, position.FirstColumn, false);
			}

            // current ScriptContext:
            if ((overload.Flags & OverloadFlags.NeedsScriptContext) != 0)
            {
                script_context = codeGenerator.ScriptContextPlace;
            }

			// number of optional arguments passed to a function (empty or a literal place):
			if ((overload.Flags & OverloadFlags.IsVararg) != 0)
			{
				opt_arg_count = new IndexedPlace(PlaceHolder.None, callSignature.Parameters.Count - overload.ParamCount);
			}

			// this reference?
			if ((options & FunctionImplOptions.NeedsThisReference) != 0)
			{
				self_ref = codeGenerator.SelfPlace;
			}

			// run-time variables table:
			if ((options & FunctionImplOptions.NeedsVariables) != 0)
			{
				rt_variables = codeGenerator.RTVariablesTablePlace;
			}

			// naming context
			if ((options & FunctionImplOptions.NeedsNamingContext) != 0)
			{
                naming_context =
                    (codeGenerator.SourceUnit.NamingContextFieldBuilder != null) ?
                        (IPlace)new Place(null, codeGenerator.SourceUnit.NamingContextFieldBuilder) : (IPlace)LiteralPlace.Null;
			}

            // call context
            if ((options & FunctionImplOptions.NeedsClassContext) != 0)
            {
                class_context = codeGenerator.TypeContextPlace;
            }


			OverloadsBuilder.ParameterLoader param_loader = new OverloadsBuilder.ParameterLoader(callSignature.EmitLibraryLoadArgument);
			OverloadsBuilder.ParametersLoader opt_param_loader = new OverloadsBuilder.ParametersLoader(callSignature.EmitLibraryLoadOptArguments);

			OverloadsBuilder builder = new OverloadsBuilder(
				codeGenerator.Context.Config.Compiler.Debug,
				null,                           // PHP stack is not used
				param_loader,                   // value parameter loader
				param_loader,                   // reference parameter loader
				opt_param_loader);              // optional parameter array loader

			// setups builder:
			builder.Aux = codeGenerator;
			builder.IL = codeGenerator.IL;
			builder.FunctionName = name;

			// emits overload call:
            Type/*!*/return_type = builder.EmitOverloadCall(overload.Method, overload.RealParameters, overload.ParamCount,
				script_context, rt_variables, naming_context, class_context, opt_arg_count, self_ref, access == AccessType.None);

            //if (return_value != null)
            //{
            //    // loads value on the stack:
            //    return_value.EmitLoad(codeGenerator.IL);

            //    return PhpTypeCodeEnum.FromType(return_value.PlaceType);
            //}
            if (return_type != Types.Void)
            {
                return PhpTypeCodeEnum.FromType(return_type);
            }
            else
            {
                if (codeGenerator.Context.Config.Compiler.Debug)
                {
                    codeGenerator.IL.Emit(OpCodes.Nop);
                }
                return PhpTypeCode.Void;
            }
		}
Example #17
0
            /// <summary>
            /// Builds <see cref="ArrayEx"/> with call signature parameters.
            /// </summary>
            /// <returns></returns>
            public ArrayEx/*!*/BuildPhpArray(CallSignature/*!*/node)
            {
                Debug.Assert(node.GenericParams == null || node.GenericParams.Count == 0);

                List<Item> arrayItems = new List<Item>(node.Parameters.Count);
                var pos = Text.Span.Invalid;

                foreach (var p in node.Parameters)
                {
                    arrayItems.Add(new ValueItem(null, p.Expression));
                    if (pos.IsValid)
                        pos = p.Span;
                    else
                        pos = Text.Span.FromBounds(pos.Start, p.Span.End);
                }

                return new ArrayEx(pos, arrayItems);
            }
Example #18
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)
		{
            Debug.Assert(instance == null || instance is ExpressionPlace);
            Debug.Assert(fallbackQualifiedName == null);

            return codeGenerator.EmitRoutineOperatorCall(declaringType, ExpressionPlace.GetExpression(instance), FullName, null, null, callSignature, access);

			// TODO: check operators: should deep-copy return value if PhpRoutine is called
		}
Example #19
0
            /// <summary>
            /// Emits IL instructions that load actual parameters and optionally add a new stack frame to
            /// current <see cref="PHP.Core.ScriptContext.Stack"/>.
            /// </summary>
            /// <param name="node">Instance.</param>
            /// <param name="codeGenerator">Code generator.</param>
            /// <remarks>
            /// Nothing is expected on the evaluation stack. Nothing is left on the evaluation stack.
            /// </remarks>
            public void EmitLoadOnPhpStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator)
            {
                List<ActualParam> parameters = node.Parameters;
                List<TypeRef> genericParams = node.GenericParams;

                PhpStackBuilder.EmitAddFrame(codeGenerator.IL, codeGenerator.ScriptContextPlace, genericParams.Count, parameters.Count,
                  delegate(ILEmitter il, int i)
                  {
                      // generic arguments:
                      genericParams[i].EmitLoadTypeDesc(codeGenerator, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
                  },
                  delegate(ILEmitter il, int i)
                  {
                      // regular arguments:
                      var p = parameters[i];
                      codeGenerator.EmitBoxing(p.NodeCompiler<ActualParamCompiler>().Emit(p, codeGenerator));
                  }
                );
            }
Example #20
0
 /// <summary>
 /// Helper method, loads parameters onto evaluation stack.
 /// </summary>
 private static void EmitMethodCallParameters(PHP.Core.CodeGenerator/*!*/cg, CallSignature callSignature)
 {
     foreach (var t in callSignature.GenericParams) t.EmitLoadTypeDesc(cg, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors); // load DTypeDescs on the stack
     foreach (var p in callSignature.Parameters) { cg.EmitBoxing(p.Emit(cg)); }  // load boxed args on the stack            
 }
Example #21
0
            internal void EmitLoadTypeArgsOnEvalStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
            {
                ILEmitter il = codeGenerator.IL;

                int mandatory_count = (routine.Signature != null) ? routine.Signature.MandatoryGenericParamCount : 0;
                int formal_count = (routine.Signature != null) ? routine.Signature.GenericParamCount : 0;
                int actual_count = node.GenericParams.Count;

                // loads all actual parameters which are not superfluous:
                for (int i = 0; i < Math.Min(actual_count, formal_count); i++)
                    node.GenericParams[i].EmitLoadTypeDesc(codeGenerator, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);

                // loads missing mandatory arguments:
                for (int i = actual_count; i < mandatory_count; i++)
                {
                    // CALL PhpException.MissingTypeArgument(<i+1>,<name>);
                    il.LdcI4(i + 1);
                    il.Emit(OpCodes.Ldstr, routine.FullName);
                    codeGenerator.EmitPhpException(Methods.PhpException.MissingTypeArgument);

                    // LOAD DTypeDesc.ObjectTypeDesc;
                    il.Emit(OpCodes.Ldsfld, Fields.DTypeDesc.ObjectTypeDesc);
                }

                // loads missing optional arguments:
                for (int i = Math.Max(mandatory_count, actual_count); i < formal_count; i++)
                {
                    // LOAD Arg.DefaultType;
                    il.Emit(OpCodes.Ldsfld, Fields.Arg_DefaultType);
                }
            }
Example #22
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);
        }
Example #23
0
            /// <summary>
            /// Emits parameter loading.
            /// </summary>
            /// <param name="node">Instance.</param>
            /// <param name="il">Emitter.</param>
            /// <param name="index">The index of the parameter starting from 0.</param>
            /// <param name="codeGenerator">Code generator.</param>
            /// <param name="param">Target <see cref="ParameterInfo"/>.</param>
            /// <returns>The type of the actual argument or its value if it is a leteral.</returns>
            public object EmitLibraryLoadArgument(CallSignature/*!*/node, ILEmitter/*!*/ il, int index, object/*!*/ codeGenerator, ParameterInfo param)
            {
                Debug.Assert(codeGenerator != null);
                Debug.Assert(index < node.Parameters.Count, "Missing arguments prevents code generation");

                // returns value if the parameter is evaluable at compile time:
                if (node.Parameters[index].Expression.HasValue())
                    return node.Parameters[index].Expression.GetValue();

                // emits parameter evaluation:
                var p = node.Parameters[index];
                return PhpTypeCodeEnum.ToType(p.NodeCompiler<ActualParamCompiler>().Emit(p, (CodeGenerator)codeGenerator, PhpRwAttribute.IsDefined(param)));
            }
Example #24
0
        /// <summary>
        /// Make an array containing types for CallSite generic type used for method invocation.
        /// </summary>
        /// <param name="callSignature">The method call signature.</param>
        /// <param name="targetType">The type of value passed as method target (object for instance method, DTypeDesc for static method).</param>
        /// <param name="additionalArgs">Additional arguments added after the target expression.</param>
        /// <param name="returnType">The return value type.</param>
        /// <returns></returns>
        private Type[]/*!*/MethodCallDelegateTypeArgs(CallSignature callSignature, Type/*!*/targetType, IEnumerable<Type> additionalArgs, Type/*!*/returnType)
        {
            List<Type> typeArgs = new List<Type>(callSignature.Parameters.Count + callSignature.GenericParams.Count + 6);

            // Type[]{CallSite, <targetType>, ScriptContext, {argsType}, (DTypeDesc)?, (DTypeDesc)?, (object)?, <returnType>}:

            // CallSite:
            typeArgs.Add(Types.CallSite[0]);

            // object instance / target type:
            typeArgs.Add(targetType);

            // ScriptContext:
            typeArgs.Add(Types.ScriptContext[0]);

            // parameters:
            foreach (var t in callSignature.GenericParams) typeArgs.Add(Types.DTypeDesc[0]);
            foreach (var p in callSignature.Parameters) typeArgs.Add(Types.Object[0]);

            // DTypeDesc: (in case of static method call)
            // class context (if not known at compile time):
            // method name (if now known at compile time):
            if (additionalArgs != null) typeArgs.AddRange(additionalArgs);

            // return type:
            typeArgs.Add(returnType);

            //
            return typeArgs.ToArray();
        }
Example #25
0
 public CustomAttribute(Text.Span span, QualifiedName qualifiedName, List<ActualParam>/*!*/ parameters,
         List<NamedActualParam>/*!*/ namedParameters)
     : base(span)
 {
     this.qualifiedName = qualifiedName;
     this.namedParameters = namedParameters;
     this.callSignature = new CallSignature(parameters, TypeRef.EmptyList);
 }
Example #26
0
 /// <summary>
 /// Emits the call of DRoutine.
 /// </summary>
 /// <param name="codeGenerator">Used code generator.</param>
 /// <param name="fallbackQualifiedName">Fallback function name to call, if the origin one does not exist.</param>
 /// <param name="callSignature">Call signature.</param>
 /// <param name="instance">IPlace containing instance of object in case of non static method call.</param>
 /// <param name="runtimeVisibilityCheck">True to check visibility during runtime.</param>
 /// <param name="overloadIndex">The index of overload (used in case of PhpLibraryFunction).</param>
 /// <param name="type">Type used to resolve this routine.</param>
 /// <param name="position">Position of the call expression.</param>
 /// <param name="access">Access type of the routine call. Used to determine wheter the caller does not need return value. In such case additional operations (like CastToFalse) should not be emitted.</param>
 /// <param name="callVirt">True to call the instance method virtually, using <c>.callvirt</c> instruction. This is used when current routine is non-static routine called on instance, not statically.</param>
 /// <returns>PhpTypeCode of the resulting value that is on the top of the evaluation stack after the DRoutine call. Value types are not boxed.</returns>
 internal abstract PhpTypeCode EmitCall(CodeGenerator/*!*/ codeGenerator, string fallbackQualifiedName, CallSignature callSignature,
     IPlace instance, bool runtimeVisibilityCheck, int overloadIndex, DType type, Position position,
     AccessType access, bool callVirt);
Example #27
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;
        }
Example #28
0
            /// <summary>
            /// Gets true if all the Parameters (after the analysis) have the value and could be evaluated during the compilation time.
            /// </summary>
            public bool AllParamsHaveValue(CallSignature/*!*/node)
            {
                foreach (var p in node.Parameters)
                    if (!p.Expression.HasValue())
                        return false;

                return true;
            }
Example #29
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)
 {
     // calling closured function directly is not handled yet (not needed without type inference),
     // anyway in future, this will be probably handled thru Closure::__invoke( instance, stack ).
     throw new NotImplementedException();
 }
Example #30
0
		/// <summary>
		/// Finds most suitable overload. Returns <see cref="InvalidOverloadIndex"/> and 
		/// <see cref="UnknownSignature.Default"/> in <c>overloadSignature</c> if no suitable overload exists.
		/// </summary>
		internal abstract int ResolveOverload(Analyzer/*!*/ analyzer, CallSignature callSignature, Position position,
			out RoutineSignature overloadSignature);