Beispiel #1
0
        /// <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);
        }