/// <summary>
        /// Stores a reference on the top of the stack to a specified variable.
        /// </summary>
        internal void StoreLocalRefAssign(CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName)
        {
            ILEmitter il = codeGenerator.IL;

            Debug.Assert(variable == null ^ variableName == null);

            if (variable != null)
            {
                Debug.Assert(variable.IsPhpReference);
                variable.Variable.EmitStore(il);
            }
            else
            {
                // temp = STACK
                LocalBuilder temp = il.GetTemporaryLocal(Types.PhpReference[0], true);
                il.Stloc(temp);

                // CALL Operators.SetVariableRef(<local variables table>,<name>,temp);
                codeGenerator.EmitLoadScriptContext();
                codeGenerator.EmitLoadRTVariablesTable();
                il.Ldloc(variableName);
                il.Ldloc(temp);
                il.Emit(OpCodes.Call, Methods.Operators.SetVariableRef);
            }
        }
            /// <summary>
            /// Stores a value on the top of the stack to a specified variable.
            /// </summary>
            internal static void StoreLocalAssign(IndirectVarUse node, CodeGenerator codeGenerator, VariablesTable.Entry variable, LocalBuilder variableName)
            {
                ILEmitter il = codeGenerator.IL;

                Debug.Assert(variable == null ^ variableName == null);
                LocalBuilder temp;

                if (variable != null)
                {
                    if (variable.IsPhpReference)
                    {
                        // temp = STACK
                        temp = il.GetTemporaryLocal(Types.Object[0], true);
                        il.Stloc(temp);

                        // <variable>.value = temp;
                        variable.Variable.EmitLoad(il);
                        il.Ldloc(temp);
                        il.Emit(OpCodes.Stfld, Fields.PhpReference_Value);
                    }
                    else
                    {
                        variable.Variable.EmitStore(il);
                    }
                }
                else
                {
                    // temp = STACK
                    temp = il.GetTemporaryLocal(Types.Object[0], true);
                    il.Stloc(temp);

                    // CALL Operators.SetVariable(<local variables table>,<name>,temp);
                    codeGenerator.EmitLoadScriptContext();
                    codeGenerator.EmitLoadRTVariablesTable();
                    il.Ldloc(variableName);
                    il.Ldloc(temp);
                    il.Emit(OpCodes.Call, Methods.Operators.SetVariable);
                }
            }
Beispiel #3
0
        /// <summary>
        /// Loads the value represented by this object from the runtime variables table,
        /// stores it to a local variable and loads the address of this local.
        /// </summary>
        /// <remarks>This method is used only in non-optimized user functions and global code.
        /// Specified local variable is obtained from current <see cref="ILEmitter"/> by
        /// <see cref="ILEmitter.GetTemporaryLocal"/> and stored to <see cref="TabledLocalAddressStorage"/>
        /// for later use. Once the local become useless, <see cref="ILEmitter.ReturnTemporaryLocal"/>
        /// should be called.
        /// </remarks>
        /// <param name="codeGenerator">Currently used <see cref="CodeGenerator"/>.</param>
        internal virtual void LoadTabledVariableAddress(CodeGenerator codeGenerator)
        {
            // This function should be call only once on every SimpleVarUse object
            // TODO: ASSERTION FAILS (e.g. PhpMyAdmin, common.lib.php)
            // Debug.Assert(this.TabledLocalAddressStorage == null);
            ILEmitter il = codeGenerator.IL;

            // Load the value represented by this node from the runtime variables table

            // LOAD Operators.GetVariableUnchecked(<script context>, <local variables table>, <variable name>);
            codeGenerator.EmitLoadScriptContext();
            codeGenerator.EmitLoadRTVariablesTable();
            EmitName(codeGenerator);
            codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.GetVariableUnchecked);

            // Get local from ILEmitter
            this.TabledLocalAddressStorage = il.GetTemporaryLocal(Types.Object[0]);
            // Store the value
            il.Stloc(this.TabledLocalAddressStorage);
            // Load the address
            il.Ldloca(this.TabledLocalAddressStorage);
        }
Beispiel #4
0
        /// <summary>
        /// Emits the try block and the catch blocks.
        /// </summary>
        /// <param name="codeGenerator">A code generator.</param>
        /// <remarks>
        /// <code>
        ///	try
        /// {
        ///   // guarded code //
        /// }
        /// catch(E1 $e1)
        /// {
        ///   // E1 //
        /// }
        /// catch(E2 $e2)
        /// {
        ///   // E2 //
        /// }
        /// </code>
        /// is translated as follows:
        /// <code>
        /// try
        /// {
        ///   // guarded code //
        /// }
        /// catch(PhpUserException _e)
        /// {
        ///   PhpObject _o = _e.UserException;
        ///   if (_o instanceOf E1)
        ///   {
        ///     $e1 = _o;
        ///     // E1 //
        ///   }
        ///   else if (_o instanceOf E2)
        ///   {
        ///     $e2 = _o;
        ///     // E2 //
        ///   }
        ///   else
        ///   {
        ///     throw;
        ///   }
        /// }
        /// </code>
        /// </remarks>
        internal override void Emit(CodeGenerator /*!*/ codeGenerator)
        {
            Statistics.AST.AddNode("TryStmt");

            // emit try block without CLR exception block if possible

            if (!HasCatches && !HasFinallyStatements)
            {
                this.Statements.Emit(codeGenerator);
                return;
            }

            // emit CLR exception block

            ILEmitter il = codeGenerator.IL;

            codeGenerator.ExceptionBlockNestingLevel++;

            // TRY
            Label end_label = il.BeginExceptionBlock();

            this.Statements.Emit(codeGenerator);

            // catches

            if (HasCatches)
            {
                // catch (PHP.Core.ScriptDiedException)
                // { throw; }

                il.BeginCatchBlock(typeof(PHP.Core.ScriptDiedException));
                il.Emit(OpCodes.Rethrow);

                // catch (System.Exception ex)

                il.BeginCatchBlock(typeof(System.Exception));

                // <exception_local> = (DObject) (STACK is PhpUserException) ? ((PhpUserException)STACK).UserException : ClrObject.WrapRealObject(STACK)

                Label        clrExceptionLabel = il.DefineLabel();
                Label        wrapEndLabel      = il.DefineLabel();
                LocalBuilder exception_local   = il.GetTemporaryLocal(typeof(DObject));

                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Isinst, typeof(PHP.Core.PhpUserException)); // <STACK> as PhpUserException
                il.Emit(OpCodes.Brfalse, clrExceptionLabel);

                // if (<STACK> as PhpUserException != null)
                {
                    il.Emit(OpCodes.Ldfld, Fields.PhpUserException_UserException);
                    il.Emit(OpCodes.Br, wrapEndLabel);
                }

                // else
                il.MarkLabel(clrExceptionLabel);
                {
                    il.Emit(OpCodes.Call, Methods.ClrObject_WrapRealObject);
                }
                il.MarkLabel(wrapEndLabel);
                il.Stloc(exception_local);

                // emits all PHP catch-blocks processing into a single CLI catch-block:
                foreach (CatchItem c in catches)
                {
                    Label next_catch_label = il.DefineLabel();

                    // IF (exception <instanceOf> <type>);
                    c.Emit(codeGenerator, exception_local, end_label, next_catch_label);

                    // ELSE
                    il.MarkLabel(next_catch_label);
                }

                il.ReturnTemporaryLocal(exception_local);

                // emits the "else" branch invoked if the exceptions is not catched:
                il.Emit(OpCodes.Rethrow);
            }

            // finally

            if (HasFinallyStatements)
            {
                finallyItem.Emit(codeGenerator);
            }

            //
            il.EndExceptionBlock();

            codeGenerator.ExceptionBlockNestingLevel--;
        }
Beispiel #5
0
        /// <author>Tomas Matousek</author>
        /// <remarks>
        /// Emits the following code:
        /// <code>
        /// IPhpEnumerable enumerable = ARRAY as IPhpEnumerable;
        /// if (enumerable==null)
        /// {
        ///   PhpException.InvalidForeachArgument();
        /// }
        /// else
        /// FOREACH_BEGIN:
        /// {
        ///   IDictionaryEnumerator enumerator = enumerable.GetForeachEnumerator(KEYED,ALIASED,TYPE_HANDLE);
        ///
        ///   goto LOOP_TEST;
        ///   LOOP_BEGIN:
        ///   {
        ///     ASSIGN(value,enumerator.Value);
        ///     ASSIGN(key,enumerator.Key);
        ///
        ///     BODY;
        ///   }
        ///   LOOP_TEST:
        ///   if (enumerator.MoveNext()) goto LOOP_BEGIN;
        /// }
        /// FOREACH_END:
        /// </code>
        /// </remarks>
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal override void Emit(CodeGenerator codeGenerator)
        {
            Statistics.AST.AddNode("Loop.Foreach");
            ILEmitter il = codeGenerator.IL;

            Label foreach_end   = il.DefineLabel();
            Label foreach_begin = il.DefineLabel();
            Label loop_begin    = il.DefineLabel();
            Label loop_test     = il.DefineLabel();

            codeGenerator.BranchingStack.BeginLoop(loop_test, foreach_end,
                                                   codeGenerator.ExceptionBlockNestingLevel);

            LocalBuilder enumerable = il.GetTemporaryLocal(typeof(IPhpEnumerable));

            // marks foreach "header" (the first part of the IL code):
            codeGenerator.MarkSequencePoint(
                enumeree.Position.FirstLine,
                enumeree.Position.FirstColumn,
                valueVariable.Position.LastLine,
                valueVariable.Position.LastColumn + 1);

            // enumerable = array as IPhpEnumerable;
            enumeree.Emit(codeGenerator);
            il.Emit(OpCodes.Isinst, typeof(IPhpEnumerable));
            il.Stloc(enumerable);

            // if (enumerable==null)
            il.Ldloc(enumerable);
            il.Emit(OpCodes.Brtrue, foreach_begin);
            {
                // CALL PhpException.InvalidForeachArgument();
                codeGenerator.EmitPhpException(Methods.PhpException.InvalidForeachArgument);
                il.Emit(OpCodes.Br, foreach_end);
            }
            // FOREACH_BEGIN:
            il.MarkLabel(foreach_begin);
            {
                LocalBuilder enumerator = il.GetTemporaryLocal(typeof(System.Collections.IDictionaryEnumerator));

                // enumerator = enumerable.GetForeachEnumerator(KEYED,ALIASED,TYPE_HANDLE);
                il.Ldloc(enumerable);
                il.LoadBool(keyVariable != null);
                il.LoadBool(valueVariable.Alias);
                codeGenerator.EmitLoadClassContext();
                il.Emit(OpCodes.Callvirt, Methods.IPhpEnumerable_GetForeachEnumerator);
                il.Stloc(enumerator);

                // goto LOOP_TEST;
                il.Emit(OpCodes.Br, loop_test);

                // LOOP_BEGIN:
                il.MarkLabel(loop_begin);
                {
                    // enumerator should do dereferencing and deep copying (if applicable):
                    // ASSIGN(value,enumerator.Value);
                    valueVariable.Emit(codeGenerator);
                    il.Ldloc(enumerator);
                    il.Emit(OpCodes.Callvirt, Properties.IDictionaryEnumerator_Value.GetGetMethod());
                    if (valueVariable.Alias)
                    {
                        il.Emit(OpCodes.Castclass, typeof(PhpReference));
                    }
                    valueVariable.EmitAssign(codeGenerator);

                    if (keyVariable != null)
                    {
                        // enumerator should do dereferencing and deep copying (if applicable):
                        // ASSIGN(key,enumerator.Key);
                        keyVariable.Emit(codeGenerator);
                        il.Ldloc(enumerator);
                        il.Emit(OpCodes.Callvirt, Properties.IDictionaryEnumerator_Key.GetGetMethod());
                        keyVariable.EmitAssign(codeGenerator);
                    }

                    // BODY:
                    body.Emit(codeGenerator);
                }
                // LOOP_TEST:
                il.MarkLabel(loop_test);

                // marks foreach "header" (the second part of the code):
                codeGenerator.MarkSequencePoint(
                    enumeree.Position.FirstLine,
                    enumeree.Position.FirstColumn,
                    valueVariable.Position.LastLine,
                    valueVariable.Position.LastColumn + 1);

                // if (enumerator.MoveNext()) goto LOOP_BEGIN;
                il.Ldloc(enumerator);
                il.Emit(OpCodes.Callvirt, Methods.IEnumerator_MoveNext);
                il.Emit(OpCodes.Brtrue, loop_begin);

                //
                il.ReturnTemporaryLocal(enumerator);
            }
            // FOREACH_END:
            il.MarkLabel(foreach_end);

            il.ReturnTemporaryLocal(enumerable);

            codeGenerator.BranchingStack.EndLoop();

            il.ForgetLabel(foreach_end);
            il.ForgetLabel(foreach_begin);
            il.ForgetLabel(loop_begin);
            il.ForgetLabel(loop_test);
        }
        /// <summary>
        /// Emits local variable switch and performs a specified operation on each case.
        /// </summary>
        /// <param name="codeGenerator">The code generator.</param>
        /// <param name="method">The operation performed in each case.</param>
        internal void EmitSwitch(CodeGenerator codeGenerator, SwitchMethod method)
        {
            ILEmitter il = codeGenerator.IL;

            Debug.Assert(method != null);

            Label          default_case       = il.DefineLabel();
            Label          end_label          = il.DefineLabel();
            LocalBuilder   ivar_local         = il.GetTemporaryLocal(Types.String[0], true);
            LocalBuilder   non_interned_local = il.DeclareLocal(Types.String[0]);
            VariablesTable variables          = codeGenerator.CurrentVariablesTable;

            Label[] labels = new Label[variables.Count];

            // non_interned_local = <name expression>;
            EmitName(codeGenerator);
            il.Stloc(non_interned_local);

            // ivar_local = String.IsInterned(non_interned_local)
            il.Ldloc(non_interned_local);
            il.Emit(OpCodes.Call, Methods.String_IsInterned);
            il.Stloc(ivar_local);

            // switch for every compile-time variable:
            int i = 0;

            foreach (VariablesTable.Entry variable in variables)
            {
                labels[i] = il.DefineLabel();

                // IF (ivar_local == <i-th variable name>) GOTO labels[i];
                il.Ldloc(ivar_local);
                il.Emit(OpCodes.Ldstr, variable.VariableName.ToString());
                il.Emit(OpCodes.Beq, labels[i]);
                i++;
            }

            // GOTO default_case:
            il.Emit(OpCodes.Br, default_case);

            // operation on each variable:
            i = 0;
            foreach (VariablesTable.Entry variable in variables)
            {
                // labels[i]:
                il.MarkLabel(labels[i]);

                // operation:
                method(codeGenerator, variable, null);

                // GOTO end;
                il.Emit(OpCodes.Br, end_label);
                i++;
            }

            // default case - new variable created at runtime:
            il.MarkLabel(default_case);
            method(codeGenerator, null, non_interned_local);

            // END:
            il.MarkLabel(end_label);
        }