Пример #1
0
		/// <summary>
		/// Emits code that loads current <see cref="PHP.Core.ScriptContext"/> by calling
		/// <see cref="PHP.Core.ScriptContext.CurrentContext"/> and remembers it in a local.
		/// </summary>
		/// <param name="il"></param>
		public void EmitLoad(ILEmitter il)
		{
			if (localBuilder == null)
			{
				localBuilder = il.DeclareLocal(typeof(ScriptContext));
				il.EmitCall(OpCodes.Call, Methods.ScriptContext.GetCurrentContext, null);
				il.Stloc(localBuilder);
			}
			il.Ldloc(localBuilder);
		}
Пример #2
0
		public static void EmitArgFullPreCall(ILEmitter/*!*/ il, IPlace/*!*/ stack, bool argsAware,
		  int formalParamCount, int formalTypeParamCount, out LocalBuilder locArgsCount)
		{
			if (argsAware)
			{
				locArgsCount = il.DeclareLocal(typeof(int));

				// locArgsCount = stack.MakeArgsAware(<formal tpye param count | formal param count>);
				stack.EmitLoad(il);
				il.LdcI4((formalTypeParamCount << 16) | formalParamCount);
				il.Emit(OpCodes.Call, Methods.PhpStack.MakeArgsAware);
				il.Stloc(locArgsCount);
			}
			else
			{
				locArgsCount = null;

				// CALL stack.RemoveFrame();
				stack.EmitLoad(il);
				il.Emit(OpCodes.Call, Methods.PhpStack.RemoveFrame);
			}
		}
Пример #3
0
		/// <summary>
		/// Converts object to CLR type
		/// </summary>
		private static bool EmitConvertObjectToClr(ILEmitter il, PhpTypeCode typeCode, Type formalType, LocalBuilder strictnessLocal)
		{
			MethodInfo convert_method = null;
			switch (Type.GetTypeCode(formalType))
			{
				case TypeCode.Boolean: if (typeCode != PhpTypeCode.Boolean)
						convert_method = Methods.ConvertToClr.TryObjectToBoolean; break;
				case TypeCode.Int32: if (typeCode != PhpTypeCode.Integer)
						convert_method = Methods.ConvertToClr.TryObjectToInt32; break;
				case TypeCode.Int64: if (typeCode != PhpTypeCode.LongInteger)
						convert_method = Methods.ConvertToClr.TryObjectToInt64; break;
				case TypeCode.Double: if (typeCode != PhpTypeCode.Double)
						convert_method = Methods.ConvertToClr.TryObjectToDouble; break;
				case TypeCode.String: if (typeCode != PhpTypeCode.String)
						convert_method = Methods.ConvertToClr.TryObjectToString; break;

				case TypeCode.SByte: convert_method = Methods.ConvertToClr.TryObjectToInt8; break;
				case TypeCode.Int16: convert_method = Methods.ConvertToClr.TryObjectToInt16; break;
				case TypeCode.Byte: convert_method = Methods.ConvertToClr.TryObjectToUInt8; break;
				case TypeCode.UInt16: convert_method = Methods.ConvertToClr.TryObjectToUInt16; break;
				case TypeCode.UInt32: convert_method = Methods.ConvertToClr.TryObjectToUInt32; break;
				case TypeCode.UInt64: convert_method = Methods.ConvertToClr.TryObjectToUInt64; break;
				case TypeCode.Single: convert_method = Methods.ConvertToClr.TryObjectToSingle; break;
				case TypeCode.Decimal: convert_method = Methods.ConvertToClr.TryObjectToDecimal; break;
				case TypeCode.Char: convert_method = Methods.ConvertToClr.TryObjectToChar; break;
				case TypeCode.DateTime: convert_method = Methods.ConvertToClr.TryObjectToDateTime; break;
				case TypeCode.DBNull: convert_method = Methods.ConvertToClr.TryObjectToDBNull; break;

				case TypeCode.Object:
					{
						if (formalType.IsValueType)
						{
							if (formalType.IsGenericType && NullableType == formalType.GetGenericTypeDefinition())
							{
								// This is an ugly corner case (using generic TryObjectToStruct wouldn't work, because
								// for nullables .IsValueType returns true, but it doesn't match "T : struct" constraint)!
								// We have to try converting object to Nullable<T> first and then to T
								// (which requires a new call to 'EmitConvertObjectToClr') 
								Type nullableArg = formalType.GetGenericArguments()[0];
								Type nullableType = NullableType.MakeGenericType(nullableArg);
								
								LocalBuilder tmpVar = il.DeclareLocal(typeof(object));
								
								// This succeeds only for exact match
								il.Emit(OpCodes.Call, Methods.ConvertToClr.UnwrapNullable);
								il.Emit(OpCodes.Dup);
								il.Stloc(tmpVar);

								// <stack_0> = tmpVar = UnwrapNullable(...)
								// if (<stack_0> != null) 
								Label lblNull = il.DefineLabel(), lblDone = il.DefineLabel();
								il.Emit(OpCodes.Ldnull);
								il.Emit(OpCodes.Beq, lblNull);
								// {

								// Convert tmpVar to T and wrap it into Nullable<T>
								il.Ldloc(tmpVar);
								bool ret = EmitConvertObjectToClr(il, typeCode, nullableArg, strictnessLocal);
								// TODO: use reflection cache?
								il.Emit(OpCodes.Newobj, nullableType.GetConstructors()[0]);
								il.Emit(OpCodes.Br, lblDone);
								
								// } else /* == null */ {
								il.MarkLabel(lblNull);

								// return (T?)null;
								LocalBuilder tmpNull = il.DeclareLocal(nullableType);
								il.Ldloca(tmpNull);
								il.Emit(OpCodes.Initobj, nullableType);
								il.Ldloc(tmpNull);
								// }
								
								il.MarkLabel(lblDone);
								return ret;
							}
							else
								convert_method = Methods.ConvertToClr.TryObjectToStruct.MakeGenericMethod(formalType);
						}
						else
						{
							if (formalType.IsArray)
								convert_method = Methods.ConvertToClr.TryObjectToArray.MakeGenericMethod(formalType.GetElementType());
							else if (typeof(Delegate).IsAssignableFrom(formalType))
								convert_method = Methods.ConvertToClr.TryObjectToDelegate.MakeGenericMethod(formalType);
							else
								convert_method = Methods.ConvertToClr.TryObjectToClass.MakeGenericMethod(formalType);
						}
						break;
					}

				default:
					Debug.Fail();
					return true;
			}

			if (convert_method != null)
			{
				il.Ldloca(strictnessLocal);
				il.Emit(OpCodes.Call, convert_method);
				return false;
			}
			else return true;
		}
Пример #4
0
		protected virtual GetterDelegate/*!*/ GenerateGetterStub()
		{
#if SILVERLIGHT
			DynamicMethod stub = new DynamicMethod("<^GetterStub>", Types.Object[0], Types.Object);
#else
			DynamicMethod stub = new DynamicMethod("<^GetterStub>", PhpFunctionUtils.DynamicStubAttributes, CallingConventions.Standard,
				Types.Object[0], Types.Object, this.declaringType.RealType, true);
#endif

			ILEmitter il = new ILEmitter(stub);

			ClrEvent clr_event;
			ClrProperty clr_property;

			Type result_type;

			if ((clr_event = Member as ClrEvent) != null)
			{
                Debug.Assert(!declaringType.RealType.IsValueType, "Value type with ClrEvent not handled! TODO: arg(0) is ClrValue<T>.");

				LocalBuilder temp = il.DeclareLocal(declaringType.RealType);

				il.Ldarg(0);
				il.Emit(OpCodes.Castclass, declaringType.RealType);
				il.Stloc(temp);

				clr_event.EmitGetEventObject(il, new Place(null, Properties.ScriptContext_CurrentContext),
					new Place(temp), true);
			}
			else
			{
				if ((clr_property = Member as ClrProperty) != null)
				{
					// return error-throwing getter if the property is write-only
					if (!clr_property.HasGetter) return new GetterDelegate(MissingGetter);

					if (!clr_property.Getter.IsStatic)
					{
                        ClrOverloadBuilder.EmitLoadInstance(il, IndexedPlace.ThisArg, declaringType.RealType);
//                        il.Emit(OpCodes.Ldarg_0);
						
//                        if (declaringType.RealType.IsValueType) 
//                            il.Emit(OpCodes.Unbox, declaringType.RealType);
//#if EMIT_VERIFIABLE_STUBS
//                        else
//                            il.Emit(OpCodes.Castclass, this.declaringType.RealType);
//#endif
					}

					il.Emit(OpCodes.Call, clr_property.Getter);

					result_type = clr_property.Getter.ReturnType;
				}
				else
				{
					ClrField clr_field = ClrField;

					if (!clr_field.FieldInfo.IsStatic)
					{
                        ClrOverloadBuilder.EmitLoadInstance(il, IndexedPlace.ThisArg, declaringType.RealType);
                        //il.Emit(OpCodes.Ldarg_0);
                        ////il.Emit(OpCodes.Castclass, this.declaringType.RealType);

                        //if (declaringType.RealType.IsValueType) il.Emit(OpCodes.Unbox, declaringType.RealType);
						il.Emit(OpCodes.Ldfld, clr_field.FieldInfo);
					}
					else
					{
						il.Emit(OpCodes.Ldsfld, clr_field.FieldInfo);
					}

					result_type = clr_field.FieldInfo.FieldType;
				}

				il.EmitBoxing(ClrOverloadBuilder.EmitConvertToPhp(il, result_type/*, null*/));
			}

			il.Emit(OpCodes.Ret);

			return (GetterDelegate)stub.CreateDelegate(typeof(GetterDelegate));
		}
Пример #5
0
		/// <summary>
		/// Called when a <see cref="PHP.Core.AST.MethodDecl"/> AST node is entered during the emit phase.
		/// </summary>
		public void EnterMethodDeclaration(PhpMethod/*!*/ method)
		{
            bool is_optimized = (method.Properties & RoutineProperties.HasUnoptimizedLocals) == 0;
			bool rt_variables_table = (method.Properties & RoutineProperties.HasRTVariablesTable) != 0;

			CompilerLocationStack.TypeDeclContext class_context = locationStack.PeekTypeDecl();

			CompilerLocationStack.MethodDeclContext md_context = new CompilerLocationStack.MethodDeclContext();
			md_context.Type = class_context.Type;
			md_context.Method = method;

			// Set whether access to variables should be generated via locals or table
			md_context.OptimizedLocals = this.OptimizedLocals;
			OptimizedLocals = is_optimized;

			// set compile-time variables table:
			md_context.CurrentVariablesTable = this.currentVariablesTable;
			currentVariablesTable = method.Builder.LocalVariables;

			// set compile-time variables table:
			md_context.CurrentLabels = this.currentLabels;
			currentLabels = method.Builder.Labels;

			// Set the valid method to emit the "return" statement
			md_context.ReturnsPhpReference = this.ReturnsPhpReference;
			this.ReturnsPhpReference = method.Signature.AliasReturn;

            // CallSites (same as in TypeDecl, not changed):
            //md_context.CallSites = callSites;
            //this.callSites = new Compiler.CodeGenerator.CallSites(/*class_context = TypeContextPlace*/);

            // create new IL emitter for the method:
            md_context.IL = il;
			il = new ILEmitter(method.ArgFullInfo);

			// set RT variables table place:
			md_context.RTVariablesTablePlace = RTVariablesTablePlace;
			if (rt_variables_table)
			{
				LocalBuilder var_table_local = il.DeclareLocal(PhpVariable.RTVariablesTableType);
				if (sourceUnit.SymbolDocumentWriter != null)
					var_table_local.SetLocalSymInfo("<locals>");
				RTVariablesTablePlace = new Place(var_table_local);
			}
			else
				RTVariablesTablePlace = LiteralPlace.Null;

			// sets ScriptContext and Self places appropriately:
			md_context.ClassContextPlace = TypeContextPlace;
			md_context.ScriptContextPlace = ScriptContextPlace;
			md_context.SelfPlace = SelfPlace;
            md_context.LateStaticBindTypePlace = LateStaticBindTypePlace;

			if (method.IsStatic)
			{
				ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, FunctionBuilder.ArgContextStatic);
				SelfPlace = LiteralPlace.Null;
			}
			else
			{
				ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, FunctionBuilder.ArgContextInstance);
				if (method.DeclaringPhpType.ProxyFieldInfo != null)
				{
					// the real this is not a DObject
					SelfPlace = new Place(IndexedPlace.ThisArg, method.DeclaringPhpType.ProxyFieldInfo);
				}
				else
				{
					// the real this is a DObject
					SelfPlace = IndexedPlace.ThisArg;
				}
			}

			// set Result place and return label:
			md_context.ResultPlace = ResultPlace;
			md_context.ReturnLabel = ReturnLabel;
			ResultPlace = null;
            LateStaticBindTypePlace = null;

			// set exception block nesting:
			md_context.ExceptionBlockNestingLevel = ExceptionBlockNestingLevel;
			ExceptionBlockNestingLevel = 0;

            // set current PhpRoutine
            md_context.PhpRoutine = method;

            //
			locationStack.PushMethodDecl(md_context);
		}
Пример #6
0
        private bool EnterFunctionDeclarationInternal(PhpRoutine/*!*/ function, QualifiedName qualifiedName)
		{
            Debug.Assert(function.IsFunction);

			bool is_optimized = (function.Properties & RoutineProperties.HasUnoptimizedLocals) == 0;
			bool indirect_local_access = (function.Properties & RoutineProperties.IndirectLocalAccess) != 0;

			CompilerLocationStack.FunctionDeclContext fd_context = new CompilerLocationStack.FunctionDeclContext();
            fd_context.Name = qualifiedName;

			// Set whether access to variables should be generated via locals or table
			fd_context.OptimizedLocals = this.OptimizedLocals;
			this.OptimizedLocals = is_optimized;

			// Set the valid method to emit the "return" statement
			fd_context.ReturnsPhpReference = this.ReturnsPhpReference;
			this.ReturnsPhpReference = function.Signature.AliasReturn;

            // CallSites
            fd_context.CallSites = null;//fd_context.CallSites = callSites;
            //this.callSites = new Compiler.CodeGenerator.CallSitesBuilder(
            //    sourceUnit.CompilationUnit.Module.GlobalType.RealModuleBuilder,
            //    fd_context.Name.ToString(),
            //    LiteralPlace.Null);
            // keep current site container, just change the class context (to avoid of creating and baking so many types)
            this.callSites.PushClassContext(LiteralPlace.Null, null);
            
            // Set ILEmitter to function's body
			fd_context.IL = this.il;
			this.il = new ILEmitter(function.ArgFullInfo);

			// Set current variables table (at codeGenerator)
			fd_context.CurrentVariablesTable = this.currentVariablesTable;
			this.currentVariablesTable = function.Builder.LocalVariables;

			// Set current variables table (at codeGenerator)
			fd_context.CurrentLabels = this.currentLabels;
			this.currentLabels = function.Builder.Labels;

			// Set place for loading hashtable with variables at runtime
			fd_context.RTVariablesTablePlace = this.RTVariablesTablePlace;

			if (indirect_local_access || !is_optimized)
			{
				LocalBuilder var_table_local = il.DeclareLocal(PhpVariable.RTVariablesTableType);
				if (sourceUnit.SymbolDocumentWriter != null)
					var_table_local.SetLocalSymInfo("<locals>");
				this.RTVariablesTablePlace = new Place(var_table_local);
			}
			else
				this.RTVariablesTablePlace = LiteralPlace.Null;

			// Set ScriptContext
			fd_context.ScriptContextPlace = this.ScriptContextPlace;
			this.ScriptContextPlace = new IndexedPlace(PlaceHolder.Argument, FunctionBuilder.ArgContext);

			// Set Class context
			fd_context.ClassContextPlace = this.TypeContextPlace;
			this.TypeContextPlace = LiteralPlace.Null;

			// Set Self
			fd_context.SelfPlace = this.SelfPlace;
			this.SelfPlace = LiteralPlace.Null;

            // Set Static
            fd_context.LateStaticBindTypePlace = this.LateStaticBindTypePlace;
            this.LateStaticBindTypePlace = null;

            // set Result place
			fd_context.ResultPlace = this.ResultPlace;
			fd_context.ReturnLabel = this.ReturnLabel;
			this.ResultPlace = null;
            
			// set exception block nesting:
			fd_context.ExceptionBlockNestingLevel = this.ExceptionBlockNestingLevel;
			this.ExceptionBlockNestingLevel = 0;

            // set current PhpRoutine
            fd_context.PhpRoutine = function;

            //
			locationStack.PushFunctionDecl(fd_context);
			return true;
		}
Пример #7
0
        /// <summary>
        /// Emit static method that creates an instance of given value type using default ctor.
        /// </summary>
        /// <param name="valueType">Value type to be instantiated by resulting method.</param>
        /// <returns>The method that returns value boxed into new instance of <see cref="ClrValue&lt;T&gt;"/>.</returns>
        private static MethodBase BuildDefaultValueCtor(Type/*!*/valueType)
        {
            Debug.Assert(valueType != null && valueType.IsValueType, "Argument 'valueType' must not be null and must represent a value type!");

            DynamicMethod method = new DynamicMethod(valueType.Name + "..ctor", Types.Object[0], Type.EmptyTypes);
            Emit.ILEmitter il = new PHP.Core.Emit.ILEmitter(method);

            // local 0
            // ldloca.s 0
            // initobj <valueType>
            
            var loc = il.DeclareLocal(valueType);

            il.Emit(OpCodes.Ldloca_S, loc);
            il.Emit(OpCodes.Initobj, valueType);
            
            // LOAD <loc>
            // box ConvertToPhp <valueType>

            il.Emit(OpCodes.Ldloc, loc);
            il.EmitBoxing(ClrOverloadBuilder.EmitConvertToPhp(il, valueType));

            // return
            il.Emit(OpCodes.Ret);

            // done
            return method;
        }