Beispiel #1
0
		/// <summary>
		/// Called when a <see cref="PHP.Core.AST.FieldDecl"/> AST node is visited during the emit phase.
		/// </summary>
		public void InitializeField(PhpField/*!*/ field, AST.Expression initVal)
		{
			ILEmitter cil;
			IPlace sc_place;
            
			if (field.IsStatic)
			{
                // (J) even overiding static field is created again in derivating type
				// there is no initialization taking place if the implementing CLI field does not live in current class
				//if (field.Overrides != null) return;

				if (field.IsAppStatic)
				{
					// app-static field initialization is emitted into the static ctor
					cil = field.DeclaringPhpType.Builder.StaticCtorEmitter;

					sc_place = new LazyLoadSCPlace();
				}
				else
				{
					// thread-static field initialization is emitted into the __InitializeStaticFields method
					cil = new ILEmitter(field.DeclaringPhpType.StaticFieldInitMethodBuilder);

					sc_place = new IndexedPlace(PlaceHolder.Argument, ScriptBuilder.ArgContext);
				}
			}
			else
			{
                if (initVal == null && field.Implementor != field.DeclaringType)
                    return;

				// instance field initialization is emitted into the <InitializeInstanceFields> method
				cil = field.DeclaringPhpType.Builder.InstanceFieldInitEmitter;

				sc_place = new IndexedPlace(PlaceHolder.Argument, FunctionBuilder.ArgContextInstance);

				cil.Ldarg(FunctionBuilder.ArgThis);
			}

			if (initVal != null)
			{
				// emit the expression evaluating code
				ILEmitter old_il = il;
				IPlace old_sc_place = ScriptContextPlace;

				try
				{
					// set il and SC-emitter appropriately
					il = cil;
					ScriptContextPlace = sc_place;

					EmitBoxing(initVal.Emit(this));
				}
				finally
				{
					// restore the saved il and SC-emitter
					il = old_il;
					ScriptContextPlace = old_sc_place;
				}

				cil.Emit(OpCodes.Newobj, Constructors.PhpSmartReference.Object);
			}
			else cil.Emit(OpCodes.Newobj, Constructors.PhpSmartReference.Void);

			// store it in the field
            Debug.Assert(field.IsStatic == field.RealField.IsStatic);
			cil.Emit(field.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, field.RealField);
		}
Beispiel #2
0
		public PhpFieldBuilder(PhpField/*!*/ field)
		{
			this.field = field;
		}
Beispiel #3
0
		/// <summary>
		/// Emits property stubs for a overriden or implemented CLR property.
		/// </summary>
		/// <param name="stubs">Already generated stubs.</param>
		/// <param name="target">The overriding/implementing field.</param>
		/// <param name="declaringType">The type where the stubs should be emitted.</param>
		/// <param name="template">The property being overriden/implemented.</param>
		/// <param name="newSlot"><B>True</B> if the stub should be assigned a new vtable slot,
		/// <B>false</B> otherwise.</param>
		private void EmitOverrideStubs(IDictionary<Type, PropertyBuilder>/*!*/ stubs, PhpField/*!*/ target,
			PhpType/*!*/ declaringType, DMemberRef/*!*/ template, bool newSlot)
		{
			ClrProperty clr_template = template.Member as ClrProperty;
			if (clr_template == null) return;

			MethodInfo getter = clr_template.Getter;
			MethodInfo setter = clr_template.Setter;

			// we're only interested in non-final virtual getters/setters
			if (getter != null && (!getter.IsVirtual || getter.IsFinal)) getter = null;
			if (setter != null && (!setter.IsVirtual || setter.IsFinal)) setter = null;

			ConstructedType constructed_type = template.Type as ConstructedType;

			// map property type according to constructed type
			Type property_type = clr_template.RealProperty.PropertyType;
			if (constructed_type != null) property_type = constructed_type.MapRealType(property_type);

			// do we already have getter/setter of this type?
			PropertyBuilder prop_builder;
			if (stubs.TryGetValue(property_type, out prop_builder))
			{
				if (prop_builder.GetGetMethod(true) != null) getter = null;
				if (prop_builder.GetSetMethod(true) != null) setter = null;
			}

			if (getter != null || setter != null)
			{
				if (prop_builder == null)
				{
					// the property might already exist - we could be just adding an accessor
					TypeBuilder type_builder = declaringType.RealTypeBuilder;

					prop_builder = type_builder.DefineProperty(
						clr_template.Name.ToString(),
						Reflection.Enums.ToPropertyAttributes(target.MemberDesc.MemberAttributes),
						property_type,
						Type.EmptyTypes);

					stubs.Add(property_type, prop_builder);
				}

				if (getter != null)
				{
					// add getter
					MethodBuilder getter_builder = DefineOverrideAccessor(
						declaringType,
						target,
						getter,
						newSlot,
						property_type,
						Type.EmptyTypes);

					prop_builder.SetGetMethod(getter_builder);

					EmitFieldExportGetter(target, prop_builder, getter_builder);
				}

				if (setter != null)
				{
					// add setter
					MethodBuilder setter_builder = DefineOverrideAccessor(
						declaringType,
						target,
						setter,
						newSlot,
						Types.Void,
						new Type[] { property_type });

					prop_builder.SetSetMethod(setter_builder);

					EmitFieldExportSetter(target, prop_builder, setter_builder);
				}
			}
		}
Beispiel #4
0
		/// <summary>
		/// Defines a property accessor method and installs an explicit override if necessary.
		/// </summary>
		private MethodBuilder/*!*/ DefineOverrideAccessor(PhpType/*!*/ declaringType, PhpField/*!*/ target,
			MethodInfo/*!*/ template, bool newSlot, Type/*!*/ returnType, Type[]/*!!*/ paramTypes)
		{
			bool changed;
			string name = ClrStubBuilder.GetNonConflictingMethodName(declaringType.TypeDesc, template.Name, out changed);

			MethodAttributes attr;

			if (changed) attr = MethodAttributes.PrivateScope;
			else attr = Reflection.Enums.ToMethodAttributes(target.MemberDesc.MemberAttributes);

			attr |= (MethodAttributes.Virtual | MethodAttributes.HideBySig);
			if (newSlot) attr |= MethodAttributes.NewSlot;

			MethodBuilder method_builder = declaringType.RealTypeBuilder.DefineMethod(
				name,
				attr,
				returnType,
				paramTypes);

			if (changed)
			{
				declaringType.RealTypeBuilder.DefineMethodOverride(
					method_builder,
					template);
			}

			return method_builder;
		}
Beispiel #5
0
		public void EmitFieldExportStubs(PhpField/*!*/ field, PropertyBuilder/*!*/ property)
		{
			Debug.Assert(field != null && property != null);

			MethodBuilder getter = (MethodBuilder)property.GetGetMethod(true);
			MethodBuilder setter = (MethodBuilder)property.GetSetMethod(true);

			// emit getter:
			if (getter != null) EmitFieldExportGetter(field, property, getter);

			// emit setter:
			if (setter != null) EmitFieldExportSetter(field, property, setter);
		}
Beispiel #6
0
		/// <summary>
		/// Emits stubs for overriden/implemented properties and explicit export stubs.
		/// </summary>
		/// <param name="field">The overriding/implementing/exported field.</param>
		public void EmitOverrideAndExportStubs(PhpField/*!*/ field)
		{
			// keep track of property types that have already been generated
			Dictionary<Type, PropertyBuilder> stubs = null;

			// emit explicit export stub
			// (note: the property builder is already defined - needed for custom attributes usage)

			if (field.IsExported)
			{
				Debug.Assert(field.ExportedPropertyBuilder != null);

				PropertyBuilder prop_builder = field.ExportedPropertyBuilder;
				EmitFieldExportStubs(field, prop_builder);

				stubs = new Dictionary<Type, PropertyBuilder>();
				stubs.Add(prop_builder.PropertyType, prop_builder);
			}
			// emit stubs for overriden property

			if (field.Overrides != null)
			{
				if (stubs == null) stubs = new Dictionary<Type, PropertyBuilder>();
				EmitOverrideStubs(stubs, field, field.DeclaringPhpType, field.Overrides, false);
			}

			if (field.Implements != null)
			{
				// emit stubs(s) for implemented property/ies

				for (int i = 0; i < field.Implements.Count; i++)
				{
					if (stubs == null) stubs = new Dictionary<Type, PropertyBuilder>();
					EmitOverrideStubs(stubs, field, field.DeclaringPhpType, field.Implements[i], true);
				}
			}
		}
Beispiel #7
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);
			}
		}
Beispiel #8
0
		public void EmitFieldExportGetter(PhpField/*!*/ field, PropertyBuilder/*!*/ property, MethodBuilder/*!*/ getter)
		{
			IPlace instance_place = (field.IsStatic ? null : IndexedPlace.ThisArg);

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

			il = new ILEmitter(getter);
			try
			{
				// read the field
				PhpTypeCode type_code = field.EmitGet(this, instance_place, false, null, false);

				// convert it to the return type
				ClrOverloadBuilder.EmitConvertToClr(
					il,
					type_code,
					property.PropertyType);

				il.Emit(OpCodes.Ret);
			}
			finally
			{
				RestorePlaces(emission_context);
			}
		}
Beispiel #9
0
		/// <summary>
		/// I do not like PHP-specific access code emission here. TODO: Move to PhpField
		/// </summary>
		/// <param name="phpField"></param>
		/// <param name="ensureArray"></param>
		void EmitEnsureStaticPhpFieldDirect(PhpField phpField, bool ensureArray)
		{
			ILEmitter il = codeGenerator.IL;
			MethodInfo static_init_info = ((PhpType)phpField.Implementor).StaticFieldInitMethodInfo;

			// ensure that the field has been initialized for this request by invoking __InitializeStaticFields
			if (static_init_info != null && !il.IsFeatureControlFlowPrecedent(phpField.Implementor))
			{
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Call, static_init_info);

				// remember that we have just initialized class_entry's static fields
				il.MarkFeature(phpField.Implementor);
			}

			// LOAD EnsureVariableIs[Array|Object](ref <field>.value,[<context>]);
			il.Emit(OpCodes.Ldsfld, phpField.RealField);
			il.Emit(OpCodes.Ldflda, Fields.PhpReference_Value);

			if (ensureArray)
			{
				il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsArray);
			}
			else
			{
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsObject);
			}
		}
Beispiel #10
0
		/// <summary>
		/// I do not like PHP-specific access code emission here. TODO: Move to PhpField
		/// </summary>
		/// <param name="field"></param>
		/// <param name="fieldName"></param>
		/// <param name="ensureArray"></param>
		private void EmitEnsurePhpFieldDirect(PhpField/*!*/ field, SimpleVarUse/*!*/ fieldName, bool ensureArray)
		{
			ILEmitter il = codeGenerator.IL;

			// check whether the field is set
			il.Ldarg(FunctionBuilder.ArgThis);
			il.Emit(OpCodes.Ldfld, field.RealField);

			Label direct_ensure = il.DefineLabel();
			Label ensuring_over = il.DefineLabel();

			// test whether it is set
			il.Emit(OpCodes.Callvirt, Properties.PhpReference_IsSet.GetGetMethod());
			il.Emit(OpCodes.Brtrue, direct_ensure);

			// the field has been unset -> must call operator that handles __get/__set
			if (ensureArray) this.Lengthen();  // TODO: ???
			codeGenerator.EmitLoadSelf();
			fieldName.EmitName(codeGenerator);
			codeGenerator.EmitLoadClassContext();
			if (ensureArray)
			{
				il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsArray);
			}
			else
			{
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Call, Methods.Operators.EnsurePropertyIsObject);
			}
			il.Emit(OpCodes.Br, ensuring_over);

			// read the field again and call EnsureVariableIsArray
			il.MarkLabel(direct_ensure, true);
			il.Ldarg(FunctionBuilder.ArgThis);
			il.Emit(OpCodes.Ldfld, field.RealField);
			il.Emit(OpCodes.Ldflda, Fields.PhpReference_Value);

			if (ensureArray)
			{
				il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsArray);
			}
			else
			{
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Call, Methods.Operators.EnsureVariableIsObject);
			}

			il.MarkLabel(ensuring_over, true);
			EmitErrorCheck(ensureArray);
		}
Beispiel #11
0
		internal void AnalyzeMember(Analyzer/*!*/ analyzer, PhpField/*!*/ field)
		{
			this.field = field;
		}