/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal void Emit(CodeGenerator/*!*/ codeGenerator) { // TODO: improve codeGenerator.EnterGlobalCodeDeclaration(this.varTable, labels, sourceUnit); // custom body prolog emittion: PluginHandler.EmitBeforeBody(codeGenerator.IL, statements); // if (codeGenerator.CompilationUnit.IsTransient) { codeGenerator.DefineLabels(labels); codeGenerator.ChainBuilder.Create(); foreach (Statement statement in statements) statement.Emit(codeGenerator); codeGenerator.ChainBuilder.End(); // return + appended file emission: codeGenerator.EmitRoutineEpilogue(this, true); } #if !SILVERLIGHT else if (codeGenerator.CompilationUnit.IsPure) { codeGenerator.ChainBuilder.Create(); foreach (Statement statement in statements) { // skip empty statements in global code (they emit sequence points, which is undesirable): if (!(statement is EmptyStmt)) statement.Emit(codeGenerator); } codeGenerator.ChainBuilder.End(); } else { ScriptCompilationUnit unit = (ScriptCompilationUnit)codeGenerator.CompilationUnit; ILEmitter il = codeGenerator.IL; if (codeGenerator.Context.Config.Compiler.Debug) { codeGenerator.MarkSequencePoint(1, 1, 1, 2); il.Emit(OpCodes.Nop); } codeGenerator.DefineLabels(labels); // CALL <self>.<Declare>(context); codeGenerator.EmitLoadScriptContext(); il.Emit(OpCodes.Call, unit.ScriptBuilder.DeclareHelperBuilder); // IF (<is main script>) CALL <prepended script>.Main() if (prependedInclusion != null) prependedInclusion.Emit(codeGenerator); codeGenerator.ChainBuilder.Create(); foreach (Statement statement in statements) statement.Emit(codeGenerator); codeGenerator.ChainBuilder.End(); // return + appended file emission: codeGenerator.EmitRoutineEpilogue(this, false); } #endif codeGenerator.LeaveGlobalCodeDeclaration(); }
/// <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); }