Beispiel #1
0
            /// <summary>
            /// Assigns null into given lvalues recursively.
            /// </summary>
            /// <param name="codeGenerator"></param>
            /// <param name="vals"></param>
            private static void EmitAssignListNulls(CodeGenerator codeGenerator, List <Expression> vals)
            {
                // clear lvalues recursively

                for (int i = 0; i < vals.Count; ++i)
                {
                    if (vals[i] == null)
                    {
                        continue;
                    }

                    if (vals[i] is VariableUse)
                    {
                        // Prepare stack for writing result...
                        codeGenerator.ChainBuilder.Create();
                        (vals[i] as VariableUse).Emit(codeGenerator);

                        codeGenerator.IL.Emit(OpCodes.Ldnull);

                        // Store result
                        VariableUseHelper.EmitAssign((VariableUse)vals[i], codeGenerator);
                        codeGenerator.ChainBuilder.End();
                    }
                    else if (vals[i] is ListEx)
                    {
                        EmitAssignListNulls(codeGenerator, (vals[i] as ListEx).LValues);
                    }
                    else
                    {
                        Debug.Fail("Unsupported list argument of type " + vals[i].GetType().ToString());
                    }
                }
            }
Beispiel #2
0
            private static void EmitAssignListArray(CodeGenerator codeGenerator, List <Expression> vals, LocalBuilder o1)
            {
                //
                // the array is on the top of the evaluation stack, value will be kept, must be duplicated to be used
                //

                // Process in the reverse order !
                for (int i = vals.Count - 1; i >= 0; i--)
                {
                    if (vals[i] == null)
                    {
                        continue;
                    }

                    // push the array item onto the stack

                    // LOAD array.GetArrayItem(i,false)
                    codeGenerator.IL.Emit(OpCodes.Dup);         // copy of the array
                    codeGenerator.IL.Emit(OpCodes.Ldc_I4, i);   // i
                    codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);    // false (!quiet)
                    codeGenerator.IL.Emit(OpCodes.Callvirt, Methods.PhpArray.GetArrayItem_Int32);

                    // assign the item from the stack into vals[i]

                    if (vals[i] is VariableUse)
                    {
                        // o1 = stack[0]
                        codeGenerator.IL.Stloc(o1);                 // store the value into local variable o1

                        // PREPARE <variable>:
                        codeGenerator.ChainBuilder.Create();
                        vals[i].Emit(codeGenerator);

                        // LOAD o1
                        codeGenerator.IL.Ldloc(o1);

                        // LOAD PhpVariable.Copy(STACK,CopyReason.Assigned)
                        codeGenerator.EmitVariableCopy(CopyReason.Assigned, null);

                        // STORE <variable>:
                        VariableUseHelper.EmitAssign((VariableUse)vals[i], codeGenerator);
                        codeGenerator.ChainBuilder.End();
                    }
                    else if (vals[i] is ListEx)
                    {
                        EmitAssignList(codeGenerator, (vals[i] as ListEx).LValues, o1);
                        codeGenerator.IL.Emit(OpCodes.Pop); // removes used value from the stack
                    }
                    else
                    {
                        codeGenerator.IL.Emit(OpCodes.Pop); // removes used value from the stack

                        Debug.Fail("Unsupported list argument of type " + vals[i].GetType().ToString());
                    }
                }
            }
Beispiel #3
0
            public override PhpTypeCode Emit(IssetEx node, CodeGenerator codeGenerator)
            {
                Debug.Assert(access == AccessType.None || access == AccessType.Read);
                Statistics.AST.AddNode("IssetEx");
                ILEmitter il = codeGenerator.IL;

                codeGenerator.ChainBuilder.Create();
                codeGenerator.ChainBuilder.QuietRead = true;

                var vars = node.VarList;

                if (vars.Count == 1)
                {
                    codeGenerator.EmitBoxing(VariableUseHelper.EmitIsset(vars[0], codeGenerator, false));

                    // Compare the result with "null"
                    il.CmpNotNull();
                }
                else
                {
                    // Define labels
                    Label f_label = il.DefineLabel();
                    Label x_label = il.DefineLabel();

                    // Get first variable
                    codeGenerator.EmitBoxing(VariableUseHelper.EmitIsset(vars[0], codeGenerator, false));

                    // Compare the result with "null"
                    il.CmpNotNull();

                    // Process following variables and include branching
                    for (int i = 1; i < vars.Count; i++)
                    {
                        il.Emit(OpCodes.Brfalse, f_label);
                        codeGenerator.EmitBoxing(VariableUseHelper.EmitIsset(vars[i], codeGenerator, false));

                        // Compare the result with "null"
                        codeGenerator.IL.CmpNotNull();
                    }

                    il.Emit(OpCodes.Br, x_label);
                    il.MarkLabel(f_label, true);
                    il.Emit(OpCodes.Ldc_I4_0);
                    il.MarkLabel(x_label, true);
                }

                codeGenerator.ChainBuilder.End();

                if (access == AccessType.None)
                {
                    il.Emit(OpCodes.Pop);
                    return(PhpTypeCode.Void);
                }

                return(PhpTypeCode.Boolean);
            }
Beispiel #4
0
            internal override void Emit(UnsetStmt node, CodeGenerator codeGenerator)
            {
                Statistics.AST.AddNode("UnsetStmt");

                codeGenerator.MarkSequencePoint(node.Span);

                foreach (VariableUse variable in node.VarList)
                {
                    codeGenerator.ChainBuilder.Create();
                    codeGenerator.ChainBuilder.QuietRead = true;
                    VariableUseHelper.EmitUnset(variable, codeGenerator);
                    codeGenerator.ChainBuilder.End();
                }
            }
Beispiel #5
0
            public PhpTypeCode EmitAssign(ForeachVar /*!*/ node, CodeGenerator codeGenerator)
            {
                // Object (or PhpReference) is on top of evaluation stack

                var varuse = node.Variable;

                if (varuse != null)
                {
                    return(VariableUseHelper.EmitAssign(varuse, codeGenerator));
                }
                else
                {
                    var listex = node.List;
                    if (listex != null)
                    {
                        return(listex.NodeCompiler <ListExCompiler>().EmitAssign(listex, codeGenerator));
                    }
                    else
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
Beispiel #6
0
            public override PhpTypeCode Emit(AssignEx node, CodeGenerator codeGenerator)
            {
                Debug.Assert(access == AccessType.None || access == AccessType.Read || access == AccessType.ReadRef ||
                             access == AccessType.ReadUnknown);
                Statistics.AST.AddNode("Assign.Ref");

                //ChainBuilder.RefErrorLabelInfo labelInfo;

                // Strict Standards: Only variables should be assigned by reference

                /*if (rvalue is FunctionCall)//TODO: only variables (but also variables given by function call return value!)
                 * {
                 *  il.LdcI4( (int)PhpError.Strict );
                 *  il.Emit(OpCodes.Ldstr, CoreResources.GetString("only_vars_assign ed_by_ref"));
                 *  codeGenerator.EmitPhpException(il,Methods.PhpException.Throw);
                 * }*/

                // PREPARE:
                codeGenerator.ChainBuilder.Create();
                node.LValue.Emit(codeGenerator);

                // LOAD <right hand side>:
                codeGenerator.ChainBuilder.Create();
                ((RefAssignEx)node).RValue.Emit(codeGenerator);
                codeGenerator.ChainBuilder.End();

                PhpTypeCode result;

                // Dup source value if assignment is read
                switch (access)
                {
                case AccessType.Read:
                case AccessType.ReadUnknown:
                case AccessType.ReadRef:
                {
                    // DUP
                    codeGenerator.IL.Emit(OpCodes.Dup);

                    // STORE tmp
                    codeGenerator.IL.Stloc(codeGenerator.IL.GetAssignmentLocalRef());

                    // STORE prepared,result
                    VariableUseHelper.EmitAssign(node.LValue, codeGenerator);

                    // LOAD DEREF tmp
                    codeGenerator.IL.Ldloc(codeGenerator.IL.GetAssignmentLocalRef());

                    if (access == AccessType.Read)
                    {
                        codeGenerator.IL.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
                        result = PhpTypeCode.Object;
                    }
                    else
                    {
                        result = PhpTypeCode.PhpReference;
                    }
                    break;
                }

                case AccessType.None:
                    VariableUseHelper.EmitAssign(node.LValue, codeGenerator);
                    result = PhpTypeCode.Void;
                    break;

                default:
                    throw new InvalidOperationException();
                    //result = PhpTypeCode.Invalid;
                    //break;
                }
                codeGenerator.ChainBuilder.End();

                return(result);
            }
Beispiel #7
0
            /// <summary>
            /// Emits assignment.
            /// </summary>
            /// <remarks>
            /// Pattern: a op= b
            ///
            /// PREPARE a      (prepared)
            /// LOAD a         (prepared,a)
            /// LOAD b         (prepared,a,b)
            /// OP             (prepared,result)
            /// *DUP           (prepared,result,result)
            /// *STORE tmp     (prepared,result)           must be this stack here!
            /// STORE a        ()
            /// *LOAD tmp      (result)
            ///
            /// * only if the resulting value needs to be propagated to the right
            ///
            /// Note: There is a possible improvement: some store operations (SetVariable) may return the value set
            /// which would replace DUP and second temp op.
            /// </remarks>
            public override PhpTypeCode Emit(AssignEx node, CodeGenerator codeGenerator)
            {
                Debug.Assert(access == AccessType.Read || access == AccessType.None || access == AccessType.ReadRef ||
                             access == AccessType.ReadUnknown);
                Statistics.AST.AddNode("Assign.Value");

                AccessType old_selector = codeGenerator.AccessSelector;

                codeGenerator.ChainBuilder.Create();

                PhpTypeCode result;

                if (node.Operation == Operations.AssignValue)
                {
                    //
                    // Access Type = ReadRef/ReadUnknown
                    // ---------------------------------
                    //
                    // f(&$x) { }
                    //
                    // f($a = $b);
                    // f($a = $b =& $c);
                    //
                    // Destination variable $a is prepared for reference write.
                    // A new reference is created and its value set to a deep copy of the result of RHS ($b, $b =& $c).
                    // RHS has Read access => it has been dereferenced.
                    //

                    // PREPARE a:
                    codeGenerator.AccessSelector = AccessType.Write;
                    node.lvalue.Emit(codeGenerator);
                    codeGenerator.AccessSelector = AccessType.None;

                    PhpTypeCode src_type_code = EmitSourceValRead((ValueAssignEx)node, codeGenerator);

                    // RHS should have Read access => should be dereferenced
                    Debug.Assert(src_type_code != PhpTypeCode.PhpReference);

                    // LOAD BOX b
                    codeGenerator.EmitBoxing(src_type_code);

                    // makes a copy if necessary:
                    if (PhpTypeCodeEnum.IsDeeplyCopied(src_type_code))
                    {
                        codeGenerator.EmitVariableCopy(CopyReason.Assigned, ((ValueAssignEx)node).rvalue);
                    }
                }
                else
                {
                    // PREPARE a:
                    codeGenerator.AccessSelector = AccessType.Write;
                    node.LValue.Emit(codeGenerator);
                    codeGenerator.AccessSelector = AccessType.None;

                    // LOAD b,a (rvalue must be processed first, than +-*/ with lvalue, since lvalu can be changed by rvalue expression)
                    //must be the second operand// EmitDestVarRead(codeGenerator);
                    PhpTypeCode right_type = EmitSourceValRead((ValueAssignEx)node, codeGenerator);
                    var         rvalue_tmp = codeGenerator.IL.GetTemporaryLocal(PhpTypeCodeEnum.ToType(right_type), false);
                    codeGenerator.IL.Emit(OpCodes.Stloc, rvalue_tmp);
                    EmitDestVarRead(node, codeGenerator);
                    codeGenerator.IL.Emit(OpCodes.Ldloc, rvalue_tmp);
                    codeGenerator.IL.ReturnTemporaryLocal(rvalue_tmp);

                    switch (node.Operation)
                    {
                        #region Arithmetic

                    case Operations.AssignAdd:
                    {
                        switch (right_type)
                        {
                        case PhpTypeCode.Integer:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Int32);
                            break;

                        case PhpTypeCode.Double:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Double);
                            break;

                        default:
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Object);
                            break;
                        }
                        break;
                    }

                    case Operations.AssignSub:
                    {
                        switch (right_type)
                        {
                        case PhpTypeCode.Integer:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Int);
                            break;

                        default:
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Object);
                            break;
                        }
                        break;
                    }

                    case Operations.AssignDiv:
                    {
                        switch (right_type)
                        {
                        case PhpTypeCode.Integer:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Int32);
                            break;

                        case PhpTypeCode.Double:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Double);
                            break;

                        default:
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Object);
                            break;
                        }
                        break;
                    }

                    case Operations.AssignMul:
                    {
                        switch (right_type)
                        {
                        case PhpTypeCode.Integer:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Int32);
                            break;

                        case PhpTypeCode.Double:
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Double);
                            break;

                        default:
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Object);
                            break;
                        }
                        break;
                    }

                    case Operations.AssignPow:
                        codeGenerator.EmitBoxing(right_type);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.Pow.Object_Object);
                        break;

                    case Operations.AssignMod:

                        if (right_type == PhpTypeCode.Integer)
                        {
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Int32);
                        }
                        else
                        {
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Object);
                        }
                        break;


                        #endregion

                        #region Bitwise

                    case Operations.AssignAnd:
                        codeGenerator.EmitBoxing(right_type);
                        codeGenerator.IL.Emit(OpCodes.Ldc_I4, (int)Operators.BitOp.And);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.BitOperation);
                        break;

                    case Operations.AssignOr:
                        codeGenerator.EmitBoxing(right_type);
                        codeGenerator.IL.Emit(OpCodes.Ldc_I4, (int)Operators.BitOp.Or);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.BitOperation);
                        break;

                    case Operations.AssignXor:
                        codeGenerator.EmitBoxing(right_type);
                        codeGenerator.IL.Emit(OpCodes.Ldc_I4, (int)Operators.BitOp.Xor);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.BitOperation);
                        break;

                    case Operations.AssignShiftLeft:
                        codeGenerator.EmitBoxing(right_type);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.ShiftLeft);
                        break;

                    case Operations.AssignShiftRight:
                        codeGenerator.EmitBoxing(right_type);
                        result = codeGenerator.EmitMethodCall(Methods.Operators.ShiftRight);
                        break;

                        #endregion

                        #region String

                    case Operations.AssignAppend:
                    {
                        if (right_type == PhpTypeCode.String)
                        {
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Append.Object_String);
                        }
                        else if (right_type == PhpTypeCode.PhpBytes)
                        {
                            result = codeGenerator.EmitMethodCall(Methods.PhpBytes.Append_Object_PhpBytes);
                        }
                        else
                        {
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Append.Object_Object);
                        }
                        break;
                    }

                    case Operations.AssignPrepend:
                    {
                        if (right_type == PhpTypeCode.String)
                        {
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Prepend.Object_String);
                        }
                        else
                        {
                            codeGenerator.EmitBoxing(right_type);
                            result = codeGenerator.EmitMethodCall(Methods.Operators.Prepend.Object_Object);
                        }
                        break;
                    }

                        #endregion

                    default:
                        throw new InvalidOperationException();
                    }

                    codeGenerator.IL.EmitBoxing(result);
                }

                switch (access)
                {
                case AccessType.Read:
                {
                    // DUP
                    codeGenerator.IL.Emit(OpCodes.Dup);

                    // STORE tmp
                    codeGenerator.IL.Stloc(codeGenerator.IL.GetAssignmentLocal());

                    // STORE prepared, result
                    codeGenerator.AccessSelector = AccessType.Write;
                    result = VariableUseHelper.EmitAssign(node.LValue, codeGenerator);
                    codeGenerator.AccessSelector = AccessType.None;
                    Debug.Assert(result == PhpTypeCode.Void);

                    // LOAD result
                    codeGenerator.IL.Ldloc(codeGenerator.IL.GetAssignmentLocal());

                    result = PhpTypeCode.Object;
                    break;
                }

                case AccessType.ReadRef:
                case AccessType.ReadUnknown:

                    // STORE prepared,result
                    codeGenerator.AccessSelector = AccessType.Write;
                    result = VariableUseHelper.EmitAssign(node.LValue, codeGenerator);
                    codeGenerator.AccessSelector = AccessType.None;
                    Debug.Assert(result == PhpTypeCode.Void);

                    // loads a reference on the LHS variable:
                    codeGenerator.AccessSelector = access;
                    codeGenerator.ChainBuilder.Create();
                    result = node.LValue.Emit(codeGenerator);
                    codeGenerator.ChainBuilder.EndRef();
                    codeGenerator.AccessSelector = AccessType.None;
                    break;

                case AccessType.None:

                    // STORE a:
                    codeGenerator.AccessSelector = AccessType.Write;
                    result = VariableUseHelper.EmitAssign(node.LValue, codeGenerator);
                    codeGenerator.AccessSelector = AccessType.None;
                    Debug.Assert(result == PhpTypeCode.Void);

                    break;

                default:
                    Debug.Fail("Invalid access type.");
                    result = PhpTypeCode.Invalid;
                    break;
                }

                codeGenerator.ChainBuilder.End();

                codeGenerator.AccessSelector = old_selector;

                return(result);
            }