private void EmitLoadArgfullParameters(ParameterInfo[] /*!*/ stubParameters, Type[] /*!*/ stubTypeParameters, PhpMethod /*!*/ target) { for (int i = 0; i < target.Signature.GenericParamCount; i++) { if (i < stubTypeParameters.Length) { il.Emit(OpCodes.Ldtoken, stubTypeParameters[i]); il.Emit(OpCodes.Call, Methods.DTypeDesc_Create); } else { // optional type parameter, whose value is not supplied il.Emit(OpCodes.Ldsfld, Fields.Arg_DefaultType); } } for (int i = 0; i < target.Signature.ParamCount; i++) { if (i < stubParameters.Length) { EmitLoadClrParameter( stubParameters[i], target.Signature.IsAlias(i) ? PhpTypeCode.PhpReference : PhpTypeCode.Object); } else { // optional parameter, whose value is not supplied il.Emit(OpCodes.Ldsfld, Fields.Arg_Default); } } }
/// <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 EmitExportedConstructors(PhpType /*!*/ phpType) { PhpMethod ctor = phpType.GetConstructor() as PhpMethod; foreach (StubInfo info in phpType.Builder.ClrConstructorStubs) { EmitExportedConstructor( phpType, info.ConstructorBuilder, ctor, info.Parameters); } }
private void EmitLoadArglessParameters(ParameterInfo[] /*!*/ stubParameters, Type[] /*!*/ stubTypeParameters, PhpMethod /*!*/ target) { PhpStackBuilder.EmitAddFrame(il, scriptContextPlace, stubTypeParameters.Length, stubParameters.Length, delegate(ILEmitter eil, int i) { il.Emit(OpCodes.Ldtoken, stubTypeParameters[i]); il.Emit(OpCodes.Call, Methods.DTypeDesc_Create); }, delegate(ILEmitter eil, int i) { EmitLoadClrParameter(stubParameters[i], PhpTypeCode.Unknown); }); }
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> /// Add at runtime a method to a type /// </summary> /// <param name="typedesc">Type to modify</param> /// <param name="attributes">New method attributes</param> /// <param name="func_name">Method name</param> /// <param name="callback">Method body</param> /// <remarks>Used by PDO_SQLITE</remarks> public void AddMethodToType(DTypeDesc typedesc, PhpMemberAttributes attributes, string func_name, Func <object, PhpStack, object> callback) { Debug.Assert(typedesc != null); var name = new Name(func_name); var method_desc = new PhpRoutineDesc(typedesc, attributes); if (!typedesc.Methods.ContainsKey(name)) { typedesc.Methods.Add(name, method_desc); // assign member: if (method_desc.Member == null) { Func <ScriptContext, object> dummyArgFullCallback = DummyArgFull; PhpMethod method = new PhpMethod(name, (PhpRoutineDesc)method_desc, dummyArgFullCallback.Method, (callback != null) ? callback.Method : null); method.WriteUp(PhpRoutineSignature.FromArgfullInfo(method, dummyArgFullCallback.Method)); method_desc.Member = method; } } }
/// <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); }