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); } }
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); } }
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); }
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); }; }
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; } }
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); }
/// <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> /// 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)); }
/// <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> /// 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); }
/// <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); }
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); }