Exemplo n.º 1
0
		/// <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();
		}
Exemplo n.º 2
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));
        }
Exemplo n.º 3
0
        internal override PhpTypeCode EmitCall(CodeGenerator/*!*/ codeGenerator, string fallbackQualifiedName, CallSignature callSignature,
            IPlace instance, bool runtimeVisibilityCheck, int overloadIndex, DType type, Position position,
            AccessType access, bool callVirt)
		{
            if (IsStatic != (instance == null) || runtimeVisibilityCheck)
			{
                Expression targetExpression = null;
                if (instance != null)
                {
                    targetExpression = ExpressionPlace.GetExpression(instance); // the instance expression, $this would be determined in runtime
                    Debug.Assert(targetExpression != null || instance == IndexedPlace.ThisArg,
                        "Unexpected instance IPlace type" + this.Name.Value);
                }

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

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

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

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

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

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

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

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

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

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

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

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

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

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