Example #1
0
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override PhpTypeCode Emit(CodeGenerator codeGenerator)
		{
			Statistics.AST.AddNode("ListEx");

			Debug.Assert(access == AccessType.Read || access == AccessType.None);

            Debug.Assert(RValue != null);   // the root of the lists structure must have RValue assigned. list(whatever) = RValue

            
            codeGenerator.EmitBoxing(RValue.Emit(codeGenerator));   // put object on the top of the stack

            LocalBuilder o1 = codeGenerator.IL.GetTemporaryLocal(Types.Object[0]);   // temporary variable for object to be copied
            EmitAssignList(codeGenerator, LValues, o1);                 // assign particular elements of the list, using the array from the stack

            // return temporary local
            codeGenerator.IL.ReturnTemporaryLocal(o1);

            // the original top of the stack is replaced with the instance of array or null
            if (access == AccessType.Read)
            {
                return PhpTypeCode.PhpArray;    // return the top of the stack (null or array)
            }
            else
            {
                codeGenerator.IL.Emit(OpCodes.Pop); // remove the top of the stack, not used
                return PhpTypeCode.Void;
            }
		}
Example #2
0
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override PhpTypeCode Emit(CodeGenerator/*!*/ codeGenerator)
		{
			Statistics.AST.AddNode("InstanceOfEx");

			// emits load of expression value on the stack:
			codeGenerator.EmitBoxing(expression.Emit(codeGenerator));

			if (classNameRef.ResolvedType != null && typeArgsResolved)
			{
				// type is resolvable (doesn't mean known) //

				classNameRef.ResolvedType.EmitInstanceOf(codeGenerator, null);
			}
			else
			{
				// type is unresolvable (there is some variable or the type is a generic parameter) //

				codeGenerator.EmitInstanceOfOperator(null, classNameRef, null);
			}

			if (access == AccessType.None)
			{
				codeGenerator.IL.Emit(OpCodes.Pop);
				return PhpTypeCode.Void;
			}
			else
			{
				return PhpTypeCode.Boolean;
			}
		}
Example #3
0
        /// <summary>
        /// Emits strict equality operation.
        /// </summary>
        /// <param name="codeGenerator">A code generator.</param>
        /// <returns>A type code of the result (boolean).</returns>
        private PhpTypeCode EmitStrictEquality(CodeGenerator codeGenerator)
        {
            if (IsEmptyArrayEx(leftExpr))
            {
                EmitEmptyArrayStrictEquality(codeGenerator, rightExpr);
            }
            else if (IsEmptyArrayEx(rightExpr))
            {
                EmitEmptyArrayStrictEquality(codeGenerator, leftExpr);
            }
            else
            {
                // LOAD Operators.StrictEquality(box left,box right);
                codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
                codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
                codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEquality);
            }

            return PhpTypeCode.Boolean;
        }
Example #4
0
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override void Emit(CodeGenerator/*!*/ codeGenerator)
		{
			Statistics.AST.AddNode("SwitchStmt");
			ILEmitter il = codeGenerator.IL;

			// Note: 
			//  SwitchStmt is now implemented in the most general (and unefficient) way. The whole switch
			//  is understood as a series of if-elseif-else statements.

			Label exit_label = il.DefineLabel();
			bool fall_through = false;
			Label fall_through_label = il.DefineLabel();
			Label last_default_label = il.DefineLabel();
			DefaultItem last_default = GetLastDefaultItem();
			LocalBuilder branch_to_lastdefault = null;

			if (last_default != null)
			{
				branch_to_lastdefault = il.DeclareLocal(Types.Bool[0]);
				il.LdcI4(0);
				il.Stloc(branch_to_lastdefault);
			}

			codeGenerator.BranchingStack.BeginLoop(exit_label, exit_label,
			  codeGenerator.ExceptionBlockNestingLevel);

			// marks a sequence point containing the discriminator evaluation:
			codeGenerator.MarkSequencePoint(
			  switchValue.Position.FirstLine,
			  switchValue.Position.FirstColumn,
			  switchValue.Position.LastLine,
			  switchValue.Position.LastColumn + 1);

			// Evaluate condition value and store the result into local variable
            codeGenerator.EmitBoxing(switchValue.Emit(codeGenerator));
			LocalBuilder condition_value = il.DeclareLocal(Types.Object[0]);
			il.Stloc(condition_value);

			foreach (SwitchItem item in switchItems)
			{
				item.MarkSequencePoint(codeGenerator);

				// switch item is either CaseItem ("case xxx:") or DefaultItem ("default") item:
				CaseItem case_item = item as CaseItem;
				if (case_item != null)
				{
					Label false_label = il.DefineLabel();

					// PhpComparer.Default.CompareEq(<switch expr. value>,<case value>);
                    /*changed to static method*/ //il.Emit(OpCodes.Ldsfld, Fields.PhpComparer_Default);
                    codeGenerator.EmitCompareEq(
                        cg => { cg.IL.Ldloc(condition_value); return PhpTypeCode.Object; },
                        cg => case_item.EmitCaseValue(cg));
					
					// IF (!STACK) GOTO false_label;
					il.Emit(OpCodes.Brfalse, false_label);
					if (fall_through == true)
					{
						il.MarkLabel(fall_through_label, true);
						fall_through = false;
					}

					case_item.EmitStatements(codeGenerator);

					if (fall_through == false)
					{
						fall_through_label = il.DefineLabel();
						fall_through = true;
					}

					il.Emit(OpCodes.Br, fall_through_label);

					il.MarkLabel(false_label, true);
				}
				else
				{
					DefaultItem default_item = (DefaultItem)item;

					// Only the last default branch defined in source code is used.
					// So skip default while testing "case" items at runtime.
					Label false_label = il.DefineLabel();
					il.Emit(OpCodes.Br, false_label);

					if (default_item == last_default)
					{
						il.MarkLabel(last_default_label, false);
					}

					if (fall_through == true)
					{
						il.MarkLabel(fall_through_label, true);
						fall_through = false;
					}

					default_item.EmitStatements(codeGenerator);

					if (fall_through == false)
					{
						fall_through_label = il.DefineLabel();
						fall_through = true;
					}

					il.Emit(OpCodes.Br, fall_through_label);
					il.MarkLabel(false_label, true);
				}
			}

			// If no case branch matched, branch to last default case if any is defined
			if (last_default != null)
			{
				// marks a sequence point containing the condition evaluation or skip of the default case:
				codeGenerator.MarkSequencePoint(
				  last_default.Position.FirstLine,
				  last_default.Position.FirstColumn,
				  last_default.Position.LastLine,
				  last_default.Position.LastColumn + 1);

				Debug.Assert(branch_to_lastdefault != null);
				Label temp = il.DefineLabel();

				// IF (!branch_to_lastdefault) THEN 
				il.Ldloc(branch_to_lastdefault);
				il.LdcI4(0);
				il.Emit(OpCodes.Bne_Un, temp);
				if (true)
				{
					// branch_to_lastdefault = TRUE; 
					il.LdcI4(1);
					il.Stloc(branch_to_lastdefault);

					// GOTO last_default_label;
					il.Emit(OpCodes.Br, last_default_label);
				}
				il.MarkLabel(temp, true);
				// END IF;

				il.ForgetLabel(last_default_label);
			}

			if (fall_through == true)
			{
				il.MarkLabel(fall_through_label, true);
			}

			il.MarkLabel(exit_label);
			codeGenerator.BranchingStack.EndLoop();
			il.ForgetLabel(exit_label);
		}
Example #5
0
		/// <summary>
		/// Emits code to load <see cref="PhpRuntimeChain"/> onto an evaluation stack. Supports operators chaining.
		/// </summary>
		/// <param name="codeGenerator"></param>
		private PhpTypeCode EmitNodeReadUnknown(CodeGenerator codeGenerator)
		{
			ChainBuilder chain = codeGenerator.ChainBuilder;
			PhpTypeCode result = PhpTypeCode.PhpRuntimeChain;

			if (chain.IsArrayItem)
			{
				// 3: a_[x]_[x]
				chain.Lengthen(); // for []
				chain.EmitRTChainAddItem(this);
				return result;
			}
			// 1,2,4,5,6,7
			if (chain.IsMember)
			{
				// 4, 5
				if (this.isMemberOf != null)
				{
					// 5: ...->a[]->...

					// Lengthen chain for isMemberOf
					chain.Lengthen(); // for hop over ->
					PhpTypeCode res = isMemberOf.Emit(codeGenerator);
					if (res != PhpTypeCode.PhpRuntimeChain)
					{
						codeGenerator.EmitBoxing(res);
						chain.EmitCreateRTChain();
					}
					// Lengthen chain for own []
					chain.Lengthen();
					chain.IsArrayItem = true;
					chain.IsLastMember = false;
					chain.EmitRTChainAddItem(this);
					chain.IsArrayItem = false;
					return result;
				}
				// 4: a[x]->...
				// Lengthen chain for itself
				chain.Lengthen(); // for own []
				chain.IsArrayItem = true;
				chain.IsLastMember = true;
				chain.EmitRTChainAddItem(this);
				chain.IsArrayItem = false;
				return result;
			}
			// 1, 2, 6, 7
			if (this.isMemberOf != null)
			{
				// 6 , 7: ...->a[]_[]_ , ...->a_[]_
				bool quiet_read = chain.QuietRead;
				chain.Create();
				chain.Begin();
				chain.QuietRead = quiet_read;
				chain.Lengthen(); // for hop over ->
				PhpTypeCode res = isMemberOf.Emit(codeGenerator);
				if (res != PhpTypeCode.PhpRuntimeChain)
				{
					codeGenerator.EmitBoxing(res);
					chain.EmitCreateRTChain();
				}
				chain.IsArrayItem = true;
				chain.IsLastMember = false;
				chain.EmitRTChainAddItem(this);
				chain.IsArrayItem = false;
				chain.End();
				return result;
			}
			// 1, 2
			if (array is ItemUse || array is DirectStFldUse || array is IndirectStFldUse /* ??? */)
			{
				// 2: a[]_[]_
				bool quiet_read = chain.QuietRead;
				chain.Create();
				chain.Begin();
				chain.QuietRead = quiet_read;
				chain.IsArrayItem = true;
				chain.IsLastMember = true;
				chain.EmitRTChainAddItem(this);
				chain.IsArrayItem = false;
				chain.End();
				return result;
			}
			// 1: a_[x]_
			chain.IsArrayItem = true;
			chain.IsLastMember = true;
			chain.EmitRTChainAddItem(this);
			chain.IsArrayItem = false;
			return result;
		}
Example #6
0
		/// <summary>
		/// Emits bit operation <see cref="leftExpr"/> OP <see cref="rightExpr"/>.
		/// </summary>
		/// <param name="codeGenerator">A code generator.</param>
		/// <param name="op">The operation.</param>
		/// <returns>A type code of the result.</returns>
		private PhpTypeCode EmitBitOperation(CodeGenerator/*!*/ codeGenerator, Operators.BitOp op)
		{
			ILEmitter il = codeGenerator.IL;

			// LOAD Operators.BitOperation(box <leftSon>, box <rightSon>);
			codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
			codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
			il.Emit(OpCodes.Ldc_I4, (int)op);
			il.Emit(OpCodes.Call, Methods.Operators.BitOperation);

			return PhpTypeCode.Object;
		}
Example #7
0
            internal void EmitLoadArgsOnEvalStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator, PhpRoutine/*!*/ routine)
            {
                ILEmitter il = codeGenerator.IL;

                int mandatory_count = (routine.Signature != null) ? routine.Signature.MandatoryParamCount : 0;
                int formal_count = (routine.Signature != null) ? routine.Signature.ParamCount : 0;
                int actual_count = node.Parameters.Count;
                PhpTypeCode param_type;

                // loads all actual parameters which are not superfluous:
                for (int i = 0; i < Math.Min(actual_count, formal_count); i++)
                {
                    var p = node.Parameters[i];
                    codeGenerator.EmitBoxing(param_type = p.NodeCompiler<ActualParamCompiler>().Emit(p, codeGenerator));

                    // Actual param emitter should emit "boxing" to a reference if its access type is ReadRef.
                    // That's why no operation is needed here and references should match.
                    Debug.Assert((routine.Signature == null || routine.Signature.IsAlias(i)) == (param_type == PhpTypeCode.PhpReference));
                }

                // loads missing mandatory arguments:
                for (int i = actual_count; i < mandatory_count; i++)
                {
                    // CALL PhpException.MissingArgument(<i+1>,<name>);
                    il.LdcI4(i + 1);
                    il.Emit(OpCodes.Ldstr, routine.FullName);
                    codeGenerator.EmitPhpException(Methods.PhpException.MissingArgument);

                    // LOAD null;
                    if (routine.Signature.IsAlias(i))
                        il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
                    else
                        il.Emit(OpCodes.Ldnull);
                }

                // loads missing optional arguments:
                for (int i = Math.Max(mandatory_count, actual_count); i < formal_count; i++)
                {
                    // LOAD Arg.Default;
                    il.Emit(OpCodes.Ldsfld, Fields.Arg_Default);
                }
            }
Example #8
0
		/// <summary>
		/// Emits IL instructions that load actual parameters and optionally add a new stack frame to
		/// current <see cref="PHP.Core.ScriptContext.Stack"/>.
		/// </summary>
		/// <param name="codeGenerator">Code generator.</param>
		/// <remarks>
		/// Nothing is expected on the evaluation stack. Nothing is left on the evaluation stack.
		/// </remarks>
		internal void EmitLoadOnPhpStack(CodeGenerator/*!*/ codeGenerator)
		{
			List<ActualParam> parameters = this.parameters;
			List<TypeRef> genericParams = this.genericParams;

			PhpStackBuilder.EmitAddFrame(codeGenerator.IL, codeGenerator.ScriptContextPlace, genericParams.Count, parameters.Count,
			  delegate(ILEmitter il, int i)
			  {
				  // generic arguments:
				  genericParams[i].EmitLoadTypeDesc(codeGenerator, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
			  },
			  delegate(ILEmitter il, int i)
			  {
				  // regular arguments:
				  codeGenerator.EmitBoxing(parameters[i].Emit(codeGenerator));
			  }
			);
		}
Example #9
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 #10
0
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override PhpTypeCode Emit(CodeGenerator codeGenerator)
		{
			Statistics.AST.AddNode("TernaryEx");
			Debug.Assert(access == AccessType.Read || access == AccessType.None);

			Label end_label = codeGenerator.IL.DefineLabel();
			
            if (trueExpr != null)   // standard ternary operator
            {
                Label else_label = codeGenerator.IL.DefineLabel();
                
                // IF (<(bool) condition>) THEN
                codeGenerator.EmitConversion(condExpr, PhpTypeCode.Boolean);
                codeGenerator.IL.Emit(OpCodes.Brfalse, else_label);
                {
                    codeGenerator.EmitBoxing(trueExpr.Emit(codeGenerator));
                    codeGenerator.IL.Emit(OpCodes.Br, end_label);
                }
                // ELSE
                codeGenerator.IL.MarkLabel(else_label, true);
                {
                    codeGenerator.EmitBoxing(falseExpr.Emit(codeGenerator));
                }
            }
            else
            {   // ternary shortcut:
                var il = codeGenerator.IL;

                // condExpr ?? rightExpr

                il.EmitBoxing(condExpr.Emit(codeGenerator));
                
                // IF (<stack>):
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);

                codeGenerator.IL.Emit(OpCodes.Brtrue, end_label);
                // ELSE:
                {
                    il.Emit(OpCodes.Pop);
                    il.EmitBoxing(falseExpr.Emit(codeGenerator));                    
                }
            }

			// END IF;
			codeGenerator.IL.MarkLabel(end_label, true);


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

			return PhpTypeCode.Object;
		}
Example #11
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 #12
0
		private void EmitReturnPhpReference(CodeGenerator codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;
			PhpTypeCode result;

			if (expr != null)
			{
				result = expr.Emit(codeGenerator);

				if (result != PhpTypeCode.PhpReference)
				{
					// return value is "boxed" to PhpReference:
					if (result != PhpTypeCode.Void)
					{
						codeGenerator.EmitBoxing(result);

						// We can box the value without making a copy since the result of the return expression
						// is not accessible after returnign from the routine as it is a value (not a reference).
						il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
					}
					else
					{
						il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
					}
				}
			}
			else
			{
				il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
			}

			codeGenerator.EmitReturnBranch();
		}
Example #13
0
		/// <summary>
		/// Return value is not deeply copied since the deep copy takes place when the caller accesses the value.
		/// </summary>
		private void EmitReturnObject(CodeGenerator/*!*/ codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;
			PhpTypeCode result;

			if (expr != null)
			{
				result = expr.Emit(codeGenerator);

				// dereference return value:
				if (result == PhpTypeCode.PhpReference)
                {
					il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
                }
                else if (result == PhpTypeCode.PhpArray)
                {
                    // <array>.InplaceCopyOnReturn = true;
                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.Emit(OpCodes.Call, Properties.PhpArray_InplaceCopyOnReturn.GetSetMethod());
                }
				else
                {
					codeGenerator.EmitBoxing(result);
                }
			}
			else
			{
				il.Emit(OpCodes.Ldnull);
			}

			codeGenerator.EmitReturnBranch();
		}
Example #14
0
        /// <summary>
        /// Emits strict equality to empty PHP array.
        /// </summary>
        /// <param name="codeGenerator">A code generator.</param>
        /// <param name="expr">Expression to be compared against.</param>
        private static void EmitEmptyArrayStrictEquality(CodeGenerator/*!*/codeGenerator, Expression/*!*/expr)
        {
            if (IsEmptyArrayEx(expr))
            {
                // array() === array()
                // LOAD true
                codeGenerator.IL.LoadBool(true);
            }
            else if (expr is Literal)
            {
                // array() === NULL|int|double|string|...
                // LOAD false
                codeGenerator.IL.LoadBool(false);
            }
            else
            {
                // array() === <expr>

                // LOAD <expr>
                var exprTypeCode = expr.Emit(codeGenerator);

                // check whether <expr> type can be an array
                switch (exprTypeCode)
                {
                    case PhpTypeCode.Boolean:
                    case PhpTypeCode.DObject:
                    case PhpTypeCode.Double:
                    case PhpTypeCode.Integer:
                    case PhpTypeCode.LongInteger:
                    case PhpTypeCode.PhpBytes:
                    case PhpTypeCode.PhpString:
                    case PhpTypeCode.String:
                        // always FALSE
                        codeGenerator.IL.Emit(OpCodes.Pop);
                        codeGenerator.IL.LoadBool(false);
                        break;
                    case PhpTypeCode.PhpArray:
                        // compare (PhpArray)<expr> with array()
                        codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEmptyPhpArrayEquality_PhpArray);
                        break;
                    default:
                        // compare <expr> with array()
                        codeGenerator.EmitBoxing(exprTypeCode);
                        codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEmptyPhpArrayEquality);
                        break;
                }                
            }
        }
Example #15
0
        internal override PhpTypeCode Emit(CodeGenerator codeGenerator)
        {
            Debug.Assert(access == AccessType.Read || access == AccessType.None);
            Statistics.AST.AddNode("Class.Concat." + expressions.Count);

            PhpTypeCode result;

            //
            // For low numbers call specialized methods
            switch (expressions.Count)
            {
                case 1:
                    result = expressions[0].Emit(codeGenerator);

                    if (result != PhpTypeCode.PhpBytes && result != PhpTypeCode.String)
                    {
                        var lbl = codeGenerator.IL.DefineLabel();
                        codeGenerator.EmitBoxing(result);
                        codeGenerator.IL.Emit(OpCodes.Dup);
                        codeGenerator.IL.Emit(OpCodes.Isinst,typeof(PhpBytes));

                        // IF (STACK)
                        codeGenerator.IL.Emit(OpCodes.Brtrue_S,lbl);                      
                        if (true)
                        {
                            codeGenerator.IL.Emit(OpCodes.Call, Methods.Convert.ObjectToString);
                        }
                        
                        // ELSE                        
                        codeGenerator.IL.MarkLabel(lbl, true);

                        //END IF

                        result = PhpTypeCode.Object;
                    }
                    break;

                case 2:
                    result = EmitConcat(codeGenerator, expressions[0], expressions[1]);
                    break;

                default:

                    codeGenerator.EmitObjectArrayPopulation(expressions);
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.Concat.ObjectArray);

                    result = PhpTypeCode.Object;    // string, PhpBytes
                    break;
            }

            switch (access)
            {
                case AccessType.Read:
                    // do nothing
                    break;

                case AccessType.None:
                    // pop result from stack
                    codeGenerator.IL.Emit(OpCodes.Pop);
                    result = PhpTypeCode.Void;
                    break;
            }

            return result;
        }
Example #16
0
        /// <summary>
        /// Emits load of an argument of a concatenation.
        /// </summary>
        private static PhpTypeCode EmitConcatExpressionLoad(CodeGenerator/*!*/ codeGenerator, Expression/*!*/ expression)
        {
            // tries to evaluate the expression:
            if (expression.HasValue)
            {
                if (expression.Value is PhpBytes)
                {
                    codeGenerator.IL.LoadLiteral(expression.Value);
                    return PhpTypeCode.PhpBytes;
                }
                else
                {
                    // evaluated expression is converted to a string if necessary:
                    codeGenerator.IL.Emit(OpCodes.Ldstr, Convert.ObjectToString(expression.Value));
                    return PhpTypeCode.String;
                }
            }
            else
            {
                // emits non-evaluable expression:
                PhpTypeCode result = expression.Emit(codeGenerator);

                // the result should be converted to string: (so we know the type for the further analysis)
                if (result != PhpTypeCode.String && // string already
                    result != PhpTypeCode.Object && // object can contain PhpBytes, should be converted just when we know we need string
                    result != PhpTypeCode.PhpBytes  // keep PhpBytes
                    )
                {
                    codeGenerator.EmitBoxing(result);   // in case of value-type
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.Convert.ObjectToString);
                    result = PhpTypeCode.String;
                }

                return result;
            }
        }
Example #17
0
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override PhpTypeCode Emit(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;

			if (varList.Count == 1)
			{
				codeGenerator.EmitBoxing(varList[0].EmitIsset(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(varList[0].EmitIsset(codeGenerator, false));

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

				// Process following variables and include branching
				for (int i = 1; i < varList.Count; i++)
				{
					il.Emit(OpCodes.Brfalse, f_label);
					codeGenerator.EmitBoxing(varList[i].EmitIsset(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;
		}
Example #18
0
            /// <summary>
            /// Emits IL instructions that load actual parameters and optionally add a new stack frame to
            /// current <see cref="PHP.Core.ScriptContext.Stack"/>.
            /// </summary>
            /// <param name="node">Instance.</param>
            /// <param name="codeGenerator">Code generator.</param>
            /// <remarks>
            /// Nothing is expected on the evaluation stack. Nothing is left on the evaluation stack.
            /// </remarks>
            public void EmitLoadOnPhpStack(CallSignature/*!*/node, CodeGenerator/*!*/ codeGenerator)
            {
                List<ActualParam> parameters = node.Parameters;
                List<TypeRef> genericParams = node.GenericParams;

                PhpStackBuilder.EmitAddFrame(codeGenerator.IL, codeGenerator.ScriptContextPlace, genericParams.Count, parameters.Count,
                  delegate(ILEmitter il, int i)
                  {
                      // generic arguments:
                      genericParams[i].EmitLoadTypeDesc(codeGenerator, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
                  },
                  delegate(ILEmitter il, int i)
                  {
                      // regular arguments:
                      var p = parameters[i];
                      codeGenerator.EmitBoxing(p.NodeCompiler<ActualParamCompiler>().Emit(p, codeGenerator));
                  }
                );
            }
Example #19
0
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		/// <remarks>
		/// Nothing is expected on the evaluation stack. The result value is left on the
		/// evaluation stack.
		/// </remarks>
		internal override PhpTypeCode Emit(CodeGenerator codeGenerator)
		{
			Debug.Assert(access == AccessType.Read || access == AccessType.None);
			Statistics.AST.AddNode("EmptyEx");

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

			// call EmitIsset in order to evaluate the variable quietly
			codeGenerator.EmitBoxing(variable.EmitIsset(codeGenerator, true));
			codeGenerator.IL.Emit(OpCodes.Call, Methods.PhpVariable.IsEmpty);

			codeGenerator.ChainBuilder.End();

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

			return PhpTypeCode.Boolean;
		}
Example #20
0
		/// <remarks>
		/// Nothing is expected at the evaluation stack. If AST node is read by other node,
		/// the operation result is left at the stack, otherwise it is poped from the stack.
		/// </remarks>
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override PhpTypeCode Emit(CodeGenerator codeGenerator)
		{
			Debug.Assert(access == AccessType.None || access == AccessType.Read);
			Statistics.AST.AddNode("BinaryEx");

			PhpTypeCode returned_typecode;
			PhpTypeCode lo_typecode;
			PhpTypeCode ro_typecode;

			switch (operation)
			{
				#region Arithmetic Operations

				case Operations.Add:
					// Template: x + y : Operators.Add(x,y) [overloads]

                    switch (lo_typecode = leftExpr.Emit(codeGenerator))
                    {
                        case PhpTypeCode.Double:
                            switch (ro_typecode = rightExpr.Emit(codeGenerator))
                            {
                                case PhpTypeCode.Integer:
                                    codeGenerator.IL.Emit(OpCodes.Conv_R8);
                                    goto case PhpTypeCode.Double;   // fallback:
                                case PhpTypeCode.Double:
                                    codeGenerator.IL.Emit(OpCodes.Add);
                                    returned_typecode = PhpTypeCode.Double;
                                    break;
                                default:
                                    codeGenerator.EmitBoxing(ro_typecode);
                                    returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Double_Object);
                                    break;
                            }
                            
                            break;
                        default:
                            codeGenerator.EmitBoxing(lo_typecode);
                            ro_typecode = rightExpr.Emit(codeGenerator);

                            switch (ro_typecode)
                            {
                                case PhpTypeCode.Integer:
                                    returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Int32);
                                    break;

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

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

				case Operations.Sub:
					//Template: "x - y"        Operators.Subtract(x,y) [overloads]
					lo_typecode = leftExpr.Emit(codeGenerator);
                    switch (lo_typecode)
                    {
                        case PhpTypeCode.Integer:
                            codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
                            returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Int32_Object);
                            break;
                        case PhpTypeCode.Double:
                            switch (ro_typecode = rightExpr.Emit(codeGenerator))
                            {
                                case PhpTypeCode.Integer:
                                    codeGenerator.IL.Emit(OpCodes.Conv_R8);
                                    goto case PhpTypeCode.Double;   // fallback:
                                case PhpTypeCode.Double:
                                    codeGenerator.IL.Emit(OpCodes.Sub);
                                    returned_typecode = PhpTypeCode.Double;
                                    break;
                                default:
                                    codeGenerator.EmitBoxing(ro_typecode);
                                    returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Double_Object);
                                    break;
                            }
                            
                            break;
                        default:
                            codeGenerator.EmitBoxing(lo_typecode);
                            ro_typecode = rightExpr.Emit(codeGenerator);
                            if (ro_typecode == PhpTypeCode.Integer)
                            {
                                returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Int);
                            }
                            else
                            {
                                codeGenerator.EmitBoxing(ro_typecode);
                                returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Object);
                            }
                            break;
                    }
					break;

				case Operations.Div:
					//Template: "x / y"   Operators.Divide(x,y)

					lo_typecode = leftExpr.Emit(codeGenerator);
					switch (lo_typecode)
					{
						case PhpTypeCode.Integer:
							codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
							returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Int32_Object);
							break;

						case PhpTypeCode.Double:
                            switch (ro_typecode = rightExpr.Emit(codeGenerator))
                            {
                                case PhpTypeCode.Double:
                                    codeGenerator.IL.Emit(OpCodes.Div);
                                    returned_typecode = PhpTypeCode.Double;
                                    break;
                                default:
                                    codeGenerator.EmitBoxing(ro_typecode);
                                    returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Double_Object);
                                    break;
                            }
                            break;

						default:
							codeGenerator.EmitBoxing(lo_typecode);
							ro_typecode = rightExpr.Emit(codeGenerator);

							switch (ro_typecode)
							{
								case PhpTypeCode.Integer:
									returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Int32);
									break;

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

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

				case Operations.Mul:
					switch (lo_typecode = leftExpr.Emit(codeGenerator))
                    {
                        case PhpTypeCode.Double:
                            // "x * (double)y"
                            // Operators.Multiply((double)x,(object)y)

                            switch (ro_typecode = rightExpr.Emit(codeGenerator))
                            {
                                case PhpTypeCode.Integer:
                                    codeGenerator.IL.Emit(OpCodes.Conv_R8);
                                    goto case PhpTypeCode.Double;   // fallback:
                                case PhpTypeCode.Double:
                                    codeGenerator.IL.Emit(OpCodes.Mul);
                                    returned_typecode = PhpTypeCode.Double;
                                    break;
                                default:
                                    codeGenerator.EmitBoxing(ro_typecode);
                                    returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Double_Object);
							        break;
                            }
                    
                            break;
                        default:
                            //Template: "x * y"  Operators.Multiply((object)x,y) [overloads]
                            codeGenerator.EmitBoxing(lo_typecode);

                            ro_typecode = rightExpr.Emit(codeGenerator);
					        switch (ro_typecode)
					        {
						        case PhpTypeCode.Integer:
							        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Int32);
							        break;

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

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

				case Operations.Mod:
					//Template: "x % y"        Operators.Remainder(x,y)
					codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
					ro_typecode = rightExpr.Emit(codeGenerator);
					switch (ro_typecode)
					{
						case PhpTypeCode.Integer:
							returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Int32);
							break;

						default:
							codeGenerator.EmitBoxing(ro_typecode);
							returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Object);
							break;
					}
					break;

				case Operations.ShiftLeft:

					// LOAD Operators.ShiftLeft(box left, box right);
					codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
					codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
					returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftLeft);
					break;

				case Operations.ShiftRight:

					// LOAD Operators.ShiftRight(box left, box right);
					codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
					codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
					returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftRight);
					break;

				#endregion

				#region Boolean and Bitwise Operations

				case Operations.And:
					returned_typecode = EmitBinaryBooleanOperation(codeGenerator, true);
					break;

				case Operations.Or:
					returned_typecode = EmitBinaryBooleanOperation(codeGenerator, false);
					break;

				case Operations.Xor:

					// LOAD <(bool) leftSon> == <(bool) rightSon>;
					codeGenerator.EmitConversion(leftExpr, PhpTypeCode.Boolean);
					codeGenerator.EmitConversion(rightExpr, PhpTypeCode.Boolean);
                    codeGenerator.IL.Emit(OpCodes.Ceq);

                    codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                    codeGenerator.IL.Emit(OpCodes.Ceq);

					returned_typecode = PhpTypeCode.Boolean;
					break;

				case Operations.BitAnd:
					returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.And);
					break;

				case Operations.BitOr:
					returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.Or);
					break;

				case Operations.BitXor:
					returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.Xor);
					break;

				#endregion

				#region Comparing Operations

				case Operations.Equal:

					// LOAD PhpComparer.Default.CompareEq
					returned_typecode = EmitComparison(codeGenerator, true);
					break;

				case Operations.NotEqual:

					// LOAD PhpComparer.Default.CompareEq == false
					EmitComparison(codeGenerator, true);
                    codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                    codeGenerator.IL.Emit(OpCodes.Ceq);

					returned_typecode = PhpTypeCode.Boolean;
					break;

				case Operations.GreaterThan:

					// LOAD PhpComparer.Default.Compare > 0;
					EmitComparison(codeGenerator, false);
                    codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                    codeGenerator.IL.Emit(OpCodes.Cgt);

					returned_typecode = PhpTypeCode.Boolean;
					break;

				case Operations.LessThan:

					// LOAD PhpComparer.Default.Compare < 0;
					EmitComparison(codeGenerator, false);
                    codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                    codeGenerator.IL.Emit(OpCodes.Clt);

					returned_typecode = PhpTypeCode.Boolean;
					break;

				case Operations.GreaterThanOrEqual:

					// LOAD PhpComparer.Default.Compare >= 0 (not less than)
					EmitComparison(codeGenerator, false);
                    codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                    codeGenerator.IL.Emit(OpCodes.Clt);
                    codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                    codeGenerator.IL.Emit(OpCodes.Ceq);

					returned_typecode = PhpTypeCode.Boolean;
					break;

				case Operations.LessThanOrEqual:

					// LOAD PhpComparer.Default.Compare >= 0 (not greater than)
					EmitComparison(codeGenerator, false);
                    codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                    codeGenerator.IL.Emit(OpCodes.Cgt);
                    codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                    codeGenerator.IL.Emit(OpCodes.Ceq);

					returned_typecode = PhpTypeCode.Boolean;
					break;

				case Operations.Identical:

					// LOAD Operators.StrictEquality(box left,box right);
					codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
					codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEquality);

					returned_typecode = PhpTypeCode.Boolean;
					break;

				case Operations.NotIdentical:

					// LOAD Operators.StrictEquality(box left,box right) == false;
					codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
					codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEquality);
                    codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                    codeGenerator.IL.Emit(OpCodes.Ceq);

					returned_typecode = PhpTypeCode.Boolean;
					break;

				#endregion

				case Operations.Concat:
					returned_typecode = ConcatEx.EmitConcat(codeGenerator, leftExpr, rightExpr);
					break;

				default:
					throw null;
			}

			switch (access)
			{
				case AccessType.Read:
					// Result is read, do nothing.
					break;

				case AccessType.None:
					// Result is not read, pop the result
                    codeGenerator.IL.Emit(OpCodes.Pop);
					returned_typecode = PhpTypeCode.Void;
					break;
			}

			return returned_typecode;
		}
Example #21
0
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override PhpTypeCode Emit(CodeGenerator/*!*/ codeGenerator)
		{
			// not emitted in release mode:
			Debug.Assert(kind != EvalKinds.LambdaFunction, "Invalid eval kind.");
			Debug.Assert(kind != EvalKinds.Assert || codeGenerator.Context.Config.Compiler.Debug, "Assert should be cut off in release mode.");
			Debug.Assert(access == AccessType.None || access == AccessType.Read || access == AccessType.ReadRef);
			Debug.Assert(inlinedCode != null || codeGenerator.RTVariablesTablePlace != null, "Function should have variables table.");
			Statistics.AST.AddNode("EvalEx");

			ILEmitter il = codeGenerator.IL;
            PhpTypeCode result;

			if (inlinedCode != null)
			{
				Debug.Assert(kind == EvalKinds.Assert, "Only assert can be inlined so far.");
				Label endif_label = il.DefineLabel();
				Label else_label = il.DefineLabel();

				// IF DynamicCode.PreAssert(context) THEN
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Call, Methods.DynamicCode.PreAssert);
				il.Emit(OpCodes.Brfalse, else_label);
				if (true)
				{
					// LOAD <evaluated assertion>;
					codeGenerator.EmitBoxing(((Expression)code).Emit(codeGenerator));

					// CALL DynamicCode.PostAssert(context);
					codeGenerator.EmitLoadScriptContext();
					il.Emit(OpCodes.Call, Methods.DynamicCode.PostAssert);

					// LOAD bool CheckAssertion(STACK, <inlined code>, context, <source path>, line, column);
					il.Emit(OpCodes.Ldstr, inlinedCode);
					codeGenerator.EmitLoadScriptContext();
					il.Emit(OpCodes.Ldstr, codeGenerator.SourceUnit.SourceFile.RelativePath.ToString());
					il.LdcI4(this.position.FirstLine);
					il.LdcI4(this.position.FirstColumn);
					codeGenerator.EmitLoadNamingContext();
					il.Emit(OpCodes.Call, Methods.DynamicCode.CheckAssertion);

					// GOTO END IF;
					il.Emit(OpCodes.Br, endif_label);
				}
				// ELSE
				il.MarkLabel(else_label);
				if (true)
				{
					// LOAD true;
					il.Emit(OpCodes.Ldc_I4_1);
				}
				// END IF;
				il.MarkLabel(endif_label);

                result = PhpTypeCode.Object;
			}
			else
			{
                result = codeGenerator.EmitEval(kind, code, position, currentNamespace, aliases);
			}

			// handles return value according to the access type:
			codeGenerator.EmitReturnValueHandling(this, false, ref result);
			return result;
		}
Example #22
0
		/// <summary>
		/// Emits call to a default comparator method.
		/// </summary>
		/// <param name="codeGenerator">A code generator.</param>
		/// <param name="equality">Whether to emit equality comparison (or generic comparison otherwise).</param>
		/// <returns>A type code of the result.</returns>
		private PhpTypeCode EmitComparison(CodeGenerator codeGenerator, bool equality)
		{
            PhpTypeCode x, y;
			// PhpComparer.Default.<CompareEq | Compare>(box left, box right <|, false>);
			/*changed to static method*/ //codeGenerator.IL.Emit(OpCodes.Ldsfld, Fields.PhpComparer_Default);
			
			if (equality)
			{
                return codeGenerator.EmitCompareEq(cg => this.leftExpr.Emit(cg), cg => this.rightExpr.Emit(cg));
			}
			else
			{
                x = leftExpr.Emit(codeGenerator);

                if (x == PhpTypeCode.Integer)
                {
                    y = rightExpr.Emit(codeGenerator);

                    // int, ?

                    if (y == PhpTypeCode.Integer)
                    {
                        // int, int
                        codeGenerator.IL.Emit(OpCodes.Call, Methods.CompareOp_int_int);
                        return PhpTypeCode.Integer;
                    }
                    else
                    {
                        codeGenerator.EmitBoxing(y);

                        // int, object
                        codeGenerator.IL.LdcI4(0);  // throws = false
                        codeGenerator.IL.Emit(OpCodes.Call, Methods.CompareOp_int_object_bool);
                        return PhpTypeCode.Integer;
                    }

                }
                else
                {
                    codeGenerator.EmitBoxing(x);

                    y = rightExpr.Emit(codeGenerator);

                    // object, ?

                    if (y == PhpTypeCode.Integer)
                    {
                        // object, int
                        codeGenerator.IL.LdcI4(0);  // throws = false
                        codeGenerator.IL.Emit(OpCodes.Call, Methods.CompareOp_object_int_bool);
                        return PhpTypeCode.Integer;
                    }
                    else
                    {
                        codeGenerator.EmitBoxing(y);

                        // object, object
                        codeGenerator.IL.LdcI4(0);  // throws = false
                        codeGenerator.IL.Emit(OpCodes.Call, Methods.CompareOp_object_object_bool);
                        return PhpTypeCode.Integer;
                    }
                }
			}
		}
Example #23
0
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override PhpTypeCode Emit(CodeGenerator/*!*/ codeGenerator)
		{
			Debug.Assert(access == AccessType.None || access == AccessType.Read);
			Statistics.AST.AddNode("ExitEx");

			codeGenerator.EmitLoadScriptContext();

			if (resultExpr == null)
			{
				codeGenerator.IL.Emit(OpCodes.Ldnull);
			}
			else
			{
				codeGenerator.EmitBoxing(resultExpr.Emit(codeGenerator));
			}
			codeGenerator.IL.Emit(OpCodes.Call, Methods.ScriptContext.Die);

			if (access == AccessType.Read)
			{
				codeGenerator.IL.Emit(OpCodes.Ldnull);
				return PhpTypeCode.Object;
			}
			else return PhpTypeCode.Void;
		}
Example #24
0
		/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
		internal override PhpTypeCode Emit(CodeGenerator/*!*/ codeGenerator)
		{
			Debug.Assert(access == AccessType.Read || access == AccessType.None);
			Statistics.AST.AddNode("UnaryEx");

			ILEmitter il = codeGenerator.IL;

			PhpTypeCode returned_typecode, o_typecode;

			switch (operation)
			{
				case Operations.AtSign:	// special arrangement
					// Template:
					//		context.DisableErrorReporting();
					//		s;
					//		context.EnableErrorReporting();
					codeGenerator.EmitLoadScriptContext();
					il.Emit(OpCodes.Call, Methods.ScriptContext.DisableErrorReporting);
					returned_typecode = expr.Emit(codeGenerator);
					codeGenerator.EmitLoadScriptContext();
					il.Emit(OpCodes.Call, Methods.ScriptContext.EnableErrorReporting);
					break;

				case Operations.BitNegation:
					//Template: "~x" Operators.BitNot(x)                                     
					codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
					il.Emit(OpCodes.Call, Methods.Operators.BitNot);
					returned_typecode = PhpTypeCode.Object;
					break;

				case Operations.Clone:
					// Template: clone x        Operators.Clone(x,DTypeDesc,ScriptContext)
					codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
					codeGenerator.EmitLoadClassContext();
					codeGenerator.EmitLoadScriptContext();
					il.Emit(OpCodes.Call, Methods.Operators.Clone);
					returned_typecode = PhpTypeCode.Object;
					break;

				case Operations.LogicNegation:
					//Template: "!x"  !Convert.ObjectToBoolean(x);                              
                    if (((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.Boolean))
                    {
                        codeGenerator.EmitBoxing(returned_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
                    }
					il.Emit(OpCodes.Ldc_I4_0);
					il.Emit(OpCodes.Ceq);
					returned_typecode = PhpTypeCode.Boolean;
					break;

				case Operations.Minus:
					//Template: "-x"  Operators.Minus(x)
                    switch (o_typecode = expr.Emit(codeGenerator))
                    {
                        case PhpTypeCode.Double:
                            il.Emit(OpCodes.Neg);
                            returned_typecode = PhpTypeCode.Double;
                            break;
                        default:
					        codeGenerator.EmitBoxing(o_typecode);
                            returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Minus);
					        break;
                    }
                    break;

				case Operations.ObjectCast:
					//Template: "(object)x"   Convert.ObjectToDObject(x,ScriptContext)
					codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
					codeGenerator.EmitLoadScriptContext();
					il.Emit(OpCodes.Call, Methods.Convert.ObjectToDObject);
					returned_typecode = PhpTypeCode.Object;
					break;

				case Operations.Plus:
					//Template: "+x"  Operators.Plus(x)
					codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
					il.Emit(OpCodes.Call, Methods.Operators.Plus);
					returned_typecode = PhpTypeCode.Object;
					break;

				case Operations.Print:
					codeGenerator.EmitEcho(this.expr);
					// Always returns 1
					il.Emit(OpCodes.Ldc_I4_1);
					returned_typecode = PhpTypeCode.Integer;
					break;

				case Operations.BoolCast:
					//Template: "(bool)x"     Convert.ObjectToBoolean(x)
                    if (((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.Boolean))
                    {
                        codeGenerator.EmitBoxing(returned_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
                        returned_typecode = PhpTypeCode.Boolean;
                    }
					break;

				case Operations.Int8Cast:
				case Operations.Int16Cast:
				case Operations.Int32Cast:
				case Operations.UInt8Cast:
				case Operations.UInt16Cast:
					// CALL int Convert.ObjectToInteger(<expr>)
                    o_typecode = expr.Emit(codeGenerator);
                    if (o_typecode != PhpTypeCode.Integer)
                    {
                        codeGenerator.EmitBoxing(o_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToInteger);
                    }

					// CONV for unsigned:
					switch (operation)
					{
						case Operations.UInt8Cast: il.Emit(OpCodes.Conv_U1); il.Emit(OpCodes.Conv_I4); break;
						case Operations.UInt16Cast: il.Emit(OpCodes.Conv_U2); il.Emit(OpCodes.Conv_I4); break;
					}

					returned_typecode = PhpTypeCode.Integer;
					break;

				case Operations.UInt64Cast:
				case Operations.UInt32Cast:
				case Operations.Int64Cast:
					// CALL long Convert.ObjectToLongInteger(<expr>)
                    o_typecode = expr.Emit(codeGenerator);
                    if (o_typecode != PhpTypeCode.LongInteger)
                    {
                        codeGenerator.EmitBoxing(o_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToLongInteger);
                    }

					// CONV for unsigned:
					switch (operation)
					{
						case Operations.UInt32Cast: il.Emit(OpCodes.Conv_U4); il.Emit(OpCodes.Conv_I8); break;
						case Operations.UInt64Cast: il.Emit(OpCodes.Conv_U8); il.Emit(OpCodes.Conv_I8); break;
					}

					returned_typecode = PhpTypeCode.LongInteger;
					break;

				case Operations.DecimalCast:
				case Operations.DoubleCast:
				case Operations.FloatCast:
					// CALL double Convert.ObjectToDouble(<expr>)
                    o_typecode = expr.Emit(codeGenerator);
                    if (o_typecode != PhpTypeCode.Double)
                    {
                        codeGenerator.EmitBoxing(o_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToDouble);
                    }
					returned_typecode = PhpTypeCode.Double;
					break;

				case Operations.UnicodeCast: // TODO
				case Operations.StringCast:
                    if ((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.String)
                    {
                        codeGenerator.EmitBoxing(returned_typecode);
                        //codeGenerator.EmitLoadClassContext();
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToString);
                        returned_typecode = PhpTypeCode.String;
                    }
					break;

                case Operations.BinaryCast:
                    if ((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.PhpBytes)
                    {
                        codeGenerator.EmitBoxing(returned_typecode);
                        //codeGenerator.EmitLoadClassContext();
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToPhpBytes);
                        returned_typecode = PhpTypeCode.PhpBytes;
                    }
                    break;

				case Operations.ArrayCast:
					//Template: "(array)x"   Convert.ObjectToArray(x)
                    o_typecode = expr.Emit(codeGenerator);
                    if (o_typecode != PhpTypeCode.PhpArray)
                    {
                        codeGenerator.EmitBoxing(o_typecode);
                        il.Emit(OpCodes.Call, Methods.Convert.ObjectToPhpArray);
                    }
					returned_typecode = PhpTypeCode.PhpArray;
					break;

				case Operations.UnsetCast:
					// Template: "(unset)x"  null
					il.Emit(OpCodes.Ldnull);
					returned_typecode = PhpTypeCode.Object;
					break;

				default:
					Debug.Assert(false, "illegal type of operation!");
					returned_typecode = PhpTypeCode.Void;
					break;
			}

			switch (access)
			{
				case AccessType.Read:
					// do nothing
					break;
				case AccessType.None:
					// pop operation's result value from stack
					if (returned_typecode != PhpTypeCode.Void)
						il.Emit(OpCodes.Pop);
					return PhpTypeCode.Void;
			}

			return returned_typecode;
		}
Example #25
0
		internal void Emit(CodeGenerator codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;
			string id = codeGenerator.GetLocationId();

			if (id == null)
			{
				// we are in global code -> just assign the iniVal to the variable
				variable.Emit(codeGenerator);

				if (initializer != null)
				{
					codeGenerator.EmitBoxing(initializer.Emit(codeGenerator));
					il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
				}
				else il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);

				variable.EmitAssign(codeGenerator);
			}
			else
			{
                // (J): cache the integer index of static local variable to access its value fast from within the array

                // unique static local variable string ID
				id = String.Format("{0}${1}${2}${3}", id, variable.VarName, position.FirstLine, position.FirstColumn);

                // create static field for static local index: private static int <id>;
                var type = codeGenerator.IL.TypeBuilder;
                Debug.Assert(type != null, "The method does not have declaring type! (global code in pure mode?)");
                var field_id = type.DefineField(id, Types.Int[0], System.Reflection.FieldAttributes.Private | System.Reflection.FieldAttributes.Static);

				// we are in a function or method -> try to retrieve the local value from ScriptContext
				variable.Emit(codeGenerator);

                // <context>.GetStaticLocal( <field> )
                codeGenerator.EmitLoadScriptContext();  // <context>
                il.Emit(OpCodes.Ldsfld, field_id);         // <field>
                il.Emit(OpCodes.Callvirt, Methods.ScriptContext.GetStaticLocal);    // GetStaticLocal
                il.Emit(OpCodes.Dup);

                // ?? <context>.AddStaticLocal( <field> != 0 ? <field> : ( <field> = ScriptContext.GetStaticLocalId(<id>) ), <initializer> )
                if (true)
                {
                    // if (GetStaticLocal(<field>) == null)
                    Label local_initialized = il.DefineLabel();
                    il.Emit(OpCodes.Brtrue/*not .S, initializer can emit really long code*/, local_initialized);

                    il.Emit(OpCodes.Pop);
                    
                    // <field> != 0 ? <field> : ( <field> = ScriptContext.GetStaticLocalId(<id>) )
                    il.Emit(OpCodes.Ldsfld, field_id);         // <field>

                    if (true)
                    {
                        // if (<field> == 0)
                        Label id_initialized = il.DefineLabel();
                        il.Emit(OpCodes.Brtrue_S, id_initialized);

                        // <field> = GetStaticLocalId( <id> )
                        il.Emit(OpCodes.Ldstr, id);
                        il.Emit(OpCodes.Call, Methods.ScriptContext.GetStaticLocalId);
                        il.Emit(OpCodes.Stsfld, field_id);

                        il.MarkLabel(id_initialized);
                    }

                    // <context>.AddStaticLocal(<field>,<initialize>)
                    codeGenerator.EmitLoadScriptContext();  // <context>
                    il.Emit(OpCodes.Ldsfld, field_id);         // <field>
                    if (initializer != null) codeGenerator.EmitBoxing(initializer.Emit(codeGenerator)); // <initializer>
				    else il.Emit(OpCodes.Ldnull);
                    il.Emit(OpCodes.Callvirt, Methods.ScriptContext.AddStaticLocal);    // AddStaticLocal

                    // 
                    il.MarkLabel(local_initialized);
                }

                // (J) Following code used Dictionary. It was replaced by the code above.
                /*
                codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Ldstr, id);
				il.Emit(OpCodes.Call, Methods.ScriptContext.GetStaticLocal);

				Label reference_gotten = codeGenerator.IL.DefineLabel();
				il.Emit(OpCodes.Dup);
				il.Emit(OpCodes.Brtrue, reference_gotten);
				il.Emit(OpCodes.Pop);

				// this is the first time execution reach the statement for current request -> initialize the local
				codeGenerator.EmitLoadScriptContext();
				il.Emit(OpCodes.Ldstr, id);

				if (initializer != null)
					codeGenerator.EmitBoxing(initializer.Emit(codeGenerator));
				else
					il.Emit(OpCodes.Ldnull);

				il.Emit(OpCodes.Call, Methods.ScriptContext.AddStaticLocal);
                
				// assign the resulting PhpReference into the variable
				il.MarkLabel(reference_gotten, true);
                */

				variable.EmitAssign(codeGenerator);
			}
		}
Example #26
0
		private PhpTypeCode EmitNodeReadUnknown(CodeGenerator codeGenerator)
		{
			if (codeGenerator.ChainBuilder.IsMember)
			{
				// 1,4,5,6,9
				if (this.isMemberOf != null)
				{
					// 1: ...->$a->...
					codeGenerator.ChainBuilder.Lengthen(); // for hop over ->
					PhpTypeCode res = isMemberOf.Emit(codeGenerator);
					if (res != PhpTypeCode.PhpRuntimeChain)
					{
						codeGenerator.EmitBoxing(res);
						codeGenerator.ChainBuilder.EmitCreateRTChain();
					}
					codeGenerator.ChainBuilder.EmitRTChainAddField(this);
					return PhpTypeCode.PhpRuntimeChain;
				}

				if (codeGenerator.ChainBuilder.IsArrayItem && !codeGenerator.ChainBuilder.IsLastMember)
				{
					// 6: $b->${"a"}[3]
					codeGenerator.ChainBuilder.EmitRTChainAddField(this);
					return PhpTypeCode.PhpRuntimeChain;
				}

				// 4: ${"a"}[][] 
				// 5: $$a->b->c->... 
				// 9: $$a->b
				this.EmitLoadRef(codeGenerator);
				codeGenerator.ChainBuilder.EmitCreateRTChain();
				return PhpTypeCode.PhpRuntimeChain;
			}
			// 2,3,7,8
			if (this.isMemberOf != null)
			{
				// 2: $b->$a
				// 8: b[]->$a
				codeGenerator.ChainBuilder.Create();
				codeGenerator.ChainBuilder.Begin();
				codeGenerator.ChainBuilder.Lengthen(); // for hop over ->
				PhpTypeCode res = isMemberOf.Emit(codeGenerator);
				if (res != PhpTypeCode.PhpRuntimeChain)
				{
					codeGenerator.EmitBoxing(res);
					codeGenerator.ChainBuilder.EmitCreateRTChain();
				}
				codeGenerator.ChainBuilder.EmitRTChainAddField(this);
				codeGenerator.ChainBuilder.End();
				return PhpTypeCode.PhpRuntimeChain;
			}

			// 3: ${"a"}[3]
			// 7: $$a
			this.EmitLoadRef(codeGenerator);
			return PhpTypeCode.PhpReference;
		}
Example #27
0
		/// <summary>
		/// Emits the literal. The common code for all literals.
		/// </summary>
		internal override PhpTypeCode Emit(CodeGenerator/*!*/ codeGenerator)
		{
			ILEmitter il = codeGenerator.IL;

			// loads the value:
			il.LoadLiteral(Value);

			switch (access)
			{
				case AccessType.Read:
					return ValueTypeCode;

				case AccessType.None:
					il.Emit(OpCodes.Pop);
					return ValueTypeCode;

				case AccessType.ReadUnknown:
				case AccessType.ReadRef:
					// created by evaluation a function called on literal, e.g. $x =& sin(10);
					codeGenerator.EmitBoxing(ValueTypeCode);
					il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);

					return PhpTypeCode.PhpReference;
			}

			Debug.Fail("Invalid access type");
			return PhpTypeCode.Invalid;
		}