Пример #1
0
        /// <summary>
        /// Emits IL instructions that load the "$this" variable onto the evaluation stack.
        /// </summary>
        private PhpTypeCode EmitLoadThis(CodeGenerator codeGenerator)
        {
            ILEmitter             il            = codeGenerator.IL;
            CompilerLocationStack locationStack = codeGenerator.LocationStack;

            // special treatment of $this
            switch (locationStack.LocationType)
            {
            case LocationTypes.GlobalCode:
            {
                // load $this from one of Main's arguments and check for null
                Label this_non_null = il.DefineLabel();

                codeGenerator.EmitLoadSelf();
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Brtrue_S, this_non_null);
                il.Emit(OpCodes.Ldstr, VariableName.ThisVariableName.Value);
                codeGenerator.EmitPhpException(Methods.PhpException.UndefinedVariable);
                il.MarkLabel(this_non_null, true);

                return(PhpTypeCode.Object);
            }

            case LocationTypes.FunctionDecl:
            {
                // always null
                il.Emit(OpCodes.Ldstr, VariableName.ThisVariableName.Value);
                codeGenerator.EmitPhpException(Methods.PhpException.UndefinedVariable);
                il.Emit(OpCodes.Ldnull);

                return(PhpTypeCode.Object);
            }

            case LocationTypes.MethodDecl:
            {
                CompilerLocationStack.MethodDeclContext context = locationStack.PeekMethodDecl();
                if (context.Method.IsStatic)
                {
                    // always null in static methods
                    il.Emit(OpCodes.Ldstr, VariableName.ThisVariableName.Value);
                    codeGenerator.EmitPhpException(Methods.PhpException.UndefinedVariable);
                    il.Emit(OpCodes.Ldnull);

                    return(PhpTypeCode.Object);
                }
                else
                {
                    // arg0 or <proxy> in instance methods
                    codeGenerator.EmitLoadSelf();
                    return(PhpTypeCode.DObject);
                }
            }

            default:
                Debug.Fail("Invalid location type.");
                return(PhpTypeCode.Invalid);
            }
        }
Пример #2
0
        /// <summary>
        /// Loads a PhpReference to "this" special variable to the evaluation stack.
        /// If "this" is not available, loads an empty PhpReference.
        /// </summary>
        private PhpTypeCode EmitLoadThisRef(CodeGenerator /*!*/ codeGenerator)
        {
            ILEmitter il = codeGenerator.IL;

            switch (codeGenerator.LocationStack.LocationType)
            {
            case LocationTypes.GlobalCode:
            {
                // load $this from one of Main's arguments:
                codeGenerator.EmitLoadSelf();

                // NOTE: If $this is used by ref somewhere in the method each access to it is boxed to the reference.
                // Only calls to methods use the "this" pointer itself. Thus the rule "no duplicate pointers" is slightly
                // broken here yet everything should work fine.
                il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
                break;
            }

            case LocationTypes.FunctionDecl:
            {
                // always null referencing PhpReference
                il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
                break;
            }

            case LocationTypes.MethodDecl:
            {
                CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
                if (context.Method.IsStatic)
                {
                    // always null referencing PhpReference in static methods
                    il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
                }
                else
                {
                    // arg0 or <proxy> referencing PhpReference in instance methods
                    codeGenerator.EmitLoadSelf();

                    // NOTE: If $this is used by ref somewhere in the method each access to it is boxed to the reference.
                    // Only calls to methods use the "this" pointer itself. Thus the rule "no duplicate pointers" is slightly
                    // broken here yet everything should work fine.
                    il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
                }
                break;
            }

            default:
                Debug.Fail("Invalid location type.");
                break;
            }

            // always returns a reference:
            return(PhpTypeCode.PhpReference);
        }
Пример #3
0
        /// <summary>
        /// Emits IL instructions that prepare a field of $this for writing.
        /// </summary>
        private AssignmentCallback EmitWriteFieldOfThis(CodeGenerator /*!*/ codeGenerator, bool writeRef)
        {
            ILEmitter il = codeGenerator.IL;

            // $this->a
            switch (codeGenerator.LocationStack.LocationType)
            {
            case LocationTypes.GlobalCode:
            {
                // load $this from one of Main's arguments and check for null
                Label this_non_null = il.DefineLabel();

                codeGenerator.EmitLoadSelf();
                il.Emit(OpCodes.Brtrue_S, this_non_null);
                codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
                il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.ErrorLabel);
                il.MarkLabel(this_non_null, true);

                // prepare the stack for SetObjectProperty call
                codeGenerator.EmitLoadSelf();
                EmitName(codeGenerator);

                return(new AssignmentCallback(EmitCallSetObjectField));
            }

            case LocationTypes.FunctionDecl:
            {
                // always throws error
                codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
                return(new AssignmentCallback(EmitPopValue));
            }

            case LocationTypes.MethodDecl:
            {
                CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
                if (context.Method.IsStatic)
                {
                    // always throws error
                    codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
                    return(new AssignmentCallback(EmitPopValue));
                }

                // attempt direct field writing (DirectVarUse only)
                return(EmitWriteFieldOfThisInInstanceMethod(codeGenerator, writeRef));
            }
            }

            Debug.Fail("Invalid lcoation type.");
            return(null);
        }
Пример #4
0
        /// <summary>
        /// Emits IL instructions that read the value of a field of $this instance.
        /// </summary>
        /// <param name="codeGenerator">The current <see cref="CodeGenerator"/>.</param>
        /// <param name="wantRef">If <B>false</B> the field value should be left on the evaluation stack,
        /// if <B>true</B> the <see cref="PhpReference"/> should be left on the evaluation stack.</param>
        /// <returns></returns>
        private PhpTypeCode EmitReadFieldOfThis(CodeGenerator /*!*/ codeGenerator, bool wantRef)
        {
            ILEmitter il = codeGenerator.IL;

            // $this->a
            switch (codeGenerator.LocationStack.LocationType)
            {
            case LocationTypes.GlobalCode:
            {
                // load $this from one of Main's arguments and check for null
                Label this_non_null = il.DefineLabel();
                Label reading_over  = il.DefineLabel();

                codeGenerator.EmitLoadSelf();
                il.Emit(OpCodes.Brtrue_S, this_non_null);
                EmitThisUsedOutOfObjectThrow(codeGenerator, wantRef);
                il.Emit(OpCodes.Br, reading_over);
                il.MarkLabel(this_non_null, true);

                // call GetObjectProperty/GetObjectPropertyRef
                EmitGetFieldOfPlace(codeGenerator.SelfPlace, codeGenerator, wantRef);

                il.MarkLabel(reading_over, true);

                break;
            }

            case LocationTypes.FunctionDecl:
            {
                EmitThisUsedOutOfObjectThrow(codeGenerator, wantRef);
                break;
            }

            case LocationTypes.MethodDecl:
            {
                CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
                if (context.Method.IsStatic)
                {
                    EmitThisUsedOutOfObjectThrow(codeGenerator, wantRef);
                    break;
                }

                // attempt direct field reading (DirectVarUse only)
                return(EmitReadFieldOfThisInInstanceMethod(codeGenerator, wantRef));
            }
            }

            return(wantRef ? PhpTypeCode.PhpReference : PhpTypeCode.Object);
        }
Пример #5
0
        internal override PhpTypeCode EmitIsset(CodeGenerator codeGenerator, bool empty)
        {
            // Template: "isset(x)"     x != null
            //				isset doesn't distinguish between the NULL and uninitialized variable
            //				a reference is dereferenced, i.e. isset tells us whether the referenced variable is set

            Debug.Assert(access == AccessType.Read);
            // Cases 1, 4, 5, 6, 9 never reached
            Debug.Assert(codeGenerator.ChainBuilder.IsMember == false);
            // Case 3 never reached
            Debug.Assert(codeGenerator.ChainBuilder.IsArrayItem == false);

            codeGenerator.ChainBuilder.QuietRead = true;

            // 2,7,8
            if (this.isMemberOf != null)
            {
                // 2: $b->a
                // 8: b[]->a
                codeGenerator.ChainBuilder.Create();
                codeGenerator.ChainBuilder.Begin();
                codeGenerator.ChainBuilder.QuietRead = true;
                EmitReadField(codeGenerator, false);
                codeGenerator.ChainBuilder.End();
                return(PhpTypeCode.Object);
            }
            // 7: $a
            // Check whether this variable is set
            //codeGenerator.EmitVariableIsset(this);
            ILEmitter il = codeGenerator.IL;

            if (varName.IsThisVariableName && codeGenerator.LocationStack.LocationType == LocationTypes.MethodDecl)
            {
                CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
                if (!context.Method.IsStatic)
                {
                    // $this is always set in instance methods
                    il.Emit(OpCodes.Ldarg_0);
                    return(PhpTypeCode.Object);
                }
            }
            this.EmitLoad(codeGenerator);
            return(PhpTypeCode.Object);
        }
Пример #6
0
        /// <summary>
        /// Emits IL instructions that unset an instance field.
        /// </summary>
        /// <remarks>
        /// Nothing is expected on the evaluation stack. Nothing is left on the evaluation stack.
        /// </remarks>
        private void EmitUnsetField(CodeGenerator /*!*/ codeGenerator)
        {
            ILEmitter il = codeGenerator.IL;

            DirectVarUse direct_instance = isMemberOf as DirectVarUse;

            if (direct_instance != null && direct_instance.VarName.IsThisVariableName)
            {
                // $this->a
                switch (codeGenerator.LocationStack.LocationType)
                {
                case LocationTypes.GlobalCode:
                {
                    // load $this from one of Main's arguments and check for null
                    Label this_non_null = il.DefineLabel();

                    codeGenerator.EmitLoadSelf();
                    il.Emit(OpCodes.Brtrue_S, this_non_null);
                    codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
                    il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.ErrorLabel);
                    il.MarkLabel(this_non_null, true);

                    // call UnsetProperty
                    codeGenerator.EmitLoadSelf();
                    il.Emit(OpCodes.Ldstr, varName.ToString());                                     // TODO
                    codeGenerator.EmitLoadClassContext();

                    il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
                    return;
                }

                case LocationTypes.FunctionDecl:
                {
                    // always throws error
                    codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
                    il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.ErrorLabel);
                    break;
                }

                case LocationTypes.MethodDecl:
                {
                    CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
                    if (context.Method.IsStatic)
                    {
                        // always throws error
                        codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
                        il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.ErrorLabel);
                    }
                    else
                    {
                        DProperty property;
                        if (context.Type.GetProperty(varName, context.Type, out property) == GetMemberResult.OK &&
                            !property.IsStatic)
                        {
                            // ask the DProperty to emit its unsetting code
                            property.EmitUnset(codeGenerator, IndexedPlace.ThisArg, null, false);
                        }
                        else
                        {
                            // unable to resolve the field -> call UnsetProperty
                            codeGenerator.EmitLoadSelf();
                            il.Emit(OpCodes.Ldstr, varName.ToString());
                            codeGenerator.EmitLoadClassContext();

                            il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
                        }
                    }
                }
                break;
                }
            }
            else
            {
                // call UnsetProperty
                isMemberOf.Emit(codeGenerator);
                il.Emit(OpCodes.Ldstr, varName.ToString());
                codeGenerator.EmitLoadClassContext();

                il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
            }
        }