Ejemplo n.º 1
0
		private PhpTypeCode EmitGetInternal(CodeGenerator/*!*/ codeGenerator, IPlace instance, bool wantRef,
			ConstructedType constructedType, bool runtimeVisibilityCheck, bool setAliasedFlag)
		{
			ILEmitter il = codeGenerator.IL;

			if (IsStatic)
			{
				if (runtimeVisibilityCheck || UpgradesVisibility)
				{
					// let the operator to check the visibility:
					return codeGenerator.EmitGetStaticPropertyOperator(DeclaringType, this.FullName, null, wantRef);
				}

				if (!IsAppStatic) Implementor.EmitThreadStaticInit(codeGenerator, constructedType);

				// retrieve field value
				il.Emit(OpCodes.Ldsfld, DType.MakeConstructed(RealField, constructedType));
				if (wantRef)
				{
					if (setAliasedFlag)
					{
						// set IsAliased to true
						il.Emit(OpCodes.Dup);
						il.Emit(OpCodes.Ldc_I4_1);
						il.EmitCall(OpCodes.Callvirt, Properties.PhpReference_IsAliased.GetSetMethod(), null);
					}

					return PhpTypeCode.PhpReference;
				}
				else
				{
					il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);

					return PhpTypeCode.Object;
				}
			}
			else
			{
				// LOAD Operators.GetObjectFieldDirect[Ref](this,this.<field>,<name>,<type desc>,[<quiet>]);
				codeGenerator.EmitLoadSelf();
				instance.EmitLoad(il);
				il.Emit(OpCodes.Ldfld, DType.MakeConstructed(RealField, constructedType));
				il.Emit(OpCodes.Ldstr, Name.ToString());
				codeGenerator.EmitLoadClassContext();

				if (wantRef)
				{
					il.Emit(OpCodes.Call, Methods.Operators.GetObjectFieldDirectRef);

					return PhpTypeCode.PhpReference;
				}
				else
				{
					il.LoadBool(codeGenerator.ChainBuilder.QuietRead);
					il.Emit(OpCodes.Call, Methods.Operators.GetObjectFieldDirect);

					return PhpTypeCode.Object;
				}
			}
		}
Ejemplo n.º 2
0
        /// <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));
        }
Ejemplo n.º 3
0
		/// <author>Tomas Matousek</author>
		/// <remarks>
		/// Emits the following code:
		/// <code>
		/// IPhpEnumerable enumerable = ARRAY as IPhpEnumerable;
		/// if (enumerable==null)
		/// {
		///   PhpException.InvalidForeachArgument();
		/// }
		/// else
		/// FOREACH_BEGIN:
		/// {
		///   IDictionaryEnumerator enumerator = enumerable.GetForeachEnumerator(KEYED,ALIASED,TYPE_HANDLE);
		///    
		///   goto LOOP_TEST;
		///   LOOP_BEGIN:
		///   {
		///     ASSIGN(value,enumerator.Value);
		///     ASSIGN(key,enumerator.Key);
		///     
		///     BODY; 
		///   }
		///   LOOP_TEST:
		///   if (enumerator.MoveNext()) goto LOOP_BEGIN;
		/// } 
		/// FOREACH_END:
		/// </code>
		/// </remarks>
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override void Emit(CodeGenerator codeGenerator)
		{
			Statistics.AST.AddNode("Loop.Foreach");
			ILEmitter il = codeGenerator.IL;

			Label foreach_end = il.DefineLabel();
			Label foreach_begin = il.DefineLabel();
			Label loop_begin = il.DefineLabel();
			Label loop_test = il.DefineLabel();

			codeGenerator.BranchingStack.BeginLoop(loop_test, foreach_end,
			  codeGenerator.ExceptionBlockNestingLevel);

			LocalBuilder enumerable = il.GetTemporaryLocal(typeof(IPhpEnumerable));

			// marks foreach "header" (the first part of the IL code):
			codeGenerator.MarkSequencePoint(
			  enumeree.Position.FirstLine,
			  enumeree.Position.FirstColumn,
			  valueVariable.Position.LastLine,
			  valueVariable.Position.LastColumn + 1);

			// enumerable = array as IPhpEnumerable;
			enumeree.Emit(codeGenerator);
			il.Emit(OpCodes.Isinst, typeof(IPhpEnumerable));
			il.Stloc(enumerable);

			// if (enumerable==null)
			il.Ldloc(enumerable);
			il.Emit(OpCodes.Brtrue, foreach_begin);
			{
				// CALL PhpException.InvalidForeachArgument();
				codeGenerator.EmitPhpException(Methods.PhpException.InvalidForeachArgument);
				il.Emit(OpCodes.Br, foreach_end);
			}
			// FOREACH_BEGIN:
			il.MarkLabel(foreach_begin);
			{
				LocalBuilder enumerator = il.GetTemporaryLocal(typeof(System.Collections.IDictionaryEnumerator));

				// enumerator = enumerable.GetForeachEnumerator(KEYED,ALIASED,TYPE_HANDLE);
				il.Ldloc(enumerable);
				il.LoadBool(keyVariable != null);
				il.LoadBool(valueVariable.Alias);
				codeGenerator.EmitLoadClassContext();
				il.Emit(OpCodes.Callvirt, Methods.IPhpEnumerable_GetForeachEnumerator);
				il.Stloc(enumerator);

				// goto LOOP_TEST;
				il.Emit(OpCodes.Br, loop_test);

				// LOOP_BEGIN:
				il.MarkLabel(loop_begin);
				{
					// enumerator should do dereferencing and deep copying (if applicable):
					// ASSIGN(value,enumerator.Value);
					valueVariable.Emit(codeGenerator);
					il.Ldloc(enumerator);
					il.Emit(OpCodes.Callvirt, Properties.IDictionaryEnumerator_Value.GetGetMethod());
					if (valueVariable.Alias) il.Emit(OpCodes.Castclass, typeof(PhpReference));
					valueVariable.EmitAssign(codeGenerator);

					if (keyVariable != null)
					{
						// enumerator should do dereferencing and deep copying (if applicable):
						// ASSIGN(key,enumerator.Key);
						keyVariable.Emit(codeGenerator);
						il.Ldloc(enumerator);
						il.Emit(OpCodes.Callvirt, Properties.IDictionaryEnumerator_Key.GetGetMethod());
						keyVariable.EmitAssign(codeGenerator);
					}

					// BODY:
					body.Emit(codeGenerator);
				}
				// LOOP_TEST:
				il.MarkLabel(loop_test);

				// marks foreach "header" (the second part of the code):
				codeGenerator.MarkSequencePoint(
				  enumeree.Position.FirstLine,
				  enumeree.Position.FirstColumn,
				  valueVariable.Position.LastLine,
				  valueVariable.Position.LastColumn + 1);

				// if (enumerator.MoveNext()) goto LOOP_BEGIN;
				il.Ldloc(enumerator);
				il.Emit(OpCodes.Callvirt, Methods.IEnumerator_MoveNext);
				il.Emit(OpCodes.Brtrue, loop_begin);

                //
                il.ReturnTemporaryLocal(enumerator);
			}
			// FOREACH_END:
			il.MarkLabel(foreach_end);

            il.ReturnTemporaryLocal(enumerable);

			codeGenerator.BranchingStack.EndLoop();

			il.ForgetLabel(foreach_end);
			il.ForgetLabel(foreach_begin);
			il.ForgetLabel(loop_begin);
			il.ForgetLabel(loop_test);
		}
Ejemplo n.º 4
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));
        }