internal virtual void AddAbstractOverride(DMemberRef/*!*/ abstractMember) { Debug.Fail("N/A"); throw null; }
internal virtual void AddAbstractOverride(DMemberRef /*!*/ abstractMember) { Debug.Fail("N/A"); throw null; }
internal override void AddAbstractOverride(DMemberRef/*!*/ abstractMethod) { // nop, we don't need to maintain information about abstract overrides }
internal override void AddAbstractOverride(DMemberRef/*!*/ abstractProperty) { if (abstractProperty.Member.DeclaringType.IsInterface) { if (implements == null) implements = new List<DMemberRef>(); implements.Add(abstractProperty); } else overrides = abstractProperty; }
/// <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)); } } } }
/// <summary> /// Emits stubs for all overloads of one overridden or implemented 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.</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<string, MethodBuilder>/*!*/ stubs, PhpMethod/*!*/ target, DType/*!*/ targetType, PhpType/*!*/ declaringType, DMemberRef/*!*/ template, bool newSlot) { ClrMethod clr_template = template.Member as ClrMethod; if (clr_template == null) { if (!target.IsStatic) EmitOverrideStubsForPhpTemplate(stubs, target, targetType, declaringType, template, newSlot); return; } // // following code emits stubs in case of CLR base method // ConstructedType constructed_type = template.Type as ConstructedType; TypeBuilder type_builder = declaringType.RealTypeBuilder; // override all virtual non-final overloads foreach (ClrMethod.Overload overload in clr_template.Overloads) { if (overload.Method.IsVirtual && !overload.Method.IsFinal) { // map generic type parameters according to the constructed type Type constructed_return_type; ParameterInfo[] constructed_params = overload.MakeConstructed(constructed_type, out constructed_return_type); // check whether we have not generated this signature before string clr_sig = ClrMethod.Overload.ClrSignatureToString( overload.GenericParamCount, constructed_params, constructed_return_type); if (stubs.ContainsKey(clr_sig)) continue; Type[] param_types = new Type[constructed_params.Length]; for (int j = 0; j < param_types.Length; j++) { param_types[j] = constructed_params[j].ParameterType; } // determine the stub attributes MethodAttributes attr; string name; name = overload.Method.Name; attr = Reflection.Enums.ToMethodAttributes(target.MemberDesc.MemberAttributes); attr |= (MethodAttributes.Virtual | MethodAttributes.HideBySig); if (newSlot) attr |= MethodAttributes.NewSlot; MethodBuilder overload_builder = type_builder.DefineMethod(name, attr); if (overload.MandatoryGenericParamCount > 0) { // define the same generic parameters that are defined for the overridden method // (the same constraints but possibly having different names) ClrStubBuilder.DefineStubGenericParameters( overload_builder, overload.GenericParameters, target.Signature, param_types); } overload_builder.SetReturnType(constructed_return_type); overload_builder.SetParameters(param_types); // set parameter names and attributes ClrStubBuilder.DefineStubParameters(overload_builder, target.Builder.Signature.FormalParams, constructed_params); if (!overload_builder.IsAbstract) { EmissionContext emission_context = SetupStubPlaces(target.DeclaringPhpType, false); try { // convert parameters and invoke the target ClrStubBuilder.EmitMethodStubBody( new ILEmitter(overload_builder), ScriptContextPlace, constructed_params, overload.GenericParameters, constructed_return_type, target, targetType); } finally { RestorePlaces(emission_context); } } stubs.Add(clr_sig, overload_builder); } } }
/// <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); } } }
internal override void AddAbstractOverride(DMemberRef/*!*/ abstractMethod) { throw new NotSupportedException(); }
internal override void AddAbstractOverride(DMemberRef/*!*/ abstractMethod) { if (abstractMethod.Member.DeclaringType.IsInterface) { if (implements == null) implements = new List<DMemberRef>(); implements.Add(abstractMethod); Debug.WriteLine("F-ANALYSIS", "GetUserEntryPoint '{0}::{1}': implemens += '{2}::{3}'", DeclaringType.FullName, FullName, abstractMethod.Type.MakeFullGenericName(), abstractMethod.Member.FullName); } else { overrides = abstractMethod; Debug.WriteLine("F-ANALYSIS", "GetUserEntryPoint '{0}::{1}': overrides = '{2}::{3}'", DeclaringType.FullName, FullName, overrides.Type.MakeFullGenericName(), overrides.Member.FullName); } }