Example #1
0
		/// <summary>
		/// Emits IL instructions that write the value of a field of $this instance when we know that we
		/// are in an instance method and hence there's a chance of actually resolving the field being written.
		/// </summary>
		/// <param name="codeGenerator">The current <see cref="CodeGenerator"/>.</param>
		/// <param name="writeRef">If <B>true</B> the value being written is a <see cref="PhpReference"/>; if
		/// <B>false</B> the value being written is an <see cref="Object"/>.</param>
		/// <returns></returns>
		internal virtual AssignmentCallback EmitWriteFieldOfThisInInstanceMethod(CodeGenerator/*!*/ codeGenerator, bool writeRef)
		{
			// prepare for SetObjectProperty call
			codeGenerator.EmitLoadSelf();
			EmitName(codeGenerator);

			return new AssignmentCallback(EmitCallSetObjectField);
		}
Example #2
0
		/// <summary>
		/// Emits IL instructions that read the value of a field of $this instance.
		/// </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></returns>
		private PhpTypeCode EmitReadFieldOfThis(CodeGenerator/*!*/ codeGenerator, bool wantRef)
		{
			ILEmitter il = codeGenerator.IL;

			// $this->a
			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();
						Label reading_over = il.DefineLabel();

						codeGenerator.EmitLoadSelf();
						il.Emit(OpCodes.Brtrue_S, this_non_null);
						EmitThisUsedOutOfObjectThrow(codeGenerator, wantRef);
						il.Emit(OpCodes.Br, reading_over);
						il.MarkLabel(this_non_null, true);

						// call GetObjectProperty/GetObjectPropertyRef
						EmitGetFieldOfPlace(codeGenerator.SelfPlace, codeGenerator, wantRef);

						il.MarkLabel(reading_over, true);

						break;
					}

				case LocationTypes.FunctionDecl:
					{
						EmitThisUsedOutOfObjectThrow(codeGenerator, wantRef);
						break;
					}

				case LocationTypes.MethodDecl:
					{
						CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
						if (context.Method.IsStatic)
						{
							EmitThisUsedOutOfObjectThrow(codeGenerator, wantRef);
							break;
						}

						// attempt direct field reading (DirectVarUse only)
						return EmitReadFieldOfThisInInstanceMethod(codeGenerator, wantRef);
					}
			}

			return wantRef ? PhpTypeCode.PhpReference : PhpTypeCode.Object;
		}
Example #3
0
		/// <summary>
		/// Emits IL instructions that prepare a field of $this for writing.
		/// </summary>
		private AssignmentCallback EmitWriteFieldOfThis(CodeGenerator/*!*/ codeGenerator, bool writeRef)
		{
			ILEmitter il = codeGenerator.IL;

			// $this->a
			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, codeGenerator.ChainBuilder.ErrorLabel);
						il.MarkLabel(this_non_null, true);

						// prepare the stack for SetObjectProperty call
						codeGenerator.EmitLoadSelf();
						EmitName(codeGenerator);

						return new AssignmentCallback(EmitCallSetObjectField);
					}

				case LocationTypes.FunctionDecl:
					{
						// always throws error
						codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
						return new AssignmentCallback(EmitPopValue);
					}

				case LocationTypes.MethodDecl:
					{
						CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
						if (context.Method.IsStatic)
						{
							// always throws error
							codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
							return new AssignmentCallback(EmitPopValue);
						}

						// attempt direct field writing (DirectVarUse only)
						return EmitWriteFieldOfThisInInstanceMethod(codeGenerator, writeRef);
					}
			}

			Debug.Fail("Invalid lcoation type.");
			return null;
		}
Example #4
0
		/// <summary>
		/// Loads a PhpReference to "this" special variable to the evaluation stack.
		/// If "this" is not available, loads an empty PhpReference.
		/// </summary>
		private PhpTypeCode EmitLoadThisRef(CodeGenerator/*!*/ codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;

			switch (codeGenerator.LocationStack.LocationType)
			{
				case LocationTypes.GlobalCode:
					{
						// load $this from one of Main's arguments:
						codeGenerator.EmitLoadSelf();

						// NOTE: If $this is used by ref somewhere in the method each access to it is boxed to the reference.
						// Only calls to methods use the "this" pointer itself. Thus the rule "no duplicate pointers" is slightly
						// broken here yet everything should work fine.
						il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
						break;
					}

				case LocationTypes.FunctionDecl:
					{
						// always null referencing PhpReference
						il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
						break;
					}

				case LocationTypes.MethodDecl:
					{
						CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
						if (context.Method.IsStatic)
						{
							// always null referencing PhpReference in static methods
							il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
						}
						else
						{
							// arg0 or <proxy> referencing PhpReference in instance methods
							codeGenerator.EmitLoadSelf();

							// NOTE: If $this is used by ref somewhere in the method each access to it is boxed to the reference.
							// Only calls to methods use the "this" pointer itself. Thus the rule "no duplicate pointers" is slightly
							// broken here yet everything should work fine.
							il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
						}
						break;
					}

				default:
					Debug.Fail("Invalid location type.");
					break;
			}

			// always returns a reference:
			return PhpTypeCode.PhpReference;
		}
Example #5
0
		/// <summary>
		/// Emits IL instructions that load the "$this" variable onto the evaluation stack.
		/// </summary>
		private PhpTypeCode EmitLoadThis(CodeGenerator codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;
			CompilerLocationStack locationStack = codeGenerator.LocationStack;

			// special treatment of $this
			switch (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.Dup);
						il.Emit(OpCodes.Brtrue_S, this_non_null);
						il.Emit(OpCodes.Ldstr, VariableName.ThisVariableName.Value);
						codeGenerator.EmitPhpException(Methods.PhpException.UndefinedVariable);
						il.MarkLabel(this_non_null, true);

						return PhpTypeCode.Object;
					}

				case LocationTypes.FunctionDecl:
					{
						// always null
						il.Emit(OpCodes.Ldstr, VariableName.ThisVariableName.Value);
						codeGenerator.EmitPhpException(Methods.PhpException.UndefinedVariable);
						il.Emit(OpCodes.Ldnull);

						return PhpTypeCode.Object;
					}

				case LocationTypes.MethodDecl:
					{
						CompilerLocationStack.MethodDeclContext context = locationStack.PeekMethodDecl();
						if (context.Method.IsStatic)
						{
							// always null in static methods
							il.Emit(OpCodes.Ldstr, VariableName.ThisVariableName.Value);
							codeGenerator.EmitPhpException(Methods.PhpException.UndefinedVariable);
							il.Emit(OpCodes.Ldnull);

							return PhpTypeCode.Object;
						}
						else
						{
							// arg0 or <proxy> in instance methods
							codeGenerator.EmitLoadSelf();
							return PhpTypeCode.DObject;
						}
					}

				default:
					Debug.Fail("Invalid location type.");
					return PhpTypeCode.Invalid;
			}
		}
Example #6
0
		/// <summary>
		/// Emits IL instructions that unset an instance field.
		/// </summary>
		/// <remarks>
		/// Nothing is expected on the evaluation stack. Nothing is left on the evaluation stack.
		/// </remarks>
		private void EmitUnsetField(CodeGenerator/*!*/ codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;

			DirectVarUse direct_instance = isMemberOf as DirectVarUse;
			if (direct_instance != null && direct_instance.VarName.IsThisVariableName)
			{
				// $this->a
				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, codeGenerator.ChainBuilder.ErrorLabel);
							il.MarkLabel(this_non_null, true);

							// call UnsetProperty
							codeGenerator.EmitLoadSelf();
							il.Emit(OpCodes.Ldstr, varName.ToString()); // TODO
							codeGenerator.EmitLoadClassContext();

							il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
							return;
						}

					case LocationTypes.FunctionDecl:
						{
							// always throws error
							codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
							il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.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, codeGenerator.ChainBuilder.ErrorLabel);
							}
							else
							{
								DProperty property;
								if (context.Type.GetProperty(varName, context.Type, out property) == GetMemberResult.OK &&
									!property.IsStatic)
								{
									// ask the DProperty to emit its unsetting code
									property.EmitUnset(codeGenerator, IndexedPlace.ThisArg, null, false);
								}
								else
								{
									// unable to resolve the field -> call UnsetProperty
									codeGenerator.EmitLoadSelf();
									il.Emit(OpCodes.Ldstr, varName.ToString());
									codeGenerator.EmitLoadClassContext();

									il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
								}
							}
						}
						break;
				}
			}
			else
			{
				// call UnsetProperty
				isMemberOf.Emit(codeGenerator);
				il.Emit(OpCodes.Ldstr, varName.ToString());
				codeGenerator.EmitLoadClassContext();

				il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
			}
		}
Example #7
0
		/// <summary>
		/// Emits dynamic inclusion.
		/// </summary>
		private PhpTypeCode EmitDynamicInclusion(CodeGenerator/*!*/ codeGenerator)
		{
			// do not generate dynamic auto inclusions:
			if (InclusionTypesEnum.IsAutoInclusion(inclusionType))
				return PhpTypeCode.Void;

			ILEmitter il = codeGenerator.IL;

			// CALL context.DynamicInclude(<file name>,<relative includer source path>,variables,self,includer);
			codeGenerator.EmitLoadScriptContext();
			codeGenerator.EmitConversion(fileNameEx, PhpTypeCode.String);
			il.Emit(OpCodes.Ldstr, codeGenerator.SourceUnit.SourceFile.RelativePath.ToString());
			codeGenerator.EmitLoadRTVariablesTable();
			codeGenerator.EmitLoadSelf();
			codeGenerator.EmitLoadClassContext();
			il.LoadLiteral(inclusionType);
			il.Emit(OpCodes.Call, Methods.ScriptContext.DynamicInclude);

			return PhpTypeCode.Object;
		}
		/// <summary>
		/// Emits a static inclusion.
		/// </summary>
		private PhpTypeCode EmitStaticInclusion(CodeGenerator/*!*/ codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;
			Label endif_label = il.DefineLabel();
			Label else_label = il.DefineLabel();
			MethodInfo method;

			// if the expression should be emitted:
			if (characteristic == Characteristic.StaticArgEvaluated)
			{
                if (!(fileNameEx is StringLiteral || fileNameEx is BinaryStringLiteral))
                {
                    // emits expression evaluation and ignores the result:
                    fileNameEx.Emit(codeGenerator);
                    il.Emit(OpCodes.Pop);
                }
			}

			if (characteristic == Characteristic.StaticAutoInclusion)
			{
				// calls the Main routine only if this script is the main one:
				il.Ldarg(ScriptBuilder.ArgIsMain);
			}
			else
			{
                RelativePath relativePath = new RelativePath(inclusion.Includee.RelativeSourcePath);    // normalize the relative path

				// CALL context.StaticInclude(<relative included script source path>,<this script type>,<inclusion type>);
				codeGenerator.EmitLoadScriptContext();
                il.Emit(OpCodes.Ldc_I4, (int)relativePath.Level);
                il.Emit(OpCodes.Ldstr, relativePath.Path);
				il.Emit(OpCodes.Ldtoken, inclusion.Includee.ScriptClassType);
				il.LoadLiteral(inclusionType);
				il.Emit(OpCodes.Call, Methods.ScriptContext.StaticInclude);
			}

			// IF (STACK)
			il.Emit(OpCodes.Brfalse, else_label);
			if (true)
			{
				// emits a call to the main helper of the included script:
				method = inclusion.Includee.MainHelper;

				// CALL <Main>(context, variables, self, includer, false):
				codeGenerator.EmitLoadScriptContext();
				codeGenerator.EmitLoadRTVariablesTable();
				codeGenerator.EmitLoadSelf();
				codeGenerator.EmitLoadClassContext();
				il.Emit(OpCodes.Ldc_I4_0);
				il.Emit(OpCodes.Call, method);

				il.Emit(OpCodes.Br, endif_label);
			}

			// ELSE

			il.MarkLabel(else_label);
			if (true)
			{
				// LOAD <PhpScript.SkippedIncludeReturnValue>;                          
				il.LoadLiteral(ScriptModule.SkippedIncludeReturnValue);
				il.Emit(OpCodes.Box, ScriptModule.SkippedIncludeReturnValue.GetType());
			}

			il.MarkLabel(endif_label);
			// END IF 

			return PhpTypeCode.Object;
		}