/// <summary> /// Defines CLR-friendly constructors based on a PHP "constructor" method. /// </summary> public static void DefineExportedConstructors(PhpType /*!*/ phpType) { phpType.Builder.ClrConstructorStubs = new List <StubInfo>(); PhpMethod ctor = phpType.GetConstructor() as PhpMethod; if (ctor == null) { // the class defines (nor inherits) no constructor -> create a parameter-less CLR constructor ConstructorBuilder ctor_builder = phpType.RealTypeBuilder.DefineConstructor( DefaultConstructorAttributes, CallingConventions.Standard, Type.EmptyTypes); phpType.ClrConstructorInfos = new ConstructorInfo[] { ctor_builder }; phpType.Builder.ClrConstructorStubs.Add( new StubInfo(ctor_builder, new ParameterInfo[0], StubInfo.EmptyGenericParameters, null)); } else if (!ctor.IsAbstract) { Debug.Assert(!ctor.IsStatic && ctor.Signature.GenericParamCount == 0); if (ctor.Builder == null) { // contructor not defined in this class phpType.ClrConstructorInfos = new ConstructorInfo[0]; return; } // infer constructor visibility List <ConstructorInfo> ctor_infos = new List <ConstructorInfo>(); MethodAttributes attr = Reflection.Enums.ToMethodAttributes(ctor.RoutineDesc.MemberAttributes); foreach (StubInfo info in ClrStubBuilder.DefineMethodExportStubs( ctor, attr, true, delegate(string[] genericParamNames, object[] parameterTypes, object returnType) { // accept all overloads return(true); })) { phpType.Builder.ClrConstructorStubs.Add(info); // infos are returned in ascending order w.r.t. parameter count ctor_infos.Add(info.ConstructorBuilder); } phpType.ClrConstructorInfos = ctor_infos.ToArray(); } }
private static void EmitExportedConstructor(PhpType /*!*/ phpType, ConstructorBuilder /*!*/ ctorStubBuilder, PhpMethod phpCtor, ParameterInfo[] /*!*/ parameters) { // set parameter names and attributes if (phpCtor != null) { ClrStubBuilder.DefineStubParameters( ctorStubBuilder, phpCtor.Builder.Signature.FormalParams, parameters); } // emit ctor body ILEmitter cil = new ILEmitter(ctorStubBuilder); // [ this(ScriptContext.CurrentContext ] cil.Ldarg(FunctionBuilder.ArgThis); cil.EmitCall(OpCodes.Call, Methods.ScriptContext.GetCurrentContext, null); LocalBuilder sc_local = cil.DeclareLocal(Types.ScriptContext[0]); cil.Stloc(sc_local); cil.Ldloc(sc_local); cil.LdcI4(1); cil.Emit(OpCodes.Call, phpType.ShortConstructorInfo); if (phpCtor != null) { // invoke the PHP ctor method ClrStubBuilder.EmitMethodStubBody( cil, new Place(sc_local), parameters, new GenericTypeParameterBuilder[0], Types.Void, phpCtor, phpCtor.DeclaringType); } else { cil.Emit(OpCodes.Ret); } }
/// <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); }
/// <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); }