/// <summary> /// Emits (ScriptContext, DTypeDesc) constructor. /// </summary> private static void EmitLongConstructor(PhpType /*!*/ phpType) { // (ScriptContext, DTypeDesc) constructor ConstructorBuilder ctor_builder = phpType.LongConstructorBuilder; ctor_builder.DefineParameter(1, ParameterAttributes.None, "context"); ctor_builder.DefineParameter(2, ParameterAttributes.None, "caller"); // [ this(arg1,true) ] ILEmitter cil = new ILEmitter(ctor_builder); cil.Ldarg(FunctionBuilder.ArgThis); cil.Ldarg(FunctionBuilder.ArgContextInstance); cil.LdcI4(1); cil.Emit(OpCodes.Call, phpType.ShortConstructorInfo); if (phpType.ProxyFieldInfo != null) { // [ <proxy>.InvokeConstructor(args) ] cil.Ldarg(FunctionBuilder.ArgThis); cil.Emit(OpCodes.Ldfld, phpType.ProxyFieldInfo); cil.Ldarg(1); cil.Ldarg(2); cil.Emit(OpCodes.Call, Methods.DObject_InvokeConstructor); } else { // try to find constructor method and call it directly // if it is publically visible without any reason to throw a warning in runtime DRoutineDesc construct = null; // = found constructor; if not null, can be called statically without runtime checks bool constructorFound = false; // try to find constructor for (DTypeDesc type_desc = phpType.TypeDesc; type_desc != null; type_desc = type_desc.Base) { construct = type_desc.GetMethod(DObject.SpecialMethodNames.Construct); if (construct == null) { construct = type_desc.GetMethod(new Name(type_desc.MakeSimpleName())); } if (construct != null) { constructorFound = true; if (!construct.IsPublic || construct.IsStatic || construct.PhpRoutine == null || construct.PhpRoutine.ArgLessInfo == null) { construct = null; // invalid constructor found, fall back to dynamic behavior } break; } } // emit constructor call if (construct != null) { // publically visible not static constructor, can be called statically anywhere // [ __construct( this, context.Stack ) ] cil.Ldarg(FunctionBuilder.ArgThis); // this cil.Ldarg(1); cil.Emit(OpCodes.Ldfld, Emit.Fields.ScriptContext_Stack); // context.Stack cil.Emit(OpCodes.Call, construct.PhpRoutine.ArgLessInfo); // __construct cil.Emit(OpCodes.Pop); } else if (!constructorFound) // there is no ctor at all { // [ context.Stack.RemoveFrame() ] cil.Ldarg(1); cil.Emit(OpCodes.Ldfld, Emit.Fields.ScriptContext_Stack); // context.Stack cil.Emit(OpCodes.Callvirt, Emit.Methods.PhpStack.RemoveFrame); // .RemoveFrame } else { // constructor should be checked in runtime (various visibility cases) // warnings can be displayed // [ InvokeConstructor(arg2) ] cil.Ldarg(FunctionBuilder.ArgThis); cil.Ldarg(1); cil.Ldarg(2); cil.Emit(OpCodes.Call, Methods.DObject_InvokeConstructor); } } cil.Emit(OpCodes.Ret); }