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); }
public FunctionCall(Position position, List<ActualParam>/*!*/ parameters, List<TypeRef>/*!*/ genericParams) : base(position) { Debug.Assert(parameters != null); this.callSignature = new CallSignature(parameters, genericParams); }
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; }
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(); }
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; }
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); }
/// <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> }
/// <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); }
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); } }
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); }
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; }
internal override int ResolveOverload(Analyzer analyzer, CallSignature callSignature, Position position, out RoutineSignature overloadSignature) { overloadSignature = signature; return 0; }
internal override int ResolveOverload(Analyzer/*!*/ analyzer, CallSignature callSignature, Position position, out RoutineSignature overloadSignature) { overloadSignature = UnknownSignature.Default; return 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); }
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; }
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; } }
/// <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); }
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 }
/// <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)); } ); }
/// <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 }
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); } }
/// <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); }
/// <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))); }
/// <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(); }
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); }
/// <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);
/// <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; }
/// <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; }
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(); }
/// <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);