Пример #1
0
		public static void EmitAddFrame(ILEmitter/*!*/ il, IPlace/*!*/ scriptContextPlace, int typeArgCount, int argCount,
		  Action<ILEmitter, int> typeArgEmitter, Action<ILEmitter, int>/*!*/ argEmitter)
		{
			Debug.Assert(typeArgCount == 0 || typeArgEmitter != null);

			// type args:
			if (typeArgCount > 0)
			{
				scriptContextPlace.EmitLoad(il);
				il.Emit(OpCodes.Ldfld, Fields.ScriptContext_Stack);

				il.EmitOverloadedArgs(Types.DTypeDesc[0], typeArgCount, Methods.PhpStack.AddTypeFrame.ExplicitOverloads, typeArgEmitter);
			}

			// args:
			scriptContextPlace.EmitLoad(il);
			il.Emit(OpCodes.Ldfld, Fields.ScriptContext_Stack);

			il.EmitOverloadedArgs(Types.Object[0], argCount, Methods.PhpStack.AddFrame.ExplicitOverloads, argEmitter);

			il.Emit(OpCodes.Call, Methods.PhpStack.AddFrame.Overload(argCount));

			// AddFrame adds empty type frame by default, so if there are no type parameters, we can skip AddTypeFrame call:
			if (typeArgCount > 0)
				il.Emit(OpCodes.Call, Methods.PhpStack.AddTypeFrame.Overload(typeArgCount));
		}
Пример #2
0
		public ClrStubBuilder(ILEmitter/*!*/ il, IPlace/*!*/ scriptContextPlace, int paramCount, int paramOffset)
		{
			this.il = il;
			this.scriptContextPlace = scriptContextPlace;
			this.paramOffset = paramOffset;

			this.referenceLocals = new LocalBuilder[paramCount];
		}
Пример #3
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);
		}
Пример #4
0
			/// <summary>
			/// Initializes a new empty instance of the <see cref="Chain"/>.
			/// </summary>
			/// <param name="il">An IL emitter.</param>
			public Chain(ILEmitter il)
			{
				isChainMember = false;
				isArrayItem = false;
				IsLastChainMember = false;
				length = 0;
				errorLabelHasValue = false;
				this.il = il;
				this.QuietRead = false;
			}
Пример #5
0
		public static void EmitArgFullPostCall(ILEmitter/*!*/ il, IPlace/*!*/ stack, LocalBuilder locArgsCount)
		{
			// args-aware:
			if (locArgsCount != null)
			{
				// CALL stack.RemoveArgsAwareFrame(count);
				stack.EmitLoad(il);
				il.Ldloc(locArgsCount);
				il.Emit(OpCodes.Call, Methods.PhpStack.RemoveArgsAwareFrame);
			}
		}
Пример #6
0
        /// <summary>
        /// Emit <see cref="PhpVariable.Copy"/> if needed. It means <see cref="Expression.Access"/> has to be <see cref="AccessType.Read"/> and <paramref name="returnType"/> has to be copiable.
        /// </summary>
        /// <param name="il">The <see cref="ILEmitter"/>.</param>
        /// <param name="returnType"><see cref="PhpTypeCode"/> of function call return value.</param>
        protected void EmitReturnValueCopy(ILEmitter/*!*/il, PhpTypeCode returnType)
        {
            Debug.Assert(il != null);

            // copy only if we are reading the return value &&
            // only if return type is copiable:
            if (access != AccessType.None &&   // reading, not literals:
                PhpTypeCodeEnum.IsDeeplyCopied(returnType) &&
                returnType != PhpTypeCode.PhpReference) // PhpSmartReference can be an issue if method returns an object field (but this is handled by binders)
            {
                il.LdcI4((int)CopyReason.ReturnedByCopy);
                il.Emit(OpCodes.Call, Methods.PhpVariable.Copy);
            }
        }
Пример #7
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);
			}
		}
Пример #8
0
		public void DefineContextType()
		{
			linqContextBuilder = cg.IL.TypeBuilder.DefineNestedType(ContextTypeName + cg.IL.GetNextUniqueIndex(),
				TypeAttributes.Class | TypeAttributes.NestedPrivate | TypeAttributes.Sealed,
				typeof(PHP.Core.LinqContext), null);

			// .ctor:

			ConstructorBuilder ctor = linqContextBuilder.DefineConstructor(MethodAttributes.Assembly,
				CallingConventions.HasThis, Types.LinqContextArgs);

			ILEmitter il = new ILEmitter(ctor);
			il.Ldarg(0);
			il.Ldarg(1);
			il.Ldarg(2);
			il.Ldarg(3);
			il.Ldarg(4);
			il.Emit(OpCodes.Call, Constructors.LinqContext);
			il.Emit(OpCodes.Ret);

			linqContextCtor = ctor;
		}
Пример #9
0
        /// <summary>
        /// Emit LOAD <paramref name="instance"/>.
        /// </summary>ILEmiter
        /// <param name="il"><see cref="ILEmitter"/> object instance.</param>
        /// <param name="instance">The place where to load the instance from.</param>
        /// <param name="declaringType">The type of resulting instance.</param>
        /// <remarks>Instance of value types are wrapped in <see cref="ClrValue&lt;T&gt;"/> object instance.</remarks>
        internal static void EmitLoadInstance(ILEmitter/*!*/il, IPlace/*!*/instance, Type/*!*/declaringType)
        {
            Debug.Assert(il != null && instance != null && declaringType != null, "ClrOverloadBuilder.EmitLoadInstance() null argument!");

            // LOAD <instance>
            instance.EmitLoad(il);

            if (declaringType.IsValueType)
            {
                var clrValueType = ClrObject.valueTypesCache.Get(declaringType).Item1;
                Debug.Assert(clrValueType != null, "Specific ClrValue<T> not found!");

                // CAST (ClrValue<T>)
                il.Emit(OpCodes.Castclass, clrValueType);

                // LOAD .realValue
                var realValueField = clrValueType.GetField("realValue");
                Debug.Assert(realValueField != null, "ClrValue<T>.realValue field not found!");
                il.Emit(OpCodes.Ldflda, clrValueType.GetField("realValue"));
            }
            else
            {
                // CAST (T)
                il.Emit(OpCodes.Castclass, declaringType);
            }
        }
Пример #10
0
		/// <summary>
		/// Converts a value of the given CLR type to PHP value.
		/// </summary>
		internal static PhpTypeCode EmitConvertToPhp(ILEmitter/*!*/ il, Type/*!*/ type)
		{
			// box generic parameter
			if (type.IsGenericParameter)
			{
				il.Emit(OpCodes.Box, type);
				type = Types.Object[0];
			}

			switch (Type.GetTypeCode(type))
			{
				// primitives:
				case TypeCode.Boolean: return PhpTypeCode.Boolean;
				case TypeCode.Int32: return PhpTypeCode.Integer;
				case TypeCode.Int64: return PhpTypeCode.LongInteger;
				case TypeCode.Double: return PhpTypeCode.Double;
				case TypeCode.String: return PhpTypeCode.String;

				// coercion:
				case TypeCode.SByte:
				case TypeCode.Int16:
				case TypeCode.Byte:
				case TypeCode.UInt16:
					{
						il.Emit(OpCodes.Conv_I4);
						return PhpTypeCode.Integer;
					}

				case TypeCode.UInt32: EmitConstrainedCoercion(il, typeof(int), typeof(long), Int32.MaxValue); return PhpTypeCode.Object;
				case TypeCode.UInt64: EmitConstrainedCoercion(il, typeof(int), typeof(long), Int32.MaxValue); return PhpTypeCode.Object;

				case TypeCode.Single: il.Emit(OpCodes.Conv_R8); return PhpTypeCode.Double;
                case TypeCode.Char:
                    il.Emit(OpCodes.Box, type);
                    il.Emit(OpCodes.Callvirt, Methods.Object_ToString);
                    return PhpTypeCode.String;

				case TypeCode.DBNull:
					{
						il.Emit(OpCodes.Pop);
						il.Emit(OpCodes.Ldnull);
						return PhpTypeCode.Object;
					}

				case TypeCode.Decimal: // TODO: what to do with this guy?
				case TypeCode.DateTime:
					{
						il.Emit(OpCodes.Box, type);
						il.Emit(OpCodes.Call, Methods.ClrObject_Wrap);
						return PhpTypeCode.DObject;
					}

				case TypeCode.Object:
					{
						if (!typeof(IPhpVariable).IsAssignableFrom(type))
						{
							if (type.IsValueType)
								il.Emit(OpCodes.Box, type);

							il.Emit(OpCodes.Call, Methods.ClrObject_WrapDynamic);

							return PhpTypeCode.Object;
						}
						else return PhpTypeCodeEnum.FromType(type);
					}

				default:
					{
						Debug.Fail();
						return PhpTypeCode.Invalid;
					}
			}
		}
Пример #11
0
		internal static void EmitConstrainedCoercion(ILEmitter/*!*/ il, Type/*!*/ narrow, Type/*!*/ wide, object threshold)
		{
			Label else_label = il.DefineLabel();
			Label endif_label = il.DefineLabel();

			il.Emit(OpCodes.Dup);

			// IF (STACK <= threshold) THEN
			il.LoadLiteral(threshold);
			il.Emit(OpCodes.Bgt_S, else_label);

			// LOAD (narrow)STACK
			il.Conv(narrow, false);
			il.Emit(OpCodes.Box, narrow);

			il.Emit(OpCodes.Br_S, endif_label);

			// ELSE
			il.MarkLabel(else_label);

			// LOAD (wide)STACK

			il.Conv(wide, false);
			il.Emit(OpCodes.Box, wide);

			// ENDIF
			il.MarkLabel(endif_label);
		}
Пример #12
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;
		}
Пример #13
0
		public ClrOverloadBuilder(ILEmitter/*!*/ il, ClrMethod/*!*/ method, ConstructedType constructedType,
			IPlace/*!*/ stack, IPlace/*!*/ instance, bool emitParentCtorCall,
			ParameterLoader/*!*/ loadValueArg, ParameterLoader/*!*/ loadReferenceArg)
		{
			this.il = il;
			this.method = method;
			this.constructedType = constructedType;
			this.stack = stack;
			this.instance = instance;
			this.loadValueArg = loadValueArg;
			this.loadReferenceArg = loadReferenceArg;
			this.emitParentCtorCall = emitParentCtorCall;

			this.overloads = new List<Overload>(method.Overloads);
			SortOverloads(this.overloads);
		}
Пример #14
0
		/// <summary>
		/// Converts a PHP value to the given CLR type (the caller is not interested in the success of the conversion).
		/// </summary>
		public static void EmitConvertToClr(ILEmitter/*!*/ il, PhpTypeCode typeCode, Type/*!*/ formalType)
		{
			EmitConvertToClr(il, typeCode, formalType, il.GetTemporaryLocal(typeof(ConversionStrictness), true));
		}
Пример #15
0
		/// <summary>
		/// Converts a PHP value to the given CLR type (the caller passes a <paramref name="strictnessLocal"/> that will
		/// receive one of the <see cref="PHP.Core.ConvertToClr.ConversionStrictness"/> enumeration values that
		/// describe the conversion result (the Failed value indicates that conversion was not successful).
		/// </summary>
		/// <returns><B>True</B> if it the conversion will surely succeed.</returns>
		internal static bool EmitConvertToClr(ILEmitter/*!*/ il, PhpTypeCode typeCode,
			Type/*!*/ formalType, LocalBuilder/*!*/ strictnessLocal)
		{
			Debug.Assert(strictnessLocal.LocalType == typeof(ConversionStrictness));

			// preprocess the value according to the PHP type code
			switch (typeCode)
			{
				case PhpTypeCode.PhpReference:
					{
						// dereference
						il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
						typeCode = PhpTypeCode.Object;
						break;
					}

				case PhpTypeCode.ObjectAddress:
					{
						// dereference
						il.Emit(OpCodes.Ldind_Ref);
						typeCode = PhpTypeCode.Object;
						break;
					}

				case PhpTypeCode.LinqSource:
				case PhpTypeCode.PhpRuntimeChain:
					{
						Debug.Fail();
						return true;
					}
			}

			// special treatment for generic parameters
			if (formalType.IsGenericParameter)
			{
				EmitConvertToClrGeneric(il, formalType, strictnessLocal);
				return false;
			}

			// convert CLR type
			return EmitConvertObjectToClr(il, typeCode, formalType, strictnessLocal);
		}
Пример #16
0
        /// <summary>
        /// Emit publically accessible stub that just calls argfull of <paramref name="function"/>.
        /// </summary>
        /// <returns><see cref="MethodInfo"/> of newly created function stub.</returns>
        private MethodInfo/*!*/EmitPhpFunctionPublicStub(ref TypeBuilder publicsContainer, PhpFunction/*!*/function)
        {
            Debug.Assert(function != null);
            Debug.Assert(function.ArgFullInfo != null, "!function.ArgFullInfo");

            if (publicsContainer == null)
            {
                publicsContainer = PureAssemblyBuilder.RealModuleBuilder.DefineType(
                    string.Format("{1}<{0}>",
                        StringUtils.ToClsCompliantIdentifier(Path.ChangeExtension(PureAssemblyBuilder.FileName, "")),
                        QualifiedName.Global.ToString()),
                    TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class | TypeAttributes.SpecialName);
            }

            Type returnType;
            var parameterTypes = function.Signature.ToArgfullSignature(1, out returnType);
            parameterTypes[0] = Types.ScriptContext[0];

            var mi = publicsContainer.DefineMethod(function.GetFullName(), MethodAttributes.Public | MethodAttributes.Static, returnType, parameterTypes);
            var il = new ILEmitter(mi);

            // load arguments
            for (int i = 0; i < parameterTypes.Length; i++)
            {
                if (function.Builder != null)
                    mi.DefineParameter(i + 1, ParameterAttributes.None, function.Builder.ParameterBuilders[i].Name);

                il.Ldarg(i);
            }
            
            // call function.ArgFullInfo
            il.Emit(OpCodes.Call, function.ArgFullInfo);
            
            // .ret
            il.Emit(OpCodes.Ret);

            //
            return mi;
        }
Пример #17
0
        internal static void EmitGetterStub(ILEmitter/*!*/ il, PropertyInfo/*!*/ propertyInfo, Type/*!*/ declaringType)
        {
            var getter = propertyInfo.GetGetMethod(/*false*/);

            if (getter == null)
            {
                il.Emit(OpCodes.Ldstr, declaringType.Name);
                il.Emit(OpCodes.Ldstr, "get_" + propertyInfo.Name);
                il.Emit(OpCodes.Call, Methods.PhpException.UndefinedMethodCalled);
                il.Emit(OpCodes.Ldnull);

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

            if (getter.IsStatic)
            {
                // [ return getter() ]
                il.Emit(OpCodes.Call, getter);
            }
            else
            {
                // [ return ((self)<instance>).getter() ]
                il.Ldarg(0);
                il.Emit(OpCodes.Castclass, declaringType);
                il.Emit(OpCodes.Call, getter);
            }

            // box
            il.EmitBoxing(PhpTypeCodeEnum.FromType(getter.ReturnType));

            //
            il.Emit(OpCodes.Ret);
        }
Пример #18
0
		/// <summary>
		/// Emits helper declaring all single-declared functions and classes in the script being built.
		/// </summary>
		/// <remarks>
		/// For each function and class emits a call to <see cref="ApplicationContext.DeclareFunction"/> and 
        /// <see cref="ApplicationContext.DeclareType"/>, respectively, which declares it.
		/// The helper is called as the first instruction of Main helper. 
		/// </remarks>		
		private void EmitDeclareHelper()
		{
			PureCompilationUnit unit = this.PureCompilationUnit;
			ILEmitter il = new ILEmitter(declareHelperBuilder);
			IndexedPlace app_context_place = new IndexedPlace(PlaceHolder.Argument, 0);
            TypeBuilder publicsContainer = null;    // container type for public stubs of global declarations (which are inaccessible from other assemblies)

			foreach (PhpFunction function in unit.GetDeclaredFunctions())
			{
				if (function.IsDefinite)
				{
					app_context_place.EmitLoad(il);

					// NEW RoutineDelegate(<static method>);
					il.Emit(OpCodes.Ldnull);
					il.Emit(OpCodes.Ldftn, function.ArgLessInfo);
					il.Emit(OpCodes.Newobj, Constructors.RoutineDelegate);

					// LOAD <full name>;
					il.Emit(OpCodes.Ldstr, function.FullName);

					// LOAD <attributes>;
					il.LdcI4((int)function.MemberDesc.MemberAttributes);

                    // LOAD <argfull>
                    if (function.ArgFullInfo != null)
                        CodeGenerator.EmitLoadMethodInfo(
                            il,
                            (function.ArgFullInfo.DeclaringType != null)
                                ? function.ArgFullInfo
                                : EmitPhpFunctionPublicStub(ref publicsContainer, function) // function.ArgFullInfo is real global method not accessible from other assemblies, must be wrapped
                            /*, AssemblyBuilder.DelegateBuilder*/);
                    else
                        il.Emit(OpCodes.Ldnull);
                    
					// CALL <application context>.DeclareFunction(<stub>, <name>, <member attributes>, <argfull>)
					il.Emit(OpCodes.Call, Methods.ApplicationContext.DeclareFunction);
				}
			}

			foreach (PhpType type in unit.GetDeclaredTypes())
			{
				if (type.IsDefinite)
				{
					// CALL <application context>.DeclareType(<type desc>, <name>);
					type.EmitAutoDeclareOnApplicationContext(il, app_context_place);
				}
			}

			foreach (GlobalConstant constant in unit.GetDeclaredConstants())
			{
				if (constant.IsDefinite)
				{
					app_context_place.EmitLoad(il);

					// CALL <application context>.DeclareConstant(<name>, <value>);
					il.Emit(OpCodes.Ldstr, constant.FullName);
                    //il.Emit(OpCodes.Ldsfld, constant.RealField);
                    //if (constant.RealField.FieldType.IsValueType) il.Emit(OpCodes.Box, constant.RealField.FieldType);
                    il.LoadLiteralBox(constant.Value);
					il.Emit(OpCodes.Call, Methods.ApplicationContext.DeclareConstant);
				}
			}

			il.Emit(OpCodes.Ret);

            // complete the publicsContainer type, if created:
            if (publicsContainer != null)
                publicsContainer.CreateType();
		}
Пример #19
0
		public void EmitStore(ILEmitter/*!*/ il)
		{
			throw new InvalidOperationException();
		}
Пример #20
0
		protected virtual SetterDelegate/*!*/ GenerateSetterStub()
		{
			if (Member is ClrEvent) return new SetterDelegate(EventSetter);

#if SILVERLIGHT
			DynamicMethod stub = new DynamicMethod("<^SetterStub>", Types.Void, Types.Object_Object);

            /*DynamicMethod stub = new DynamicMethod("<^SetterStub>", PhpFunctionUtils.DynamicStubAttributes, CallingConventions.Standard,
                Types.Void, Types.Object_Object, this.declaringType.RealType, true);*/
#else
			DynamicMethod stub = new DynamicMethod("<^SetterStub>", PhpFunctionUtils.DynamicStubAttributes, CallingConventions.Standard,
				Types.Void, Types.Object_Object, this.declaringType.RealType, true);
#endif
#if DEBUG_DYNAMIC_STUBS

			// Debugging - save the generated stub to TEMP
			AssemblyName name = new AssemblyName("SetterStub_" + Property.FullName.ToString().Replace(':', '_'));
			AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Save, "C:\\Temp");
			ModuleBuilder mb = ab.DefineDynamicModule(name.Name, name.Name + ".dll");
			TypeBuilder tb = mb.DefineType("Stub");
			MethodBuilder meb = tb.DefineMethod(DeclaringType.ToString() + "::" + Property.FullName,
				MethodAttributes.PrivateScope | MethodAttributes.Static, Types.Void, Types.Object_Object);

			ILEmitter il_dbg = new ILEmitter(meb);
			IndexedPlace instance2 = new IndexedPlace(PlaceHolder.Argument, 0);
			IndexedPlace stack = new IndexedPlace(PlaceHolder.Argument, 1);

			ClrProperty clr_property_dbg = Member as ClrProperty;
			if (clr_property_dbg != null && clr_property_dbg.HasSetter)
			{
				if (!clr_property_dbg.Setter.IsStatic)
				{
					il_dbg.Emit(OpCodes.Ldarg_0);
                    if (declaringType.RealType.IsValueType)
                        il_dbg.Emit(OpCodes.Unbox, declaringType.RealType);
#if EMIT_VERIFIABLE_STUBS
                    else
                        il_dbg.Emit(OpCodes.Castclass, declaringType.RealType);
#endif
				}
				il_dbg.Emit(OpCodes.Ldarg_1);
				EmitSetConversion(il_dbg, PhpTypeCode.Object, clr_property_dbg.Setter.GetParameters()[0].ParameterType);
				il_dbg.Emit(OpCodes.Call, clr_property_dbg.Setter);
			}

			il_dbg.Emit(OpCodes.Ret);
			tb.CreateType();
			ab.Save("SetterStub_" + Property.FullName.ToString().Replace(':', '_') + ".dll");
#endif

			ILEmitter il = new ILEmitter(stub);

			ClrProperty clr_property = Member as ClrProperty;
			Type arg_type;

			if (clr_property != null)
			{
				// return error-throwing setter if the property is read-only
				if (!clr_property.HasSetter) return new SetterDelegate(MissingSetter);

				if (!clr_property.Setter.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, declaringType.RealType);
//#endif

				}

				il.Emit(OpCodes.Ldarg_1);

				arg_type = clr_property.Setter.GetParameters()[0].ParameterType;
				EmitSetConversion(il, PhpTypeCode.Object, arg_type);

				il.Emit(OpCodes.Call, clr_property.Setter);
			}
			else
			{
				ClrField clr_field = ClrField;

				// return error-throwing setter if the field is initonly
				if (clr_field.FieldInfo.IsInitOnly) return new SetterDelegate(MissingSetter);

				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.Ldarg_1);

				arg_type = clr_field.FieldInfo.FieldType;
				EmitSetConversion(il, PhpTypeCode.Object, arg_type);

				il.Emit((clr_field.FieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld), clr_field.FieldInfo);
			}

			il.Emit(OpCodes.Ret);

			return (SetterDelegate)stub.CreateDelegate(typeof(SetterDelegate));
		}
Пример #21
0
		private void EmitLoadAccessorDelegate(ILEmitter/*!*/ il, ConstructorInfo/*!*/ delegateCtor,
			IPlace instance, bool dynamicStub, MethodInfo accessor)
		{
			if (accessor != null)
			{
				if (instance != null) instance.EmitLoad(il); else il.Emit(OpCodes.Ldnull);
				if (!dynamicStub && accessor.IsVirtual)
				{
					instance.EmitLoad(il);
					il.Emit(OpCodes.Ldvirtftn, accessor);
				}
				else il.Emit(OpCodes.Ldftn, accessor);

				il.Emit(OpCodes.Newobj, delegateCtor);
			}
			else il.Emit(OpCodes.Ldnull);
		}
Пример #22
0
		internal void EmitGetEventObject(ILEmitter/*!*/ il, IPlace/*!*/ contextPlace, IPlace instance, bool dynamicStub)
		{
			// [ ClrEventObject<handlerType>.Wrap(<SC>, <event name>, <addMethod>, <removeMethod>) ]

			contextPlace.EmitLoad(il);
			il.Emit(OpCodes.Ldstr, FullName);

			ConstructorInfo hook_ctor = typeof(Library.EventClass<>.HookDelegate).MakeGenericType(HandlerType).
				GetConstructor(Types.DelegateCtorArgs);

			// create delegates to the add and remove methods
			EmitLoadAccessorDelegate(il, hook_ctor, instance, dynamicStub, AddMethod);
			EmitLoadAccessorDelegate(il, hook_ctor, instance, dynamicStub, RemoveMethod);

			MethodInfo wrap_method = typeof(Library.EventClass<>).MakeGenericType(HandlerType).GetMethod("Wrap");
			il.Emit(OpCodes.Call, wrap_method);
		}
Пример #23
0
 /// <summary>
 /// Emit (stack_top dup).IsAliased = true;
 /// </summary>
 /// <param name="il"></param>
 private void EmitIsAliased(ILEmitter/*!*/il)
 {
     // set IsAliased to true
     il.Emit(OpCodes.Dup);
     il.Emit(OpCodes.Ldc_I4_1);
     il.EmitCall(OpCodes.Callvirt, Properties.PhpReference_IsAliased.GetSetMethod(), null);
 }
Пример #24
0
        internal static void EmitSetterStub(ILEmitter/*!*/ il, PropertyInfo/*!*/ propertyInfo, Type/*!*/ declaringType)
        {
            var setter = propertyInfo.GetSetMethod(/*false*/);

            if (setter == null)
            {
                il.Emit(OpCodes.Ldstr, declaringType.Name);
                il.Emit(OpCodes.Ldstr, "set_" + propertyInfo.Name);
                il.Emit(OpCodes.Call, Methods.PhpException.UndefinedMethodCalled);  // CoreResources.readonly_property_written
                
                il.Emit(OpCodes.Ret);
                return;
            }

            var parameters = setter.GetParameters();
            Debug.Assert(parameters.Length == 1 /*&& parameters[0].ParameterType == Types.PhpReference[0]*/);

            if (!setter.IsStatic)
            {
                // [ ((self)<instance>). ]
                il.Ldarg(0);
                il.Emit(OpCodes.Castclass, declaringType);
            }
            
            // [ setter((object)value) ]
            il.Ldarg(1);
            il.Emit(OpCodes.Castclass, parameters[0].ParameterType);
            il.Emit(OpCodes.Call, setter);
            
            //
            il.Emit(OpCodes.Ret);
        }
Пример #25
0
		internal void EmitHelpers()
		{
			CompilationUnit unit = this.CompilationUnit;
			ILEmitter il = new ILEmitter(DeclareHelperBuilder);
			IndexedPlace script_context_place = new IndexedPlace(PlaceHolder.Argument, 0);

			foreach (PhpFunction function in unit.GetDeclaredFunctions())
			{
				if (function.IsDefinite)
				{
                    CodeGenerator.EmitDeclareFunction(il, script_context_place, function);
				}
			}

			foreach (PhpType type in unit.GetDeclaredTypes())
			{
				if (type.IsDefinite)
				{
					// CALL <context>.DeclareType(<type desc>, <name>);
					type.EmitAutoDeclareOnScriptContext(il, script_context_place);
				}
                else if (!type.IsComplete)
                {
                    if (type.IncompleteClassDeclareMethodInfo != null)
                    {
                        // check whether base class is known at this point of execution,
                        // if so, declare this incomplete class immediately. As PHP does.

                        type.EmitDeclareIncompleteOnScriptContext(il, script_context_place);
                    }
                }
			}

            foreach (GlobalConstant constant in unit.GetDeclaredConstants())
            {
                if (constant.IsDefinite)
                {
                    var field = constant.RealField;
                    Debug.Assert(field != null);
                    Debug.Assert(field.IsStatic);

                    // CALL <context>.DeclareConstant(<name>, <value>);
                    script_context_place.EmitLoad(il);

                    il.Emit(OpCodes.Ldstr, constant.FullName);
                    il.LoadLiteralBox(constant.Value);  //il.Emit(OpCodes.Ldsfld, field);   // const field cannot be referenced in IL
                    il.Emit(OpCodes.Call, Methods.ScriptContext.DeclareConstant);
                }
            }

			il.Emit(OpCodes.Ret);
		}
Пример #26
0
		/// <summary>
		/// Converts a PHP value to the given CLR type that is a generic parameter.
		/// </summary>
		private static void EmitConvertToClrGeneric(ILEmitter/*!*/ il, Type/*!*/ formalType, LocalBuilder/*!*/ strictnessLocal)
		{
			Debug.Assert(formalType.IsGenericParameter);

			// f...ing GenericTypeParameterBuilder will not allow us to read its attributes and constraints :(
			if (!(formalType is GenericTypeParameterBuilder))
			{
				GenericParameterAttributes attrs = formalType.GenericParameterAttributes;
				if (Reflection.Enums.GenericParameterAttrTest(attrs, GenericParameterAttributes.NotNullableValueTypeConstraint))
				{
					// we know that we are converting to a value type
					il.Ldloca(strictnessLocal);
					il.Emit(OpCodes.Call, Methods.ConvertToClr.TryObjectToStruct.MakeGenericMethod(formalType));
					return;
				}

				Type[] constraints = formalType.GetGenericParameterConstraints();
				for (int i = 0; i < constraints.Length; i++)
				{
					if (constraints[i].IsClass)
					{
						if (!constraints[i].IsArray && !typeof(Delegate).IsAssignableFrom(constraints[i]))
						{
							// we know that we are converting to a class that is not an array nor a delegate
							il.Ldloca(strictnessLocal);
							il.Emit(OpCodes.Call, Methods.ConvertToClr.TryObjectToClass.MakeGenericMethod(formalType));
							return;
						}
						else break;
					}
				}
			}

			// postpone the conversion to runtime
			il.Ldloca(strictnessLocal);
			il.Emit(OpCodes.Call, Methods.Convert.TryObjectToType.MakeGenericMethod(formalType));
		}
Пример #27
0
		public void EmitLoad(ILEmitter/*!*/ il)
		{
			Debug.Assert(ReferenceEquals(il, codeGenerator.IL));
			typeCode = expression.Emit(codeGenerator);
		}
Пример #28
0
		protected override void EmitEntryPoint(MethodBuilder/*!*/ builder)
		{
			PureCompilationUnit unit = PureModuleBuilder.PureCompilationUnit;

			Debug.Assert(unit.EntryPoint != null);

			ILEmitter il = new ILEmitter(builder);

			// LOAD new RoutineDelegate(<main PHP method>);
			il.Emit(OpCodes.Ldnull);
			il.Emit(OpCodes.Ldftn, unit.EntryPoint.ArgLessInfo);
			il.Emit(OpCodes.Newobj, Constructors.RoutineDelegate);

			// ScriptContext.RunApplication(<main helper delegate>, null, null);
			il.Emit(OpCodes.Ldnull);
			il.Emit(OpCodes.Ldnull);
			il.Emit(OpCodes.Call, Methods.ScriptContext.RunApplication);

			// RETURN;
			il.Emit(OpCodes.Ret);
		}
Пример #29
0
		public void EmitLoadAddress(ILEmitter/*!*/ il)
		{
			throw new InvalidOperationException();
		}
Пример #30
0
        protected override void EmitEntryPoint(MethodBuilder/*!*/ methodBuilder)
        {
            ScriptBuilder script_builder = GetEntryScriptBuilder();
            Debug.Assert(script_builder.CompilationUnit is ScriptCompilationUnit);

            if (script_builder == null)
                throw new InvalidOperationException(CoreResources.GetString("entrypoint_not_specified"));

            PhpSourceFile entry_file = ((ScriptCompilationUnit)script_builder.CompilationUnit).SourceUnit.SourceFile;

            ILEmitter il = new ILEmitter(methodBuilder);

            // LOAD new PhpScript.MainHelperDelegate(Default.Main);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldftn, script_builder.MainHelper);
            il.Emit(OpCodes.Newobj, Constructors.MainHelperDelegate);

            // LOAD <source name>
            il.Emit(OpCodes.Ldstr, entry_file.RelativePath.ToString());

            // LOAD Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)
            il.Emit(OpCodes.Call, Methods.Assembly.GetEntryAssembly);
            il.Emit(OpCodes.Callvirt, Properties.Assembly_Location.GetGetMethod());
            il.Emit(OpCodes.Call, Methods.Path.GetDirectoryName);

            // ScriptContext.RunApplication(<main helper delegate>, <source name>, <entry assembly directory> );
            il.Emit(OpCodes.Call, Methods.ScriptContext.RunApplication);

            // RETURN;
            il.Emit(OpCodes.Ret);
        }