示例#1
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;
		}
示例#2
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;
        }
示例#3
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);
        }
示例#4
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);
        }
示例#5
0
		internal static void EmitSetterStub(ILEmitter/*!*/ il, FieldInfo/*!*/ fieldInfo, Type/*!*/ declaringType)
		{
			Debug.Assert(fieldInfo.FieldType == Types.PhpReference[0]);

			if (fieldInfo.IsStatic)
			{
				// [ <real_field> = (PhpReference)value ]
				il.Ldarg(1);
				il.Emit(OpCodes.Castclass, Types.PhpReference[0]);
				il.Emit(OpCodes.Stsfld, fieldInfo);
			}
			else
			{
				// [ ((self)<instance>).<real_field> = (PhpReference)value ]
				il.Ldarg(0);
				il.Emit(OpCodes.Castclass, declaringType);
				il.Ldarg(1);
				il.Emit(OpCodes.Castclass, Types.PhpReference[0]);
				il.Emit(OpCodes.Stfld, fieldInfo);
			}
			il.Emit(OpCodes.Ret);
		}
示例#6
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));
		}
示例#7
0
		internal static void EmitGetterStub(ILEmitter/*!*/ il, FieldInfo/*!*/ fieldInfo, Type/*!*/ declaringType)
		{
			if (fieldInfo.IsStatic)
			{
				// [ return <real_field> ]
				il.Emit(OpCodes.Ldsfld, fieldInfo);
			}
			else
			{
				// [ return ((self)<instance>).<real_field> ]
				il.Ldarg(0);
				il.Emit(OpCodes.Castclass, declaringType);
				il.Emit(OpCodes.Ldfld, fieldInfo);
			}
			il.Emit(OpCodes.Ret);
		}
示例#8
0
		/// <summary>
		/// Emits stubs for one overridden or implemented PHP method.
		/// </summary>
		/// <param name="stubs">Already generated stubs.</param>
		/// <param name="target">The overriding/implementing method.</param>
		/// <param name="targetType">The type (perhaps constructed) that declared <paramref name="target"/>.</param>
		/// <param name="declaringType">The type where the stubs should be emitted.</param>
		/// <param name="template">The method being overridden/implemented (surely PHP).</param>
		/// <param name="newSlot"><B>True</B> if the stub should be assigned a new vtable slot,
		/// <B>false</B> otherwise.</param>
		/// <remarks>
		/// This method handles situations where method overriding/implementing does not work by itself because of
		/// the fact that method names in PHP are case insensitive.
		/// </remarks>
		private void EmitOverrideStubsForPhpTemplate(IDictionary<string, MethodBuilder>/*!*/ stubs,
			PhpMethod/*!*/ target, DType/*!*/ targetType, PhpType/*!*/ declaringType, DMemberRef/*!*/ template,
			bool newSlot)
		{
            PhpMethod php_template = (PhpMethod)template.Member;

            // Emit method stub if needed here ... (resolve .NET incompatibility of base method and overriding method)
            // 
            // Until now, several possible cases or their combination are known:
            // - base and overriding methods match, but their name letter-casing don't (need to define override explicitly to properly Bake the type)
            // - base and overriding methods name match exactly, but overriding methods has additional arguments (with default values) (in PHP it is allowed) (stub needed)
            // - ghost stub, where B extends A implements I, where A contains definition of method in I and casing does not match
            //
            // if signatures don't match, virtual sealed stub must be created, it only calls the target method
            // if signatures match, only explicit override must be stated

            if (target.Name.ToString() != php_template.Name.ToString() ||           // the names differ (perhaps only in casing)
                target.Signature.ParamCount != php_template.Signature.ParamCount || // signature was extended (additional arguments added, with implicit value only)
                target.Signature.AliasReturn != php_template.Signature.AliasReturn  // returns PhpReference instead of Object
                )
			{
				MethodInfo target_argfull = DType.MakeConstructed(target.ArgFullInfo, targetType as ConstructedType);
				TypeBuilder type_builder = declaringType.RealTypeBuilder;

				// we have to generate a pass-thru override stub that overrides the template based on
				// name since it is impossible to install an explicit override of a method declared by
				// a generic type in v2.0 SRE (feedback ID=97425)
				bool sre_bug_workaround = (template.Type is ConstructedType);

                if (target.DeclaringType == declaringType && !sre_bug_workaround &&
                    target.Signature.ParamCount == php_template.Signature.ParamCount &&
                    target.Signature.AliasReturn == php_template.Signature.AliasReturn)
				{
                    // signatures match, just install an explicit override if possible
					type_builder.DefineMethodOverride(target_argfull,
						DType.MakeConstructed(php_template.ArgFullInfo, template.Type as ConstructedType));
				}
				else
				{
					string stubs_key = null;
					MethodAttributes attrs;

                    if (sre_bug_workaround)
                    {
                        // check whether we have generated a stub having the template name before
                        if (stubs.ContainsKey(stubs_key = "," + php_template.ArgFullInfo.Name)) return;

                        attrs = php_template.ArgFullInfo.Attributes & ~MethodAttributes.Abstract;
                    }
                    else
                    {
                        attrs = MethodAttributes.PrivateScope | MethodAttributes.Virtual;
                    }

                    if (newSlot) attrs |= MethodAttributes.NewSlot; 
					else attrs &= ~MethodAttributes.NewSlot;

					// determine stub return and parameters type
					Type return_type;
					Type[] param_types = php_template.Signature.ToArgfullSignature(1, out return_type);
                    param_types[0] = Types.ScriptContext[0];

					MethodBuilder override_stub = type_builder.DefineMethod(
                        (sre_bug_workaround ? php_template.ArgFullInfo.Name : "<Override>"),
						attrs, return_type, param_types);

					ILEmitter il = new ILEmitter(override_stub);

                    //
                    // return target( [arg1, ...[, default, ...]] );
                    //

					// pass-thru all arguments, including this (arg0)
                    int pass_args = Math.Min(param_types.Length, target.Signature.ParamCount + 1);
					for (int i = 0; i <= pass_args; ++i) il.Ldarg(i);  // this, param1, ....
                    for (int i = pass_args; i <= target.Signature.ParamCount; ++i)
                    {
                        // ... // PhpException.MissingArgument(i, target.FullName); // but in some override it can be optional argument 
                        il.Emit(OpCodes.Ldsfld, PHP.Core.Emit.Fields.Arg_Default);  // paramN
                    }
                    il.Emit(OpCodes.Callvirt, target_argfull);

                    // return
                    if (target.Signature.AliasReturn != php_template.Signature.AliasReturn)
                        il.Emit(OpCodes.Call, target.Signature.AliasReturn
                            ? Methods.PhpVariable.Dereference       // PhpVariable.Deference(obj)                   
                            : Methods.PhpVariable.MakeReference);   // PhpVariable.MakeReference(obj)
                    il.Emit(OpCodes.Ret);

					if (sre_bug_workaround)
					{
						stubs.Add(stubs_key, override_stub);
					}
					else
					{
                        if (!php_template.ArgFullInfo.IsVirtual)
                            throw new InvalidOperationException(string.Format("Cannot override non-virtual method '{0}'!", php_template.ArgFullInfo.Name));

						type_builder.DefineMethodOverride(override_stub,
							DType.MakeConstructed(php_template.ArgFullInfo, template.Type as ConstructedType));
					}
				}
			}
		}
示例#9
0
		public void EmitFieldExportSetter(PhpField/*!*/ field, PropertyBuilder/*!*/ property, MethodBuilder/*!*/ setter)
		{
			IPlace instance_place = (field.IsStatic ? null : IndexedPlace.ThisArg);

			EmissionContext emission_context = SetupStubPlaces(field.DeclaringPhpType, setter.IsStatic);

			il = new ILEmitter(setter);
			try
			{
				// prepare the field for writing
				AssignmentCallback callback = field.EmitSet(this, instance_place, false, null, false);

				// load and convert the argument
				il.Ldarg(setter.IsStatic ? 0 : 1);
				PhpTypeCode type_code = ClrOverloadBuilder.EmitConvertToPhp(
					il,
					property.PropertyType/*,
					ScriptContextPlace*/);

				EmitBoxing(type_code);

				// write the field
				callback(this, PhpTypeCode.Object);

				il.Emit(OpCodes.Ret);
			}
			finally
			{
				RestorePlaces(emission_context);
			}
		}
示例#10
0
		/// <summary>
		/// Emits stub for one overridden/implemented/exported CLR overload.
		/// </summary>
		/// <param name="il"></param>
		/// <param name="scriptContextPlace"></param>
		/// <param name="stubParameters">The overload parameters.</param>
		/// <param name="stubTypeParameters">The overload type parameters.</param>
		/// <param name="stubReturnType">The overload return type.</param>
		/// <param name="target">The overriding/implementing/exporting method.</param>
		/// <param name="targetType">The type (perhaps constructed) that declared <paramref name="target"/>.</param>
		public static void EmitMethodStubBody(ILEmitter/*!*/ il, IPlace/*!*/ scriptContextPlace,
			ParameterInfo[]/*!*/ stubParameters, Type[]/*!*/ stubTypeParameters,
			Type/*!*/ stubReturnType, PhpMethod/*!*/ target, DType/*!*/ targetType)
		{
			bool stub_is_static = il.MethodBase.IsStatic;

			ClrStubBuilder stub_builder =
				new ClrStubBuilder(il, scriptContextPlace, stubParameters.Length, (stub_is_static ? 0 : 1));

			if (stubParameters.Length >= target.Signature.MandatoryParamCount &&
				stubTypeParameters.Length >= target.Signature.MandatoryGenericParamCount &&
				(target.Properties & RoutineProperties.IsArgsAware) == 0)
			{
				// we can directly call the target argful

				if (!stub_is_static) il.Ldarg(FunctionBuilder.ArgThis);
				scriptContextPlace.EmitLoad(il);

				stub_builder.EmitLoadArgfullParameters(stubParameters, stubTypeParameters, target);

				// invoke the target (virtually if it's not static)
				il.Emit(stub_is_static ? OpCodes.Call : OpCodes.Callvirt,
					DType.MakeConstructed(target.ArgFullInfo, targetType as ConstructedType));
			}
			else
			{
				// we have to take the argless way

				stub_builder.EmitLoadArglessParameters(stubParameters, stubTypeParameters, target);

				// invoke the target's argless
				// TODO: this is not behaving 100% correct, because we're losing virtual dispatch here
				if (stub_is_static) il.Emit(OpCodes.Ldnull);
				else il.Ldarg(FunctionBuilder.ArgThis);

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

				il.Emit(OpCodes.Call, DType.MakeConstructed(target.ArgLessInfo, targetType as ConstructedType));
			}

			// do not keep it on stack needlessly
			if (stubReturnType == Types.Void) il.Emit(OpCodes.Pop);

			// convert ref/out parameters back to CLR type
			for (int i = 0; i < stubParameters.Length; i++)
			{
				stub_builder.EmitStoreClrParameter(stubParameters[i]);
			}

			if (stubReturnType != Types.Void)
			{
				// convert the return parameter back to CLR type
				stub_builder.EmitConvertReturnValue(
					stubReturnType,
					target.Signature.AliasReturn ? PhpTypeCode.PhpReference : PhpTypeCode.Object);
			}

			il.Emit(OpCodes.Ret);
		}
示例#11
0
		/// <summary>
		/// Define a non-virtual intermediate method that performs the (non-virtual) argfull call.
		/// </summary>
		private MethodInfo/*!*/ BuildNonVirtualMediator()
		{
			Type ret_type;
			Type[] arg_types = signature.ToArgfullSignature(1, out ret_type);

			arg_types[0] = Types.ScriptContext[0];

			MethodInfo mediator = DefineRealMethod(
			  "<Mediator>", MethodAttributes.PrivateScope | MethodAttributes.SpecialName, ret_type, arg_types);

			// just delegate the call to the real argfull
			ILEmitter il = new ILEmitter(mediator);

			for (int i = 0; i <= arg_types.Length; i++) il.Ldarg(i);
			il.Emit(OpCodes.Call, argfull);
			il.Emit(OpCodes.Ret);

			return mediator;
		}
示例#12
0
        /// <summary>
        /// Create static <see cref="DynamicMethod"/> that wraps call of given <paramref name="mi"/>. The call is performed statically, method's overrides are not called.
        /// </summary>
        /// <param name="mi"><see cref="MethodInfo"/> to be called statically.</param>
        /// <returns>New <see cref="MethodInfo"/> representing static method stub.</returns>
        public static MethodInfo/*!*/WrapInstanceMethodCall(MethodInfo/*!*/mi)
        {
            Debug.Assert(mi != null);
            Debug.Assert(!mi.IsStatic, "'mi' must not be static!");

            var parameters = mi.GetParameters();

            // array of parameters type
            // Type[]{ <DeclaringType>, <arg1.Type>, ..., <argn.Type> }
            var paramTypes = new Type[parameters.Length + 1]; // = new Type[]{ mi.DeclaringType }.Concat(parameters.Select<ParameterInfo, Type>(p => p.ParameterType)).ToArray();
            paramTypes[0] = mi.DeclaringType;
            for (int i = 0; i < parameters.Length; i++)
                paramTypes[i + 1] = parameters[i].ParameterType;

            // create static dynamic method that calls given MethodInfo statically
            DynamicMethod stub = new DynamicMethod(mi.Name + "_", mi.ReturnType, paramTypes, mi.DeclaringType);
            ILEmitter il = new ILEmitter(stub);

            // return <mi>( instance, arg_1, arg_2, ..., arg_n ):
            for (int i = 0; i <= parameters.Length; i++)
                il.Ldarg(i);

            il.Emit(OpCodes.Call, mi);
            il.Emit(OpCodes.Ret);
            
            //
            return stub;
        }
示例#13
0
		/// <summary>
		/// Emits code that loads the value from this storage place.
		/// </summary>
		/// <param name="il">The <see cref="ILEmitter"/> to emit the code to.</param>
		public void EmitLoad(ILEmitter il)
		{
			switch (holder)
			{
				case PlaceHolder.Local: il.Ldloc(index); break;
				case PlaceHolder.Argument: il.Ldarg(index); break;
				case PlaceHolder.None: il.LdcI4(index); break;
			}
		}