Example #1
0
            internal void EmitLoadArgsOnEvalStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
            {
                ILEmitter il = codeGenerator.IL;

                int mandatory_count = (routine.Signature != null) ? routine.Signature.MandatoryParamCount : 0;
                int formal_count = (routine.Signature != null) ? routine.Signature.ParamCount : 0;
                int actual_count = node.Parameters.Count;
                PhpTypeCode param_type;

                // loads all actual parameters which are not superfluous:
                for (int i = 0; i < Math.Min(actual_count, formal_count); i++)
                {
                    var p = node.Parameters[i];
                    codeGenerator.EmitBoxing(param_type = p.NodeCompiler<ActualParamCompiler>().Emit(p, codeGenerator));

                    // Actual param emitter should emit "boxing" to a reference if its access type is ReadRef.
                    // That's why no operation is needed here and references should match.
                    Debug.Assert((routine.Signature == null || routine.Signature.IsAlias(i)) == (param_type == PhpTypeCode.PhpReference));
                }

                // loads missing mandatory arguments:
                for (int i = actual_count; i < mandatory_count; i++)
                {
                    // CALL PhpException.MissingArgument(<i+1>,<name>);
                    il.LdcI4(i + 1);
                    il.Emit(OpCodes.Ldstr, routine.FullName);
                    codeGenerator.EmitPhpException(Methods.PhpException.MissingArgument);

                    // LOAD null;
                    if (routine.Signature.IsAlias(i))
                        il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
                    else
                        il.Emit(OpCodes.Ldnull);
                }

                // loads missing optional arguments:
                for (int i = Math.Max(mandatory_count, actual_count); i < formal_count; i++)
                {
                    // LOAD Arg.Default;
                    il.Emit(OpCodes.Ldsfld, Fields.Arg_Default);
                }
            }
Example #2
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 #3
0
            internal void EmitLoadTypeArgsOnEvalStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
            {
                ILEmitter il = codeGenerator.IL;

                int mandatory_count = (routine.Signature != null) ? routine.Signature.MandatoryGenericParamCount : 0;
                int formal_count = (routine.Signature != null) ? routine.Signature.GenericParamCount : 0;
                int actual_count = node.GenericParams.Count;

                // loads all actual parameters which are not superfluous:
                for (int i = 0; i < Math.Min(actual_count, formal_count); i++)
                    node.GenericParams[i].EmitLoadTypeDesc(codeGenerator, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);

                // loads missing mandatory arguments:
                for (int i = actual_count; i < mandatory_count; i++)
                {
                    // CALL PhpException.MissingTypeArgument(<i+1>,<name>);
                    il.LdcI4(i + 1);
                    il.Emit(OpCodes.Ldstr, routine.FullName);
                    codeGenerator.EmitPhpException(Methods.PhpException.MissingTypeArgument);

                    // LOAD DTypeDesc.ObjectTypeDesc;
                    il.Emit(OpCodes.Ldsfld, Fields.DTypeDesc.ObjectTypeDesc);
                }

                // loads missing optional arguments:
                for (int i = Math.Max(mandatory_count, actual_count); i < formal_count; i++)
                {
                    // LOAD Arg.DefaultType;
                    il.Emit(OpCodes.Ldsfld, Fields.Arg_DefaultType);
                }
            }
Example #4
0
		/// <summary>
		/// Emits type hint test on the argument if specified.
		/// </summary>
		internal void EmitTypeHintTest(CodeGenerator/*!*/ codeGenerator)
		{
			int real_index = routine.FirstPhpParameterIndex + index;

			// not type hint specified:
			if (typeHint == null) return;

			Debug.Assert(resolvedTypeHint != null);

			ILEmitter il = codeGenerator.IL;
			Label endif_label = il.DefineLabel();

			// IF (DEREF(ARG[argIdx]) is not of hint type) THEN
			il.Ldarg(real_index);
			if (PassedByRef) il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);

			resolvedTypeHint.EmitInstanceOf(codeGenerator, null);
			il.Emit(OpCodes.Brtrue, endif_label);

			// add a branch allowing null values if the argument is optional with null default value (since PHP 5.1.0);
			if (initValue != null && initValue.HasValue && initValue.Value == null)
			{
				// IF (DEREF(ARG[argIdx]) != null) THEN
				il.Ldarg(real_index);
				if (PassedByRef) il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
				il.Emit(OpCodes.Brfalse, endif_label);
			}

			// CALL PhpException.InvalidArgumentType(<param_name>, <class_name>);
			il.Emit(OpCodes.Ldstr, name.ToString());
			il.Emit(OpCodes.Ldstr, resolvedTypeHint.FullName);
			codeGenerator.EmitPhpException(Methods.PhpException.InvalidArgumentType);

			// END IF;
			// END IF;
			il.MarkLabel(endif_label);
		}
Example #5
0
		/// <summary>
		/// Emits error reporting call when "this" variable is used out of object context.
		/// </summary>
		private static void EmitThisUsedOutOfObjectThrow(CodeGenerator/*!*/ codeGenerator, bool wantRef)
		{
			codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
			if (wantRef)
				codeGenerator.IL.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
			else
				codeGenerator.IL.Emit(OpCodes.Ldnull);
		}
Example #6
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 #7
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 #8
0
		internal override void EmitStoreRefAssign(CodeGenerator codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;

			if (varName.IsThisVariableName)
			{
				// emit error throwing code
				il.Emit(OpCodes.Pop);
				codeGenerator.EmitPhpException(Methods.PhpException.CannotReassignThis);
			}
			else if (codeGenerator.VariableIsAutoGlobal(varName))
			{
				// Check if the variable is auto-global
				codeGenerator.EmitAutoGlobalStoreRefAssign(varName);
			}
			else if (codeGenerator.OptimizedLocals)
			{
				VariablesTable.Entry entry = codeGenerator.CurrentVariablesTable[varName];
				entry.Variable.EmitStore(il);
			}
			else
			{
				// call instance IDictionary.set_Item(object, object)
				// OBSOLETE: il.Emit(OpCodes.Callvirt, Methods.IDictionary_SetItem);
				il.Emit(OpCodes.Call, Methods.Operators.SetVariableRef);
			}
		}
Example #9
0
		internal override void EmitStoreAssign(CodeGenerator codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;

			if (varName.IsThisVariableName)
			{
				// emit error throwing code
				il.Emit(OpCodes.Pop);
				codeGenerator.EmitPhpException(Methods.PhpException.CannotReassignThis);
			}
			else if (codeGenerator.VariableIsAutoGlobal(varName))
			{
				// Check if the variable is auto-global
				codeGenerator.EmitAutoGlobalStoreAssign();
			}
			else if (codeGenerator.OptimizedLocals)
			{
				// Template:
				//		"WRITE($x,value);"
				//		**** // if specified variable is of type PhpReference
				//		ldloc local
				//		**** // Otherwise do nothing

				VariablesTable.Entry entry = codeGenerator.CurrentVariablesTable[varName];

				if (entry.IsPhpReference)
					il.Emit(OpCodes.Stfld, Fields.PhpReference_Value);
				else
					entry.Variable.EmitStore(il);
			}
			else
			{
				// CALL Operators.SetVariable(STACK:table,STACK:name,STACK:value);
				il.Emit(OpCodes.Call, Methods.Operators.SetVariable);
			}
		}
Example #10
0
		internal override void Emit(CodeGenerator/*!*/ codeGenerator)
		{
			Statistics.AST.AddNode("Class.MethodDecl");

			base.Emit(codeGenerator);

			// emit attributes on return value, generic and regular parameters:
			signature.Emit(codeGenerator);
			typeSignature.Emit(codeGenerator);

            if(method.IsDllImport) {
                //TODO: Support for DllImport
                Debug.Assert(false, "DllImport - not supported");
            } else if(!method.IsAbstract)
			{
                // returns immediately if the method is abstract:
				codeGenerator.EnterMethodDeclaration(method);

				// emits the arg-full overload:
				codeGenerator.EmitArgfullOverloadBody(method, body, entireDeclarationPosition, declarationBodyPosition);

				// restores original code generator settings:
				codeGenerator.LeaveMethodDeclaration();
			}
			else
			{
				// static abstract method is non-abstract in CLR => needs to have a body:
				if (method.IsStatic)
				{
					ILEmitter il = new ILEmitter(method.ArgFullInfo);
					il.Emit(OpCodes.Ldstr, method.DeclaringType.FullName);
					il.Emit(OpCodes.Ldstr, method.FullName);
					codeGenerator.EmitPhpException(il, Methods.PhpException.AbstractMethodCalled);
					il.Emit(OpCodes.Ldnull);
					il.Emit(OpCodes.Ret);
				}
			}

			// emits stubs for overridden/implemented methods and export stubs:
			codeGenerator.EmitOverrideAndExportStubs(method);
		}