Example #1
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>
		internal override PhpTypeCode Emit(CodeGenerator/*!*/ codeGenerator)
		{
			Debug.Assert(access == AccessType.Read || access == AccessType.None || access == AccessType.ReadRef ||
			  access == AccessType.ReadUnknown);
			Statistics.AST.AddNode("Assign.Value");

			ILEmitter il = codeGenerator.IL;

			AccessType old_selector = codeGenerator.AccessSelector;

			codeGenerator.ChainBuilder.Create();

			PhpTypeCode result;

			if (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;
				lvalue.Emit(codeGenerator);
				codeGenerator.AccessSelector = AccessType.None;

				PhpTypeCode src_type_code = EmitSourceValRead(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, rvalue);
			}
			else
			{
				// PREPARE a:
				codeGenerator.AccessSelector = AccessType.Write;
				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(codeGenerator);
                var rvalue_tmp = codeGenerator.IL.GetTemporaryLocal(PhpTypeCodeEnum.ToType(right_type), false);
                codeGenerator.IL.Emit(OpCodes.Stloc, rvalue_tmp);
                EmitDestVarRead(codeGenerator);
                codeGenerator.IL.Emit(OpCodes.Ldloc, rvalue_tmp);
                codeGenerator.IL.ReturnTemporaryLocal(rvalue_tmp);

				switch (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.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);
						il.Emit(OpCodes.Ldc_I4, (int)Operators.BitOp.And);
						result = codeGenerator.EmitMethodCall(Methods.Operators.BitOperation);
						break;

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

					case Operations.AssignXor:
						codeGenerator.EmitBoxing(right_type);
						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:
						Debug.Fail();
						throw null;
				}

				il.EmitBoxing(result);
			}

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

						// STORE tmp
						il.Stloc(il.GetAssignmentLocal());

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

						// LOAD result
						il.Ldloc(il.GetAssignmentLocal());

						result = PhpTypeCode.Object;
						break;
					}

				case AccessType.ReadRef:
				case AccessType.ReadUnknown:

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

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

				case AccessType.None:

					// STORE a:
					codeGenerator.AccessSelector = AccessType.Write;
					result = lvalue.EmitAssign(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;
		}
Example #2
0
		/// <summary>
		/// Emit IL instructions that load the value of array item at the stack and make a copy 
		/// of it if necessary.
		/// </summary>
		internal override PhpTypeCode EmitValue(CodeGenerator/*!*/ codeGenerator)
		{
			Debug.Assert(valueExpr != null);
			Statistics.AST.AddNode("Array.ValueItem");

			codeGenerator.EmitBoxing(valueExpr.Emit(codeGenerator));
			codeGenerator.EmitVariableCopy(CopyReason.Assigned, valueExpr);

			return PhpTypeCode.Object;
		}
Example #3
0
        private 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>:
                    (vals[i] as VariableUse).EmitAssign(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());
                }   
            }
        }