示例#1
0
        private void EmitNodeWriteAssign(CodeGenerator codeGenerator)
        {
            ChainBuilder chain = codeGenerator.ChainBuilder;

            // Note that for cases 1,3,4,5,6,9 EmitAssign is never called!!!

            // 2,7,8
            if (chain.IsMember)
            {
                // 2,8
                if (chain.Exists)
                {
                    // 8: b[]->$a
                    chain.EmitSetObjectField();
                }
                else
                {
                    // 2: $b->a
                    Debug.Assert(this.isMemberOf is SimpleVarUse || this.isMemberOf is FunctionCall);
                    if (this.isMemberOf is FunctionCall)
                    {
                        codeGenerator.ChainBuilder.LoadAddressOfFunctionReturnValue = true;
                    }

                    assignmentCallback(codeGenerator, PhpTypeCode.Object);

                    SimpleVarUse svu = this.isMemberOf as SimpleVarUse;
                    if (svu != null)
                    {
                        svu.EmitLoadAddress_StoreBack(codeGenerator);
                    }
                    // else do nothing
                }
                chain.End();
            }
            else
            {
                // 7: $a
                //codeGenerator.EmitVariableStoreAssign(this);
                this.EmitStoreAssign(codeGenerator);
            }
        }
示例#2
0
        /// <summary>
        /// Emits IL instructions that read the value of an instance field.
        /// </summary>
        /// <param name="codeGenerator">The current <see cref="CodeGenerator"/>.</param>
        /// <param name="wantRef">If <B>false</B> the field value should be left on the evaluation stack,
        /// if <B>true</B> the <see cref="PhpReference"/> should be left on the evaluation stack.</param>
        /// <returns>
        /// Nothing is expected on the evaluation stack. A <see cref="PhpReference"/> (if <paramref name="wantRef"/>
        /// is <B>true</B>) or the field value itself (if <paramref name="wantRef"/> is <B>false</B>) is left on the
        /// evaluation stack.
        /// </returns>
        internal virtual PhpTypeCode EmitReadField(CodeGenerator codeGenerator, bool wantRef)
        {
            ILEmitter il = codeGenerator.IL;

            DirectVarUse direct_instance = isMemberOf as DirectVarUse;

            if (direct_instance != null && direct_instance.IsMemberOf == null && direct_instance.VarName.IsThisVariableName)
            {
                return(EmitReadFieldOfThis(codeGenerator, wantRef));
            }


            if (!wantRef)
            {
                //codeGenerator.ChainBuilder.Lengthen();
                //PhpTypeCode type_code = isMemberOf.Emit(codeGenerator);
                //Debug.Assert(type_code == PhpTypeCode.Object || type_code == PhpTypeCode.DObject);

                //// CALL Operators.GetProperty(STACK,<field name>,<type desc>,<quiet>);
                //EmitName(codeGenerator);
                //codeGenerator.EmitLoadClassContext();
                //il.LoadBool(codeGenerator.ChainBuilder.QuietRead);
                //il.Emit(OpCodes.Call, Methods.Operators.GetProperty);
                //return PhpTypeCode.Object;

                string     fieldName     = (this is DirectVarUse) ? ((DirectVarUse)this).VarName.Value : null;
                Expression fieldNameExpr = (this is IndirectVarUse) ? ((IndirectVarUse)this).VarNameEx : null;
                bool       quietRead     = wantRef ? false : codeGenerator.ChainBuilder.QuietRead;
                return(codeGenerator.CallSitesBuilder.EmitGetProperty(
                           codeGenerator, wantRef,
                           isMemberOf, null, null,
                           null,
                           fieldName, fieldNameExpr,
                           quietRead));
            }

            // call GetProperty/GetObjectPropertyRef
            codeGenerator.ChainBuilder.Lengthen();
            // loads the variable which field is gotten:
            PhpTypeCode var_type_code = isMemberOf.Emit(codeGenerator);

            if (codeGenerator.ChainBuilder.Exists)
            {
                Debug.Assert(var_type_code == PhpTypeCode.DObject);

                // CALL Operators.GetObjectPropertyRef(STACK,<field name>,<type desc>);
                EmitName(codeGenerator);
                codeGenerator.EmitLoadClassContext();
                il.Emit(OpCodes.Call, Methods.Operators.GetObjectPropertyRef);
            }
            else
            {
                Debug.Assert(var_type_code == PhpTypeCode.ObjectAddress);

                // CALL Operators.GetPropertyRef(ref STACK,<field name>,<type desc>,<script context>);
                EmitName(codeGenerator);
                codeGenerator.EmitLoadClassContext();
                codeGenerator.EmitLoadScriptContext();
                il.Emit(OpCodes.Call, Methods.Operators.GetPropertyRef);

                // stores the value of variable back:
                SimpleVarUse simple_var = isMemberOf as SimpleVarUse;
                if (simple_var != null)
                {
                    simple_var.EmitLoadAddress_StoreBack(codeGenerator);
                }
            }

            return(PhpTypeCode.PhpReference);
        }
示例#3
0
		private void EmitVariableIssetOptimized(SimpleVarUse variable)
		{
			// Template: for DirectVarUse

			//	ISSET($x)
			//	 ldloc local
			// *** if local is of type PhpReference
			// 	 ldfld PhpReference.Value
			// ***
			//	 ldnull
			//	 ceq
			//	 ldc.i4.0
			//	 ceq           
			DirectVarUse direct = variable as DirectVarUse;
			if (direct != null)
			{
				VariablesTable.Entry entry = currentVariablesTable[direct.VarName];

				entry.Variable.EmitLoad(il);
				if (entry.IsPhpReference)
				{
					il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
				}
				il.Emit(OpCodes.Ldnull);
				il.Emit(OpCodes.Ceq);
				il.Emit(OpCodes.Ldc_I4_0);
				il.Emit(OpCodes.Ceq);
				return;
			}

			IndirectVarUse indirect_var = (IndirectVarUse)variable;
			indirect_var.EmitSwitch_LoadLocal(this);
			il.Emit(OpCodes.Ldnull);
			il.Emit(OpCodes.Ceq);
			il.Emit(OpCodes.Ldc_I4_0);
			il.Emit(OpCodes.Ceq);
		}
示例#4
0
		/// <summary>
		/// Emits IL instructions that ensure that the specified property of an object is
		/// of the <see cref="PhpArray"/> type.
		/// </summary>
		/// <param name="varObject">Represents the instance whose property should be examined.</param>
		/// <param name="fieldName">A <see cref="SimpleVarUse"/> that evaluates to the property name.</param>
		/// <param name="ensureArray">Whether to ensure that static property is an array (or an object).</param>
		/// <remarks>Nothing is expected on the evaluation stack. If the property is of <see cref="PhpArray"/> type
		/// it is left on the evaluation stack. Otherwise the control is transfered to the end of chain.</remarks>
		public PhpTypeCode EmitEnsureProperty(VarLikeConstructUse/*!*/ varObject, SimpleVarUse/*!*/ fieldName, bool ensureArray)
		{
			// Template: PhpArray EnsurePropertyIsArray(DObject,field,DTypeDesc)
			Debug.Assert(varObject != null && fieldName != null);
			Debug.Assert(fieldName is DirectVarUse || fieldName is IndirectVarUse);

			LocationTypes location;
			DProperty property = ResolveProperty(varObject, fieldName, out location);

			ILEmitter il = codeGenerator.IL;

			PhpField php_field = property as PhpField;
			if (php_field != null) // we can emit code that manipulates the property directly
			{
				// HACK HACK
				EmitEnsurePhpFieldDirect(php_field, fieldName, ensureArray);
			}
			else
			{
				switch (location)
				{
					case LocationTypes.GlobalCode:
						{
							// call EnsurePropertyIsArray
							codeGenerator.EmitLoadSelf();
							fieldName.EmitName(codeGenerator);
							codeGenerator.EmitLoadClassContext();

							if (ensureArray)
							{
								il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsArray);
							}
							else
							{
								codeGenerator.EmitLoadScriptContext();
								il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsObject);
							}
							break;
						}

					case LocationTypes.MethodDecl:
						{
							if (ensureArray) this.Lengthen(); // for hop over ->
							FunctionCall func = varObject as FunctionCall;
							if (func == null)
							{
								varObject.Emit(codeGenerator);
							}
							else
							{
								this.LoadAddressOfFunctionReturnValue = true;
								func.Emit(codeGenerator);
								RecastValueReturnedByFunctionCall();
							}
							fieldName.EmitName(codeGenerator);
							codeGenerator.EmitLoadClassContext();

							if (ensureArray)
							{
								il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsArray);
							}
							else
							{
								codeGenerator.EmitLoadScriptContext();
								il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsObject);
							}
							EmitErrorCheck(ensureArray);
							break;
						}

					// if the location was FunctionDecl, appropriate code was already generated by GetDProperty
				}
			}
			return (ensureArray ? PhpTypeCode.PhpArray : PhpTypeCode.DObject);
		}
示例#5
0
		/// <summary>
		/// Emits IL instructions that ensure that the specified variable is an instance of <see cref="PhpObject"/>. 
		/// </summary>
		/// <param name="variable">Variable that should be examined.</param>
		/// <remarks>
		/// This method is used in operators chains. Nothing is expected on the evaluation stack. 
		/// If the specified variable is an instance of <see cref="PhpObject"/>
		/// it is left on the evaluation stack. Otherwise the control is transfered to the end of 
		/// the chain.
		/// </remarks>
		public void EmitEnsureVariableIsObject(SimpleVarUse variable)
		{
			ILEmitter il = codeGenerator.IL;

			DirectVarUse direct_variable = variable as DirectVarUse;
			if (direct_variable != null && direct_variable.VarName.IsThisVariableName)
			{
				// special treatment of $this
				switch (codeGenerator.LocationStack.LocationType)
				{
					case LocationTypes.GlobalCode:
						{
							// load $this from one of Main's arguments and check for null
							Label this_non_null = il.DefineLabel();

							codeGenerator.EmitLoadSelf();
							il.Emit(OpCodes.Brtrue_S, this_non_null);

							codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);

							il.Emit(OpCodes.Br, TopChain.ErrorLabel);
							il.MarkLabel(this_non_null, true);
							codeGenerator.EmitLoadSelf();
							break;
						}

					case LocationTypes.FunctionDecl:
						{
							// always throws error
							codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
							il.Emit(OpCodes.Br, TopChain.ErrorLabel);
							break;
						}

					case LocationTypes.MethodDecl:
						{
							CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
							if (context.Method.IsStatic)
							{
								// always throws error
								codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
								il.Emit(OpCodes.Br, TopChain.ErrorLabel);
							}
							else
							{
								// arg0 or <proxy> in instance methods
								codeGenerator.EmitLoadSelf();
							}
							break;
						}

					default:
						Debug.Assert(false, "Invalid location type.");
						break;
				}
			}
			else
			{
				// Template: PhpObject    EnsureVariableIsObject(ref object,ScriptContext)

				// Load variable's address
				//				if (variable is FunctionCall)
				//				{
				//					variable.Emit(this);
				//					EmitLoadScriptContext();
				//					il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsObject);
				//					// Store the changed destVar into table of variables (do nothing in optimalized functions)
				//				}
				//				else
				//				{
				variable.EmitLoadAddress(codeGenerator);
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsObject);
				// Store the changed destVar into table of variables (do nothing in optimalized functions)
				variable.EmitLoadAddress_StoreBack(codeGenerator);
				//				}
				EmitErrorCheck(false);
			}
		}
示例#6
0
		/// <summary>
		/// Emits IL instructions that ensure that the specified variable is an instance of <see cref="PhpArray"/>. 
		/// </summary>
		/// <param name="variable">Variable's name-index to a table of identifiers.</param>
		/// <remarks>
		/// This method is used in operators chains. Nothing is expected on the evaluation stack. 
		/// If the specified variable is an instance of <see cref="PhpArray"/>
		/// it is left on the evaluation stack. Otherwise the control is transfered to the end of 
		/// the chain.
		/// </remarks>
		public void EmitEnsureVariableIsArray(SimpleVarUse variable)
		{
			// Template: PhpArray     EnsureVariableIsArray(ref object)

			// Load variable's address
			//this.EmitVariableLoadAddress(variable);
			variable.EmitLoadAddress(codeGenerator);
			codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsArray);
			// Store the changed destVar into table of variables (do nothing in optimalized functions)
			variable.EmitLoadAddress_StoreBack(codeGenerator);
			EmitErrorCheck(true);
		}
示例#7
0
		/// <summary>
		/// Emits IL instructions that loads the value of array's item as a <see cref="PHP.Core.PhpReference"/>.
		/// </summary>
		/// <param name="variable">A simple variable.</param>
		/// <param name="index"><see cref="Expression"/> determining the index.</param> 
		public PhpTypeCode EmitGetItemRef(SimpleVarUse/*!*/ variable, Expression index)
		{
			IsArrayItem = true;
			IsLastMember = true;
			
			PhpTypeCode index_type_code = PhpTypeCode.Invalid;

			// index:
			if (index != null)
				index_type_code = codeGenerator.EmitArrayKey(this, index);

			// array:
			variable.Emit(codeGenerator);

			// LOAD Operators.GetItemRef([<index>], ref <variable>)
			codeGenerator.EmitGetItem(index_type_code, index, true);
			
			// store the changed variable into table of variables (do nothing in optimalized functions)
			variable.EmitLoadAddress_StoreBack(codeGenerator);

			IsArrayItem = false;

			return PhpTypeCode.PhpReference;
		}
示例#8
0
		/// <summary>
		/// Emits IL instructions that load a value of the specified property of an object.
		/// </summary>
		/// <param name="variable"><see cref="PHP.Core.AST.VariableUse"/> class determining the name of the field.</param>
		/// <remarks>Expects that the <see cref="PHP.Core.Reflection.DObject"/> whose property value should be obtained
		/// is loaded on the evaluation stack. The value of the property is left on the evaluation stack.</remarks>
		public PhpTypeCode EmitGetProperty(SimpleVarUse variable)
		{
			Debug.Assert(variable is DirectVarUse || variable is IndirectVarUse);

            var il = codeGenerator.IL;

            // we already have the instance value on top of the stack,
            // it must be stored in local variable first so we can call
            // call CallSite normally.
            
            // <memberOf> = <STACK:variable>:
            var memberOf = il.GetTemporaryLocal(Types.Object[0]);
            il.Stloc(memberOf);

            // create and call the CallSite:
            string fieldName = (variable is DirectVarUse) ? ((DirectVarUse)variable).VarName.Value : null;
            Expression fieldNameExpr = (variable is IndirectVarUse) ? ((IndirectVarUse)variable).VarNameEx : null;
            
            var result = codeGenerator.CallSitesBuilder.EmitGetProperty(codeGenerator, false,
                null, null, new IndexedPlace(memberOf),
                null,
                fieldName, fieldNameExpr,
                QuietRead);

            // return temporary variable:
            il.ReturnTemporaryLocal(memberOf);

            //
            return result;

            //// CALL object Operators.GetProperty(<STACK:variable>,<field name>,<type desc>);
            //variable.EmitName(codeGenerator);
            //codeGenerator.EmitLoadClassContext();
            //codeGenerator.IL.LoadBool(QuietRead);
            //codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.GetProperty);

			//return PhpTypeCode.Object;
		}
示例#9
0
		/// <summary>
		/// Emits IL instructions that add an object field access to the current <see cref="PhpRuntimeChain"/>.
		/// </summary>
		/// <param name="varUse">AST node representing the field access.</param>
		/// <remarks>
		/// A reference to <see cref="PhpRuntimeChain"/> is expected and left on the evaluation stack.
		/// </remarks>
		public void EmitRTChainAddField(SimpleVarUse varUse)
		{
			codeGenerator.IL.Emit(OpCodes.Dup);
			varUse.EmitName(codeGenerator);
			codeGenerator.IL.EmitCall(OpCodes.Call, Methods.PhpRuntimeChain.AddField, null);
		}
示例#10
0
		/// <summary>
		/// Tries to find an instance of <see cref="DProperty"/> that corresponds to an instance property given by
		/// <paramref name="varObject"/> and <paramref name="fieldName"/>. Currently it is possible only if
		/// <paramref name="varObject"/> represents <B>$this</B> and <paramref name="fieldName"/> is a compile time
		/// known instance property, which is surely accessible from current location.
		/// </summary>
		/// <param name="varObject">Represents the left side of <B>-&gt;</B>.</param>
		/// <param name="fieldName">Represents the right side of <B>-&gt;</B>.</param>
		/// <param name="location">Current location, valid only if the return value is <B>null</B>. Used by the caller to
		/// decide what kind of run time access should be emitted.</param>
		/// <returns>A valid non-<B>null</B> <see cref="PhpField"/> if the field was found, <B>null</B> otherwise.</returns>
		internal DProperty ResolveProperty(VarLikeConstructUse varObject, SimpleVarUse fieldName, out LocationTypes location)
		{
			DirectVarUse direct_var = varObject as DirectVarUse;
			DirectVarUse direct_field_name;

			if (direct_var != null && (direct_field_name = fieldName as DirectVarUse) != null &&
				direct_var.IsMemberOf == null && direct_var.VarName.IsThisVariableName)
			{
				ILEmitter il = codeGenerator.IL;
				location = codeGenerator.LocationStack.LocationType;
				switch (location)
				{
					case LocationTypes.GlobalCode:
						{
							// load $this from one of Main's arguments and check for null
							Label this_non_null = il.DefineLabel();

							codeGenerator.EmitLoadSelf();
							il.Emit(OpCodes.Brtrue_S, this_non_null);
							codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
							il.Emit(OpCodes.Br, TopChain.ErrorLabel);
							il.MarkLabel(this_non_null, true);

							return null;
						}

					case LocationTypes.FunctionDecl:
						{
							// always throws error
							codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
							il.Emit(OpCodes.Br, TopChain.ErrorLabel);

							return null;
						}

					case LocationTypes.MethodDecl:
						{
							CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
							if (context.Method.IsStatic)
							{
								// always throws error
								codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
								il.Emit(OpCodes.Br, TopChain.ErrorLabel);

								location = LocationTypes.FunctionDecl;
								return null;
							}
							else
							{
								DProperty property;
								if (context.Type.GetProperty(direct_field_name.VarName, context.Type, out property)
									== GetMemberResult.OK && !property.IsStatic)
								{
									return property;
								}
							}
							break;
						}
				}
			}

			location = LocationTypes.MethodDecl;
			return null;
		}
示例#11
0
		/// <summary>
		/// I do not like PHP-specific access code emission here. TODO: Move to PhpField
		/// </summary>
		/// <param name="field"></param>
		/// <param name="fieldName"></param>
		/// <param name="ensureArray"></param>
		private void EmitEnsurePhpFieldDirect(PhpField/*!*/ field, SimpleVarUse/*!*/ fieldName, bool ensureArray)
		{
			ILEmitter il = codeGenerator.IL;

			// check whether the field is set
			il.Ldarg(FunctionBuilder.ArgThis);
			il.Emit(OpCodes.Ldfld, field.RealField);

			Label direct_ensure = il.DefineLabel();
			Label ensuring_over = il.DefineLabel();

			// test whether it is set
			il.Emit(OpCodes.Callvirt, Properties.PhpReference_IsSet.GetGetMethod());
			il.Emit(OpCodes.Brtrue, direct_ensure);

			// the field has been unset -> must call operator that handles __get/__set
			if (ensureArray) this.Lengthen();  // TODO: ???
			codeGenerator.EmitLoadSelf();
			fieldName.EmitName(codeGenerator);
			codeGenerator.EmitLoadClassContext();
			if (ensureArray)
			{
				il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsArray);
			}
			else
			{
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsObject);
			}
			il.Emit(OpCodes.Br, ensuring_over);

			// read the field again and call EnsureVariableIsArray
			il.MarkLabel(direct_ensure, true);
			il.Ldarg(FunctionBuilder.ArgThis);
			il.Emit(OpCodes.Ldfld, field.RealField);
			il.Emit(OpCodes.Ldflda, Fields.PhpReference_Value);

			if (ensureArray)
			{
				il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsArray);
			}
			else
			{
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsObject);
			}

			il.MarkLabel(ensuring_over, true);
			EmitErrorCheck(ensureArray);
		}